Skip to content

Commit b9ba9ea

Browse files
authored
merge: Quiz selection 화면 추가 (#29)
merge: Quiz selection 화면 추가 (#29)
2 parents 903fd92 + 89f88f9 commit b9ba9ea

File tree

10 files changed

+151
-9
lines changed

10 files changed

+151
-9
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useSuspenseQuery } from '@tanstack/react-query';
2+
3+
interface UseQuizQueryParams {
4+
id: number;
5+
}
6+
7+
export interface QuizResponse {
8+
title: string;
9+
question: string;
10+
description: string;
11+
choices: string[];
12+
}
13+
14+
const mockQuiz: QuizResponse = {
15+
title: '도깨비',
16+
question: '도깨비 팬티는?',
17+
description: '동요가 어쩌고 저쩌고...',
18+
choices: ['튼튼해요', '질기고요', '호랑이 가죽으로 만들었어요', '더러워요'],
19+
};
20+
21+
export default function useQuizQuery({ id }: UseQuizQueryParams) {
22+
return useSuspenseQuery({
23+
queryKey: ['Quiz', id],
24+
queryFn: () => {
25+
return mockQuiz;
26+
},
27+
});
28+
}

packages/react-native/src/apis/queries/useQuizzesQuery.ts renamed to packages/react-native/src/apis/queries/quiz/useQuizzesQuery.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface Location {
66
}
77

88
export interface QuizzesResponse {
9+
id: number;
910
title: string;
1011
location: string;
1112
region: string;
@@ -18,13 +19,15 @@ interface UseQuizzesQueryParams {
1819

1920
const mockQuizzes = [
2021
{
22+
id: 1,
2123
title: '도깨비',
2224
location: '주문진 방파제',
2325
region: '강원도 강릉',
2426
image:
2527
'https://t1.daumcdn.net/news/202406/27/poctan/20240627172416746baii.jpg',
2628
},
2729
{
30+
id: 2,
2831
title: '도깨비2',
2932
location: '주문한 방파제',
3033
region: '강원도 강릉',

packages/react-native/src/pages/Gamification/QuizCard.tsx renamed to packages/react-native/src/components/gamification/QuizCard.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Dimensions, Image, TouchableOpacity, View } from 'react-native';
22
import { Font } from 'design-system';
3-
import { QuizzesResponse } from '@/apis/queries/useQuizzesQuery';
3+
import { useNavigation } from '@react-navigation/native';
4+
import { QuizzesResponse } from '@/apis/queries/quiz/useQuizzesQuery';
5+
import { StackNavigation } from '@/types/navigation';
46

57
interface QuizCardProps {
68
quizData: QuizzesResponse;
@@ -11,6 +13,14 @@ const { width: fullWidth } = Dimensions.get('window');
1113
export const QUIZ_CARD_SIZE = (fullWidth * 80) / 100;
1214

1315
export default function QuizCard({ quizData }: QuizCardProps) {
16+
const navigate = useNavigation<StackNavigation<'Gamification/Main'>>();
17+
18+
const handleClickQuizStart = () => {
19+
navigate.navigate('Gamification/Quiz', {
20+
quizId: quizData.id,
21+
});
22+
};
23+
1424
return (
1525
<View
1626
style={{
@@ -47,7 +57,10 @@ export default function QuizCard({ quizData }: QuizCardProps) {
4757
</View>
4858
</View>
4959
<View className="flex gap-3 flex-row justify-center py-3">
50-
<TouchableOpacity className="bg-SPOT-red justify-center items-center px-6 py-1.5 rounded-lg">
60+
<TouchableOpacity
61+
className="bg-SPOT-red justify-center items-center px-6 py-1.5 rounded-lg"
62+
onPress={handleClickQuizStart}
63+
>
5164
<Font.Bold type="body3" color="white">
5265
퀴즈 풀기
5366
</Font.Bold>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { Font } from 'design-system';
2+
import { TouchableOpacity, View } from 'react-native';
3+
import CheckBox from '../common/CheckBox';
4+
5+
interface QuizSelectionProps {
6+
isSelected: boolean;
7+
content: string;
8+
onPress: () => void;
9+
}
10+
11+
export default function QuizSelection({
12+
isSelected,
13+
content,
14+
onPress,
15+
}: QuizSelectionProps) {
16+
return (
17+
<TouchableOpacity
18+
onPress={onPress}
19+
className={`${isSelected ? 'bg-SPOT-red' : 'bg-Button-gray'} p-4 rounded-xl items-start `}
20+
>
21+
<View className="gap-2.5 flex flex-row items-center ">
22+
<View>
23+
<CheckBox selected={isSelected} size={20} />
24+
</View>
25+
<View>
26+
{isSelected ? (
27+
<Font.Bold type="body1" color="white">
28+
{content}
29+
</Font.Bold>
30+
) : (
31+
<Font type="body1" color="white">
32+
{content}
33+
</Font>
34+
)}
35+
</View>
36+
</View>
37+
</TouchableOpacity>
38+
);
39+
}

packages/react-native/src/pages/Gamification/QuizSlider.tsx renamed to packages/react-native/src/components/gamification/QuizSlider.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useState } from 'react';
22
import { Dimensions, View, ViewToken } from 'react-native';
33
import { FlatList } from 'react-native-gesture-handler';
4-
import { QuizzesResponse } from '@/apis/queries/useQuizzesQuery';
4+
import { QuizzesResponse } from '@/apis/queries/quiz/useQuizzesQuery';
55
import Header from '@/components/common/Header';
66
import BackGroundGradient from '@/layouts/BackGroundGradient';
77
import QuizCard from './QuizCard';
@@ -25,7 +25,7 @@ export default function QuizSlider({ quizListData }: QuizSliderProps) {
2525

2626
return (
2727
<BackGroundGradient withoutScroll>
28-
<Header title={quizListData[0].title} />
28+
<Header title={quizListData[currentIndex].title} />
2929
<View className="flex-1 justify-center">
3030
<View className="justify-center items-center gap-2">
3131
<FlatList

packages/react-native/src/pages/Gamification.tsx renamed to packages/react-native/src/pages/Gamification/Gamification.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { useEffect, useState } from 'react';
2-
import useGeolocation from '@/hooks/useGeolocation';
3-
import useQuizzesQuery, { Location } from '@/apis/queries/useQuizzesQuery';
4-
import QuizLoading from './Gamification/QuizLoading';
5-
import QuizSlider from './Gamification/QuizSlider';
2+
import QuizLoading from '@components/gamification/QuizLoading';
3+
import QuizSlider from '@components/gamification/QuizSlider';
64
import withSuspense from '@/components/HOC/withSuspense';
5+
import useGeolocation from '@/hooks/useGeolocation';
6+
import useQuizzesQuery, { Location } from '@/apis/queries/quiz/useQuizzesQuery';
77

88
export default withSuspense(
99
function Gamification() {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useState } from 'react';
2+
import { View } from 'react-native';
3+
import { Button, Font } from 'design-system';
4+
import { useRoute } from '@react-navigation/native';
5+
import useQuizQuery from '@/apis/queries/quiz/useQuizQuery';
6+
import Header from '@/components/common/Header';
7+
import QuizSelection from '@/components/gamification/QuizSelection';
8+
import BackGroundGradient from '@/layouts/BackGroundGradient';
9+
import { StackRouteProps } from '@/types/navigation';
10+
import withSuspense from '@/components/HOC/withSuspense';
11+
12+
export default withSuspense(function Quiz() {
13+
const route = useRoute<StackRouteProps<'Gamification/Quiz'>>();
14+
const [selectedContent, setSelectedContent] = useState('');
15+
const { data } = useQuizQuery({ id: route.params.quizId });
16+
17+
return (
18+
<BackGroundGradient>
19+
<Header title={data.title} />
20+
<View className="p-4 gap-9">
21+
<View className="gap-2.5">
22+
<View>
23+
<Font.Bold type="mainTitle" color="white">
24+
Q. {data.question}
25+
</Font.Bold>
26+
</View>
27+
<View>
28+
<Font type="body2" color="white">
29+
{data.description}
30+
</Font>
31+
</View>
32+
</View>
33+
<View className="flex flex-col justify-start gap-2.5 ">
34+
{data.choices.map((content) => (
35+
<View>
36+
<QuizSelection
37+
onPress={() => setSelectedContent(content)}
38+
isSelected={selectedContent === content}
39+
content={content}
40+
/>
41+
</View>
42+
))}
43+
</View>
44+
<View>
45+
<Button disabled={selectedContent.length === 0}>
46+
<Font.Bold color="white" type="title1">
47+
제출
48+
</Font.Bold>
49+
</Button>
50+
</View>
51+
</View>
52+
</BackGroundGradient>
53+
);
54+
});

packages/react-native/src/routes/GamificationStackNavigator.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createStackNavigator } from '@react-navigation/stack';
2-
import Gamification from '@/pages/Gamification';
2+
import Gamification from '@/pages/Gamification/Gamification';
33
import { StackParamList } from '@/types/navigation';
4+
import Quiz from '@/pages/Gamification/Quiz';
45

56
const Stack = createStackNavigator<StackParamList>();
67

@@ -11,6 +12,7 @@ export default function GamificationStackNavigator() {
1112
initialRouteName="Gamification/Main"
1213
>
1314
<Stack.Screen name="Gamification/Main" component={Gamification} />
15+
<Stack.Screen name="Gamification/Quiz" component={Quiz} />
1416
</Stack.Navigator>
1517
);
1618
}

packages/react-native/src/types/navigation.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ export type StackParamList = {
2121
'Home/Detail': { id: number };
2222

2323
'Gamification/Main': undefined;
24+
'Gamification/Quiz': {
25+
quizId: number;
26+
};
2427

2528
'Maps/Main': undefined;
2629
'Maps/Record': { location: KoreaLocationName };

0 commit comments

Comments
 (0)