@shopify/shop-minis-cli 0.0.37 → 0.0.38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/build/commands/check/index.d.ts +1 -0
  2. package/build/commands/check/index.js +11 -1
  3. package/build/commands/check/index.js.map +1 -1
  4. package/build/commands/check/utils/manifest.d.ts +4 -0
  5. package/build/commands/check/utils/manifest.js +26 -0
  6. package/build/commands/check/utils/manifest.js.map +1 -0
  7. package/build/commands/check/utils/schemas/contextual-image.schema.json +21 -0
  8. package/build/commands/check/utils/schemas/contextual-object.schema.json +17 -0
  9. package/build/commands/check/utils/schemas/manifest.schema.json +226 -0
  10. package/build/commands/check/utils/schemas/visibility.schema.json +17 -0
  11. package/package.json +8 -1
  12. package/templates/__template_common/package.json +1 -0
  13. package/templates/__template_hello_world/src/components/ComponentLink.ts +6 -2
  14. package/templates/__template_hello_world/src/components/quiz/ImageCarouselSlide.tsx +54 -0
  15. package/templates/__template_hello_world/src/components/quiz/MultipleChoiceSlide.tsx +77 -0
  16. package/templates/__template_hello_world/src/components/quiz/QuizProvider.tsx +64 -0
  17. package/templates/__template_hello_world/src/components/quiz/QuizSlide.tsx +76 -0
  18. package/templates/__template_hello_world/src/components/quiz/QuizSlideCommander.tsx +35 -0
  19. package/templates/__template_hello_world/src/components/quiz/TextFieldSlide.tsx +47 -0
  20. package/templates/__template_hello_world/src/components/quiz/TextSlide.tsx +6 -0
  21. package/templates/__template_hello_world/src/components/quiz/types.ts +72 -0
  22. package/templates/__template_hello_world/src/hooks/useQuizData.ts +26 -0
  23. package/templates/__template_hello_world/src/hooks/useQuizState.ts +27 -0
  24. package/templates/__template_hello_world/src/routes.tsx +9 -3
  25. package/templates/__template_hello_world/src/screens/{ImageCarouselScreen.tsx → ImageMultipleChoiceScreen.tsx} +4 -6
  26. package/templates/__template_hello_world/src/screens/InputScreen.tsx +42 -58
  27. package/templates/__template_hello_world/src/screens/QuizResultScreen.tsx +82 -0
  28. package/templates/__template_hello_world/src/screens/QuizScreen.tsx +40 -0
  29. package/templates/__template_hello_world/src/screens/QuizSlideScreen.tsx +150 -0
  30. package/templates/__template_hello_world/src/types.ts +2 -1
  31. package/templates/__template_hello_world/src/utils/mockQuizData.ts +313 -0
  32. package/templates/__template_hello_world/src/utils/quizUtils.ts +75 -0
