@shopify/shop-minis-cli 0.0.37 → 0.0.39

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 (173) hide show
  1. package/.eslintrc.cjs +84 -0
  2. package/.vscode/extensions.json +3 -0
  3. package/.vscode/settings.json +8 -0
  4. package/.vscode/shop-minis-cli.code-workspace +8 -0
  5. package/build/commands/cancel-submission/index.d.ts +2 -0
  6. package/build/commands/cancel-submission/index.js +22 -0
  7. package/build/commands/cancel-submission/index.js.map +1 -0
  8. package/build/commands/cancel-submission/types.d.ts +3 -0
  9. package/build/commands/cancel-submission/types.js +2 -0
  10. package/build/commands/cancel-submission/types.js.map +1 -0
  11. package/build/commands/check-submission/index.d.ts +2 -0
  12. package/build/commands/check-submission/index.js +22 -0
  13. package/build/commands/check-submission/index.js.map +1 -0
  14. package/build/commands/check-submission/types.d.ts +3 -0
  15. package/build/commands/check-submission/types.js +2 -0
  16. package/build/commands/check-submission/types.js.map +1 -0
  17. package/build/commands/config.d.ts +10 -0
  18. package/build/commands/config.js +34 -0
  19. package/build/commands/config.js.map +1 -0
  20. package/build/commands/create-mini/index.js +38 -40
  21. package/build/commands/create-mini/index.js.map +1 -1
  22. package/build/commands/create-mini/utils/template-app.js +20 -25
  23. package/build/commands/create-mini/utils/template-app.js.map +1 -1
  24. package/build/commands/dev/index.js +13 -20
  25. package/build/commands/dev/index.js.map +1 -1
  26. package/build/commands/dev/utils/android.js +34 -48
  27. package/build/commands/dev/utils/android.js.map +1 -1
  28. package/build/commands/dev/utils/binaries.d.ts +1 -22
  29. package/build/commands/dev/utils/binaries.js +19 -98
  30. package/build/commands/dev/utils/binaries.js.map +1 -1
  31. package/build/commands/dev/utils/deeplink.d.ts +1 -1
  32. package/build/commands/dev/utils/deeplink.js +2 -7
  33. package/build/commands/dev/utils/deeplink.js.map +1 -1
  34. package/build/commands/dev/utils/interactive-terminal.d.ts +1 -1
  35. package/build/commands/dev/utils/interactive-terminal.js +46 -52
  36. package/build/commands/dev/utils/interactive-terminal.js.map +1 -1
  37. package/build/commands/dev/utils/metro/metro-config.js +19 -20
  38. package/build/commands/dev/utils/metro/metro-config.js.map +1 -1
  39. package/build/commands/dev/utils/metro/metro-reporter.d.ts +2 -3
  40. package/build/commands/dev/utils/metro/metro-reporter.js +7 -12
  41. package/build/commands/dev/utils/metro/metro-reporter.js.map +1 -1
  42. package/build/commands/dev/utils/metro/metro-server-middleware.js +5 -12
  43. package/build/commands/dev/utils/metro/metro-server-middleware.js.map +1 -1
  44. package/build/commands/dev/utils/metro/metro-server.d.ts +1 -1
  45. package/build/commands/dev/utils/metro/metro-server.js +6 -13
  46. package/build/commands/dev/utils/metro/metro-server.js.map +1 -1
  47. package/build/commands/dev/utils/network.d.ts +20 -0
  48. package/build/commands/dev/utils/network.js +62 -0
  49. package/build/commands/dev/utils/network.js.map +1 -0
  50. package/build/commands/dev/utils/qr-code.js +3 -10
  51. package/build/commands/dev/utils/qr-code.js.map +1 -1
  52. package/build/commands/dev/utils/simulator.js +25 -35
  53. package/build/commands/dev/utils/simulator.js.map +1 -1
  54. package/build/commands/dev/utils/types.d.ts +1 -0
  55. package/build/commands/dev/utils/types.js +2 -0
  56. package/build/commands/dev/utils/types.js.map +1 -0
  57. package/build/commands/dev/utils/with-retries.js +1 -5
  58. package/build/commands/dev/utils/with-retries.js.map +1 -1
  59. package/build/commands/generate-graphql-types/index.js +25 -26
  60. package/build/commands/generate-graphql-types/index.js.map +1 -1
  61. package/build/commands/schemas/contextual-image.schema.d.ts +22 -0
  62. package/build/commands/schemas/contextual-image.schema.js +23 -0
  63. package/build/commands/schemas/contextual-image.schema.js.map +1 -0
  64. package/build/commands/schemas/contextual-object.schema.d.ts +18 -0
  65. package/build/commands/schemas/contextual-object.schema.js +19 -0
  66. package/build/commands/schemas/contextual-object.schema.js.map +1 -0
  67. package/build/commands/schemas/manifest.schema.d.ts +181 -0
  68. package/build/commands/schemas/manifest.schema.js +230 -0
  69. package/build/commands/schemas/manifest.schema.js.map +1 -0
  70. package/build/commands/schemas/visibility.schema.d.ts +18 -0
  71. package/build/commands/schemas/visibility.schema.js +19 -0
  72. package/build/commands/schemas/visibility.schema.js.map +1 -0
  73. package/build/commands/submit/config.d.ts +9 -0
  74. package/build/commands/submit/config.js +18 -0
  75. package/build/commands/submit/config.js.map +1 -0
  76. package/build/commands/submit/errors.d.ts +19 -0
  77. package/build/commands/submit/errors.js +87 -0
  78. package/build/commands/submit/errors.js.map +1 -0
  79. package/build/commands/submit/gcs.d.ts +6 -0
  80. package/build/commands/submit/gcs.js +10 -0
  81. package/build/commands/submit/gcs.js.map +1 -0
  82. package/build/commands/submit/graphql.d.ts +73 -0
  83. package/build/commands/submit/graphql.js +100 -0
  84. package/build/commands/submit/graphql.js.map +1 -0
  85. package/build/commands/submit/index.d.ts +2 -0
  86. package/build/commands/submit/index.js +21 -0
  87. package/build/commands/submit/index.js.map +1 -0
  88. package/build/commands/submit/submit.d.ts +4 -0
  89. package/build/commands/submit/submit.js +171 -0
  90. package/build/commands/submit/submit.js.map +1 -0
  91. package/build/commands/submit/tasks.d.ts +39 -0
  92. package/build/commands/submit/tasks.js +167 -0
  93. package/build/commands/submit/tasks.js.map +1 -0
  94. package/build/commands/submit/types.d.ts +14 -0
  95. package/build/commands/submit/types.js +2 -0
  96. package/build/commands/submit/types.js.map +1 -0
  97. package/build/commands/submit/validation.d.ts +2 -0
  98. package/build/commands/submit/validation.js +14 -0
  99. package/build/commands/submit/validation.js.map +1 -0
  100. package/build/commands/types/autogenerated/shop-minis-admin-api/fragment-masking.d.ts +13 -0
  101. package/build/commands/types/autogenerated/shop-minis-admin-api/fragment-masking.js +7 -0
  102. package/build/commands/types/autogenerated/shop-minis-admin-api/fragment-masking.js.map +1 -0
  103. package/build/commands/types/autogenerated/shop-minis-admin-api/gql.d.ts +54 -0
  104. package/build/commands/types/autogenerated/shop-minis-admin-api/gql.js +21 -0
  105. package/build/commands/types/autogenerated/shop-minis-admin-api/gql.js.map +1 -0
  106. package/build/commands/types/autogenerated/shop-minis-admin-api/graphql.d.ts +613 -0
  107. package/build/commands/types/autogenerated/shop-minis-admin-api/graphql.js +427 -0
  108. package/build/commands/types/autogenerated/shop-minis-admin-api/graphql.js.map +1 -0
  109. package/build/commands/types/autogenerated/shop-minis-admin-api/index.d.ts +2 -0
  110. package/build/commands/types/autogenerated/shop-minis-admin-api/index.js +3 -0
  111. package/build/commands/types/autogenerated/shop-minis-admin-api/index.js.map +1 -0
  112. package/build/commands/types/helpers.d.ts +1 -0
  113. package/build/commands/types/helpers.js +2 -0
  114. package/build/commands/types/helpers.js.map +1 -0
  115. package/build/commands/utils/archive.d.ts +30 -0
  116. package/build/commands/utils/archive.js +38 -0
  117. package/build/commands/utils/archive.js.map +1 -0
  118. package/build/commands/utils/exec-async-child-process.d.ts +1 -1
  119. package/build/commands/utils/exec-async-child-process.js +6 -13
  120. package/build/commands/utils/exec-async-child-process.js.map +1 -1
  121. package/build/commands/utils/file.d.ts +1 -0
  122. package/build/commands/utils/file.js +7 -0
  123. package/build/commands/utils/file.js.map +1 -0
  124. package/build/commands/utils/minis-manifest.d.ts +5 -0
  125. package/build/commands/utils/minis-manifest.js +42 -0
  126. package/build/commands/utils/minis-manifest.js.map +1 -0
  127. package/build/commands/utils/wrap-with-loading-indicator.js +3 -10
  128. package/build/commands/utils/wrap-with-loading-indicator.js.map +1 -1
  129. package/build/dev-panel/middleware.js +5 -10
  130. package/build/dev-panel/middleware.js.map +1 -1
  131. package/build/index.js +15 -13
  132. package/build/index.js.map +1 -1
  133. package/jest.config.ts +11 -0
  134. package/package.json +11 -7
  135. package/scripts/graphql-codegen.ts +23 -0
  136. package/templates/__template_common/.eslintrc.json +2 -119
  137. package/templates/__template_common/gitignore +1 -0
  138. package/templates/__template_common/package.json +9 -7
  139. package/templates/__template_common/src/manifest.json +1 -0
  140. package/templates/__template_hello_world/src/components/ComponentLink.ts +6 -2
  141. package/templates/__template_hello_world/src/components/quiz/ImageCarouselSlide.tsx +54 -0
  142. package/templates/__template_hello_world/src/components/quiz/MultipleChoiceSlide.tsx +77 -0
  143. package/templates/__template_hello_world/src/components/quiz/QuizProvider.tsx +64 -0
  144. package/templates/__template_hello_world/src/components/quiz/QuizSlide.tsx +76 -0
  145. package/templates/__template_hello_world/src/components/quiz/QuizSlideCommander.tsx +35 -0
  146. package/templates/__template_hello_world/src/components/quiz/TextFieldSlide.tsx +47 -0
  147. package/templates/__template_hello_world/src/components/quiz/TextSlide.tsx +6 -0
  148. package/templates/__template_hello_world/src/components/quiz/types.ts +72 -0
  149. package/templates/__template_hello_world/src/hooks/useQuizData.ts +26 -0
  150. package/templates/__template_hello_world/src/hooks/useQuizState.ts +27 -0
  151. package/templates/__template_hello_world/src/routes.tsx +9 -3
  152. package/templates/__template_hello_world/src/screens/BottomSheetScreen.tsx +6 -5
  153. package/templates/__template_hello_world/src/screens/{ImageCarouselScreen.tsx → ImageMultipleChoiceScreen.tsx} +4 -6
  154. package/templates/__template_hello_world/src/screens/InputScreen.tsx +42 -58
  155. package/templates/__template_hello_world/src/screens/QuizResultScreen.tsx +82 -0
  156. package/templates/__template_hello_world/src/screens/QuizScreen.tsx +40 -0
  157. package/templates/__template_hello_world/src/screens/QuizSlideScreen.tsx +150 -0
  158. package/templates/__template_hello_world/src/types.ts +2 -1
  159. package/templates/__template_hello_world/src/utils/mockQuizData.ts +313 -0
  160. package/templates/__template_hello_world/src/utils/quizUtils.ts +75 -0
  161. package/build/commands/check/index.d.ts +0 -5
  162. package/build/commands/check/index.js +0 -77
  163. package/build/commands/check/index.js.map +0 -1
  164. package/build/commands/check/utils/versions.d.ts +0 -1
  165. package/build/commands/check/utils/versions.js +0 -14
  166. package/build/commands/check/utils/versions.js.map +0 -1
  167. package/build/commands/dev/utils/binaries.test.d.ts +0 -1
  168. package/build/commands/dev/utils/binaries.test.js +0 -275
  169. package/build/commands/dev/utils/binaries.test.js.map +0 -1
  170. package/build/commands/dev/utils/minis-manifest.d.ts +0 -1
  171. package/build/commands/dev/utils/minis-manifest.js +0 -24
  172. package/build/commands/dev/utils/minis-manifest.js.map +0 -1
  173. package/templates/__template_hello_world/src/utils/getFlagEmoji.spec.tsx +0 -19
