ignite-parse-auth-kit 1.0.0

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 (241) hide show
  1. package/CONTRIBUTING.md +0 -0
  2. package/LICENSE +21 -0
  3. package/README.md +492 -0
  4. package/app/app.tsx +116 -0
  5. package/app/components/AlertTongle.tsx +105 -0
  6. package/app/components/AutoImage.tsx +89 -0
  7. package/app/components/Button.tsx +248 -0
  8. package/app/components/Card.tsx +314 -0
  9. package/app/components/EmptyState.tsx +248 -0
  10. package/app/components/Header.tsx +332 -0
  11. package/app/components/Icon.tsx +140 -0
  12. package/app/components/ListItem.tsx +243 -0
  13. package/app/components/ListView.tsx +42 -0
  14. package/app/components/Screen.tsx +305 -0
  15. package/app/components/Text.test.tsx +23 -0
  16. package/app/components/Text.tsx +116 -0
  17. package/app/components/TextField.tsx +292 -0
  18. package/app/components/Toggle/Checkbox.tsx +123 -0
  19. package/app/components/Toggle/Radio.tsx +106 -0
  20. package/app/components/Toggle/Switch.tsx +264 -0
  21. package/app/components/Toggle/Toggle.tsx +285 -0
  22. package/app/components/index copy.ts +15 -0
  23. package/app/components/index.ts +18 -0
  24. package/app/config/config.base.ts +26 -0
  25. package/app/config/config.dev.ts +10 -0
  26. package/app/config/config.prod.ts +10 -0
  27. package/app/config/index.ts +28 -0
  28. package/app/context/AuthContext.tsx +14 -0
  29. package/app/context/EpisodeContext.tsx +136 -0
  30. package/app/context/auth/AuthProvider.tsx +340 -0
  31. package/app/context/auth/hooks.ts +29 -0
  32. package/app/context/auth/index.ts +38 -0
  33. package/app/context/auth/reducer.ts +68 -0
  34. package/app/context/auth/services.ts +394 -0
  35. package/app/context/auth/types.ts +99 -0
  36. package/app/context/auth/validation.ts +45 -0
  37. package/app/devtools/ReactotronClient.ts +9 -0
  38. package/app/devtools/ReactotronClient.web.ts +12 -0
  39. package/app/devtools/ReactotronConfig.ts +139 -0
  40. package/app/i18n/ar.ts +126 -0
  41. package/app/i18n/demo-ar.ts +464 -0
  42. package/app/i18n/demo-en.ts +462 -0
  43. package/app/i18n/demo-es.ts +469 -0
  44. package/app/i18n/demo-fr.ts +471 -0
  45. package/app/i18n/demo-hi.ts +468 -0
  46. package/app/i18n/demo-ja.ts +464 -0
  47. package/app/i18n/demo-ko.ts +457 -0
  48. package/app/i18n/en.ts +146 -0
  49. package/app/i18n/es.ts +132 -0
  50. package/app/i18n/fr.ts +132 -0
  51. package/app/i18n/hi.ts +131 -0
  52. package/app/i18n/index.ts +86 -0
  53. package/app/i18n/ja.ts +130 -0
  54. package/app/i18n/ko.ts +129 -0
  55. package/app/i18n/translate.ts +33 -0
  56. package/app/lib/Parse/index.ts +2 -0
  57. package/app/lib/Parse/parse.ts +62 -0
  58. package/app/navigators/AppNavigator.tsx +145 -0
  59. package/app/navigators/DemoNavigator.tsx +137 -0
  60. package/app/navigators/navigationUtilities.ts +208 -0
  61. package/app/screens/ChooseAuthScreen.tsx +224 -0
  62. package/app/screens/DemoCommunityScreen.tsx +141 -0
  63. package/app/screens/DemoDebugScreen.tsx +192 -0
  64. package/app/screens/DemoPodcastListScreen.tsx +387 -0
  65. package/app/screens/DemoShowroomScreen/DemoDivider.tsx +66 -0
  66. package/app/screens/DemoShowroomScreen/DemoShowroomScreen.tsx +313 -0
  67. package/app/screens/DemoShowroomScreen/DemoUseCase.tsx +52 -0
  68. package/app/screens/DemoShowroomScreen/DrawerIconButton.tsx +120 -0
  69. package/app/screens/DemoShowroomScreen/SectionListWithKeyboardAwareScrollView.tsx +59 -0
  70. package/app/screens/DemoShowroomScreen/demos/DemoAutoImage.tsx +230 -0
  71. package/app/screens/DemoShowroomScreen/demos/DemoButton.tsx +234 -0
  72. package/app/screens/DemoShowroomScreen/demos/DemoCard.tsx +181 -0
  73. package/app/screens/DemoShowroomScreen/demos/DemoEmptyState.tsx +78 -0
  74. package/app/screens/DemoShowroomScreen/demos/DemoHeader.tsx +151 -0
  75. package/app/screens/DemoShowroomScreen/demos/DemoIcon.tsx +115 -0
  76. package/app/screens/DemoShowroomScreen/demos/DemoListItem.tsx +218 -0
  77. package/app/screens/DemoShowroomScreen/demos/DemoText.tsx +144 -0
  78. package/app/screens/DemoShowroomScreen/demos/DemoTextField.tsx +233 -0
  79. package/app/screens/DemoShowroomScreen/demos/DemoToggle.tsx +354 -0
  80. package/app/screens/DemoShowroomScreen/demos/index.ts +12 -0
  81. package/app/screens/ErrorScreen/ErrorBoundary.tsx +76 -0
  82. package/app/screens/ErrorScreen/ErrorDetails.tsx +98 -0
  83. package/app/screens/ForgetPasswordScreen.tsx +180 -0
  84. package/app/screens/LoginScreen.tsx +260 -0
  85. package/app/screens/RegisterScreen.tsx +395 -0
  86. package/app/screens/WelcomeScreen.tsx +114 -0
  87. package/app/services/api/apiProblem.test.ts +73 -0
  88. package/app/services/api/apiProblem.ts +74 -0
  89. package/app/services/api/index.ts +91 -0
  90. package/app/services/api/types.ts +50 -0
  91. package/app/theme/colors.ts +85 -0
  92. package/app/theme/colorsDark.ts +50 -0
  93. package/app/theme/context.tsx +145 -0
  94. package/app/theme/context.utils.ts +25 -0
  95. package/app/theme/spacing.ts +14 -0
  96. package/app/theme/spacingDark.ts +14 -0
  97. package/app/theme/styles.ts +24 -0
  98. package/app/theme/theme.ts +23 -0
  99. package/app/theme/timing.ts +6 -0
  100. package/app/theme/types.ts +64 -0
  101. package/app/theme/typography.ts +71 -0
  102. package/app/utils/crashReporting.ts +62 -0
  103. package/app/utils/delay.ts +6 -0
  104. package/app/utils/formatDate.ts +49 -0
  105. package/app/utils/gestureHandler.native.ts +3 -0
  106. package/app/utils/gestureHandler.ts +6 -0
  107. package/app/utils/hasValidStringProp.ts +11 -0
  108. package/app/utils/openLinkInBrowser.ts +8 -0
  109. package/app/utils/storage/index.ts +82 -0
  110. package/app/utils/storage/storage.test.ts +61 -0
  111. package/app/utils/useHeader.tsx +37 -0
  112. package/app/utils/useIsMounted.ts +18 -0
  113. package/app/utils/useSafeAreaInsetsStyle.ts +46 -0
  114. package/app.config.ts +39 -0
  115. package/app.json +67 -0
  116. package/assets/icons/back.png +0 -0
  117. package/assets/icons/back@2x.png +0 -0
  118. package/assets/icons/back@3x.png +0 -0
  119. package/assets/icons/bell.png +0 -0
  120. package/assets/icons/bell@2x.png +0 -0
  121. package/assets/icons/bell@3x.png +0 -0
  122. package/assets/icons/caretLeft.png +0 -0
  123. package/assets/icons/caretLeft@2x.png +0 -0
  124. package/assets/icons/caretLeft@3x.png +0 -0
  125. package/assets/icons/caretRight.png +0 -0
  126. package/assets/icons/caretRight@2x.png +0 -0
  127. package/assets/icons/caretRight@3x.png +0 -0
  128. package/assets/icons/check.png +0 -0
  129. package/assets/icons/check@2x.png +0 -0
  130. package/assets/icons/check@3x.png +0 -0
  131. package/assets/icons/demo/clap.png +0 -0
  132. package/assets/icons/demo/clap@2x.png +0 -0
  133. package/assets/icons/demo/clap@3x.png +0 -0
  134. package/assets/icons/demo/community.png +0 -0
  135. package/assets/icons/demo/community@2x.png +0 -0
  136. package/assets/icons/demo/community@3x.png +0 -0
  137. package/assets/icons/demo/components.png +0 -0
  138. package/assets/icons/demo/components@2x.png +0 -0
  139. package/assets/icons/demo/components@3x.png +0 -0
  140. package/assets/icons/demo/debug.png +0 -0
  141. package/assets/icons/demo/debug@2x.png +0 -0
  142. package/assets/icons/demo/debug@3x.png +0 -0
  143. package/assets/icons/demo/github.png +0 -0
  144. package/assets/icons/demo/github@2x.png +0 -0
  145. package/assets/icons/demo/github@3x.png +0 -0
  146. package/assets/icons/demo/heart.png +0 -0
  147. package/assets/icons/demo/heart@2x.png +0 -0
  148. package/assets/icons/demo/heart@3x.png +0 -0
  149. package/assets/icons/demo/pin.png +0 -0
  150. package/assets/icons/demo/pin@2x.png +0 -0
  151. package/assets/icons/demo/pin@3x.png +0 -0
  152. package/assets/icons/demo/podcast.png +0 -0
  153. package/assets/icons/demo/podcast@2x.png +0 -0
  154. package/assets/icons/demo/podcast@3x.png +0 -0
  155. package/assets/icons/demo/slack.png +0 -0
  156. package/assets/icons/demo/slack@2x.png +0 -0
  157. package/assets/icons/demo/slack@3x.png +0 -0
  158. package/assets/icons/google.png +0 -0
  159. package/assets/icons/hidden.png +0 -0
  160. package/assets/icons/hidden@2x.png +0 -0
  161. package/assets/icons/hidden@3x.png +0 -0
  162. package/assets/icons/ladybug.png +0 -0
  163. package/assets/icons/ladybug@2x.png +0 -0
  164. package/assets/icons/ladybug@3x.png +0 -0
  165. package/assets/icons/lock.png +0 -0
  166. package/assets/icons/lock@2x.png +0 -0
  167. package/assets/icons/lock@3x.png +0 -0
  168. package/assets/icons/menu.png +0 -0
  169. package/assets/icons/menu@2x.png +0 -0
  170. package/assets/icons/menu@3x.png +0 -0
  171. package/assets/icons/more.png +0 -0
  172. package/assets/icons/more@2x.png +0 -0
  173. package/assets/icons/more@3x.png +0 -0
  174. package/assets/icons/settings.png +0 -0
  175. package/assets/icons/settings@2x.png +0 -0
  176. package/assets/icons/settings@3x.png +0 -0
  177. package/assets/icons/view.png +0 -0
  178. package/assets/icons/view@2x.png +0 -0
  179. package/assets/icons/view@3x.png +0 -0
  180. package/assets/icons/x.png +0 -0
  181. package/assets/icons/x@2x.png +0 -0
  182. package/assets/icons/x@3x.png +0 -0
  183. package/assets/images/app-icon-all.png +0 -0
  184. package/assets/images/app-icon-android-adaptive-background.png +0 -0
  185. package/assets/images/app-icon-android-adaptive-foreground.png +0 -0
  186. package/assets/images/app-icon-android-legacy.png +0 -0
  187. package/assets/images/app-icon-ios.png +0 -0
  188. package/assets/images/app-icon-web-favicon.png +0 -0
  189. package/assets/images/demo/cr-logo.png +0 -0
  190. package/assets/images/demo/cr-logo@2x.png +0 -0
  191. package/assets/images/demo/cr-logo@3x.png +0 -0
  192. package/assets/images/demo/rnl-logo.png +0 -0
  193. package/assets/images/demo/rnl-logo@2x.png +0 -0
  194. package/assets/images/demo/rnl-logo@3x.png +0 -0
  195. package/assets/images/demo/rnn-logo.png +0 -0
  196. package/assets/images/demo/rnn-logo@2x.png +0 -0
  197. package/assets/images/demo/rnn-logo@3x.png +0 -0
  198. package/assets/images/demo/rnr-image-1.png +0 -0
  199. package/assets/images/demo/rnr-image-1@2x.png +0 -0
  200. package/assets/images/demo/rnr-image-1@3x.png +0 -0
  201. package/assets/images/demo/rnr-image-2.png +0 -0
  202. package/assets/images/demo/rnr-image-2@2x.png +0 -0
  203. package/assets/images/demo/rnr-image-2@3x.png +0 -0
  204. package/assets/images/demo/rnr-image-3.png +0 -0
  205. package/assets/images/demo/rnr-image-3@2x.png +0 -0
  206. package/assets/images/demo/rnr-image-3@3x.png +0 -0
  207. package/assets/images/demo/rnr-logo.png +0 -0
  208. package/assets/images/demo/rnr-logo@2x.png +0 -0
  209. package/assets/images/demo/rnr-logo@3x.png +0 -0
  210. package/assets/images/logo.png +0 -0
  211. package/assets/images/logo@2x.png +0 -0
  212. package/assets/images/logo@3x.png +0 -0
  213. package/assets/images/sad-face.png +0 -0
  214. package/assets/images/sad-face@2x.png +0 -0
  215. package/assets/images/sad-face@3x.png +0 -0
  216. package/assets/images/welcome-face.png +0 -0
  217. package/assets/images/welcome-face@2x.png +0 -0
  218. package/assets/images/welcome-face@3x.png +0 -0
  219. package/babel.config.js +7 -0
  220. package/bin/cli.js +196 -0
  221. package/ignite/templates/app-icon/android-adaptive-background.png +0 -0
  222. package/ignite/templates/app-icon/android-adaptive-foreground.png +0 -0
  223. package/ignite/templates/app-icon/android-legacy.png +0 -0
  224. package/ignite/templates/app-icon/ios-universal.png +0 -0
  225. package/ignite/templates/component/NAME.tsx.ejs +39 -0
  226. package/ignite/templates/navigator/NAMENavigator.tsx.ejs +18 -0
  227. package/ignite/templates/screen/NAMEScreen.tsx.ejs +29 -0
  228. package/ignite/templates/splash-screen/logo.png +0 -0
  229. package/index.tsx +9 -0
  230. package/jest.config.js +5 -0
  231. package/metro.config.js +31 -0
  232. package/package.json +166 -0
  233. package/plugins/withSplashScreen.ts +69 -0
  234. package/src/app/_layout.tsx +58 -0
  235. package/src/app/index.tsx +5 -0
  236. package/test/i18n.test.ts +75 -0
  237. package/test/mockFile.ts +6 -0
  238. package/test/setup.ts +58 -0
  239. package/test/test-tsconfig.json +8 -0
  240. package/tsconfig.json +52 -0
  241. package/types/lib.es5.d.ts +25 -0