@@ -0,0 +1,76 @@
1
+ import {Box, Button, Text, useTheme} from '@shopify/shop-minis-platform-sdk'
2
+ import {ReactNode} from 'react'
3
+ import {StyleSheet, useWindowDimensions} from 'react-native'
4
+
5
+ import {QuizSlideType} from './types'
6
+
7
+ export interface QuizSlideProps extends QuizSlideType {
8
+ children?: ReactNode
9
+ }
10
+
11
+ export const QuizSlide = (props: QuizSlideProps) => {
12
+ const {
13
+ mainText,
14
+ subText,
15
+ ctaText,
16
+ ctaOnPressHandler,
17
+ ctaDisabled,
18
+ children,
19
+ isTallSlide,
20
+ } = props
21
+
22
+ const theme = useTheme()
23
+ const gutter = theme.spacing.gutter
24
+
25
+ const {height: windowHeight, width} = useWindowDimensions()
26
+
27
+ const containerWidth = width - gutter * 2
28
+ const containerHeight = windowHeight - 245
29
+
30
+ return (
31
+ <Box
32
+ height={containerHeight}
33
+ flex={1}
34
+ paddingHorizontal="gutter"
35
+ paddingTop={isTallSlide ? 'xxxl' : 'auto'}
36
+ position="relative"
37
+ justifyContent="center"
38
+ >
39
+ <Box marginBottom="m" width={containerWidth}>
40
+ <Text variant="subtitle">{mainText}</Text>
41
+ {subText ? (
42
+ <Text marginTop="xxs" variant="bodySmall">
43
+ {subText}
44
+ </Text>
45
+ ) : null}
46
+ </Box>
47
+ <Box marginBottom="xxxl" paddingBottom={isTallSlide ? 'l' : 'none'}>
48
+ {children}
49
+ </Box>
50
+ <Box style={styles.ctaContainer} paddingBottom="s" width={containerWidth}>
51
+ <Button
52
+ size="l"
53
+ style={{width: containerWidth}}
54
+ onPress={
55
+ ctaOnPressHandler
56
+ ? ctaOnPressHandler
57
+ : () => console.log('Next Press')
58
+ }
59
+ variant="secondary"
60
+ text={ctaText ?? 'Next'}
61
+ disabled={ctaDisabled ?? false}
62
+ />
63
+ </Box>
64
+ </Box>
65
+ )
66
+ }
67
+
68
+ const styles = StyleSheet.create({
69
+ ctaContainer: {
70
+ alignItems: 'center',
71
+ position: 'absolute',
72
+ bottom: 0,
73
+ left: 0,
74
+ right: 0,
75
+ },
76
+ })
@@ -0,0 +1,35 @@
1
+ import {ImageCarouselSlide, ImageCarouselSlideProps} from './ImageCarouselSlide'
2
+ import {
3
+ MultipleChoiceSlide,
4
+ MultipleChoiceSlideProps,
5
+ } from './MultipleChoiceSlide'
6
+ import {QuizSlide} from './QuizSlide'
7
+ import {TextFieldSlide, TextFieldSlideProps} from './TextFieldSlide'
8
+ import {TextSlide} from './TextSlide'
9
+ import {QuizSlideScreenType, TextSlideProps} from './types'
10
+
11
+ export interface QuizSlideCommanderProps {
12
+ type: QuizSlideScreenType
13
+ props: TextSlideProps | MultipleChoiceSlideProps | ImageCarouselSlideProps
14
+ }
15
+
16
+ export const QuizSlideCommander = ({type, props}: QuizSlideCommanderProps) => {
17
+ switch (type) {
18
+ case 'TextSlide':
19
+ return <TextSlide {...(props as TextSlideProps)} />
20
+ case 'TextFieldSlide':
21
+ return <TextFieldSlide {...(props as TextFieldSlideProps)} />
22
+ case 'ImageCarouselSlide':
23
+ return <ImageCarouselSlide {...(props as ImageCarouselSlideProps)} />
24
+ case 'MultipleChoiceSlide':
25
+ return <MultipleChoiceSlide {...(props as MultipleChoiceSlideProps)} />
26
+ default:
27
+ return (
28
+ <QuizSlide
29
+ mainText="error"
30
+ subText={`slide type ${type} is unknown`}
31
+ ctaText="oh no!"
32
+ />
33
+ )
34
+ }
35
+ }
@@ -0,0 +1,47 @@
1
+ import {Box, TextField} from '@shopify/shop-minis-platform-sdk'
2
+ import {ComponentProps, useCallback, useEffect, useState} from 'react'
3
+
4
+ import {QuizSlide, QuizSlideProps} from './QuizSlide'
5
+ import {SlideLogic} from './types'
6
+
7
+ export interface TextFieldSlideProps extends SlideLogic<string> {
8
+ quizSlideProps: QuizSlideProps
9
+ textFieldProps: ComponentProps<typeof TextField>
10
+ }
11
+
12
+ export const TextFieldSlide = ({
13
+ quizSlideProps,
14
+ textFieldProps,
15
+ determineCtaDisabled,
16
+ handleAnswerSelection,
17
+ }: TextFieldSlideProps) => {
18
+ const [fieldValue, setFieldValue] = useState<string>()
19
+
20
+ const [isCtaDisabled, setCtaDisabled] = useState(
21
+ quizSlideProps.ctaDisabled ?? false
22
+ )
23
+
24
+ const handleChange = useCallback((newTextValue: string) => {
25
+ setFieldValue(newTextValue)
26
+ }, [])
27
+
28
+ useEffect(() => {
29
+ if (handleAnswerSelection === undefined || fieldValue === undefined) return
30
+
31
+ handleAnswerSelection(fieldValue)
32
+ }, [fieldValue, handleAnswerSelection])
33
+
34
+ useEffect(() => {
35
+ if (determineCtaDisabled === undefined || fieldValue === undefined) return
36
+
37
+ setCtaDisabled(determineCtaDisabled(fieldValue))
38
+ }, [determineCtaDisabled, fieldValue])
39
+
40
+ return (
41
+ <QuizSlide {...quizSlideProps} ctaDisabled={isCtaDisabled}>
42
+ <Box marginBottom="xl">
43
+ <TextField {...textFieldProps} onChangeText={handleChange} />
44
+ </Box>
45
+ </QuizSlide>
46
+ )
47
+ }
@@ -0,0 +1,6 @@
1
+ import {QuizSlide} from './QuizSlide'
2
+ import {TextSlideProps} from './types'
3
+
4
+ export const TextSlide = (props: TextSlideProps) => {
5
+ return <QuizSlide {...props.quizSlideProps} />
6
+ }
@@ -0,0 +1,72 @@
1
+ import type {ImageCarouselSlideProps} from './ImageCarouselSlide'
2
+ import type {MultipleChoiceSlideProps} from './MultipleChoiceSlide'
3
+ import type {TextFieldSlideProps} from './TextFieldSlide'
4
+
5
+ export interface QuizSlideType {
6
+ mainText: string
7
+ ctaOnPressHandler?: () => void
8
+ ctaDisabled?: boolean
9
+ subText?: string
10
+ ctaText?: string // default to 'next'
11
+ isTallSlide?: boolean
12
+ }
13
+
14
+ export interface TextSlideProps extends SlideLogic<string> {
15
+ quizSlideProps: QuizSlideType
16
+ }
17
+
18
+ export type QuizSlideScreenType =
19
+ | 'TextSlide'
20
+ | 'TextFieldSlide'
21
+ | 'MultipleChoiceSlide'
22
+ | 'ImageCarouselSlide'
23
+
24
+ export interface SlideInformation {
25
+ id: string
26
+ type: QuizSlideScreenType
27
+ // When adding the slide props, we get a dependency cycle
28
+ props:
29
+ | TextSlideProps
30
+ | TextFieldSlideProps
31
+ | MultipleChoiceSlideProps
32
+ | ImageCarouselSlideProps
33
+ }
34
+
35
+ export interface QuizData {
36
+ slides: SlideInformation[]
37
+ }
38
+
39
+ export interface SlideLogic<T extends QuizAnswerType> {
40
+ handleAnswerSelection?: (answer: T) => void
41
+ determineNextSlide?: (answer: T) => string
42
+ determineCtaDisabled?: (answer: T) => boolean
43
+ nextSlideId?: string
44
+ }
45
+
46
+ // @react-navigation/native-stack requires a `type` instead of an `interface`
47
+ // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
48
+ export type QuizStackParamList = {
49
+ '__MINI_APP_HANDLE_PASCAL_CASE__.QuizResult': undefined
50
+ '__MINI_APP_HANDLE_PASCAL_CASE__.QuizSlide': {
51
+ slideIndex: number
52
+ }
53
+ }
54
+
55
+ export interface SlideChoiceConsequence {
56
+ nextSlideId?: string
57
+ skipSlideIds?: [string]
58
+ }
59
+
60
+ export type QuizAnswerType = string | number | number[]
61
+
62
+ export type DetermineNextSlide<T> = (answer: T) => string
63
+
64
+ export interface QuizResultEntry {
65
+ slideType: QuizSlideScreenType
66
+ answer: QuizAnswerType
67
+ }
68
+
69
+ // key is the ID of the question
70
+ export type QuizResult = Record<string, QuizResultEntry>
71
+
72
+ export type QuizDataState = 'Loading' | 'Ready'
@@ -0,0 +1,26 @@
1
+ import {useEffect, useState} from 'react'
2
+
3
+ import {QuizData, QuizDataState} from '../components/quiz/types'
4
+ import {mockQuizData} from '../utils/mockQuizData'
5
+
6
+ const MOCK_FETCH_TIME = 2000
7
+
8
+ export const useQuizData = () => {
9
+ const [quizDataState, setQuizDataState] = useState<QuizDataState>('Loading')
10
+ const [quizData, setQuizData] = useState<QuizData>()
11
+
12
+ // Here is where you would fetch the quesitons from your server
13
+ // and process them into the shape you need
14
+ useEffect(() => {
15
+ const timer = setTimeout(() => {
16
+ setQuizData(mockQuizData)
17
+ setQuizDataState('Ready')
18
+ }, MOCK_FETCH_TIME)
19
+ return () => clearTimeout(timer)
20
+ }, [])
21
+
22
+ return {
23
+ quizDataState,
24
+ quizData,
25
+ }
26
+ }
@@ -0,0 +1,27 @@
1
+ import {useCallback, useState} from 'react'
2
+
3
+ import {QuizResult, QuizResultEntry} from '../components/quiz/types'
4
+
5
+ export const useQuizState = () => {
6
+ const [userName, setUserName] = useState('you')
7
+
8
+ const [quizResult, setQuizResult] = useState<QuizResult>()
9
+
10
+ const recordQuestionResult = useCallback(
11
+ (id: string, answer: QuizResultEntry) => {
12
+ const newQuizResult = {
13
+ ...quizResult,
14
+ [id]: answer,
15
+ }
16
+ setQuizResult(newQuizResult)
17
+ },
18
+ [quizResult]
19
+ )
20
+
21
+ return {
22
+ recordQuestionResult,
23
+ quizResult,
24
+ setUserName,
25
+ userName,
26
+ }
27
+ }
@@ -18,7 +18,8 @@ import {ProductCardScreen} from './screens/ProductCardScreen'
18
18
  import {ProductCardGridScreen} from './screens/ProductCardGridScreen'