@@ -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="QuizScreen.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="QuizScreen.QuizResult"
32
+ component={QuizResultScreen}
33
+ options={{headerShown: false}}
34
+ />
35
+ </Stack.Navigator>
36
+ </NavigationContainer>
37
+ </>
38
+ </QuizContextProvider>
39
+ )
40
+ }
@@ -0,0 +1,150 @@
1
+ import {RouteProp, useNavigation, useRoute} from '@react-navigation/native'
2
+ import {NativeStackNavigationProp} from '@react-navigation/native-stack'
3
+ import {Box, Spinner, Text} from '@shopify/shop-minis-platform-sdk'
4
+ import {useCallback, useMemo, useState} from 'react'
5
+ import {SafeAreaView, ScrollView} from 'react-native'
6
+
7
+ import {useQuizContext} from '../components/quiz/QuizProvider'
8
+ import {
9
+ QuizSlideCommander,
10
+ QuizSlideCommanderProps,
11
+ } from '../components/quiz/QuizSlideCommander'
12
+ import {QuizAnswerType, QuizStackParamList} from '../components/quiz/types'
13
+ import {
14
+ addNameToText,
15
+ getQuizSlideDataByIndex,
16
+ getQuizSlideIndexById,
17
+ } from '../utils/quizUtils'
18
+
19
+ export const QuizSlideScreen = () => {
20
+ const navigation =
21
+ useNavigation<NativeStackNavigationProp<QuizStackParamList>>()
22
+ const route: RouteProp<{params: {slideIndex: number}}, 'params'> = useRoute()
23
+
24
+ const [currentSlideAnswer, setCurrentSlideAnswer] = useState<QuizAnswerType>()
25
+
26
+ const currentSlideIndex = route.params?.slideIndex ?? 0
27
+
28
+ const {recordQuestionResult, quizData, quizDataState, setUserName, userName} =
29
+ useQuizContext()
30
+
31
+ const slideData = useMemo(
32
+ () =>
33
+ quizData
34
+ ? getQuizSlideDataByIndex(quizData, currentSlideIndex)
35
+ : undefined,
36
+ [currentSlideIndex, quizData]
37
+ )
38
+
39
+ const determineNextSlideIndex = useCallback(() => {
40
+ if (!quizData || !slideData) return 0
41
+
42
+ let determinedNextSlideId = ''
43
+
44
+ const {nextSlideId, determineNextSlide} = slideData.props
45
+
46
+ if (nextSlideId) {
47
+ determinedNextSlideId = nextSlideId
48
+ }
49
+
50
+ if (currentSlideAnswer && determineNextSlide) {
51
+ // the type of the parameter for determineNextSlide cannot be determined
52
+ // because it is generic but it will a QuizAnswerType
53
+ determinedNextSlideId = determineNextSlide(currentSlideAnswer as any)
54
+ }
55
+
56
+ if (determinedNextSlideId === '') return currentSlideIndex + 1
57
+
58
+ return getQuizSlideIndexById(quizData, determinedNextSlideId)
59
+ }, [currentSlideAnswer, currentSlideIndex, quizData, slideData])
60
+
61
+ const handleNextCtaPress = useCallback(() => {
62
+ if (!quizData) return
63
+
64
+ if (currentSlideAnswer !== undefined) {
65
+ const {id, type: slideType} = getQuizSlideDataByIndex(
66
+ quizData,
67
+ currentSlideIndex
68
+ )
69
+
70
+ recordQuestionResult(id, {
71
+ answer: currentSlideAnswer,
72
+ slideType,
73
+ })
74
+ }
75
+
76
+ if (slideData?.id === 'enter-name' && currentSlideAnswer) {
77
+ setUserName(currentSlideAnswer as string)
78
+ }
79
+
80
+ if (slideData?.props.nextSlideId === 'results') {
81
+ navigation.replace('QuizScreen.QuizResult')
82
+ return
83
+ }
84
+
85
+ navigation.push('QuizScreen.QuizSlide', {
86
+ slideIndex: determineNextSlideIndex(),
87
+ })
88
+ }, [
89
+ currentSlideAnswer,
90
+ currentSlideIndex,
91
+ determineNextSlideIndex,
92
+ navigation,
93
+ quizData,
94
+ recordQuestionResult,
95
+ setUserName,
96
+ slideData?.id,
97
+ slideData?.props.nextSlideId,
98
+ ])
99
+
100
+ const handleAnswerSelection = useCallback((answer: QuizAnswerType) => {
101
+ setCurrentSlideAnswer(answer)
102
+ }, [])
103
+
104
+ if (quizDataState === 'Loading') {
105
+ return (
106
+ <SafeAreaView>
107
+ <ScrollView>
108
+ <Box paddingHorizontal="gutter" paddingVertical="xl">
109
+ <Text textAlign="center">Please wait, systems processing</Text>
110
+ <Box
111
+ height={180}
112
+ flex={1}
113
+ justifyContent="center"
114
+ alignItems="center"
115
+ >
116
+ <Spinner size="large" />
117
+ </Box>
118
+ </Box>
119
+ </ScrollView>
120
+ </SafeAreaView>
121
+ )
122
+ }
123
+
124
+ // if quizDataState is not Loading, then data is ready
125
+ const {type, props} = slideData!
126
+
127
+ const mainTextWithUserName = addNameToText(
128
+ props.quizSlideProps.mainText,
129
+ userName
130
+ )
131
+
132
+ const enrichedSlideProps: QuizSlideCommanderProps['props'] = {
133
+ ...props,
134
+ quizSlideProps: {
135
+ ...props.quizSlideProps,
136
+ mainText: mainTextWithUserName,
137
+ ctaOnPressHandler: handleNextCtaPress,
138
+ },
139
+ handleAnswerSelection,
140
+ }
141
+ return (
142
+ <SafeAreaView>
143
+ <ScrollView>
144
+ <Box paddingHorizontal="gutter" paddingVertical="xs">
145
+ <QuizSlideCommander type={type} props={enrichedSlideProps} />
146
+ </Box>
147
+ </ScrollView>
148
+ </SafeAreaView>
149
+ )
150
+ }
@@ -10,7 +10,7 @@ export type StackParamList = {
10
10
  '__MINI_APP_HANDLE_PASCAL_CASE__.BottomSheet': undefined
11
11
  '__MINI_APP_HANDLE_PASCAL_CASE__.Buttons': undefined
12
12
  '__MINI_APP_HANDLE_PASCAL_CASE__.Icons': undefined
13
- '__MINI_APP_HANDLE_PASCAL_CASE__.ImageCarousel': undefined
13
+ '__MINI_APP_HANDLE_PASCAL_CASE__.ImageMultipleChoice': undefined
14
14
  '__MINI_APP_HANDLE_PASCAL_CASE__.Inputs': undefined
15
15
  '__MINI_APP_HANDLE_PASCAL_CASE__.Media': undefined
16
16
  '__MINI_APP_HANDLE_PASCAL_CASE__.MultipleChoice': undefined
@@ -25,4 +25,5 @@ export type StackParamList = {
25
25
  '__MINI_APP_HANDLE_PASCAL_CASE__.Grid': undefined
26
26
  '__MINI_APP_HANDLE_PASCAL_CASE__.Avatar': undefined
27
27
  '__MINI_APP_HANDLE_PASCAL_CASE__.KeyboardAvoidingView': undefined
28
+ '__MINI_APP_HANDLE_PASCAL_CASE__.Quiz': undefined
28
29
  }
@@ -0,0 +1,313 @@
1
+ import {ImageCarouselSlideProps} from '../components/quiz/ImageCarouselSlide'
2
+ import {MultipleChoiceSlideProps} from '../components/quiz/MultipleChoiceSlide'
3
+ import {TextFieldSlideProps} from '../components/quiz/TextFieldSlide'
4
+ import {
5
+ QuizAnswerType,
6
+ QuizData,
7
+ SlideInformation,
8
+ TextSlideProps,
9
+ } from '../components/quiz/types'
10
+
11
+ const createChoices = (numberOfChoices: number) => {
12
+ return Array(numberOfChoices)
13
+ .fill(undefined)
14
+ .map((_, index) => ({
15
+ label: `Option ${index + 1}`,
16
+ value: `Value ${index + 1}`,
17
+ }))
18
+ }
19
+
20
+ const textWelcomeSlideProps: TextSlideProps = {
21
+ quizSlideProps: {
22
+ mainText: 'Welcome!',
23
+ subText:
24
+ 'This is a Text Slide which demonstrates some text. Often used as a welcome of thankyou page',
25
+ ctaText: "Let's get started!",
26
+ },
27
+ }
28
+
29
+ const textThankYouSlideProps: TextSlideProps = {
30
+ quizSlideProps: {
31
+ mainText: 'Ready for your results?',
32
+ subText: 'Click below for product recommendations',
33
+ ctaText: 'Show Me Results',
34
+ },
35
+ }
36
+
37
+ const multipleChoiceHairTypeSlideProps: MultipleChoiceSlideProps = {
38
+ quizSlideProps: {
39
+ mainText:
40
+ 'So nice to meet you, {{userName}}. What is your current hair color?',
41
+ ctaText: 'Next Question',
42
+ ctaDisabled: true,
43
+ },
44
+ multipleChoiceProps: {
45
+ choices: [
46
+ {
47
+ label: 'Grey',
48
+ value: 'Grey',
49
+ },
50
+ {
51
+ label: 'Blonde',
52
+ value: 'Blonde',
53
+ },
54
+ {
55
+ label: 'Light/Med Brown',
56
+ value: 'Light/Med Brown',
57
+ },
58
+ {
59
+ label: 'Brunette/Dark Brown',
60
+ value: 'Brunette/Dark Brown',
61
+ },
62
+ {
63
+ label: 'Nearly Black/Jet Black',
64
+ value: 'Nearly Black/Jet Black',
65
+ },
66
+ {
67
+ label: 'Red',
68
+ value: 'Red',
69
+ },
70
+ ],
71
+ onChoiceSelected: () => null,
72
+ selectedIndexes: [],
73
+ },
74
+ determineCtaDisabled: (answer: QuizAnswerType) =>
75
+ (answer as [number]).length < 1,
76
+ }
77
+
78
+ const multipleChoiceYesNoSlideProps: MultipleChoiceSlideProps = {
79
+ quizSlideProps: {
80
+ mainText: 'Are you Canadian?',
81
+ ctaText: 'Next Question',
82
+ ctaDisabled: true,
83
+ },
84
+ multipleChoiceProps: {
85
+ choices: [
86
+ {
87
+ label: 'Yes',
88
+ value: 'Yes',
89
+ },
90
+ {
91
+ label: 'No',
92
+ value: 'No',
93
+ },
94
+ ],
95
+ onChoiceSelected: () => null,
96
+ selectedIndexes: [],
97
+ },
98
+ determineNextSlide: answer => {
99
+ return answer[0] === 0 ? 'canada' : 'choose-age'
100
+ },
101
+ determineCtaDisabled: (answer: QuizAnswerType) =>
102
+ (answer as [number]).length < 1,
103
+ }
104
+
105
+ const textCanadianSlideProps: TextSlideProps = {
106
+ quizSlideProps: {
107
+ mainText: 'You are Canadian!',
108
+ ctaText: 'Ja, eh',
109
+ },
110
+ }
111
+
112
+ const ageChoices = [
113
+ {
114
+ label: '<18',
115
+ value: '<18',
116
+ },
117
+ {
118
+ label: '19-25',
119
+ value: '19-25',
120
+ },
121
+ {
122
+ label: '26-35',
123
+ value: '26-35',
124
+ },
125
+ {
126
+ label: '36+',
127
+ value: '36+',
128
+ },
129
+ ]
130
+
131
+ const textFieldSlideProps: TextFieldSlideProps = {
132
+ quizSlideProps: {
133
+ mainText: 'Well that was rude of us...we never got your name.',
134
+ ctaDisabled: true,
135
+ },
136
+ textFieldProps: {
137
+ placeholder: 'Enter your name',
138
+ },
139
+ determineCtaDisabled: (answer: QuizAnswerType) =>
140
+ (answer as string).length < 1,
141
+ }
142
+
143
+ const textFieldMutliLineSlideProps: TextFieldSlideProps = {
144
+ quizSlideProps: {
145
+ mainText: 'Leave your comments!',
146
+ subText: 'Are there some other products you would like to see?',
147
+ ctaText: 'Submit',
148
+ ctaDisabled: true,
149
+ },
150
+ textFieldProps: {
151
+ multiline: true,
152
+ numberOfLines: 4,
153
+ helper: 'Must be at least 10 characters',
154
+ placeholder: 'It would be great if you Would....',
155
+ },
156
+ determineCtaDisabled: (answer: QuizAnswerType) =>
157
+ (answer as string).length < 10,
158
+ }
159
+
160
+ const multipleChoiceSingleSelctionShortSlideProps: MultipleChoiceSlideProps = {
161
+ quizSlideProps: {
162
+ mainText: 'How old are you?',
163
+ ctaText: 'Next Question',
164
+ ctaDisabled: true,
165
+ },
166
+ multipleChoiceProps: {
167
+ choices: ageChoices,
168
+ onChoiceSelected: () => null,
169
+ selectedIndexes: [],
170
+ },
171
+ determineNextSlide: answer => `age-${ageChoices[answer[0]].value}`,
172
+ determineCtaDisabled: (answer: QuizAnswerType) =>
173
+ (answer as [number]).length < 1,
174
+ }
175
+
176
+ const multipleChoiceMustAcceptSlideProps: MultipleChoiceSlideProps = {
177
+ quizSlideProps: {
178
+ mainText: 'Do You Agree To Share Your Information?',
179
+ subText: 'We will only use it to generate recommendations',
180
+ ctaText: 'On to the questions!',
181
+ ctaDisabled: true,
182
+ },
183
+ multipleChoiceProps: {
184
+ choices: [
185
+ {label: 'No I do not', value: 'no'},
186
+ {label: 'Yes I consent', value: 'yes'},
187
+ ],
188
+ onChoiceSelected: () => null,
189
+ selectedIndexes: [],
190
+ },
191
+ determineCtaDisabled: (answer: QuizAnswerType) =>
192
+ (answer as [number])[0] !== 1,
193
+ }
194
+
195
+ const generateAgeTextSlide = (age: string): SlideInformation => ({
196
+ id: `age-${age}`,
197
+ type: 'TextSlide',
198
+ props: {
199
+ quizSlideProps: {
200
+ mainText: `Screen just for being ${age}`,
201
+ subText: `The quiz jumped to this screen because you chose ${age} on the last slide`,
202
+ },
203
+ nextSlideId: 'lots-of-options',
204
+ },
205
+ })
206
+
207
+ const multipleChoiceSingleSelctionLongSlideProps: MultipleChoiceSlideProps = {
208
+ quizSlideProps: {
209
+ isTallSlide: true,
210
+ mainText: 'What are your favorite numbers under 30',
211
+ subText: 'Choose at least 3 numbers',
212
+ },
213
+ multipleChoiceProps: {
214
+ choices: createChoices(30),
215
+ onChoiceSelected: () => null,
216
+ selectedIndexes: [],
217
+ },
218
+ isMultiSelect: true,
219
+ determineCtaDisabled: (answer: QuizAnswerType) =>
220
+ (answer as [number]).length < 3,
221
+ }
222
+
223
+ // This ensures that random images are selected each time the app is generated
224
+ const LOREM_PIXUM_OFFSET = Math.ceil(Math.random() * 100)
225
+ const multipleChoiceImageSingleSelctionProps: ImageCarouselSlideProps = {
226
+ quizSlideProps: {
227
+ mainText: 'Select an Image that you like',
228
+ },
229
+ imageCarouselProps: {
230
+ choices: createChoices(30).map((choice, i) => ({
231
+ ...choice,
232
+ imageUrl: `https://picsum.photos/id/${LOREM_PIXUM_OFFSET + i}/160`,
233
+ })),
234
+ onChoiceSelected: () => null,
235
+ selectedIndexes: [],
236
+ imageSize: 160,
237
+ },
238
+ determineCtaDisabled: (answer: QuizAnswerType) =>
239
+ (answer as [number]).length < 1,
240
+ }
241
+
242
+ export const mockQuizData: QuizData = {
243
+ slides: [
244
+ {
245
+ id: 'welcome',
246
+ type: 'TextSlide',
247
+ props: textWelcomeSlideProps,
248
+ },
249
+ {
250
+ id: 'consent',
251
+ type: 'MultipleChoiceSlide',
252
+ props: multipleChoiceMustAcceptSlideProps,
253
+ },
254
+ {
255
+ id: 'enter-name',
256
+ type: 'TextFieldSlide',
257
+ props: textFieldSlideProps,
258
+ },
259
+ {
260
+ id: 'hair-type-personalized',
261
+ type: 'MultipleChoiceSlide',
262
+ props: multipleChoiceHairTypeSlideProps,
263
+ },
264
+ {
265
+ id: 'choose-canada',
266
+ type: 'MultipleChoiceSlide',
267
+ props: multipleChoiceYesNoSlideProps,
268
+ },
269
+
270
+ {
271
+ id: 'missing-products',
272
+ type: 'TextFieldSlide',
273
+ props: textFieldMutliLineSlideProps,
274
+ },
275
+ {
276
+ id: 'choose-canada',
277
+ type: 'MultipleChoiceSlide',
278
+ props: multipleChoiceYesNoSlideProps,
279
+ },
280
+ {
281
+ id: 'canada',
282
+ type: 'TextSlide',
283
+ props: textCanadianSlideProps,
284
+ },
285
+ {
286
+ id: 'choose-age',
287
+ type: 'MultipleChoiceSlide',
288
+ props: multipleChoiceSingleSelctionShortSlideProps,
289
+ },
290
+ generateAgeTextSlide('<18'),
291
+ generateAgeTextSlide('19-25'),
292
+ generateAgeTextSlide('26-35'),
293
+ generateAgeTextSlide('36+'),
294
+ {
295
+ id: 'lots-of-options',
296
+ type: 'MultipleChoiceSlide',
297
+ props: multipleChoiceSingleSelctionLongSlideProps,
298
+ },
299
+ {
300
+ id: 'pick an image',
301
+ type: 'ImageCarouselSlide',
302
+ props: multipleChoiceImageSingleSelctionProps,
303
+ },
304
+ {
305
+ id: 'thank-you',
306
+ type: 'TextSlide',
307
+ props: {
308
+ ...textThankYouSlideProps,
309
+ nextSlideId: 'results',
310
+ },
311
+ },
312
+ ],
313
+ }
@@ -0,0 +1,75 @@
1
+ import {ImageCarouselSlideProps} from '../components/quiz/ImageCarouselSlide'
2
+ import {MultipleChoiceSlideProps} from '../components/quiz/MultipleChoiceSlide'
3
+ import {QuizData} from '../components/quiz/types'
4
+
5
+ export const getQuizSlideDataByIndex = (
6
+ quizData: QuizData,
7
+ slideIndex: number
8
+ ) => quizData.slides[slideIndex] ?? undefined
9
+
10
+ export const getQuizSlideDataById = (quizData: QuizData, id: string) =>
11
+ quizData.slides.find(slide => slide.id === id)
12
+
13
+ export const getQuizSlideIndexById = (quizData: QuizData, id: string) =>
14
+ quizData.slides.findIndex(slide => slide.id === id)
15
+
16
+ export const getQuestionById = (quizData: QuizData, questionId: string) => {
17
+ const slideWithQuestion = quizData.slides.find(
18
+ slide => slide.id === questionId
19
+ )
20
+ if (!slideWithQuestion) {
21
+ console.error('slide not founod')
22
+ return `text question not found for slide with id ${questionId}`
23
+ }
24
+
25
+ return slideWithQuestion.props.quizSlideProps.mainText
26
+ }
27
+
28
+ export const getMultilpleChoiceAnswerLabels = (
29
+ quizData: QuizData,
30
+ questionId: string,
31
+ selectedIndexes: number[]
32
+ ) => {
33
+ const multipleChoiceSlide = quizData.slides.find(
34
+ slide => slide.id === questionId
35
+ )
36
+ if (
37
+ !multipleChoiceSlide ||
38
+ multipleChoiceSlide.type !== 'MultipleChoiceSlide'
39
+ ) {
40
+ console.error('only works for multiple choice slides')
41
+ return []
42
+ }
43
+
44
+ const answers = (
45
+ multipleChoiceSlide.props as MultipleChoiceSlideProps
46
+ ).multipleChoiceProps.choices.map(({label}) => label)
47
+
48
+ return answers.filter((_, index) => selectedIndexes.includes(index))
49
+ }
50
+
51
+ export const getImageCarouselAnswerUrls = (
52
+ quizData: QuizData,
53
+ questionId: string,
54
+ selectedIndexes: number[]
55
+ ) => {
56
+ const imageCarouselSlide = quizData.slides.find(
57
+ slide => slide.id === questionId
58
+ )
59
+ if (!imageCarouselSlide || imageCarouselSlide.type !== 'ImageCarouselSlide') {
60
+ console.error('only works for ImageCarouselSlide')
61
+ return []
62
+ }
63
+
64
+ const imageAnswers = (
65
+ imageCarouselSlide.props as ImageCarouselSlideProps
66
+ ).imageCarouselProps.choices.map(({imageUrl}) => imageUrl)
67
+
68
+ return imageAnswers.filter((_, index) => selectedIndexes.includes(index))
69
+ }
70
+
71
+ export const addNameToText = (text: string, name?: string) => {
72
+ const regex = new RegExp('{{userName}}', 'g')
73
+
74
+ return text.replace(regex, name ? name : 'Anonymous')
75
+ }
@@ -1,5 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare function assertDependenciesUpToDate(): Promise<void>;
3
- export declare function assertApiKeyIsSet(): void;
4
- export declare function assertNoActiveSubmissions(): Promise<void>;
5
- export declare function loadCommand(parentProgram: Command): Promise<void>;
@@ -1,77 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.loadCommand = exports.assertNoActiveSubmissions = exports.assertApiKeyIsSet = exports.assertDependenciesUpToDate = void 0;
30
- const commander_1 = require("commander");
31
- const semver_1 = __importDefault(require("semver"));
32
- const chalk_1 = __importDefault(require("chalk"));
33
- const dotenv = __importStar(require("dotenv"));
34
- const exec_async_child_process_1 = require("../utils/exec-async-child-process");
35
- const versions_1 = require("./utils/versions");
36
- async function assertDependenciesUpToDate() {
37
- const { stdout: latestCliVersion } = await (0, exec_async_child_process_1.execAsync)({
38
- cmd: 'npm show @shopify/shop-minis-cli version',
39
- });
40
- const installedCliVersion = (0, versions_1.getInstalledPackageVersion)('@shopify/shop-minis-cli') ?? '0.0.0';
41
- const isUpToDate = semver_1.default.eq(installedCliVersion, latestCliVersion[0]);
42
- if (!isUpToDate) {
43
- console.warn(chalk_1.default.red('Check failed: Shop Minis CLI has to be updated.'));
44
- console.log(`Installed version: ${installedCliVersion} (latest: ${latestCliVersion})`);
45
- console.log(`Use ${chalk_1.default.blue.underline.bold('npm update @shopify/shop-minis-cli@latest')} to update.`);
46
- process.exit(1);
47
- }
48
- }
49
- exports.assertDependenciesUpToDate = assertDependenciesUpToDate;
50
- function assertApiKeyIsSet() {
51
- dotenv.config();
52
- const apiKey = process.env.SHOP_MINIS_API_KEY;
53
- if (!apiKey) {
54
- console.warn(chalk_1.default.red('Check failed: Shop Minis API key is not set.'));
55
- console.log(`To continue, set the environment variable in .env ${chalk_1.default.blue.underline.bold('SHOP_MINIS_API_KEY=<your-shop-minis-api-key>')}`);
56
- process.exit(1);
57
- }
58
- }
59
- exports.assertApiKeyIsSet = assertApiKeyIsSet;
60
- async function assertNoActiveSubmissions() {
61
- // TODO: check if there are any active submissions
62
- }
63
- exports.assertNoActiveSubmissions = assertNoActiveSubmissions;
64
- async function loadCommand(parentProgram) {
65
- const command = new commander_1.Command()
66
- .name('check')
67
- .version('2.0.0')
68
- .description('Check your Shop Mini configuration')
69
- .action(async () => {
70
- assertApiKeyIsSet();
71
- await assertDependenciesUpToDate();
72
- await assertNoActiveSubmissions();
73
- });
74
- parentProgram.addCommand(command);
75
- }
76
- exports.loadCommand = loadCommand;
77
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/check/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAAiC;AACjC,oDAA2B;AAC3B,kDAAyB;AACzB,+CAAgC;AAEhC,gFAA2D;AAE3D,+CAA2D;AAEpD,KAAK,UAAU,0BAA0B;IAC9C,MAAM,EAAC,MAAM,EAAE,gBAAgB,EAAC,GAAG,MAAM,IAAA,oCAAS,EAAC;QACjD,GAAG,EAAE,0CAA0C;KAChD,CAAC,CAAA;IACF,MAAM,mBAAmB,GACvB,IAAA,qCAA0B,EAAC,yBAAyB,CAAC,IAAI,OAAO,CAAA;IAElE,MAAM,UAAU,GAAG,gBAAM,CAAC,EAAE,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAA;IAEtE,IAAI,CAAC,UAAU,EAAE;QACf,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC,CAAA;QAC1E,OAAO,CAAC,GAAG,CACT,sBAAsB,mBAAmB,aAAa,gBAAgB,GAAG,CAC1E,CAAA;QACD,OAAO,CAAC,GAAG,CACT,OAAO,eAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAC9B,2CAA2C,CAC5C,aAAa,CACf,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAChB;AACH,CAAC;AArBD,gEAqBC;AAED,SAAgB,iBAAiB;IAC/B,MAAM,CAAC,MAAM,EAAE,CAAA;IACf,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAE7C,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,CAAC,IAAI,CAAC,eAAK,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC,CAAA;QACvE,OAAO,CAAC,GAAG,CACT,qDAAqD,eAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAC5E,8CAA8C,CAC/C,EAAE,CACJ,CAAA;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAChB;AACH,CAAC;AAbD,8CAaC;AAEM,KAAK,UAAU,yBAAyB;IAC7C,kDAAkD;AACpD,CAAC;AAFD,8DAEC;AAEM,KAAK,UAAU,WAAW,CAAC,aAAsB;IACtD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE;SAC1B,IAAI,CAAC,OAAO,CAAC;SACb,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,iBAAiB,EAAE,CAAA;QACnB,MAAM,0BAA0B,EAAE,CAAA;QAClC,MAAM,yBAAyB,EAAE,CAAA;IACnC,CAAC,CAAC,CAAA;IAEJ,aAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;AACnC,CAAC;AAZD,kCAYC"}
@@ -1 +0,0 @@
1
- export declare function getInstalledPackageVersion(packageName: string): string | null;