Skip to content

Commit

Permalink
Feat : modal창 구현 #34
Browse files Browse the repository at this point in the history
- home 버튼을 누르면 type이 out인 모달창 작동
- 마지막 문제 버튼 누를시 type이 check인 모달창 작동
  • Loading branch information
sheepdog13 committed Feb 26, 2024
1 parent 6ed13de commit bab7777
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 102 deletions.
Binary file added packages/frontend/public/img/checkPencil.webp
Binary file not shown.
Binary file added packages/frontend/public/img/outPencil.webp
Binary file not shown.
Binary file added packages/frontend/public/img/xmark.webp
Binary file not shown.
107 changes: 107 additions & 0 deletions packages/frontend/src/components/practice/PracticeModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { PracticeModalProps } from '@/types/PracticeModalProps';
import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';

const ModalOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
`;

const ModalContent = styled.div`
display: flex;
flex-direction: column;
gap: 7px;
align-items: center;
background: #fff;
width: 417px;
padding: 20px;
border-radius: 8px;
`;
const XmarkImg = styled.img`
width: 16px;
height: 16px;
margin-left: auto;
`;

const ModalBox = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex: 1;
`;

const PencilImg = styled.img`
width: 110px;
height: 110px;
`;

const Title = styled.h1`
font-weight: 600;
font-size: 25px;
`;

const SubTitle = styled.h2`
font-weight: 600;
font-size: 16px;
color: #939393;
`;

const Btn = styled.button<{ $color: string }>`
width: 150px;
height: 47px;
margin-top: 15px;
border-radius: 20px;
background-color: ${(props) => props.$color};
color: #fff;
font-weight: bold;
font-size: 20px;
`;

function PracticeModal({
type,
setIsOpen,
img_path,
color,
title,
sub_title,
btn_text,
}: PracticeModalProps) {
const navigate = useNavigate();
return (
<>
<ModalOverlay>
<ModalContent>
<XmarkImg onClick={setIsOpen} src={`/img/xmark.webp`} />
<ModalBox>
<PencilImg src={img_path} />
<Title>{title}</Title>
<SubTitle>{sub_title}</SubTitle>
<Btn
onClick={() => {
if (type === 'check') {
navigate('/result');
} else if (type === 'out') {
navigate('/main');
}
}}
$color={color}
>
{btn_text}
</Btn>
</ModalBox>
</ModalContent>
</ModalOverlay>
</>
);
}

export default PracticeModal;
57 changes: 53 additions & 4 deletions packages/frontend/src/pages/Practice.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useNavigate } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '../redux/hook';
import { selectChoice } from '../redux/_reducers/choices';
import { fetchGetProblem } from '@/redux/_reducers/problem';
import Loading from './Loading';
import PracticeModal from '@/components/practice/PracticeModal';

const Wrapper = styled.div`
position: relative;
Expand Down Expand Up @@ -179,7 +179,6 @@ function Practice() {
: setIsNextDisabled(false);
}, [questionIndex, isLoading]);

const navigate = useNavigate();
const problemdata = data.questions[questionIndex];
const problem = problemdata.content;
const choices = problemdata.choice;
Expand All @@ -195,24 +194,74 @@ function Practice() {
);
// 선택했던 답의 index 번호
const currentChoiceIndex = currentChoice?.choiceIndex;

const extracAnswer = (s: string): string => {
// 정규 표현식을 사용하여 "()"와 같은 패턴을 찾습니다.
const pattern = /\((\w+)\)/;
const match = s.match(pattern);
if (match) {
// 정규 표현식에 일치하는 그룹을 추출하여 리턴합니다.
return match[1];
} else {
return '';
}
};

// choice를 클릭했을때 문제 번호와 답, 답의 index 저장
const clickChoice = (answer: string, i: number) => {
const exAnswer = extracAnswer(answer);
// 마지막 문제가 아닐때
if (questionIndex !== lastIndex) {
dispatch(selectChoice({ questionIndex, answer, choiceIndex: i }));
dispatch(
selectChoice({ questionIndex, answer: exAnswer, choiceIndex: i }),
);
setQuestionIndex((prev) => prev + 1);
} else {
dispatch(
selectChoice({ questionIndex, answer: exAnswer, choiceIndex: i }),
);
setIsOpenCheckModal(true);
}
};

// 마지막 문제 클릭시 나오는 모달창의 isopen
const [isOpenCheckModal, setIsOpenCheckModal] = useState(false);
// 홈 버튼을 눌렀을때 나오는 모달창의 isopen
const [isOpenOutModal, setIsOpenOutModal] = useState(false);

return (
<Wrapper>
{isLoading ? (
<Loading />
) : (
<>
{isOpenCheckModal && (
<PracticeModal
type="check"
setIsOpen={() => {
setIsOpenCheckModal(false);
}}
img_path="/img/checkPencil.webp"
color="#35DE73"
title="마지막 문제입니다."
sub_title="답안지를 제출하겠습니까?"
btn_text="제출하기"
/>
)}
{isOpenOutModal && (
<PracticeModal
type="out"
setIsOpen={() => setIsOpenOutModal(false)}
img_path="/img/outPencil.webp"
color="#FF5573"
title="이대로 나갈 건가요?"
sub_title="풀었던 문제들은 저장되지 않아요."
btn_text="나가기"
/>
)}
<HomeImg
onClick={() => {
navigate('/main');
setIsOpenOutModal(true);
}}
src={`/img/homewhite.webp`}
/>
Expand Down
98 changes: 0 additions & 98 deletions packages/frontend/src/pages/practicedata.json

This file was deleted.

9 changes: 9 additions & 0 deletions packages/frontend/src/types/PracticeModalProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type PracticeModalProps = {
type: 'check' | 'out';
setIsOpen: () => void;
img_path: string;
color: string;
title: string;
sub_title: string;
btn_text: string;
};

0 comments on commit bab7777

Please sign in to comment.