Merge branch 'fe/fixLiveQuiz' into 'frontend'

[Front-End] 퀴즈 API 변경사항 반영

See merge request s11-webmobile1-sub2/S11P12A701!86
This commit is contained in:
정기영 2024-08-07 14:29:37 +09:00
commit 4035fbb250
7 changed files with 65 additions and 22 deletions

View File

@ -69,7 +69,7 @@ export default function ChatRoom({ isTeacher, ...props }) {
<>
<div
{...props}
className={`lk-chat ${wsChat.quizSetId ? styles.none : ''}`}
className={`lk-chat ${wsChat.quizSetInfo ? styles.none : ''}`}
>
<header className={styles.header}>
<h2 className={styles.title}>채팅</h2>
@ -131,15 +131,16 @@ export default function ChatRoom({ isTeacher, ...props }) {
</button>
</form>
</div>
{wsChat.quizSetId && (
{wsChat.quizSetInfo && (
<div className="lk-chat">
<header className={styles.header}>
<h2 className={styles.title}>퀴즈</h2>
</header>
<Suspense fallback={<></>}>
<QuizSet
quizSetId={wsChat.quizSetId}
finish={() => wsChat.setQuizSetId(null)}
quizSetId={wsChat.quizSetInfo[0]}
reportSetId={wsChat.quizSetInfo[1]}
finish={() => wsChat.setQuizSetInfo(null)}
/>
</Suspense>
</div>

View File

@ -0,0 +1,22 @@
import { useEffect, useState } from 'react';
export default function Countdown({ seconds }) {
// eslint-disable-next-line no-undef
const [remainedTime, setRemainedTime] = useState(seconds);
useEffect(() => {
const interval = setInterval(() => {
setRemainedTime((prev) => {
if (prev === 0) {
clearInterval(interval);
return 0;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}, [remainedTime]);
return <span>{remainedTime}</span>;
}

View File

@ -2,6 +2,7 @@
display: flex;
flex-direction: column;
justify-content: space-between;
min-width: 1360px;
min-height: 100vh;
}

View File

@ -1,14 +1,13 @@
import styles from './QuizSet.module.css';
import { useCallback, useEffect, useRef, useState } from 'react';
import Quiz from '../Quiz/Quiz';
import { useParams } from 'react-router-dom';
import LoadingIndicator from '../LoadingIndicator.jsx/LoadingIndicator';
import instance from '../../utils/axios/instance';
import { API_URL } from '../../constants';
import { useStudentQuizsetDetail } from '../../hooks/api/useStudentQuizsetDetail';
import Countdown from '../Countdown/Countdown';
export default function QuizSet({ quizSetId, finish }) {
const { roomId } = useParams();
export default function QuizSet({ quizSetId, reportSetId, finish }) {
const [step, setStep] = useState(null);
const { data } = useStudentQuizsetDetail(quizSetId);
const quizSetData = data?.data;
@ -20,9 +19,9 @@ export default function QuizSet({ quizSetId, finish }) {
const requestData = {
answer: data,
};
instance.post(`${API_URL}/report/submit/${roomId}/quizset/${quizSetId}`, requestData).catch(() => {});
instance.post(`${API_URL}/report/submit/${reportSetId}/quizset/${quizSetId}`, requestData).catch(() => {});
},
[quizSetId, roomId]
[quizSetId, reportSetId]
);
const QuizComponents = [
...quizList.map((quiz, index) => (
@ -39,7 +38,10 @@ export default function QuizSet({ quizSetId, finish }) {
key={Infinity}
className={styles.message}
>
퀴즈 종료
<div>
<div>퀴즈 종료!</div>
<div className={styles.subMsg}>답안을 전송하고 있어요</div>
</div>
</div>,
];
@ -80,7 +82,9 @@ export default function QuizSet({ quizSetId, finish }) {
<>
{step === null ? (
<div className={styles.message}>
<span>10 퀴즈를 시작합니다.</span>
<span>
<Countdown seconds={10} /> 퀴즈를 시작합니다.
</span>
<LoadingIndicator />
</div>
) : (

View File

@ -17,6 +17,7 @@
gap: 32px;
width: 100%;
height: 100%;
text-align: center;
font-size: 24px;
font-style: normal;
font-weight: 700;
@ -42,3 +43,22 @@
transform-origin: left center;
animation: progress 10s linear infinite;
}
@keyframes shake {
0% {
rotate: -2.5deg;
}
100% {
rotate: 2.5deg;
}
}
.subMsg {
margin-top: 8px;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: 1.5;
color: #ccc;
animation: shake 1s ease-in-out alternate-reverse infinite;
}

View File

@ -3,8 +3,6 @@ import { chatClient } from '../../utils/chat/chatClient';
import useBoundStore from '../../store';
import { useQuizsets } from '../api/useQuizsets';
const USER_ID = crypto.getRandomValues(new Uint32Array(1))[0];
export default function useChatRoom(roomId) {
const client = chatClient;
const [messages, setMessages] = useState([]);
@ -13,13 +11,12 @@ export default function useChatRoom(roomId) {
const chatListRef = useRef(null);
const { data: quizSetData } = useQuizsets();
const quizSets = quizSetData?.data ?? [];
const [quizSetId, setQuizSetId] = useState(null);
const [quizSetInfo, setQuizSetInfo] = useState(null);
const startQuiz = (quizSetId) => {
chatClient.publish({
destination: `/pub/chat.quiz.${roomId}`,
body: JSON.stringify({
userId: USER_ID,
quizSetId,
}),
});
@ -36,7 +33,6 @@ export default function useChatRoom(roomId) {
chatClient.publish({
destination: `/pub/chat.message.${roomId}`,
body: JSON.stringify({
userId: USER_ID,
name: userName,
content: text,
}),
@ -48,13 +44,13 @@ export default function useChatRoom(roomId) {
client.onConnect = () => {
client.subscribe(`/exchange/chat.exchange/*.room.${roomId}`, (response) => {
const data = JSON.parse(response.body);
const { content: message, name, quizSetId } = data;
const { content: message, name, quizSetId, reportSetId } = data;
if (quizSetId !== undefined) {
setQuizSetId(quizSetId);
setQuizSetInfo([quizSetId, reportSetId]);
return;
}
setMessages((prev) => [...prev, { id: prev.length, text: message, isMine: USER_ID === data.userId, name }]);
setMessages((prev) => [...prev, { id: prev.length, text: message, name }]);
});
};
client.activate();
@ -77,7 +73,7 @@ export default function useChatRoom(roomId) {
chatListRef,
startQuiz,
quizSets,
quizSetId,
setQuizSetId,
quizSetInfo,
setQuizSetInfo,
};
}

View File

@ -167,7 +167,6 @@ body {
sans-serif;
margin: 0;
padding: 0;
min-width: 1360px;
}
a {