Skip to content

Commit

Permalink
Merge pull request #45 from modern-agile-team/publish/#34/Quiz_page
Browse files Browse the repository at this point in the history
퀴즈페이지 레이아웃 완성
  • Loading branch information
rhehfl authored Oct 13, 2024
2 parents 165a9e6 + b2faa3f commit 4a79f10
Show file tree
Hide file tree
Showing 13 changed files with 357 additions and 1 deletion.
95 changes: 95 additions & 0 deletions src/features/Quiz/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import styled from 'styled-components';

//문제(Quiz)의 제목(title)과 문항(question)이 들어갈 공간
export const QuestionSection = styled.section`
display: flex;
flex-direction: column;
height: 343px;
margin-top: 22px;
border-radius: 2px;
border: 1px solid #afb1b6;
background: #efeff0;
grid-column: 3;
font-size: 1rem;
`;
//답을 적거나 클릭하는 영역을 잡는 스타일
interface ResponseBoxProps {
$gapColumn?: string;
$gridColumn?: string;
$justifyContent?: string;
}

export const ResponseBoxSection = styled.section<ResponseBoxProps>`
display: flex;
justify-content: ${({ $justifyContent }) => $justifyContent || 'center'};
align-items: center;
flex-wrap: wrap;
background: #efeff0;
grid-column: ${({ $gridColumn }) => $gridColumn || 3};
margin-top: 20px;
border-radius: 2px;
border: 1px solid #afb1b6;
column-gap: ${({ $gapColumn }) => $gapColumn || '0px'};
`;
//캐릭터가 들어갈 박스
interface CharacterBoxProps {
$margin: string;
}

export const CharacterBox = styled.div<CharacterBoxProps>`
width: 176px;
height: 115.757px;
border: 2px solid #afb1b6;
background: #efeff0;
margin: ${({ $margin }) => $margin || '0'};
border-radius: 8px;
`;
//ox유형에서 ox버튼
export const OXButton = styled.button`
width: 110px;
height: 108px;
border-radius: 10px;
`;
//객관식에서 각 문항 버튼
export const MultipleChoiceQuestionButton = styled.button`
width: 372px;
height: 26px;
border-radius: 8px;
background: #19191b;
color: #ffffff;
margin-top: 13px;
`;
//단답형 문항에서 단답형을 쓰는 인풋박스
export const ShortAnswerInput = styled.input`
width: 372px;
height: 23px;
`;
//블럭유형에서 리스트박스를 잡는 리스트 박스
export const CombinationUl = styled.ul`
display: flex;
grid-column: 3;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
margin: 49px 0 0 0;
padding: 0;
:nth-last-child(1) {
margin-right: auto;
}
`;

//블럭유형에서 각 텍스트에 해당하는 리스트 스타일
export const TextBlockLi = styled.li`
border-radius: 8px;
background: #19191b;
color: #ffffff;
list-style-type: none;
padding: 0 20px;
height: 26px;
`;
//화면 하단의
export const ResponseButton = styled.button`
width: 94px;
height: 26px;
border-radius: 24px;
`;
13 changes: 13 additions & 0 deletions src/features/Quiz/ui/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
interface ButtonProps {
buttonName: string;
handleClick: () => void;
}
import { ResponseButton } from '../styles';
export default function Button({ buttonName, handleClick }: ButtonProps) {
//답을 제출하고
return (
<>
<ResponseButton onClick={handleClick}>{buttonName}</ResponseButton>
</>
);
}
14 changes: 14 additions & 0 deletions src/features/Quiz/ui/Combination.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Quiz from '../../../types/Quiz';
import { CombinationUl, TextBlockLi } from '../styles';