19
19
  import {InputScreen} from './screens/InputScreen'
20
20
  import {MultipleChoiceScreen} from './screens/MultipleChoiceScreen'
21
- import {ImageCarouselScreen} from './screens/ImageCarouselScreen'
21
+ import {QuizScreen} from './screens/QuizScreen'
22
+ import {ImageMultipleChoiceScreen} from './screens/ImageMultipleChoiceScreen'
22
23
 
23
24
  const Stack = createNativeStackNavigator()
24
25
 
@@ -116,8 +117,13 @@ export const __MINI_APP_HANDLE_PASCAL_CASE__Navigator = () => {
116
117
  options={{headerShown: false}}
117
118
  />
118
119
  <Stack.Screen
119
- name="__MINI_APP_HANDLE_PASCAL_CASE__.ImageCarousel"
120
- component={ImageCarouselScreen}
120
+ name="__MINI_APP_HANDLE_PASCAL_CASE__.ImageMultipleChoice"
121
+ component={ImageMultipleChoiceScreen}
122
+ options={{headerShown: false}}
123
+ />
124
+ <Stack.Screen
125
+ name="__MINI_APP_HANDLE_PASCAL_CASE__.Quiz"
126
+ component={QuizScreen}
121
127
  options={{headerShown: false}}
122
128
  />
123
129
  </Stack.Navigator>
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Box,
3
3
  Button,
4
- ImageCarousel,
4
+ ImageMultipleChoice,
5
5
  ImageChoiceType,
6
6
  Text,
7
7
  useMultiSelect,
@@ -9,7 +9,6 @@ import {
9
9
  } from '@shopify/shop-minis-platform-sdk'
10
10
  import {useMemo, useState} from 'react'
11
11
  import {SafeAreaView, ScrollView} from 'react-native'
12
- import {Header} from '../components/Header'
13
12
 
14
13
  const DEFAULT_IMAGE_SIZE = 160
15
14
  const MOCK_IMAGE_INDEX_OFFSET = 20
@@ -62,7 +61,7 @@ const ControlSection = ({label, children}: ControlSectionProps) => (
62
61
  {children}
63
62
  </Box>
64
63
  )
65
- export const ImageCarouselScreen = () => {
64
+ export const ImageMultipleChoiceScreen = () => {
66
65
  const [choiceText, setChoiceText] =
67
66
  useState<keyof typeof textOptions>('short')
68
67
 
@@ -82,7 +81,6 @@ export const ImageCarouselScreen = () => {
82
81
 
83
82
  return (
84
83
  <SafeAreaView style={{flex: 1}}>
85
- <Header />
86
84
  <Box paddingVertical="xs">
87
85
  <ControlSection label="Text Length">
88
86
  <Box flexDirection="row">
@@ -120,7 +118,7 @@ export const ImageCarouselScreen = () => {
120
118
  <Box marginVertical="s" marginHorizontal="gutter">
121
119
  <Text variant="headerNormal">Single Select</Text>
122
120
  </Box>
123
- <ImageCarousel
121
+ <ImageMultipleChoice
124
122
  initialOffsetX={theme.spacing.gutter}
125
123
  imageSize={imageSize}
126
124
  choices={choices}
@@ -133,7 +131,7 @@ export const ImageCarouselScreen = () => {
133
131
  <Box marginVertical="s" marginHorizontal="gutter">
134
132
  <Text variant="headerNormal">Multi Select</Text>
135
133
  </Box>
136
- <ImageCarousel
134
+ <ImageMultipleChoice
137
135
  initialOffsetX={theme.spacing.gutter}
138
136
  imageSize={imageSize}
139
137
  choices={choices}
@@ -2,22 +2,23 @@ import {ItemValue} from '@react-native-community/picker/typings/Picker'
2
2
  import {
3
3
  Box,
4
4
  DatePicker,
5
- Icon,
6
5
  KeyboardAvoidingView,
7
6
  Picker,
7
+ TextFieldPhoneNumber,
8
8
  TextField,
9
+ TextFieldAutofill,
9
10
  Text,
11
+ countryCodesAndPhonePrefixes,
12
+ getFlagEmoji,
10
13
  } from '@shopify/shop-minis-platform-sdk'
11
14
  import {useState} from 'react'
12
15
  import {
13
16
  NativeSyntheticEvent,
14
- Pressable,
15
17
  SafeAreaView,
16
18
  ScrollView,
17
19
  TextInputEndEditingEventData,
18
20
  } from 'react-native'
19
21
 
20
- import {getFlagEmoji} from '../utils/getFlagEmoji'
21
22
  import {Header} from '../components/Header'
22
23
 
23
24
  interface Item {
@@ -26,31 +27,12 @@ interface Item {
26
27
  selected?: boolean
27
28
  }
28
29
 
29
- const countryCodeToPrefixMap = {
30
- US: '+1',
31
- DE: '+49',
32
- NL: '+31',
33
- BR: '+55',
34
- }
35
-
36
- const countryData: Item[] = [
37
- {
38
- value: 'US',
39
- label: `US ${getFlagEmoji('US')}`,
40
- },
41
- {
42
- value: 'DE',
43
- label: `DE ${getFlagEmoji('DE')}`,
44
- },
45
- {
46
- value: 'BR',
47
- label: `BR ${getFlagEmoji('BR')}`,
48
- },
49
- {
50
- value: 'NL',
51
- label: `NL ${getFlagEmoji('NL')}`,
52
- },
53
- ]
30
+ const countryData: Item[] = countryCodesAndPhonePrefixes.map(
31
+ ({code, name}) => ({
32
+ value: code,
33
+ label: `${name} ${getFlagEmoji(code)}`,
34
+ })
35
+ )
54
36
 
55
37
  export const InputScreen = () => {
56
38
  const [showCountryPicker, setShowCountryPicker] = useState(false)
@@ -85,14 +67,38 @@ export const InputScreen = () => {
85
67
  </Box>
86
68
  <Box marginBottom="s">
87
69
  <Box marginBottom="xs">
88
- <Text variant="bodyLargeBold">Text / Email</Text>
70
+ <Text variant="bodyLargeBold">Text</Text>
89
71
  </Box>
90
72
 
91
73
  <TextField
74
+ placeholder="Enter a word"
75
+ onChangeText={console.log}
76
+ />
77
+ </Box>
78
+ <Box marginBottom="s">
79
+ <Box marginBottom="xs">
80
+ <Text variant="bodyLargeBold">Email with Autofill</Text>
81
+ </Box>
82
+
83
+ <TextFieldAutofill
84
+ type="email"
85
+ shopId="shopify"
92
86
  placeholder="Enter your email"
93
87
  onChangeText={console.log}
94
88
  />
95
89
  </Box>
90
+ <Box marginBottom="s">
91
+ <Box marginBottom="xs">
92
+ <Text variant="bodyLargeBold">Name with Autofill</Text>
93
+ </Box>
94
+
95
+ <TextFieldAutofill
96
+ type="name"
97
+ shopId="shopify"
98
+ placeholder="Enter your name"
99
+ onChangeText={console.log}
100
+ />
101
+ </Box>
96
102
  <Box marginBottom="s">
97
103
  <Box marginBottom="xs">
98
104
  <Text variant="bodyLargeBold">Date</Text>
@@ -113,36 +119,14 @@ export const InputScreen = () => {
113
119
  </Box>
114
120
  <Box marginBottom="s">
115
121
  <Box marginBottom="xs">
116
- <Text variant="bodyLargeBold">Select / Trailing component</Text>
122
+ <Text variant="bodyLargeBold">TextFieldPhoneNumber</Text>
117
123
  </Box>
118
- <TextField
119
- placeholder="Enter Your Phone"
120
- leadingComponent={
121
- selectedCountry ? (
122
- <Text marginEnd="xs">
123
- {
124
- countryCodeToPrefixMap[
125
- selectedCountry as keyof typeof countryCodeToPrefixMap
126
- ]
127
- }
128
- </Text>
129
- ) : null
130
- }
131
- trailingComponent={
132
- <Pressable onPress={() => setShowCountryPicker(true)}>
133
- <Box
134
- flexDirection="row"
135
- borderStartWidth={1}
136
- borderStartColor="inputs-border-color"
137
- paddingStart="xs"
138
- >
139
- <Text marginEnd="xs">
140
- {getFlagEmoji(selectedCountry ?? 'US')}
141
- </Text>
142
- <Icon name="chevron-down" />
143
- </Box>
144
- </Pressable>
145
- }
124
+ <TextFieldPhoneNumber
125
+ selectedCountry={selectedCountry}
126
+ onFlagPress={() => setShowCountryPicker(true)}
127
+ shopId="shop"
128
+ autofill
129
+ onPhoneInfoChange={console.log}
146
130
  />
147
131
  </Box>
148
132
  <Box marginBottom="s">
@@ -0,0 +1,82 @@
1
+ import {Box, Text} from '@shopify/shop-minis-platform-sdk'
2
+ import {useMemo} from 'react'
3
+ import {Image, SafeAreaView, ScrollView} from 'react-native'
4
+
5
+ import {useQuizContext} from '../components/quiz/QuizProvider'
6
+ import {
7
+ addNameToText,
8
+ getImageCarouselAnswerUrls,
9
+ getMultilpleChoiceAnswerLabels,
10
+ getQuestionById,
11
+ } from '../utils/quizUtils'
12
+
13
+ export const QuizResultScreen = () => {
14
+ const {quizResult, quizData, userName} = useQuizContext()
15
+
16
+ const formattedResults = useMemo(() => {
17
+ if (!quizData) return []
18
+
19
+ return Object.entries(quizResult!).map(([questionId, result]) => {
20
+ let answer = ''
21
+ // image carousel type will be an imageUrl
22
+ let type: 'imageUrl' | 'string' = 'string'
23
+
24
+ switch (result.slideType) {
25
+ case 'MultipleChoiceSlide':
26
+ answer = getMultilpleChoiceAnswerLabels(
27
+ quizData,
28
+ questionId,
29
+ result.answer as number[]
30
+ ).join(', ')
31
+ break
32
+ case 'ImageCarouselSlide':
33
+ type = 'imageUrl'
34
+ answer = getImageCarouselAnswerUrls(
35
+ quizData,
36
+ questionId,
37
+ result.answer as number[]
38
+ )[0]
39
+ break
40
+ default:
41
+ answer = result.answer as string
42
+ }
43
+
44
+ const question = addNameToText(
45
+ getQuestionById(quizData, questionId),
46
+ userName
47
+ )
48
+
49
+ return {
50
+ type,
51
+ question,
52
+ answer,
53
+ }
54
+ })
55
+ }, [quizData, quizResult, userName])
56
+
57
+ return (
58
+ <SafeAreaView>
59
+ <ScrollView>
60
+ <Box paddingHorizontal="gutter" paddingVertical="xs">
61
+ <Text variant="posterXS" textAlign="center" marginVertical="m">
62
+ Results
63
+ </Text>
64
+ {formattedResults.map(({question, answer, type}, index) => (
65
+ <Box key={question} marginBottom="s">
66
+ <Text variant="headerNormal" marginBottom="xs">
67
+ {index + 1}. {question}
68
+ </Text>
69
+ {type === 'imageUrl' ? (
70
+ <Image
71
+ style={{width: 160, height: 160}}
72
+ source={{uri: answer}}
73
+ />
74
+ ) : null}
75
+ {type === 'string' ? <Text>Answer: {answer}</Text> : null}
76
+ </Box>
77
+ ))}
78
+ </Box>
79
+ </ScrollView>
80
+ </SafeAreaView>
81
+ )
82
+ }
@@ -0,0 +1,40 @@
1
+ import {NavigationContainer} from '@react-navigation/native'
2
+ import {createNativeStackNavigator} from '@react-navigation/native-stack'
3
+
4
+ import {Header} from '../components/Header'
5
+ import {QuizContextProvider} from '../components/quiz/QuizProvider'
6
+
7
+ import {QuizResultScreen} from './QuizResultScreen'
8
+ import {QuizSlideScreen} from './QuizSlideScreen'
9
+
10
+ const Stack = createNativeStackNavigator()
11
+
12
+ export const QuizScreen = () => {
13
+ return (
14
+ <QuizContextProvider>
15
+ <>
16
+ <Header />
17
+ <NavigationContainer independent>
18
+ <Stack.Navigator>
19
+ <Stack.Screen
20
+ name="__MINI_APP_HANDLE_PASCAL_CASE__.QuizSlide"
21
+ component={QuizSlideScreen}
22
+ options={{
23
+ title: '__MINI_APP_HANDLE_PASCAL_CASE__ Quiz',
24
+ headerBackTitle: 'Previous',
25
+ }}
26
+ initialParams={{
27
+ slideIndex: 0,
28
+ }}
29
+ />
30
+ <Stack.Screen
31
+ name="__MINI_APP_HANDLE_PASCAL_CASE__.QuizResult"
32
+ component={QuizResultScreen}
33
+ options={{headerShown: false}}
34
+ />
35
+ </Stack.Navigator>
36
+ </NavigationContainer>
37
+ </>
38
+ </QuizContextProvider>
39
+ )
40
+ }