diff --git a/TERMTERM/@types/Quiz.d.ts b/TERMTERM/@types/Quiz.d.ts index 5e73eb33..9db6d52d 100644 --- a/TERMTERM/@types/Quiz.d.ts +++ b/TERMTERM/@types/Quiz.d.ts @@ -35,9 +35,17 @@ declare module "Quiz" { export type QuizSubmit = { quizType: string; - results: QuizResult[]; + result: QuizResult; }; + export type QuizAnswerResult = { + termId: number; + termName: string; + termDescription: string; + memberSelectedTermName: string; + isAnswerRight: boolean; + } + export type QuizStatus = { status: "NOT_STARTED" | "IN_PROGRESS" | "COMPLETED"; }; diff --git a/TERMTERM/Container.tsx b/TERMTERM/Container.tsx index 4a22986d..8bb6dacc 100644 --- a/TERMTERM/Container.tsx +++ b/TERMTERM/Container.tsx @@ -32,6 +32,7 @@ import { ReviewQuizIntro, ReviewQuiz, ReviewQuizResult, + QuizReViewDetail, } from "@screens/index"; import ToolBar from "@screens/ToolBar"; import { @@ -141,7 +142,7 @@ const Container = () => { header: (props) => { return ( props.navigation.pop()} /> ); @@ -584,6 +585,23 @@ const Container = () => { }, }} /> + { + return ( + props.navigation.pop()} + onBookmark={() => null} + bookmarked={false} + /> + ); + }, + }} + /> diff --git a/TERMTERM/assets/walkthrough/archive.png b/TERMTERM/assets/walkthrough/archive.png index 6d881473..28fdefa2 100644 Binary files a/TERMTERM/assets/walkthrough/archive.png and b/TERMTERM/assets/walkthrough/archive.png differ diff --git a/TERMTERM/assets/walkthrough/curation.png b/TERMTERM/assets/walkthrough/curation.png index 091b6f49..0554ed3b 100644 Binary files a/TERMTERM/assets/walkthrough/curation.png and b/TERMTERM/assets/walkthrough/curation.png differ diff --git a/TERMTERM/assets/walkthrough/point.png b/TERMTERM/assets/walkthrough/point.png index f4140305..7de17a29 100644 Binary files a/TERMTERM/assets/walkthrough/point.png and b/TERMTERM/assets/walkthrough/point.png differ diff --git a/TERMTERM/assets/walkthrough/quiz.png b/TERMTERM/assets/walkthrough/quiz.png index 3de7f957..093f1e51 100644 Binary files a/TERMTERM/assets/walkthrough/quiz.png and b/TERMTERM/assets/walkthrough/quiz.png differ diff --git a/TERMTERM/src/api/QuizApi.ts b/TERMTERM/src/api/QuizApi.ts index 8554621d..e59378a1 100644 --- a/TERMTERM/src/api/QuizApi.ts +++ b/TERMTERM/src/api/QuizApi.ts @@ -1,4 +1,4 @@ -import { QuizDetail, QuizReviewDetail, QuizStatus, QuizSubmit } from "Quiz"; +import { QuizAnswerResult, QuizDetail, QuizReviewDetail, QuizStatus, QuizSubmit } from "Quiz"; import { post, get } from "./AxiosCreate"; @@ -16,8 +16,8 @@ class QuizApi { }; /** 데일리/복습 퀴즈 결과 제출 */ - registerQuizResult = async (input: QuizSubmit): Promise => { - const data = await post(`/v1/quiz/result`, input); + registerQuizResult = async (apiUrl: string, input: QuizSubmit): Promise => { + const data = await post(apiUrl, input); return data; }; diff --git a/TERMTERM/src/components/quiz/AnswerReminder.tsx b/TERMTERM/src/components/quiz/AnswerReminder.tsx index a97c493c..a07babd9 100644 --- a/TERMTERM/src/components/quiz/AnswerReminder.tsx +++ b/TERMTERM/src/components/quiz/AnswerReminder.tsx @@ -2,6 +2,7 @@ import AutoSizedImage from "@components/common/AutoSizedImage"; import { useThemeStyle } from "@hooks/useThemeStyle"; import { colorTheme, TYPO_STYLE } from "@style/designSystem"; import { screenWidth } from "@style/dimensions"; +import { divideTerm } from "@utils/termCutter"; import { useEffect, useState } from "react"; import styled from "styled-components/native"; @@ -52,7 +53,7 @@ const AnswerReminder = ({ answer, userAnswer }: AnswerReminderProps) => { <> 내가 생각한 답은{" "} - {userAnswer} + {divideTerm(userAnswer)[0]} 이에요 diff --git a/TERMTERM/src/components/quiz/Types/Start.tsx b/TERMTERM/src/components/quiz/Types/Start.tsx index 4dd14b41..4eb66499 100644 --- a/TERMTERM/src/components/quiz/Types/Start.tsx +++ b/TERMTERM/src/components/quiz/Types/Start.tsx @@ -8,8 +8,9 @@ import Clear from "./Clear"; import { useNavigation } from "@react-navigation/native"; import { StackNavigationProp } from "@react-navigation/stack"; import { RootStackParamList } from "@interfaces/RootStackParamList"; -import { useRecoilValue } from "recoil"; -import { quizState } from "@recoil/quizState"; +import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; +import { memberQuizSolveState, quizState } from "@recoil/quizState"; +import { QuizStatus } from "Quiz"; /** * async storage에 저장되는 퀴즈 현재 상태 @@ -23,25 +24,32 @@ enum QuizState { IN_PROGRESS = "IN_PROGRESS", } +export interface MemberQuizSolveState { + quizSolveState: QuizStatus; +} + /** * 용어퀴즈 시작 가능 */ const Start = ({ navigate }: ChildrenProps) => { const quizApi = new QuizApi(); const [COLOR, mode] = useThemeStyle(); - const [quizStatus, setQuizStatus] = useState(QuizState.NOT_STARTED); - // TODO : 180초로 추후 재설정 - const [countdown, setCountdown] = useState(3); + // TODO : 시간 바꿔두기 + const [countdown, setCountdown] = useState(0); const navigation = useNavigation>(); const curr = useRecoilValue(quizState); - const { currIdx } = curr + const { currIdx } = curr; + const setQuizStatus = useSetRecoilState(memberQuizSolveState); + const quizStatus = useRecoilValue(memberQuizSolveState); const remindQuizStatus = async () => { try { const res = await quizApi.getDailyQuizStatus(); - // TODO : 값 바꿔두기 - setQuizStatus(res.status); - // setQuizStatus(QuizState.COMPLETED) + setQuizStatus({ + quizSolveState: { + status: res.status, + }, + }); } catch (err) { console.log(err); } @@ -50,7 +58,7 @@ const Start = ({ navigate }: ChildrenProps) => { useEffect(() => { remindQuizStatus(); let interval: NodeJS.Timer; - if (quizStatus === QuizState.IN_PROGRESS) { + if (quizStatus.quizSolveState.status === QuizState.IN_PROGRESS) { interval = setInterval(() => { setCountdown((prevCountdown) => prevCountdown - 1); }, 1000); @@ -63,22 +71,23 @@ const Start = ({ navigate }: ChildrenProps) => { return ( <> - {quizStatus === QuizState.NOT_STARTED && currIdx <= 5 && ( - <> - - - Daily 용어 퀴즈를 시작해 볼까요? - - navigation.push("QuizIntro")}> - - - - )} + {quizStatus.quizSolveState.status === QuizState.NOT_STARTED && + currIdx <= 5 && ( + <> + + + Daily 용어 퀴즈를 시작해 볼까요? + + navigation.push("QuizIntro")}> + + + + )} - {quizStatus === QuizState.IN_PROGRESS && ( + {quizStatus.quizSolveState.status === QuizState.IN_PROGRESS && ( <> {countdown > 0 ? ( <> @@ -98,7 +107,9 @@ const Start = ({ navigate }: ChildrenProps) => { 용어 복습 퀴즈를 통해 다시 학습해요! - navigation.push("ReviewQuizIntro")}> + navigation.push("ReviewQuizIntro")} + > { )} - {quizStatus === QuizState.COMPLETED && ( + {quizStatus.quizSolveState.status === QuizState.COMPLETED && ( navigation.push("QuizReview")} /> )} diff --git a/TERMTERM/src/components/terms/QuizAnswerCard.tsx b/TERMTERM/src/components/terms/QuizAnswerCard.tsx index 0c086a7e..4ab80316 100644 --- a/TERMTERM/src/components/terms/QuizAnswerCard.tsx +++ b/TERMTERM/src/components/terms/QuizAnswerCard.tsx @@ -3,12 +3,13 @@ import { useWordReg } from "@hooks/useWordReg"; import { WordProps } from "@interfaces/word"; import { TEXT_STYLES, TYPO, colorTheme, TYPO_STYLE } from "@style/designSystem"; import { screenWidth } from "@style/dimensions"; +import { QuizAnswerResult } from "Quiz"; import { TouchableOpacityProps } from "react-native"; import { css } from "styled-components"; import styled from "styled-components/native"; interface Props extends TouchableOpacityProps { - word: WordProps; + word: QuizAnswerResult; quiz?: boolean; detail?: boolean; } @@ -18,7 +19,7 @@ interface Props extends TouchableOpacityProps { */ const QuizAnswerCard = ({ word, quiz, detail, ...props }: Props) => { const [COLOR, mode] = useThemeStyle(); - const [sub, main] = useWordReg(word.name); + const [sub, main] = useWordReg(word?.termName); return ( { - {word.description} + {word?.termDescription} ); diff --git a/TERMTERM/src/hooks/useQuiz.tsx b/TERMTERM/src/hooks/useQuiz.tsx index 8114561e..ce368cd9 100644 --- a/TERMTERM/src/hooks/useQuiz.tsx +++ b/TERMTERM/src/hooks/useQuiz.tsx @@ -1,5 +1,11 @@ import QuizApi from "@api/QuizApi"; -import { QuizDetail, QuizReviewDetail, QuizResult, QuizSubmit } from "Quiz"; +import { + QuizDetail, + QuizReviewDetail, + QuizResult, + QuizSubmit, + QuizAnswerResult, +} from "Quiz"; import { useEffect, useState } from "react"; /** @@ -12,6 +18,7 @@ export const useQuiz = () => { useState(); const [reviewQuizItem, setReviewQuizItem] = useState(); const [quizStatus, setQuizStatus] = useState(); + const [quizResultData, setQuizResultData] = useState(); /** 데일리 퀴즈 */ const getDailyQuizInfo = async (): Promise => { @@ -41,14 +48,18 @@ export const useQuiz = () => { /** 데일리/복습 퀴즈 결과 제출 */ const registerQuizResultInfo = async ( + apiUrl: string, resultData: QuizSubmit - ): Promise => { + ): Promise => { try { - await quizApi.registerQuizResult(resultData); - return true; + const data = await quizApi.registerQuizResult(apiUrl, resultData); + // console.log("퀴즈 요청 성공", apiUrl, resultData, data); + setQuizResultData(data); + // console.log("quizResultData in hook : ", quizResultData); + return data; } catch (err) { console.log(err); - return false; + return null; } }; @@ -68,6 +79,7 @@ export const useQuiz = () => { const getDailyQuizStatus = async (): Promise => { try { const res = await quizApi.getDailyQuizStatus(); + console.log("여기 : ", res); setQuizStatus(res.status); return true; } catch (err) { @@ -87,10 +99,12 @@ export const useQuiz = () => { finalQuizReviewItem, reviewQuizItem, quizStatus, + quizResultData, getDailyQuizInfo, getDailyQuizStatus, getFinalQuizReviewInfo, getReviewQuizInfo, registerQuizResultInfo, + setQuizStatus, }; }; diff --git a/TERMTERM/src/interfaces/RootStackParamList.ts b/TERMTERM/src/interfaces/RootStackParamList.ts index 507a5920..1167a31b 100644 --- a/TERMTERM/src/interfaces/RootStackParamList.ts +++ b/TERMTERM/src/interfaces/RootStackParamList.ts @@ -44,4 +44,5 @@ export type RootStackParamList = { ReviewQuiz: undefined; ReviewQuizResult: { id: number }; SelectFolder: { termId: number }; + QuizReviewDetail: { id: number }; }; diff --git a/TERMTERM/src/recoil/quizState.tsx b/TERMTERM/src/recoil/quizState.tsx index dc7e534e..f33f9e6e 100644 --- a/TERMTERM/src/recoil/quizState.tsx +++ b/TERMTERM/src/recoil/quizState.tsx @@ -1,3 +1,4 @@ +import { QuizAnswerResult, QuizReviewDetail, QuizStatus } from "Quiz"; import { atom } from "recoil"; /** @@ -12,7 +13,7 @@ export interface QuizState { const defaultState: QuizState = { totalIdx: 5, - currIdx: 1, + currIdx: 0, currReviewIdx: 0, totalReviewIdx: 0, }; @@ -21,3 +22,57 @@ export const quizState = atom({ key: "quizState", default: defaultState, }); + +/** + * 퀴즈 풀이 여부 관련 전역 상태 + */ +export interface MemberQuizSolveState { + quizSolveState: QuizStatus; +} + +const defaultSolveState: MemberQuizSolveState = { + quizSolveState: { + status: "NOT_STARTED", + }, +}; + +export const memberQuizSolveState = atom({ + key: "memberQuizSolveState", + default: defaultSolveState, +}); + +/** + * 퀴즈 제출 시 받아오는 값 관련 전역변수 + */ +const defaultQuizAnswer: QuizAnswerResult = { + termId: 0, + termName: "", + termDescription: "", + memberSelectedTermName: "", + isAnswerRight: true, +}; + +export const eachQuizAnswerResult = atom({ + key: "eachQuizAnswerResult", + default: defaultQuizAnswer, +}); + +/** + * 퀴즈 리뷰에서 사용할 전역 변수 + */ +const defaultQuizReviewList: QuizReviewDetail[] = [ + { + bookmarked: "NO", + isAnswerRight: false, + termDescription: "", + termId: 0, + termName: "", + termSource: "", + wrongChoices: [], + }, +]; + +export const quizReviewList = atom({ + key: "quizReviewList", + default: defaultQuizReviewList, +}); diff --git a/TERMTERM/src/screens/CompleteQuiz.tsx b/TERMTERM/src/screens/CompleteQuiz.tsx index 0a7331a6..95373454 100644 --- a/TERMTERM/src/screens/CompleteQuiz.tsx +++ b/TERMTERM/src/screens/CompleteQuiz.tsx @@ -9,6 +9,9 @@ import { BackBar } from "@components/header"; import { colorTheme, LIGHT_COLOR_STYLE, TYPO_STYLE } from "@style/designSystem"; import { useThemeStyle } from "@hooks/useThemeStyle"; import { Fontisto } from "@expo/vector-icons"; +import QuizApi from "@api/QuizApi"; +import { useRecoilState } from "recoil"; +import { memberQuizSolveState } from "@recoil/quizState"; export type Props = StackScreenProps; @@ -16,6 +19,8 @@ const CompleteQuiz = ({ navigation }: Props) => { const [COLOR, mode] = useThemeStyle(); const [width, setWidth] = useState(112); const [score, setScore] = useState(200); + const quizApi = new QuizApi(); + const [quizSolve, setQuizSolve] = useRecoilState(memberQuizSolveState); /** 아이콘 너비 계산 함수 */ const calcWidth = () => { @@ -34,6 +39,16 @@ const CompleteQuiz = ({ navigation }: Props) => { } }; + const handleButton = async () => { + try { + const res = await quizApi.getDailyQuizStatus(); + setQuizSolve((prev) => ({ ...prev, memberQuizSolveState: res })); + navigation.navigate("Home"); + } catch (err) { + console.log(err); + } + }; + useEffect(() => { calcWidth(); }, []); @@ -68,7 +83,7 @@ const CompleteQuiz = ({ navigation }: Props) => { navigation.navigate("Home")} + onPress={() => handleButton()} > {`홈으로 돌아가기 `} @@ -144,7 +159,8 @@ const CompleteButton = styled.TouchableOpacity<{ width: ${screenWidth - 72}px; height: 44px; z-index: 2; - background-color: ${(props) => props.mode ? props.COLOR.Neutral[100] : props.COLOR.Background.onSurface}; + background-color: ${(props) => + props.mode ? props.COLOR.Neutral[100] : props.COLOR.Background.onSurface}; border-radius: 50%; margin-top: 40px; `; diff --git a/TERMTERM/src/screens/DailyQuiz.tsx b/TERMTERM/src/screens/DailyQuiz.tsx index da516699..b7b9c94e 100644 --- a/TERMTERM/src/screens/DailyQuiz.tsx +++ b/TERMTERM/src/screens/DailyQuiz.tsx @@ -6,46 +6,55 @@ import { colorTheme, TYPO_STYLE } from "@style/designSystem"; import { SafeAreaView } from "react-native-safe-area-context"; import QuizCard from "@components/quiz/QuizCard"; import { useThemeStyle } from "@hooks/useThemeStyle"; -import useHideWord from "@hooks/useHideWord"; import { screenWidth } from "@style/dimensions"; import { useQuiz } from "@hooks/useQuiz"; -import { useRecoilState } from "recoil"; -import { quizState } from "@recoil/quizState"; +import { useRecoilState, useSetRecoilState } from "recoil"; +import { eachQuizAnswerResult, quizState } from "@recoil/quizState"; import { QuizSubmit } from "Quiz"; +import { divideTerm } from "@utils/termCutter"; export type Props = StackScreenProps; const DailyQuiz = ({ navigation }: Props) => { - const { dailyQuizItem, registerQuizResultInfo } = useQuiz(); + const { dailyQuizItem, registerQuizResultInfo, quizResultData } = useQuiz(); const [COLOR, mode] = useThemeStyle(); const [selectedIdx, setSelectedIdx] = useState(-1); const [borderColor, setBorderColor] = useState( COLOR.Background.inputBorderDefault ); const [curr, setCurr] = useRecoilState(quizState); - const currentQuiz = dailyQuizItem?.[curr.currIdx - 1]; + const currentQuiz = dailyQuizItem?.[curr.currIdx]; + const setEachQuizAnswer = useSetRecoilState(eachQuizAnswerResult); // TODO : DB에 @@ 포함되어 용어 설명 들어가면 다시 훅 사용 // const { hiddenExplain } = useHideWord(dummy[idx].explain, dummy[idx].word); - const handleButton = (idx: number) => { + const handleButton = async (idx: number) => { setSelectedIdx(idx); setBorderColor(COLOR.THEME.secondary[120]); setCurr((prev) => ({ ...prev, currIdx: prev.currIdx + 1 })); + const isFinalQuestion = curr.currIdx === 4; + let apiUrl = `/v1/quiz/result`; + const memberQuizSelect: QuizSubmit = { quizType: "DAILY", - results: [ - ...(curr.currIdx <= 5 - ? [ - { - memberSelectedTermId: idx, - problemTermId: currentQuiz?.termId || 0, - }, - ] - : []), - ], + result: { + memberSelectedTermId: idx, + problemTermId: currentQuiz?.termId || 0, + }, }; - registerQuizResultInfo(memberQuizSelect); + if (isFinalQuestion) { + apiUrl += `?final=true`; + } + + const res = await registerQuizResultInfo(apiUrl, memberQuizSelect); + setEachQuizAnswer({ + termId: res?.termId as number, + termName: res?.termName as string, + termDescription: res?.termDescription as string, + memberSelectedTermName: res?.memberSelectedTermName as string, + isAnswerRight: res?.isAnswerRight as boolean, + }) navigation.navigate("QuizResult", { id: idx }); }; @@ -74,7 +83,7 @@ const DailyQuiz = ({ navigation }: Props) => { onPress={() => handleButton(item.termId)} > - {item.optionName} + {divideTerm(item.optionName)[0]} ))} diff --git a/TERMTERM/src/screens/Login.tsx b/TERMTERM/src/screens/Login.tsx index a7c30cf2..1d33e60a 100644 --- a/TERMTERM/src/screens/Login.tsx +++ b/TERMTERM/src/screens/Login.tsx @@ -4,7 +4,7 @@ import { UrlText, NonScrollContainer } from "@components/index"; import { screenWidth } from "@style/dimensions"; import AutoSizedImage from "@components/common/AutoSizedImage"; import SocialLoginButton from "@components/buttons/SocialLogin"; -import { StackScreenProps } from "@react-navigation/stack"; +import { StackNavigationProp, StackScreenProps } from "@react-navigation/stack"; import { RootStackParamList } from "@interfaces/RootStackParamList"; import { useSafeColor } from "@hooks/useSafeColor"; import { NonUrl } from "@components/common/UrlText"; @@ -14,8 +14,8 @@ import { useHaptics } from "@hooks/useHaptics"; import * as AppleAuthentication from "expo-apple-authentication"; import AuthApi from "@api/AuthApi"; import { MemberInfo } from "Member"; -import { setAccessToken, setRefreshToken } from "@utils/tokenHandler"; import MemberApi from "@api/MemberApi"; +import { useNavigation } from "@react-navigation/native"; export type Props = StackScreenProps; @@ -42,6 +42,8 @@ const Login = ({ navigation, route }: Props) => { const { user, loading } = useMember(); const authApi = new AuthApi(); const memberApi = new MemberApi(); + const inquiryNavigation = + useNavigation>(); useSafeColor(); @@ -155,15 +157,9 @@ const Login = ({ navigation, route }: Props) => { - + inquiryNavigation.navigate("Support")}> + 이용하시는 데에 어려움이 있나요? + ); @@ -216,4 +212,10 @@ const QuestionBox = styled.View` align-items: center; `; +const InquiryLink = styled.Text` + font-size: 14px; + font-weight: 500; + color: #929292; +`; + export default Login; diff --git a/TERMTERM/src/screens/QuizResult.tsx b/TERMTERM/src/screens/QuizResult.tsx index 3d6f0140..455e3354 100644 --- a/TERMTERM/src/screens/QuizResult.tsx +++ b/TERMTERM/src/screens/QuizResult.tsx @@ -6,7 +6,6 @@ import { colorTheme } from "@style/designSystem"; import { SafeAreaView } from "react-native-safe-area-context"; import { useThemeStyle } from "@hooks/useThemeStyle"; import { WordProps } from "@interfaces/word"; -import { dummyWord } from "@assets/dummyWord"; import { CustomButton, BUTTON_STATE, @@ -14,8 +13,8 @@ import { AnswerReminder, } from "@components/index"; import QuizAnswerCard from "@components/terms/QuizAnswerCard"; -import { quizState } from "@recoil/quizState"; -import { useRecoilValue } from "recoil"; +import { eachQuizAnswerResult, quizState } from "@recoil/quizState"; +import { useRecoilValue, useSetRecoilState } from "recoil"; export type Props = StackScreenProps; @@ -24,19 +23,18 @@ const QuizResult = ({ navigation, route }: Props) => { const [answer, setAnswer] = useState(); const curr = useRecoilValue(quizState); const { currIdx } = curr; - - useEffect(() => { - //TODO : 정답 받아오는 로직 추가 - setAnswer(dummyWord); - }); + const quizResult = useRecoilValue(eachQuizAnswerResult); return ( - + diff --git a/TERMTERM/src/screens/QuizReview.tsx b/TERMTERM/src/screens/QuizReview.tsx index 06881373..3fc37dda 100644 --- a/TERMTERM/src/screens/QuizReview.tsx +++ b/TERMTERM/src/screens/QuizReview.tsx @@ -3,9 +3,11 @@ import QuizReviewRouter from "@components/quiz/QuizReviewRouter"; import { useThemeStyle } from "@hooks/useThemeStyle"; import { RootStackParamList } from "@interfaces/RootStackParamList"; import { StackScreenProps } from "@react-navigation/stack"; +import { eachQuizAnswerResult, quizReviewList } from "@recoil/quizState"; import { QuizReviewDetail } from "Quiz"; import { useEffect, useState } from "react"; import { SafeAreaView } from "react-native-safe-area-context"; +import { useRecoilValue, useSetRecoilState } from "recoil"; import styled from "styled-components/native"; export type Props = StackScreenProps; @@ -13,11 +15,29 @@ export type Props = StackScreenProps; const QuizReview = ({ navigation }: Props) => { const quizApi = new QuizApi(); const [COLOR, mode] = useThemeStyle(); - const [quizReviewList, setQuizReviewList] = useState([]); + // const [quizReviewList, setQuizReviewList] = useState([]); + const setEachQuizAnswer = useSetRecoilState(eachQuizAnswerResult); + const setQuizReviewList = useSetRecoilState(quizReviewList); + const quizReviewLocalList = useRecoilValue(quizReviewList); const getQuizReviewList = async () => { try { const res = await quizApi.getFinalQuizReview(); + + const updatedQuizReviewList: QuizReviewDetail[] = res.map((item) => ({ + termId: item.termId as number, + termName: item.termName as string, + termDescription: item.termDescription as string, + isAnswerRight: item.isAnswerRight as boolean, + bookmarked: "NO", + termSource: "", + wrongChoices: [], + })); + + setQuizReviewList(updatedQuizReviewList); + console.log("res : ", res); + console.log("quizReviewLocalList : ", quizReviewLocalList); + console.log("updatedQuizReviewList", updatedQuizReviewList); const termNameArr = res.map((item) => { return getMainTermName(item.termName); }); @@ -50,7 +70,7 @@ const QuizReview = ({ navigation }: Props) => { return ( - {quizReviewList.map((item, idx) => ( + {quizReviewLocalList.map((item, idx) => ( { wordAnswer={item.termName} userAnswer={item.wrongChoices[0]} onPress={() => - navigation.navigate("QuizResult", { id: item.termId }) + navigation.navigate("QuizReviewDetail", { id: item.termId }) } /> ))} diff --git a/TERMTERM/src/screens/QuizReviewDetail.tsx b/TERMTERM/src/screens/QuizReviewDetail.tsx new file mode 100644 index 00000000..ab375642 --- /dev/null +++ b/TERMTERM/src/screens/QuizReviewDetail.tsx @@ -0,0 +1,72 @@ +import styled from "styled-components/native"; +import { useEffect, useState } from "react"; +import { StackScreenProps } from "@react-navigation/stack"; +import { RootStackParamList } from "@interfaces/RootStackParamList"; +import { colorTheme } from "@style/designSystem"; +import { SafeAreaView } from "react-native-safe-area-context"; +import { useThemeStyle } from "@hooks/useThemeStyle"; +import { WordProps } from "@interfaces/word"; +import { + CustomButton, + BUTTON_STATE, + BUTTON_TYPE, + AnswerReminder, +} from "@components/index"; +import QuizAnswerCard from "@components/terms/QuizAnswerCard"; +import { eachQuizAnswerResult, quizState } from "@recoil/quizState"; +import { useRecoilValue, useSetRecoilState } from "recoil"; + +export type Props = StackScreenProps; + +const QuizReViewDetail = ({ navigation, route }: Props) => { + const [COLOR, mode] = useThemeStyle(); + const [answer, setAnswer] = useState(); + const curr = useRecoilValue(quizState); + const { currIdx } = curr; + const quizResult = useRecoilValue(eachQuizAnswerResult); + + return ( + + + + + + + navigation.navigate("QuizReview")} + style={{ width: "90%", alignSelf: "center", marginTop: "7%" }} + /> + + + ); +}; + +export default QuizReViewDetail; + +const Container = styled.View<{ + COLOR: colorTheme; + mode: boolean; +}>` + width: 100%; + height: 100%; +`; + +const ContentWrapper = styled.View` + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 50px 20px; +`; diff --git a/TERMTERM/src/screens/ReviewQuiz.tsx b/TERMTERM/src/screens/ReviewQuiz.tsx index 84309e11..cab2f1a0 100644 --- a/TERMTERM/src/screens/ReviewQuiz.tsx +++ b/TERMTERM/src/screens/ReviewQuiz.tsx @@ -10,8 +10,9 @@ import useHideWord from "@hooks/useHideWord"; import { screenWidth } from "@style/dimensions"; import { useQuiz } from "@hooks/useQuiz"; import { useRecoilState, useSetRecoilState } from "recoil"; -import { quizState } from "@recoil/quizState"; +import { eachQuizAnswerResult, quizState } from "@recoil/quizState"; import { QuizSubmit } from "Quiz"; +import { divideTerm } from "@utils/termCutter"; export type Props = StackScreenProps; @@ -26,28 +27,38 @@ const ReviewQuiz = ({ navigation }: Props) => { const [curr, setCurr] = useRecoilState(quizState); const currentQuiz = reviewQuizItem?.[curr.currReviewIdx]; const setTotalReviewIdx = useSetRecoilState(quizState); + const setEachQuizAnswer = useSetRecoilState(eachQuizAnswerResult); // TODO : DB에 @@ 포함되어 용어 설명 들어가면 다시 훅 사용 // const { hiddenExplain } = useHideWord(dummy[idx].explain, dummy[idx].word); - const handleButton = (idx: number) => { + const handleButton = async (idx: number) => { setSelectedIdx(idx); setBorderColor(COLOR.THEME.secondary[120]); setCurr((prev) => ({ ...prev, currReviewIdx: prev.currReviewIdx + 1 })); + const isFinalQuestion = curr.currReviewIdx + 1 === curr.totalReviewIdx; + let apiUrl = `/v1/quiz/result`; + const memberQuizSelect: QuizSubmit = { quizType: "REVIEW", - results: [ - ...(curr.currReviewIdx <= curr.totalReviewIdx - ? [ - { - memberSelectedTermId: idx, - problemTermId: currentQuiz?.termId || 0, - }, - ] - : []), - ], + result: { + memberSelectedTermId: idx, + problemTermId: currentQuiz?.termId || 0, + }, }; - registerQuizResultInfo(memberQuizSelect); + if (isFinalQuestion) { + apiUrl += `?final=true`; + // setCurr((prev) => ({ ...prev, currReviewIdx: prev.currReviewIdx * 0 })); + } + + const res = await registerQuizResultInfo(apiUrl, memberQuizSelect); + setEachQuizAnswer({ + termId: res?.termId as number, + termName: res?.termName as string, + termDescription: res?.termDescription as string, + memberSelectedTermName: res?.memberSelectedTermName as string, + isAnswerRight: res?.isAnswerRight as boolean, + }); navigation.navigate("ReviewQuizResult", { id: idx }); }; @@ -85,7 +96,7 @@ const ReviewQuiz = ({ navigation }: Props) => { onPress={() => handleButton(item.termId)} > - {item.optionName} + {divideTerm(item.optionName)[0]} ))} diff --git a/TERMTERM/src/screens/ReviewQuizResult.tsx b/TERMTERM/src/screens/ReviewQuizResult.tsx index f239f40b..62735018 100644 --- a/TERMTERM/src/screens/ReviewQuizResult.tsx +++ b/TERMTERM/src/screens/ReviewQuizResult.tsx @@ -14,8 +14,10 @@ import { AnswerReminder, } from "@components/index"; import QuizAnswerCard from "@components/terms/QuizAnswerCard"; -import { quizState } from "@recoil/quizState"; -import { useRecoilValue } from "recoil"; +import { eachQuizAnswerResult, quizState } from "@recoil/quizState"; +import { useRecoilValue, useSetRecoilState } from "recoil"; +import { useQuiz } from "@hooks/useQuiz"; +import { QuizAnswerResult } from "Quiz"; export type Props = StackScreenProps; @@ -24,19 +26,29 @@ const ReviewQuizResult = ({ navigation, route }: Props) => { const [answer, setAnswer] = useState(); const curr = useRecoilValue(quizState); const { currIdx, currReviewIdx, totalReviewIdx } = curr; + const quizResult = useRecoilValue(eachQuizAnswerResult); + const setCurrReviewIdx = useSetRecoilState(quizState); - useEffect(() => { - //TODO : 정답 받아오는 로직 추가 - setAnswer(dummyWord); - }); + const handleCompleteButton = () => { + setCurrReviewIdx((prev) => ({ ...prev, currReviewIdx: 0 })); + navigation.navigate("CompleteQuiz"); + }; + + const handleReviewButton = () => { + setCurrReviewIdx((prev) => ({ ...prev, currReviewIdx: 1 })); + navigation.navigate("ReviewQuiz"); + }; return ( - + @@ -48,8 +60,8 @@ const ReviewQuizResult = ({ navigation, route }: Props) => { state={BUTTON_STATE.active} onPress={() => currReviewIdx === totalReviewIdx - ? navigation.navigate("CompleteQuiz") - : navigation.navigate("ReviewQuiz") + ? handleCompleteButton() + : handleReviewButton() } style={{ width: "90%", alignSelf: "center", marginTop: "7%" }} /> diff --git a/TERMTERM/src/screens/index.ts b/TERMTERM/src/screens/index.ts index 390aaba9..42c3c523 100644 --- a/TERMTERM/src/screens/index.ts +++ b/TERMTERM/src/screens/index.ts @@ -28,6 +28,7 @@ import SelectFolder from "./SelectFolder"; import ReviewQuizIntro from "./ReviewQuizIntro"; import ReviewQuiz from "./ReviewQuiz"; import ReviewQuizResult from "./ReviewQuizResult"; +import QuizReViewDetail from "./QuizReviewDetail"; export { Home, @@ -60,4 +61,5 @@ export { ReviewQuizIntro, ReviewQuiz, ReviewQuizResult, + QuizReViewDetail, };