export default function Combination({
answerChoice,
}: Pick<Quiz, 'answerChoice'>) {
return (
<CombinationUl>
{answerChoice.map(value => (
<TextBlockLi>{value}</TextBlockLi>
))}
</CombinationUl>
);
}
15 changes: 15 additions & 0 deletions src/features/Quiz/ui/MultipleChoice.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Quiz from '../../../types/Quiz';
import { MultipleChoiceQuestionButton, ResponseBoxSection } from '../styles';
export default function MultipleChoice({
answerChoice,
}: Pick<Quiz, 'answerChoice'>) {
return (
<ResponseBoxSection $gapColumn="20px" $gridColumn="2/5">
{answerChoice.map((value, index) => (
<MultipleChoiceQuestionButton key={index}>
{index + 1} : {value}
</MultipleChoiceQuestionButton>
))}
</ResponseBoxSection>
);
}
13 changes: 13 additions & 0 deletions src/features/Quiz/ui/OXSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { OXButton, CharacterBox, ResponseBoxSection } from '../styles';
export default function OXSelector() {
//OX버튼을 눌러 답을 제출함
return (
<>
<ResponseBoxSection>
<OXButton></OXButton>
<CharacterBox $margin="0px 102px">캐릭터 들어갈예정</CharacterBox>
<OXButton></OXButton>
</ResponseBoxSection>
</>
);
}
15 changes: 15 additions & 0 deletions src/features/Quiz/ui/Question.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { QuestionSection } from './../styles';
interface questiontype {
title: string;
question: string;
}
export default function Question({ title, question }: questiontype) {
return (
<>
<QuestionSection>
<div>title: {title} </div>
<div>question: {question}</div>
</QuestionSection>
</>
);
}
10 changes: 10 additions & 0 deletions src/features/Quiz/ui/ShortAnswer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { ResponseBoxSection, ShortAnswerInput } from '../styles';
import { CharacterBox } from '../styles';
export default function ShortAnswer() {
return (
<ResponseBoxSection $justifyContent="flex-end">
<ShortAnswerInput type="text"></ShortAnswerInput>
<CharacterBox $margin="0px 0px 0px 118px" />
</ResponseBoxSection>
);
}
100 changes: 100 additions & 0 deletions src/pages/Quiz/Quiz.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import Question from '../../features/Quiz/ui/Question';

import { AlignCenter } from '../../style/LayOut';
import {
GridContainer,
HeaderSection,
ProgressSection,
FooterSection,
} from './styles';
import type Quiz from '../../types/Quiz';
import { useClientQuizStore } from '../../store/useQuizStore';
import Button from '../../features/Quiz/ui/Button';
import Combination from '../../features/Quiz/ui/Combination';
import MultipleChoice from '../../features/Quiz/ui/MultipleChoice';
import OXSelector from '../../features/Quiz/ui/OXSelector';
import ShortAnswer from '../../features/Quiz/ui/ShortAnswer';
import componentMapping from '../../utils/componentMap';