@@ -0,0 +1,314 @@
1
+ import { ComponentType, Fragment, ReactElement } from "react"
2
+ import {
3
+ StyleProp,
4
+ TextStyle,
5
+ TouchableOpacity,
6
+ TouchableOpacityProps,
7
+ View,
8
+ ViewProps,
9
+ ViewStyle,
10
+ } from "react-native"
11
+
12
+ import type { ThemedStyle, ThemedStyleArray } from "@/theme/types"
13
+ import { useAppTheme } from "@/theme/context"
14
+ import { $styles } from "@/theme/styles"
15
+
16
+ import { Text, TextProps } from "./Text"
17
+
18
+ type Presets = "default" | "reversed"
19
+
20
+ interface CardProps extends TouchableOpacityProps {
21
+ /**
22
+ * One of the different types of text presets.
23
+ */
24
+ preset?: Presets
25
+ /**
26
+ * How the content should be aligned vertically. This is especially (but not exclusively) useful
27
+ * when the card is a fixed height but the content is dynamic.
28
+ *
29
+ * `top` (default) - aligns all content to the top.
30
+ * `center` - aligns all content to the center.
31
+ * `space-between` - spreads out the content evenly.
32
+ * `force-footer-bottom` - aligns all content to the top, but forces the footer to the bottom.
33
+ */
34
+ verticalAlignment?: "top" | "center" | "space-between" | "force-footer-bottom"
35
+ /**
36
+ * Custom component added to the left of the card body.
37
+ */
38
+ LeftComponent?: ReactElement
39
+ /**
40
+ * Custom component added to the right of the card body.
41
+ */
42
+ RightComponent?: ReactElement
43
+ /**
44
+ * The heading text to display if not using `headingTx`.
45
+ */
46
+ heading?: TextProps["text"]
47
+ /**
48
+ * Heading text which is looked up via i18n.
49
+ */
50
+ headingTx?: TextProps["tx"]
51
+ /**
52
+ * Optional heading options to pass to i18n. Useful for interpolation
53
+ * as well as explicitly setting locale or translation fallbacks.
54
+ */
55
+ headingTxOptions?: TextProps["txOptions"]
56
+ /**
57
+ * Style overrides for heading text.
58
+ */
59
+ headingStyle?: StyleProp<TextStyle>
60
+ /**
61
+ * Pass any additional props directly to the heading Text component.
62
+ */
63
+ HeadingTextProps?: TextProps
64
+ /**
65
+ * Custom heading component.
66
+ * Overrides all other `heading*` props.
67
+ */
68
+ HeadingComponent?: ReactElement
69
+ /**
70
+ * The content text to display if not using `contentTx`.
71
+ */
72
+ content?: TextProps["text"]
73
+ /**
74
+ * Content text which is looked up via i18n.
75
+ */
76
+ contentTx?: TextProps["tx"]
77
+ /**
78
+ * Optional content options to pass to i18n. Useful for interpolation
79
+ * as well as explicitly setting locale or translation fallbacks.
80
+ */
81
+ contentTxOptions?: TextProps["txOptions"]
82
+ /**
83
+ * Style overrides for content text.
84
+ */
85
+ contentStyle?: StyleProp<TextStyle>
86
+ /**
87
+ * Pass any additional props directly to the content Text component.
88
+ */
89
+ ContentTextProps?: TextProps
90
+ /**
91
+ * Custom content component.
92
+ * Overrides all other `content*` props.
93
+ */
94
+ ContentComponent?: ReactElement
95
+ /**
96
+ * The footer text to display if not using `footerTx`.
97
+ */
98
+ footer?: TextProps["text"]
99
+ /**
100
+ * Footer text which is looked up via i18n.
101
+ */
102
+ footerTx?: TextProps["tx"]
103
+ /**
104
+ * Optional footer options to pass to i18n. Useful for interpolation
105
+ * as well as explicitly setting locale or translation fallbacks.
106
+ */
107
+ footerTxOptions?: TextProps["txOptions"]
108
+ /**
109
+ * Style overrides for footer text.
110
+ */
111
+ footerStyle?: StyleProp<TextStyle>
112
+ /**
113
+ * Pass any additional props directly to the footer Text component.
114
+ */
115
+ FooterTextProps?: TextProps
116
+ /**
117
+ * Custom footer component.
118
+ * Overrides all other `footer*` props.
119
+ */
120
+ FooterComponent?: ReactElement
121
+ }
122
+
123
+ /**
124
+ * Cards are useful for displaying related information in a contained way.
125
+ * If a ListItem displays content horizontally, a Card can be used to display content vertically.
126
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Card/}
127
+ * @param {CardProps} props - The props for the `Card` component.
128
+ * @returns {JSX.Element} The rendered `Card` component.
129
+ */
130
+ export function Card(props: CardProps) {
131
+ const {
132
+ content,
133
+ contentTx,
134
+ contentTxOptions,
135
+ footer,
136
+ footerTx,
137
+ footerTxOptions,
138
+ heading,
139
+ headingTx,
140
+ headingTxOptions,
141
+ ContentComponent,
142
+ HeadingComponent,
143
+ FooterComponent,
144
+ LeftComponent,
145
+ RightComponent,
146
+ verticalAlignment = "top",
147
+ style: $containerStyleOverride,
148
+ contentStyle: $contentStyleOverride,
149
+ headingStyle: $headingStyleOverride,
150
+ footerStyle: $footerStyleOverride,
151
+ ContentTextProps,
152
+ HeadingTextProps,
153
+ FooterTextProps,
154
+ ...WrapperProps
155
+ } = props
156
+
157
+ const {
158
+ themed,
159
+ theme: { spacing },
160
+ } = useAppTheme()
161
+
162
+ const preset: Presets = props.preset ?? "default"
163
+ const isPressable = !!WrapperProps.onPress
164
+ const isHeadingPresent = !!(HeadingComponent || heading || headingTx)
165
+ const isContentPresent = !!(ContentComponent || content || contentTx)
166
+ const isFooterPresent = !!(FooterComponent || footer || footerTx)
167
+
168
+ const Wrapper = (isPressable ? TouchableOpacity : View) as ComponentType<
169
+ TouchableOpacityProps | ViewProps
170
+ >
171
+ const HeaderContentWrapper = verticalAlignment === "force-footer-bottom" ? View : Fragment
172
+
173
+ const $containerStyle: StyleProp<ViewStyle> = [
174
+ themed($containerPresets[preset]),
175
+ $containerStyleOverride,
176
+ ]
177
+ const $headingStyle = [
178
+ themed($headingPresets[preset]),
179
+ (isFooterPresent || isContentPresent) && { marginBottom: spacing.xxxs },
180
+ $headingStyleOverride,
181
+ HeadingTextProps?.style,
182
+ ]
183
+ const $contentStyle = [
184
+ themed($contentPresets[preset]),
185
+ isHeadingPresent && { marginTop: spacing.xxxs },
186
+ isFooterPresent && { marginBottom: spacing.xxxs },
187
+ $contentStyleOverride,
188
+ ContentTextProps?.style,
189
+ ]
190
+ const $footerStyle = [
191
+ themed($footerPresets[preset]),
192
+ (isHeadingPresent || isContentPresent) && { marginTop: spacing.xxxs },
193
+ $footerStyleOverride,
194
+ FooterTextProps?.style,
195
+ ]
196
+ const $alignmentWrapperStyle = [
197
+ $alignmentWrapper,
198
+ { justifyContent: $alignmentWrapperFlexOptions[verticalAlignment] },
199
+ LeftComponent && { marginStart: spacing.md },
200
+ RightComponent && { marginEnd: spacing.md },
201
+ ]
202
+
203
+ return (
204
+ <Wrapper
205
+ style={$containerStyle}
206
+ activeOpacity={0.8}
207
+ accessibilityRole={isPressable ? "button" : undefined}
208
+ {...WrapperProps}
209
+ >
210
+ {LeftComponent}
211
+
212
+ <View style={$alignmentWrapperStyle}>
213
+ <HeaderContentWrapper>
214
+ {HeadingComponent ||
215
+ (isHeadingPresent && (
216
+ <Text
217
+ weight="bold"
218
+ text={heading}
219
+ tx={headingTx}
220
+ txOptions={headingTxOptions}
221
+ {...HeadingTextProps}
222
+ style={$headingStyle}
223
+ />
224
+ ))}
225
+
226
+ {ContentComponent ||
227
+ (isContentPresent && (
228
+ <Text
229
+ weight="normal"
230
+ text={content}
231
+ tx={contentTx}
232
+ txOptions={contentTxOptions}
233
+ {...ContentTextProps}
234
+ style={$contentStyle}
235
+ />
236
+ ))}
237
+ </HeaderContentWrapper>
238
+
239
+ {FooterComponent ||
240
+ (isFooterPresent && (
241
+ <Text
242
+ weight="normal"
243
+ size="xs"
244
+ text={footer}
245
+ tx={footerTx}
246
+ txOptions={footerTxOptions}
247
+ {...FooterTextProps}
248
+ style={$footerStyle}
249
+ />
250
+ ))}
251
+ </View>
252
+
253
+ {RightComponent}
254
+ </Wrapper>
255
+ )
256
+ }
257
+
258
+ const $containerBase: ThemedStyle<ViewStyle> = (theme) => ({
259
+ borderRadius: theme.spacing.md,
260
+ padding: theme.spacing.xs,
261
+ borderWidth: 1,
262
+ shadowColor: theme.colors.palette.neutral800,
263
+ shadowOffset: { width: 0, height: 12 },
264
+ shadowOpacity: 0.08,
265
+ shadowRadius: 12.81,
266
+ elevation: 16,
267
+ minHeight: 96,
268
+ })
269
+
270
+ const $alignmentWrapper: ViewStyle = {
271
+ flex: 1,
272
+ alignSelf: "stretch",
273
+ }
274
+
275
+ const $alignmentWrapperFlexOptions = {
276
+ "top": "flex-start",
277
+ "center": "center",
278
+ "space-between": "space-between",
279
+ "force-footer-bottom": "space-between",
280
+ } as const
281
+
282
+ const $containerPresets: Record<Presets, ThemedStyleArray<ViewStyle>> = {
283
+ default: [
284
+ $styles.row,
285
+ $containerBase,
286
+ (theme) => ({
287
+ backgroundColor: theme.colors.palette.neutral100,
288
+ borderColor: theme.colors.palette.neutral300,
289
+ }),
290
+ ],
291
+ reversed: [
292
+ $styles.row,
293
+ $containerBase,
294
+ (theme) => ({
295
+ backgroundColor: theme.colors.palette.neutral800,
296
+ borderColor: theme.colors.palette.neutral500,
297
+ }),
298
+ ],
299
+ }
300
+
301
+ const $headingPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
302
+ default: [],
303
+ reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
304
+ }
305
+
306
+ const $contentPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
307
+ default: [],
308
+ reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
309
+ }
310
+
311
+ const $footerPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
312
+ default: [],
313
+ reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
314
+ }
@@ -0,0 +1,248 @@
1
+ import { Image, ImageProps, ImageStyle, StyleProp, TextStyle, View, ViewStyle } from "react-native"
2
+
3
+ import { translate } from "@/i18n/translate"
4
+ import type { ThemedStyle } from "@/theme/types"
5
+ import { useAppTheme } from "@/theme/context"
6
+
7
+ import { Button, ButtonProps } from "./Button"
8
+ import { Text, TextProps } from "./Text"
9
+
10
+ const sadFace = require("@assets/images/sad-face.png")
11
+
12
+ interface EmptyStateProps {
13
+ /**
14
+ * An optional prop that specifies the text/image set to use for the empty state.
15
+ */
16
+ preset?: "generic"
17
+ /**
18
+ * Style override for the container.
19
+ */
20
+ style?: StyleProp<ViewStyle>
21
+ /**
22
+ * An Image source to be displayed above the heading.
23
+ */
24
+ imageSource?: ImageProps["source"]
25
+ /**
26
+ * Style overrides for image.
27
+ */
28
+ imageStyle?: StyleProp<ImageStyle>
29
+ /**
30
+ * Pass any additional props directly to the Image component.
31
+ */
32
+ ImageProps?: Omit<ImageProps, "source">
33
+ /**
34
+ * The heading text to display if not using `headingTx`.
35
+ */
36
+ heading?: TextProps["text"]
37
+ /**
38
+ * Heading text which is looked up via i18n.
39
+ */
40
+ headingTx?: TextProps["tx"]
41
+ /**
42
+ * Optional heading options to pass to i18n. Useful for interpolation
43
+ * as well as explicitly setting locale or translation fallbacks.
44
+ */
45
+ headingTxOptions?: TextProps["txOptions"]
46
+ /**
47
+ * Style overrides for heading text.
48
+ */
49
+ headingStyle?: StyleProp<TextStyle>
50
+ /**
51
+ * Pass any additional props directly to the heading Text component.
52
+ */
53
+ HeadingTextProps?: TextProps
54
+ /**
55
+ * The content text to display if not using `contentTx`.
56
+ */
57
+ content?: TextProps["text"]
58
+ /**
59
+ * Content text which is looked up via i18n.
60
+ */
61
+ contentTx?: TextProps["tx"]
62
+ /**
63
+ * Optional content options to pass to i18n. Useful for interpolation
64
+ * as well as explicitly setting locale or translation fallbacks.
65
+ */
66
+ contentTxOptions?: TextProps["txOptions"]
67
+ /**
68
+ * Style overrides for content text.
69
+ */
70
+ contentStyle?: StyleProp<TextStyle>
71
+ /**
72
+ * Pass any additional props directly to the content Text component.
73
+ */
74
+ ContentTextProps?: TextProps
75
+ /**
76
+ * The button text to display if not using `buttonTx`.
77
+ */
78
+ button?: TextProps["text"]
79
+ /**
80
+ * Button text which is looked up via i18n.
81
+ */
82
+ buttonTx?: TextProps["tx"]
83
+ /**
84
+ * Optional button options to pass to i18n. Useful for interpolation
85
+ * as well as explicitly setting locale or translation fallbacks.
86
+ */
87
+ buttonTxOptions?: TextProps["txOptions"]
88
+ /**
89
+ * Style overrides for button.
90
+ */
91
+ buttonStyle?: ButtonProps["style"]
92
+ /**
93
+ * Style overrides for button text.
94
+ */
95
+ buttonTextStyle?: ButtonProps["textStyle"]
96
+ /**
97
+ * Called when the button is pressed.
98
+ */
99
+ buttonOnPress?: ButtonProps["onPress"]
100
+ /**
101
+ * Pass any additional props directly to the Button component.
102
+ */
103
+ ButtonProps?: ButtonProps
104
+ }
105
+
106
+ interface EmptyStatePresetItem {
107
+ imageSource: ImageProps["source"]
108
+ heading: TextProps["text"]
109
+ content: TextProps["text"]
110
+ button: TextProps["text"]
111
+ }
112
+
113
+ /**
114
+ * A component to use when there is no data to display. It can be utilized to direct the user what to do next.
115
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/EmptyState/}
116
+ * @param {EmptyStateProps} props - The props for the `EmptyState` component.
117
+ * @returns {JSX.Element} The rendered `EmptyState` component.
118
+ */
119
+ export function EmptyState(props: EmptyStateProps) {
120
+ const {
121
+ theme,
122
+ themed,
123
+ theme: { spacing },
124
+ } = useAppTheme()
125
+
126
+ const EmptyStatePresets = {
127
+ generic: {
128
+ imageSource: sadFace,
129
+ heading: translate("emptyStateComponent:generic.heading"),
130
+ content: translate("emptyStateComponent:generic.content"),
131
+ button: translate("emptyStateComponent:generic.button"),
132
+ } as EmptyStatePresetItem,
133
+ } as const
134
+
135
+ const preset = EmptyStatePresets[props.preset ?? "generic"]
136
+
137
+ const {
138
+ button = preset.button,
139
+ buttonTx,
140
+ buttonOnPress,
141
+ buttonTxOptions,
142
+ content = preset.content,
143
+ contentTx,
144
+ contentTxOptions,
145
+ heading = preset.heading,
146
+ headingTx,
147
+ headingTxOptions,
148
+ imageSource = preset.imageSource,
149
+ style: $containerStyleOverride,
150
+ buttonStyle: $buttonStyleOverride,
151
+ buttonTextStyle: $buttonTextStyleOverride,
152
+ contentStyle: $contentStyleOverride,
153
+ headingStyle: $headingStyleOverride,
154
+ imageStyle: $imageStyleOverride,
155
+ ButtonProps,
156
+ ContentTextProps,
157
+ HeadingTextProps,
158
+ ImageProps,
159
+ } = props
160
+
161
+ const isImagePresent = !!imageSource
162
+ const isHeadingPresent = !!(heading || headingTx)
163
+ const isContentPresent = !!(content || contentTx)
164
+ const isButtonPresent = !!(button || buttonTx)
165
+
166
+ const $containerStyles = [$containerStyleOverride]
167
+ const $imageStyles = [
168
+ $image,
169
+ (isHeadingPresent || isContentPresent || isButtonPresent) && { marginBottom: spacing.xxxs },
170
+ $imageStyleOverride,
171
+ ImageProps?.style,
172
+ ]
173
+ const $headingStyles = [
174
+ themed($heading),
175
+ isImagePresent && { marginTop: spacing.xxxs },
176
+ (isContentPresent || isButtonPresent) && { marginBottom: spacing.xxxs },
177
+ $headingStyleOverride,
178
+ HeadingTextProps?.style,
179
+ ]
180
+ const $contentStyles = [
181
+ themed($content),
182
+ (isImagePresent || isHeadingPresent) && { marginTop: spacing.xxxs },
183
+ isButtonPresent && { marginBottom: spacing.xxxs },
184
+ $contentStyleOverride,
185
+ ContentTextProps?.style,
186
+ ]
187
+ const $buttonStyles = [
188
+ (isImagePresent || isHeadingPresent || isContentPresent) && { marginTop: spacing.xl },
189
+ $buttonStyleOverride,
190
+ ButtonProps?.style,
191
+ ]
192
+
193
+ return (
194
+ <View style={$containerStyles}>
195
+ {isImagePresent && (
196
+ <Image
197
+ source={imageSource}
198
+ {...ImageProps}
199
+ style={$imageStyles}
200
+ tintColor={theme.colors.palette.neutral900}
201
+ />
202
+ )}
203
+
204
+ {isHeadingPresent && (
205
+ <Text
206
+ preset="subheading"
207
+ text={heading}
208
+ tx={headingTx}
209
+ txOptions={headingTxOptions}
210
+ {...HeadingTextProps}
211
+ style={$headingStyles}
212
+ />
213
+ )}
214
+
215
+ {isContentPresent && (
216
+ <Text
217
+ text={content}
218
+ tx={contentTx}
219
+ txOptions={contentTxOptions}
220
+ {...ContentTextProps}
221
+ style={$contentStyles}
222
+ />
223
+ )}
224
+
225
+ {isButtonPresent && (
226
+ <Button
227
+ onPress={buttonOnPress}
228
+ text={button}
229
+ tx={buttonTx}
230
+ txOptions={buttonTxOptions}
231
+ textStyle={$buttonTextStyleOverride}
232
+ {...ButtonProps}
233
+ style={$buttonStyles}
234
+ />
235
+ )}
236
+ </View>
237
+ )
238
+ }
239
+
240
+ const $image: ImageStyle = { alignSelf: "center" }
241
+ const $heading: ThemedStyle<TextStyle> = ({ spacing }) => ({
242
+ textAlign: "center",
243
+ paddingHorizontal: spacing.lg,
244
+ })
245
+ const $content: ThemedStyle<TextStyle> = ({ spacing }) => ({
246
+ textAlign: "center",
247
+ paddingHorizontal: spacing.lg,
248
+ })