Skip to content

Commit

Permalink
[FE] - 메인 페이지 및 API 연결 (#124)
Browse files Browse the repository at this point in the history
* feat: 메인 페이지 UI 컴포넌트 추가

- FloatingSquare, FloatingQuestion 컴포넌트 추가
- floating 애니메이션 추가

* feat: 메인 페이지 UI 변경

* feat: 응답값이 없는 경우, 분기 처리

* feat: 클래스 리스트 get, 클래스 생성 api 추가 및 적용

* style: 스타일 변경

* refactor: 레이아웃 수정

- HostLayout 사이드바 삭제
- 헤더에서 로그아웃, 세팅 버튼 삭제

* fix: 오타 수정

- elasped에서 elapsed로 변경

* fix: 라우트 수정

* feat: input에 value값 추가

* feat: useCreateQuiz 추가

- classId를 useParams로 받음

* feat: 퀴즈 타이틀 모달 로직 추가

- 아직 완성되지 않은 api 미연결

* feat: 퀴즈 번호 로직 수정

* feat: 퀴즈 시작 아이디 argument로 추가

* style: input 백그라운드 색상 변경

* feat: Get quiz 연결, Post class response 연결
  • Loading branch information
dooohun authored Nov 26, 2024
1 parent cd2d629 commit 0f59044
Show file tree
Hide file tree
Showing 23 changed files with 377 additions and 137 deletions.
4 changes: 0 additions & 4 deletions packages/client/src/app/layouts/HostLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { Outlet } from 'react-router-dom';

import Header from '@/shared/ui/header/Header';
import SideNav from '@/shared/ui/side-nav/SideNav';
import SideBar from '@/shared/ui/side-bar/SideBar';

export default function HostLayout() {
return (
<div>
<Header classTitle="클래스 이름" />
<div className="flex">
<SideNav />
<SideBar title="클래스 이름" />
<Outlet />
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/app/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function Router() {
<Route path="/" element={<MainPage />} />
<Route element={<HostLayout />}>
<Route path="/quiz-list" element={<QuizList />} />
<Route path="/quiz/create" element={<QuizCreatePage />} />
<Route path="/quiz/create/:classId" element={<QuizCreatePage />} />
<Route path="/questions" element={<QnA />} />
</Route>
<Route element={<GuestLayout />}>
Expand Down
71 changes: 55 additions & 16 deletions packages/client/src/pages/main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { toastController } from '@/features/toast/model/toastController';
import { getPincodeExist } from '@/shared/api/games';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import FloatingSquare from './ui/FloatingSquare';
import FloatingQuestion from './ui/FloatingQuestion';

export default function MainPage() {
const [pinCode, setPinCode] = useState<string>('');
Expand All @@ -22,36 +24,73 @@ export default function MainPage() {
handleClick();
}
};

const handleCreateQuiz = () => {
navigate('quiz-list');
};
return (
<section className="min-h-screen flex flex-col items-center">
<h1 className="text-6xl font-bold text-primary mt-32 mb-24">You Quiz</h1>
<div className="w-full max-w-4xl px-4">
<div className="w-full flex justify-between border-[1.5px] border-primary rounded-xl p-2">
<div className="relative min-h-screen bg-gradient-to-br from-blue-50 via-sky-50 to-blue-100 flex flex-col items-center justify-center p-8 overflow-hidden">
<FloatingSquare
color="from-yellow-300/80 to-yellow-400/80"
size="128"
position="top-20 left-[20%]"
delay={0}
/>
<FloatingSquare
color="from-green-300/80 to-green-400/80"
size="160"
position="top-40 right-[20%]"
delay={0.5}
/>
<FloatingSquare
color="from-blue-400/80 to-blue-500/80"
size="192"
position="bottom-20 left-[20%]"
delay={1}
/>
<FloatingSquare
color="from-pink-300/80 to-pink-400/80"
size="144"
position="bottom-40 right-[20%]"
delay={1.5}
/>
<FloatingQuestion position="top-[170px] right-1/3" delay={0} />
<div className="text-center mb-12 z-10">
<h1 className="text-6xl font-bold bg-gradient-to-r from-blue-500 via-sky-500 to-blue-600 text-transparent bg-clip-text mb-4">
You Quiz
</h1>
<p className="text-xl text-blue-600/70">함께 만드는 즐거운 퀴즈 시간</p>
</div>
<div className="w-[720px] bg-white/80 backdrop-blur-xl px-6 py-3 rounded-3xl shadow-xl border border-blue-100 mb-8 transition-transform duration-200 hover:scale-[1.02]">
<div className="flex gap-3">
<input
type="text"
placeholder="Join Code"
className="w-3/4 border-none outline-none p-3 bg-transparent"
placeholder="참가 코드를 입력하세요"
className="flex-1 h-14 text-lg rounded-xl bg-transparent border-blue-200 focus:border-blue-400 focus:ring-blue-400 text-blue-600 placeholder:text-blue-300 focus:outline-none"
value={pinCode}
onChange={(e) => setPinCode(e.target.value)}
onKeyDown={handleKeyDown}
/>
<button
className="bg-primary text-white text-md font-semibold rounded-xl py-2 px-6"
className={`h-14 px-8 bg-gradient-to-r from-blue-500 to-sky-500 ${pinCode ? 'hover:from-blue-600 hover:to-sky-600' : ''} rounded-xl text-white shadow-lg shadow-blue-500/30`}
disabled={!pinCode}
onClick={handleClick}
>
퀴즈 참가하기
</button>
</div>
</div>

<div className="mt-4">
<button className="px-6 py-2 text-primary border border-weak rounded-full hover:bg-primary-light">
로그인
</button>
<button className="px-6 py-2 text-primary border border-weak rounded-full hover:bg-primary-light">
회원가입
</button>
<div className="text-center space-y-4 mt-16">
<p className="text-lg text-blue-600/70">나만의 특별한 퀴즈로 새로운 경험을 만들어보세요!</p>
<div className="flex-1 transition-transform duration-200 hover:scale-105 active:scale-95">
<button
className="w-[350px] h-12 bg-white/70 hover:bg-white/90 backdrop-blur-xl border-blue-200 text-blue-600 hover:text-blue-700 rounded-lg"
onClick={handleCreateQuiz}
>
퀴즈 만들기
</button>
</div>
</div>
</section>
</div>
);
}
24 changes: 24 additions & 0 deletions packages/client/src/pages/main/ui/FloatingQuestion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import MessageIcon from '@/shared/assets/icons/circle-message.svg?react';

interface FloatingQuestionProps {
delay: number;
position: string;
}

export default function FloatingQuestion({ delay, position }: FloatingQuestionProps) {
return (
<div
style={{
animationDelay: `${delay}s`,
}}
className={`absolute ${position} text-4xl w-32 h-32 font-bold text-white/30 animate-floating`}
>
<div className="relative w-full h-full">
<MessageIcon stroke="#3b82f6" className="w-full h-full opacity-20" />
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-3xl font-bold text-blue-500 opacity-40">
?
</div>
</div>
</div>
);
}
15 changes: 15 additions & 0 deletions packages/client/src/pages/main/ui/FloatingSquare.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface FloatingSquareProps {
color: string;
size: string;
position: string;
delay: number;
}

export default function FloatingSquare({ color, size, position, delay }: FloatingSquareProps) {
return (
<div
style={{ width: `${size}px`, height: `${size}px`, animationDelay: `${delay}s` }}
className={`absolute ${position} rounded-2xl animate-floating delay-${delay} drop-shadow-sm backdrop-blur bg-gradient-to-br ${color}`}
/>
);
}
30 changes: 20 additions & 10 deletions packages/client/src/pages/quiz-create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { useState } from 'react';
import { CustomButton } from '@/shared/ui/buttons';
import PlusIcon from '@/shared/assets/icons/plus.svg?react';
import QuizCreateSection from './ui/QuizCreateSection';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import { useCreateQuiz } from '@/shared/hooks/quizzes';

interface Choice {
content: string;
Expand Down Expand Up @@ -33,8 +34,10 @@ const INITIAL_QUIZ_VALUE: QuizData = {
};

export default function QuizCreatePage() {
const { classId } = useParams();
const [currentQuizIndex, setCurrentQuizIndex] = useState(0);
const [quizzes, setQuizzes] = useState<QuizData[]>([INITIAL_QUIZ_VALUE]);
const mutation = useCreateQuiz();
const navigate = useNavigate();

const addNewQuiz = () => {
Expand All @@ -52,8 +55,22 @@ export default function QuizCreatePage() {
setCurrentQuizIndex((prev) => prev + 1);
};

const handleCreateQuiz = () => {
const quizzesData = {
quizzes: quizzes,
};
mutation.mutate(
{ quizData: quizzesData, classId: Number(classId) },
{
onSuccess: () => {
navigate('/quiz-list');
},
},
);
};

return (
<div className="flex flex-col w-full mt-6 mr-6">
<div className="flex flex-col w-full mt-6 mx-6">
<div className=" flex gap-4 bg-white rounded-base p-4 mb-4">
<button className="text-weak-md" onClick={handlePreQuiz}>
이전 문제
Expand All @@ -63,7 +80,6 @@ export default function QuizCreatePage() {
</button>
<div className="flex-1 flex justify-end text-weak-md">문제 유형</div>
</div>

<QuizCreateSection
key={currentQuizIndex}
currentQuizIndex={currentQuizIndex}
Expand All @@ -76,7 +92,6 @@ export default function QuizCreatePage() {
});
}}
/>

<div className="self-start mt-10">
<CustomButton
Icon={PlusIcon}
Expand All @@ -92,12 +107,7 @@ export default function QuizCreatePage() {
/>
</div>
<div className="self-end mr-6">
<CustomButton
label="퀴즈 발행하기"
onClick={() => {
navigate('/quiz-list');
}}
/>
<CustomButton label="퀴즈 발행하기" onClick={handleCreateQuiz} />
</div>
</div>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/client/src/pages/quiz-create/ui/AnswerBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import ToggleButton from '@/shared/ui/buttons/ToggleButton';
interface AnswerBoxProps {
/**정답 체크된 상태인지 여부 */
selected: boolean;

value?: string;
/**정답 선택 함수 */
answerSetter: () => void;
/**선지 설정 함수 */
Expand All @@ -20,6 +22,7 @@ export default function AnswerBox({
optionSetter,
inputRef,
onKeyDown,
value,
}: AnswerBoxProps) {
return (
<div className="flex items-center gap-4 ">
Expand All @@ -35,6 +38,7 @@ export default function AnswerBox({
placeholder="선지를 입력해주세요"
type="underline"
ref={inputRef}
initialValue={value}
onKeyDown={onKeyDown}
onSubmit={optionSetter}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function QuizCreateSection({
};

return (
<section className="">
<section>
<article className="min-w-content min-h-[532px] flex flex-col gap-1 items-center bg-white rounded-base p-6">
<p className="self-start relative">
<span className="text-weak-md mr-3">{`${currentQuizIndex + 1}번 퀴즈`}</span>
Expand All @@ -61,6 +61,7 @@ export default function QuizCreateSection({
placeholder="문제를 입력해주세요"
type="box"
onSubmit={(value) => onQuizUpdate({ ...quizData, content: value })}
initialValue={quizData.content}
/>
</p>
<div className="flex flex-col gap-4 w-full mt-10">
Expand All @@ -76,6 +77,7 @@ export default function QuizCreateSection({
onKeyDown={(e) => {
handleKeyDown(index, e);
}}
value={choice.content}
/>
))}
</div>
Expand Down
Loading

0 comments on commit 0f59044

Please sign in to comment.