//퀴즈페이지
export default function Quiz() {
// const { section, part } = useParams();
const { currentPage, handleNextPage } = useClientQuizStore();
//대충 가져온 문제들
const quiz: Quiz[] = [
//예시 1섹션 1파트에 문제 4개
//단답형
{
id: 1,
partId: 1,
sectionId: 1,
title: '실행결과를 쓰시오',
question: 'console.log(1 + 2)',
answer: ['3'],
category: 'ShortAnswer',
answerChoice: [''],
},
//객관식
{
id: 2,
partId: 1,
sectionId: 1,
title: '실행결과를 쓰시오',
question: 'console.log(1 + 2)',
answer: ['3'],
category: 'MultipleChoice',
answerChoice: ['1', '4', '3', '7'],
},
//ox유형
{
id: 3,
partId: 1,
sectionId: 1,
title: 'OX문제',
question: '1 은 number타입이다?',
answer: ['O'],
category: 'OXSelector',
answerChoice: [''],
},
//조합형
{
id: 4,
partId: 1,
sectionId: 1,
title: '빈칸을 채우시오',
question: '[ ].log([ ])',
answer: ['3'],
category: 'Combination',
answerChoice: ['console', '1+2', 'function', '어쩌구저쩌구', '두두두두'],
},
];
const { title, question, category, answer, answerChoice } = quiz[currentPage];

const { choice } = componentMapping<Pick<Quiz, 'answerChoice'>>({
//조합식
Combination,
//객관식
MultipleChoice,
//ox
OXSelector,
//단답형
ShortAnswer,
});
return (
<AlignCenter>
<GridContainer>
<HeaderSection>
<div>로고</div>
<div>돈-??-프사 </div>
</HeaderSection>
<ProgressSection>진행도</ProgressSection>
<Question title={title} question={question}></Question>
{choice(category, { answerChoice })}
<FooterSection>
<Button buttonName={'스킵버튼'} handleClick={handleNextPage} />
<Button buttonName={'답 제출'} handleClick={handleNextPage} />
</FooterSection>
</GridContainer>
</AlignCenter>
);
}
37 changes: 37 additions & 0 deletions src/pages/Quiz/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from 'styled-components';
//그리드 나누기용 width는 나중에 글로벌스타일 들어오면 지우기
export const GridContainer = styled.div`
display: grid;
width: 1280px;
grid-template-columns: 98px 98px 764px 98px 98px;
column-gap: 20px;
`;
//헤더 영역잡기용 나중에 헤더 생기면 지우기
export const HeaderSection = styled.section`
display: flex;
grid-column: 2/6;
top: 0;
margin-top: 42px;
justify-content: space-between;
background-color: gray;
height: 42px;
`;
//진행도 영역잡기용 나중에 진행도 컴포넌트 분리되면 지우기
export const ProgressSection = styled.section`
height: 20px;
grid-column: 3;
background-color: red;
text-align: center;
margin-top: 34px;
border-radius: 2px;
border: 1px solid #afb1b6;
`;
//푸터 영역잡기
export const FooterSection = styled.section`
display: flex;
height: 108px;
align-items: center;
justify-content: space-between;
grid-column: 3;
margin-top: 19px;
`;
4 changes: 3 additions & 1 deletion src/route/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BrowserRouter, Route, Routes } from 'react-router-dom';
import Main from '../pages/main/Main';
import Quest from '../pages/Quest/Quest';
import Ranking from '../pages/Ranking/Ranking';
import Quiz from '../pages/Quiz/Quiz';
import Admin from '../admin/Admin';
import CreateQuiz from '../admin/CreateQuiz';
export default function Router() {
Expand All @@ -11,7 +12,8 @@ export default function Router() {
<Routes>
<Route path="/" element={<Main />}></Route>
<Route path="/quest" element={<Quest />}></Route>
<Route path="/Ranking" element={<Ranking />}></Route>
<Route path="/ranking" element={<Ranking />}></Route>
<Route path="/quiz/:section/:part" element={<Quiz />}></Route>
{/*어드민 페이지 부분 문제조회/추가 이외에 규모 확장 시 레포 분리 */}
<Route path="/admin" element={<Admin />} />
<Route path="/admin/create-quiz" element={<CreateQuiz />}></Route>
Expand Down
16 changes: 16 additions & 0 deletions src/store/useQuizStore.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { create } from 'zustand';
interface quizState {
currentPage: number;
userResponse: string[];
handleNextPage: () => void;
}
//퀴즈 데이터 자체는 서버상태로 관리
//전역 퀴즈 스토어
//현재 어떤 퀴즈를 보고있는지
//유저가 입력한 답이 뭔지
export const useClientQuizStore = create<quizState>(set => ({
currentPage: 0,
userResponse: [''],
//다음 페이지로 넘기기
handleNextPage: () => set(state => ({ currentPage: state.currentPage + 1 })),
}));
10 changes: 10 additions & 0 deletions src/types/Quiz.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export default interface Quiz {
id: number;
partId: number;
sectionId: number;
title: string;
question: string;
answer: string[];
category: 'Combination' | 'MultipleChoice' | 'OXSelector' | 'ShortAnswer';
answerChoice: string[];
}
16 changes: 16 additions & 0 deletions src/utils/componentMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
interface ComponentMappingParam {
[key: string]: (props: any) => JSX.Element;
}

const componentMapping = <T,>(mappingTable: ComponentMappingParam) => {
const choice = (key: keyof typeof mappingTable, props: T) => {
const Component = mappingTable[key];
if (!Component) {
return null;
}
return <Component {...props} />;
};
return { choice };
};

export default componentMapping;

0 comments on commit 4a79f10

Please sign in to comment.