@fadyshawky/react-native-magic 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 (165) hide show
  1. package/.vscode/settings.json +7 -0
  2. package/README.md +269 -0
  3. package/package.json +36 -0
  4. package/template/.bundle/config +2 -0
  5. package/template/.env.development +5 -0
  6. package/template/.env.production +5 -0
  7. package/template/.env.staging +5 -0
  8. package/template/.eslintrc.js +4 -0
  9. package/template/.prettierrc.js +7 -0
  10. package/template/.watchmanconfig +1 -0
  11. package/template/App.tsx +34 -0
  12. package/template/Gemfile +9 -0
  13. package/template/Gemfile.lock +117 -0
  14. package/template/README.md +79 -0
  15. package/template/__tests__/App.test.tsx +17 -0
  16. package/template/android/app/build.gradle +128 -0
  17. package/template/android/app/debug.keystore +0 -0
  18. package/template/android/app/proguard-rules.pro +10 -0
  19. package/template/android/app/src/debug/AndroidManifest.xml +9 -0
  20. package/template/android/app/src/main/AndroidManifest.xml +26 -0
  21. package/template/android/app/src/main/java/com/reactnativemagic/MainActivity.kt +22 -0
  22. package/template/android/app/src/main/java/com/reactnativemagic/MainApplication.kt +44 -0
  23. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  24. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  25. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  26. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  27. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  28. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  29. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  30. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  31. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  32. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  33. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  34. package/template/android/app/src/main/res/values/strings.xml +3 -0
  35. package/template/android/app/src/main/res/values/styles.xml +9 -0
  36. package/template/android/build.gradle +21 -0
  37. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  38. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  39. package/template/android/gradle.properties +39 -0
  40. package/template/android/gradlew +252 -0
  41. package/template/android/gradlew.bat +94 -0
  42. package/template/android/settings.gradle +6 -0
  43. package/template/app.json +4 -0
  44. package/template/babel.config.js +3 -0
  45. package/template/index.js +9 -0
  46. package/template/install-dev.sh +1 -0
  47. package/template/install.sh +1 -0
  48. package/template/ios/.xcode.env +11 -0
  49. package/template/ios/Podfile +42 -0
  50. package/template/ios/Podfile.lock +2461 -0
  51. package/template/ios/reactnativemagic/AppDelegate.h +6 -0
  52. package/template/ios/reactnativemagic/AppDelegate.mm +31 -0
  53. package/template/ios/reactnativemagic/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  54. package/template/ios/reactnativemagic/Images.xcassets/Contents.json +6 -0
  55. package/template/ios/reactnativemagic/Info.plist +52 -0
  56. package/template/ios/reactnativemagic/LaunchScreen.storyboard +47 -0
  57. package/template/ios/reactnativemagic/PrivacyInfo.xcprivacy +46 -0
  58. package/template/ios/reactnativemagic/main.m +10 -0
  59. package/template/ios/reactnativemagic copy-Info.plist +52 -0
  60. package/template/ios/reactnativemagic.xcodeproj/project.pbxproj +836 -0
  61. package/template/ios/reactnativemagic.xcodeproj/xcshareddata/xcschemes/reactnativemagic.xcscheme +88 -0
  62. package/template/ios/reactnativemagic.xcworkspace/contents.xcworkspacedata +10 -0
  63. package/template/ios/reactnativemagic.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
  64. package/template/ios/reactnativemagicTests/Info.plist +24 -0
  65. package/template/ios/reactnativemagicTests/reactnativemagicTests.m +66 -0
  66. package/template/ios/tmp.xcconfig +2 -0
  67. package/template/jest.config.js +3 -0
  68. package/template/metro.config.js +11 -0
  69. package/template/package-lock.json +18315 -0
  70. package/template/package.json +125 -0
  71. package/template/resources/symbols/SFSymbols.ts +2614 -0
  72. package/template/src/common/ImageResources.g.ts +14 -0
  73. package/template/src/common/components/Background.tsx +34 -0
  74. package/template/src/common/components/EmptyView.tsx +31 -0
  75. package/template/src/common/components/FlatListWrapper.tsx +66 -0
  76. package/template/src/common/components/IconPlatform.tsx +17 -0
  77. package/template/src/common/components/ImageCropPickerButton.tsx +108 -0
  78. package/template/src/common/components/LoadingComponent.tsx +16 -0
  79. package/template/src/common/components/PhotoTakingButton.tsx +99 -0
  80. package/template/src/common/components/PrimaryButton.tsx +305 -0
  81. package/template/src/common/components/PrimaryTextInput.tsx +287 -0
  82. package/template/src/common/components/RadioButton.tsx +73 -0
  83. package/template/src/common/components/RadioIcon.tsx +63 -0
  84. package/template/src/common/components/Separator.tsx +39 -0
  85. package/template/src/common/components/Svg.tsx +25 -0
  86. package/template/src/common/components/TouchablePlatform.tsx +70 -0
  87. package/template/src/common/components/TryAgain.tsx +56 -0
  88. package/template/src/common/helpers/arrayHelpers.ts +29 -0
  89. package/template/src/common/helpers/calculatePage.ts +16 -0
  90. package/template/src/common/helpers/colorHelpers.ts +34 -0
  91. package/template/src/common/helpers/defaultKeyIdExtractor.ts +5 -0
  92. package/template/src/common/helpers/dialogsHelpers.ts +66 -0
  93. package/template/src/common/helpers/imageHelpers.ts +5 -0
  94. package/template/src/common/helpers/inAppReviewHelper.ts +31 -0
  95. package/template/src/common/helpers/netInfoHelpers.ts +42 -0
  96. package/template/src/common/helpers/orientationHelpers.ts +25 -0
  97. package/template/src/common/helpers/regexHelpers.ts +7 -0
  98. package/template/src/common/helpers/shareHelpers.ts +47 -0
  99. package/template/src/common/helpers/stringsHelpers.ts +15 -0
  100. package/template/src/common/hooks/useBackHandler.ts +10 -0
  101. package/template/src/common/hooks/useDebounce.ts +17 -0
  102. package/template/src/common/hooks/useEventRegister.ts +50 -0
  103. package/template/src/common/hooks/useFlatListActions.ts +31 -0
  104. package/template/src/common/hooks/usePrevious.ts +11 -0
  105. package/template/src/common/hooks/useWhyDidYouUpdate.ts +27 -0
  106. package/template/src/common/localization/dateFormatter.ts +108 -0
  107. package/template/src/common/localization/intlFormatter.ts +37 -0
  108. package/template/src/common/localization/localization.ts +51 -0
  109. package/template/src/common/localization/translations/commonLocalization.ts +29 -0
  110. package/template/src/common/localization/translations/emptyLocalization.ts +6 -0
  111. package/template/src/common/localization/translations/errorsLocalization.ts +22 -0
  112. package/template/src/common/localization/translations/homeLocalization.ts +5 -0
  113. package/template/src/common/localization/translations/loginLocalization.ts +14 -0
  114. package/template/src/common/localization/translations/onboardingLocalization.ts +13 -0
  115. package/template/src/common/localization/translations/pagesLocalization.ts +14 -0
  116. package/template/src/common/localization/translations/profileLocalization.ts +6 -0
  117. package/template/src/common/urls/baseUrlOpener.ts +31 -0
  118. package/template/src/common/urls/emailUrl.ts +20 -0
  119. package/template/src/common/urls/httpUrl.ts +19 -0
  120. package/template/src/common/urls/mapUrl.ts +22 -0
  121. package/template/src/common/urls/phoneUrl.ts +16 -0
  122. package/template/src/common/utils/createPerfectSize.ts +15 -0
  123. package/template/src/common/utils/listHandlers.ts +30 -0
  124. package/template/src/common/utils/newState.ts +5 -0
  125. package/template/src/common/utils/serializeQueryParams.ts +10 -0
  126. package/template/src/common/validations/authValidations.ts +15 -0
  127. package/template/src/common/validations/commonValidations.ts +39 -0
  128. package/template/src/common/validations/errorValidations.ts +72 -0
  129. package/template/src/common/validations/hooks/useDatesError.ts +40 -0
  130. package/template/src/common/validations/hooks/useInputError.ts +30 -0
  131. package/template/src/common/validations/profileValidations.ts +30 -0
  132. package/template/src/common/validations/validationConstants.ts +20 -0
  133. package/template/src/core/api/responseHandlers.ts +43 -0
  134. package/template/src/core/api/serverHeaders.ts +39 -0
  135. package/template/src/core/store/app/appSlice.ts +12 -0
  136. package/template/src/core/store/app/appState.ts +3 -0
  137. package/template/src/core/store/reduxHelpers.ts +11 -0
  138. package/template/src/core/store/rootReducer.ts +10 -0
  139. package/template/src/core/store/store.tsx +41 -0
  140. package/template/src/core/store/user/userActions.ts +31 -0
  141. package/template/src/core/store/user/userSlice.ts +62 -0
  142. package/template/src/core/store/user/userState.ts +44 -0
  143. package/template/src/core/theme/colors.ts +117 -0
  144. package/template/src/core/theme/commonConsts.ts +45 -0
  145. package/template/src/core/theme/commonSizes.ts +70 -0
  146. package/template/src/core/theme/commonStyles.ts +228 -0
  147. package/template/src/core/theme/fonts.ts +12 -0
  148. package/template/src/navigation/AuthStack.tsx +39 -0
  149. package/template/src/navigation/HeaderComponents.tsx +104 -0
  150. package/template/src/navigation/MainNavigation.tsx +55 -0
  151. package/template/src/navigation/MainStack.tsx +99 -0
  152. package/template/src/navigation/RootNavigation.tsx +33 -0
  153. package/template/src/navigation/TabBar.tsx +94 -0
  154. package/template/src/navigation/TopTabBar.tsx +75 -0
  155. package/template/src/navigation/types.ts +5 -0
  156. package/template/src/screens/Login/Login.tsx +114 -0
  157. package/template/src/screens/Settings/Settings.tsx +5 -0
  158. package/template/src/screens/main/Main.tsx +5 -0
  159. package/template/src/screens/profile/Profile.tsx +5 -0
  160. package/template/src/screens/splash/Splash.tsx +19 -0
  161. package/template/src/sheetManager/sheets.tsx +14 -0
  162. package/template/tsconfig.json +3 -0
  163. package/template/types/index.ts +108 -0
  164. package/template/types/react-native-config.d.ts +19 -0
  165. package/template.config.js +4 -0
@@ -0,0 +1,287 @@
1
+ import React, {
2
+ FC,
3
+ memo,
4
+ MutableRefObject,
5
+ Ref,
6
+ useCallback,
7
+ useMemo,
8
+ useState,
9
+ } from 'react';
10
+ import {
11
+ NativeSyntheticEvent,
12
+ Platform,
13
+ StyleSheet,
14
+ Text,
15
+ TextInput,
16
+ TextInputFocusEventData,
17
+ TextInputProps,
18
+ TextInputSubmitEditingEventData,
19
+ TextStyle,
20
+ TouchableOpacity,
21
+ View,
22
+ ViewStyle,
23
+ } from 'react-native';
24
+ import {
25
+ Colors,
26
+ PlatformColorsAndroid,
27
+ PlatformColorsIOS,
28
+ } from '../../core/theme/colors';
29
+ import {isIos} from '../../core/theme/commonConsts';
30
+ import {CommonSizes} from '../../core/theme/commonSizes';
31
+ import {CommonStyles} from '../../core/theme/commonStyles';
32
+ import {platformMixedColor, platformNativeColor} from '../helpers/colorHelpers';
33
+ import {localization} from '../localization/localization';
34
+
35
+ interface IProps extends TextInputProps {
36
+ nextInputFocusRef?: MutableRefObject<any>;
37
+ inputRef?: Ref<any>;
38
+ containerStyle?: ViewStyle;
39
+ label?: string;
40
+ error?: string | null;
41
+ hint?: string;
42
+ autoComplete?:
43
+ | 'off'
44
+ | 'username'
45
+ | 'password'
46
+ | 'email'
47
+ | 'name'
48
+ | 'tel'
49
+ | 'street-address'
50
+ | 'postal-code'
51
+ | 'cc-number'
52
+ | 'cc-csc'
53
+ | 'cc-exp'
54
+ | 'cc-exp-month'
55
+ | 'cc-exp-year';
56
+ required?: boolean;
57
+ optional?: boolean;
58
+ inputContainerStyle?: ViewStyle;
59
+ }
60
+
61
+ export const PrimaryTextInput: FC<IProps> = memo(
62
+ ({
63
+ style = styles.input,
64
+ blurOnSubmit = true,
65
+ disableFullscreenUI = true,
66
+ enablesReturnKeyAutomatically = true,
67
+ underlineColorAndroid = Colors.transparent,
68
+ placeholderTextColor = platformNativeColor(
69
+ PlatformColorsIOS.placeholderText,
70
+ PlatformColorsAndroid.secondaryText,
71
+ ),
72
+ editable = true,
73
+ clearButtonMode = 'while-editing',
74
+ label,
75
+ error,
76
+ hint,
77
+ containerStyle,
78
+ inputRef,
79
+ nextInputFocusRef,
80
+ onTouchStart,
81
+ onFocus,
82
+ onBlur,
83
+ onSubmitEditing,
84
+ required,
85
+ optional,
86
+ ...props
87
+ }) => {
88
+ const [isFocused, setFocused] = useState<boolean>(false);
89
+
90
+ const onLocalFocus = useCallback(
91
+ (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
92
+ setFocused(true);
93
+ onFocus && onFocus(e);
94
+ },
95
+ [onFocus, setFocused],
96
+ );
97
+
98
+ const onLocalBlur = useCallback(
99
+ (e: NativeSyntheticEvent<TextInputFocusEventData>) => {
100
+ setFocused(false);
101
+ onBlur && onBlur(e);
102
+ },
103
+ [onBlur, setFocused],
104
+ );
105
+
106
+ const inputContainerStyle = useMemo(() => {
107
+ return getInputContainerStyle(
108
+ isFocused,
109
+ error,
110
+ onTouchStart ? true : editable,
111
+ );
112
+ }, [isFocused, error, editable, onTouchStart]);
113
+
114
+ const onLocalSubmitEditing = useCallback(
115
+ (e: NativeSyntheticEvent<TextInputSubmitEditingEventData>) => {
116
+ onSubmitEditing && onSubmitEditing(e);
117
+ nextInputFocusRef &&
118
+ nextInputFocusRef.current &&
119
+ nextInputFocusRef.current.focus();
120
+ },
121
+ [nextInputFocusRef, onSubmitEditing],
122
+ );
123
+
124
+ const pointerEvents = useMemo(() => {
125
+ return onTouchStart ? 'none' : undefined;
126
+ }, [onTouchStart]);
127
+
128
+ return (
129
+ <View style={[styles.container, containerStyle]}>
130
+ <Label text={label} required={required} optional={optional} />
131
+ <TouchableOpacity
132
+ style={[inputContainerStyle, props.inputContainerStyle]}
133
+ onPress={onTouchStart}
134
+ disabled={!onTouchStart}>
135
+ <TextInput
136
+ disableFullscreenUI={true}
137
+ selectionColor={selectionColor}
138
+ {...props}
139
+ pointerEvents={pointerEvents}
140
+ ref={inputRef}
141
+ style={[styles.input, style]}
142
+ autoCapitalize="none"
143
+ autoComplete="off"
144
+ />
145
+ </TouchableOpacity>
146
+ <BottomText error={error} hint={hint} />
147
+ </View>
148
+ );
149
+ },
150
+ );
151
+
152
+ const Label: FC<{text?: string; required?: boolean; optional?: boolean}> = memo(
153
+ ({text, required, optional}) => {
154
+ if (text != null) {
155
+ return (
156
+ <Text style={styles.label} numberOfLines={1}>
157
+ {text +
158
+ (required
159
+ ? localization.common.required
160
+ : optional
161
+ ? localization.common.optional
162
+ : '')}
163
+ </Text>
164
+ );
165
+ } else {
166
+ return null;
167
+ }
168
+ },
169
+ );
170
+
171
+ const BottomText: FC<{error?: string | null; hint?: string}> = memo(
172
+ ({error, hint}) => {
173
+ if (error != null) {
174
+ return <Text style={styles.error}>{error}</Text>;
175
+ } else if (hint != null) {
176
+ return <Text style={styles.hint}>{hint}</Text>;
177
+ } else {
178
+ return null;
179
+ }
180
+ },
181
+ );
182
+
183
+ function getInputContainerStyle(
184
+ isFocused: boolean,
185
+ error?: string | null,
186
+ isEditable?: boolean,
187
+ ): ViewStyle {
188
+ if (isIos) {
189
+ return !isEditable ? styles.disabledInputContainer : styles.inputContainer;
190
+ } else {
191
+ if (isFocused) {
192
+ return styles.focusedInputContainer;
193
+ } else if (!isEditable) {
194
+ return styles.disabledInputContainer;
195
+ } else if (error) {
196
+ return styles.errorInputContainer;
197
+ } else {
198
+ return styles.inputContainer;
199
+ }
200
+ }
201
+ }
202
+
203
+ const selectionColor = platformNativeColor(
204
+ PlatformColorsIOS.systemBlue,
205
+ PlatformColorsAndroid.primary,
206
+ );
207
+
208
+ const commonInputContainer: TextStyle = {
209
+ flexDirection: 'row',
210
+ alignItems: 'center',
211
+ justifyContent: 'center',
212
+ minHeight: CommonSizes.spacing.extraLarge,
213
+ textAlignVertical: 'center',
214
+ textAlign: 'center',
215
+ backgroundColor: Colors.white,
216
+ borderRadius: CommonSizes.borderRadius.medium,
217
+ borderWidth: CommonSizes.borderWidth.small,
218
+ borderColor: Colors.gray,
219
+ };
220
+
221
+ const styles = StyleSheet.create({
222
+ container: {
223
+ flexDirection: 'column',
224
+ } as ViewStyle,
225
+ input: {
226
+ ...CommonStyles.normalText,
227
+ flex: 1,
228
+ textAlignVertical: 'center',
229
+ paddingStart: CommonSizes.spacing.medium,
230
+ ...Platform.select({
231
+ android: {
232
+ paddingEnd: CommonSizes.spacing.medium,
233
+ },
234
+ }),
235
+ } as TextStyle,
236
+ inputContainer: {
237
+ ...commonInputContainer,
238
+ ...Platform.select({
239
+ ios: {
240
+ paddingEnd: CommonSizes.spacing.medium,
241
+ },
242
+ }),
243
+ } as TextStyle,
244
+ errorInputContainer: {
245
+ ...commonInputContainer,
246
+ ...Platform.select({
247
+ android: {
248
+ borderColor: Colors.red,
249
+ },
250
+ }),
251
+ } as TextStyle,
252
+ disabledInputContainer: {
253
+ ...commonInputContainer,
254
+ ...Platform.select({
255
+ android: {
256
+ backgroundColor: Colors.gray,
257
+ borderColor: Colors.gray,
258
+ },
259
+ }),
260
+ } as TextStyle,
261
+ focusedInputContainer: {
262
+ ...commonInputContainer,
263
+ ...Platform.select({
264
+ android: {
265
+ borderColor: Colors.darkGray,
266
+ },
267
+ }),
268
+ } as TextStyle,
269
+ label: {
270
+ ...CommonStyles.body_regular,
271
+ paddingBottom: CommonSizes.spacing.extraSmall,
272
+ } as TextStyle,
273
+ hint: {
274
+ ...CommonStyles.normalText,
275
+ fontWeight: '200',
276
+ fontSize: CommonSizes.font.small,
277
+ lineHeight: CommonSizes.lineHeight.small,
278
+ paddingTop: CommonSizes.spacing.extraSmall,
279
+ } as TextStyle,
280
+ error: {
281
+ ...CommonStyles.normalText,
282
+ color: platformMixedColor(PlatformColorsIOS.systemRed, Colors.red),
283
+ fontSize: CommonSizes.font.small,
284
+ lineHeight: CommonSizes.lineHeight.small,
285
+ paddingTop: CommonSizes.spacing.extraSmall,
286
+ } as TextStyle,
287
+ });
@@ -0,0 +1,73 @@
1
+ import React, {FC, FunctionComponent, memo, useCallback, useMemo} from 'react';
2
+ import {StyleSheet, Text, TextStyle, ViewStyle} from 'react-native';
3
+ import {RadioIcon} from './RadioIcon';
4
+ import {TouchablePlatform} from './TouchablePlatform';
5
+ import {CommonSizes} from '../../core/theme/commonSizes';
6
+ import {CommonStyles} from '../../core/theme/commonStyles';
7
+ import {
8
+ PlatformColorsAndroid,
9
+ PlatformColorsIOS,
10
+ } from '../../core/theme/colors';
11
+ import {platformNativeColor} from '../helpers/colorHelpers';
12
+
13
+ interface IIconComponentProps {
14
+ isSelected: boolean;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ interface IProps extends IIconComponentProps {
19
+ id: string;
20
+ label: string;
21
+ onPress: (id: string, nextValue: boolean) => void;
22
+ IconComponent?: FunctionComponent<IIconComponentProps>;
23
+ }
24
+
25
+ export const RadioButton: FC<IProps> = memo(
26
+ ({isSelected, label, onPress, disabled, IconComponent = RadioIcon, id}) => {
27
+ const onButtonPress = useCallback(() => {
28
+ onPress(id, !isSelected);
29
+ }, [onPress, isSelected, id]);
30
+
31
+ const labelStyle = useMemo(() => {
32
+ return disabled ? styles.labelDisabled : styles.label;
33
+ }, [disabled]);
34
+
35
+ return (
36
+ <TouchablePlatform
37
+ style={styles.container}
38
+ onPress={onButtonPress}
39
+ disabled={disabled}>
40
+ {IconComponent && (
41
+ <IconComponent disabled={disabled} isSelected={isSelected} />
42
+ )}
43
+ <Text style={labelStyle} numberOfLines={1}>
44
+ {label}
45
+ </Text>
46
+ </TouchablePlatform>
47
+ );
48
+ },
49
+ );
50
+
51
+ const commonLabel: TextStyle = {
52
+ ...CommonStyles.normalText,
53
+ flex: 1,
54
+ paddingStart: CommonSizes.spacing.extraSmall,
55
+ };
56
+
57
+ const styles = StyleSheet.create({
58
+ container: {
59
+ flexDirection: 'row',
60
+ padding: CommonSizes.spacing.medium,
61
+ alignItems: 'center',
62
+ } as ViewStyle,
63
+ label: {
64
+ ...commonLabel,
65
+ } as TextStyle,
66
+ labelDisabled: {
67
+ ...commonLabel,
68
+ color: platformNativeColor(
69
+ PlatformColorsIOS.systemFill,
70
+ PlatformColorsAndroid.secondaryText,
71
+ ),
72
+ } as TextStyle,
73
+ });
@@ -0,0 +1,63 @@
1
+ import React, {FC, memo, useMemo} from 'react';
2
+ import {StyleSheet, View, ViewStyle} from 'react-native';
3
+ import {
4
+ Colors,
5
+ PlatformColorsAndroid,
6
+ PlatformColorsIOS,
7
+ } from '../../core/theme/colors';
8
+ import {platformMixedColor, platformNativeColor} from '../helpers/colorHelpers';
9
+
10
+ interface IProps {
11
+ isSelected: boolean;
12
+ disabled?: boolean;
13
+ }
14
+
15
+ export const RadioIcon: FC<IProps> = memo(({isSelected, disabled}) => {
16
+ const outerCircleStyle = useMemo(() => {
17
+ return disabled
18
+ ? styles.outerCircle
19
+ : isSelected
20
+ ? styles.outerCircleSelected
21
+ : styles.outerCircle;
22
+ }, [isSelected, disabled]);
23
+
24
+ return (
25
+ <View style={outerCircleStyle}>
26
+ {isSelected && <View style={styles.innerCircle} />}
27
+ </View>
28
+ );
29
+ });
30
+
31
+ const commonOuterCircle: ViewStyle = {
32
+ width: 16,
33
+ height: 16,
34
+ borderRadius: 8,
35
+ borderWidth: 2,
36
+ justifyContent: 'center',
37
+ alignItems: 'center',
38
+ backgroundColor: Colors.transparent,
39
+ };
40
+
41
+ const commonInnerCircle: ViewStyle = {
42
+ width: 8,
43
+ height: 8,
44
+ borderRadius: 4,
45
+ };
46
+
47
+ const styles = StyleSheet.create({
48
+ outerCircle: {
49
+ ...commonOuterCircle,
50
+ borderColor: platformMixedColor(PlatformColorsIOS.systemFill, Colors.black),
51
+ } as ViewStyle,
52
+ outerCircleSelected: {
53
+ ...commonOuterCircle,
54
+ borderColor: platformMixedColor(PlatformColorsIOS.systemBlue, Colors.black),
55
+ } as ViewStyle,
56
+ innerCircle: {
57
+ ...commonInnerCircle,
58
+ backgroundColor: platformNativeColor(
59
+ PlatformColorsIOS.systemBlue,
60
+ PlatformColorsAndroid.primary,
61
+ ),
62
+ } as ViewStyle,
63
+ });
@@ -0,0 +1,39 @@
1
+ import React, {FC, useMemo} from 'react';
2
+ import {StyleSheet, View, ViewStyle} from 'react-native';
3
+ import {
4
+ PlatformColorsAndroid,
5
+ PlatformColorsIOS,
6
+ } from '../../core/theme/colors';
7
+ import {hairlineWidth} from '../../core/theme/commonConsts';
8
+ import {CommonSizes} from '../../core/theme/commonSizes';
9
+ import {platformNativeColor} from '../helpers/colorHelpers';
10
+
11
+ interface IProps {
12
+ isFull?: boolean;
13
+ }
14
+
15
+ export const Separator: FC<IProps> = ({isFull = true}) => {
16
+ const containerStyle = useMemo(() => {
17
+ return isFull ? styles.fullContainer : styles.container;
18
+ }, [isFull]);
19
+
20
+ return <View style={containerStyle} />;
21
+ };
22
+
23
+ const sharedStyle: ViewStyle = {
24
+ height: hairlineWidth,
25
+ backgroundColor: platformNativeColor(
26
+ PlatformColorsIOS.separator,
27
+ PlatformColorsAndroid.divider,
28
+ ),
29
+ };
30
+
31
+ const styles = StyleSheet.create({
32
+ container: {
33
+ ...sharedStyle,
34
+ marginHorizontal: CommonSizes.spacing.medium,
35
+ } as ViewStyle,
36
+ fullContainer: {
37
+ ...sharedStyle,
38
+ } as ViewStyle,
39
+ });
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+ import Svg, {G, Path, Defs, ClipPath, SvgProps} from 'react-native-svg';
3
+
4
+ const SvgComponent: React.FC<SvgProps> = props => (
5
+ <Svg width={'100%'} height={'100%'} fill="none" {...props}>
6
+ <G clipPath="url(#a)">
7
+ <Path fill="#F9FCFF" d="M0 0h428v925H0z" />
8
+ <Path
9
+ fill="#F3F2FF"
10
+ d="M293.588 913.49c-11.664-7.299-22.732-17.683-25.003-31.28-1.327-8.116.619-16.401.321-24.632-1.302-34.39-41.04-60.387-36.303-94.477 3.225-23.054 26.005-38.157 48.084-45.307 22.079-7.15 46.135-9.803 65.558-22.544 11.677-7.647 20.94-18.492 32.704-26.016 31.368-20.054 78.287-8.983 97.328 23.023 13.438 22.55 13.203 50.707 8.916 76.621-7.313 43.969-24.299 113.518-59.201 144.845-32.956 29.629-98.321 21.076-132.404-.233Z"
11
+ />
12
+ <Path
13
+ fill="#EEF8FF"
14
+ d="M80.103-35.495c11.658 7.31 22.718 17.702 24.977 31.301 1.32 8.117-.633 16.4-.342 24.631 1.274 34.392 40.991 60.422 36.225 94.508-3.244 23.051-26.037 38.135-48.122 45.267-22.085 7.132-46.143 9.764-65.577 22.489-11.683 7.638-20.955 18.474-32.725 25.989-31.385 20.028-78.294 8.917-97.31-23.105-13.419-22.56-13.16-50.717-8.852-76.628C-104.272 64.994-87.228-4.54-52.301-35.838c32.98-29.602 98.34-20.994 132.404.343Z"
15
+ />
16
+ </G>
17
+ <Defs>
18
+ <ClipPath id="a">
19
+ <Path fill="#fff" d="M0 0h428v925H0z" />
20
+ </ClipPath>
21
+ </Defs>
22
+ </Svg>
23
+ );
24
+
25
+ export default SvgComponent;
@@ -0,0 +1,70 @@
1
+ import React, {FC, memo, useCallback, useMemo} from 'react';
2
+ import {
3
+ OpaqueColorValue,
4
+ Pressable,
5
+ PressableAndroidRippleConfig,
6
+ PressableProps,
7
+ PressableStateCallbackType,
8
+ ViewStyle,
9
+ } from 'react-native';
10
+ import {Colors, PlatformColorsIOS} from '../../core/theme/colors';
11
+ import {isAndroid} from '../../core/theme/commonConsts';
12
+ import {platformMixedColor} from '../helpers/colorHelpers';
13
+
14
+ interface IProps extends PressableProps {
15
+ style?: ViewStyle | ViewStyle[];
16
+ highlightColor?: string | null | OpaqueColorValue;
17
+ }
18
+
19
+ export const TouchablePlatform: FC<IProps> = memo(
20
+ ({
21
+ children,
22
+ highlightColor = platformMixedColor(
23
+ PlatformColorsIOS.secondarySystemFill,
24
+ Colors.white,
25
+ ),
26
+ style,
27
+ ...props
28
+ }) => {
29
+ const pressableStyle = useCallback(
30
+ (state: PressableStateCallbackType) => {
31
+ if (isAndroid) {
32
+ return style;
33
+ } else {
34
+ return [
35
+ style,
36
+ state.pressed &&
37
+ ({
38
+ backgroundColor: highlightColor,
39
+ } as ViewStyle),
40
+ ];
41
+ }
42
+ },
43
+ [style, highlightColor],
44
+ );
45
+
46
+ /**
47
+ * Android can't use platform native colors
48
+ */
49
+ const rippleConfig = useMemo(() => {
50
+ return highlightColor != null
51
+ ? {...androidRippleConfig, color: highlightColor}
52
+ : androidRippleConfig;
53
+ }, [highlightColor]);
54
+
55
+ return (
56
+ <Pressable
57
+ android_disableSound={false}
58
+ android_ripple={rippleConfig}
59
+ {...props}
60
+ style={pressableStyle}>
61
+ {children}
62
+ </Pressable>
63
+ );
64
+ },
65
+ );
66
+
67
+ const androidRippleConfig: PressableAndroidRippleConfig = {
68
+ color: Colors.white,
69
+ borderless: false,
70
+ };
@@ -0,0 +1,56 @@
1
+ import React, {FC, memo} from 'react';
2
+ import {
3
+ StyleSheet,
4
+ Text,
5
+ TextStyle,
6
+ TouchableOpacity,
7
+ View,
8
+ } from 'react-native';
9
+ import {
10
+ PlatformColorsAndroid,
11
+ PlatformColorsIOS,
12
+ } from '../../core/theme/colors';
13
+ import {CommonSizes} from '../../core/theme/commonSizes';
14
+ import {CommonStyles} from '../../core/theme/commonStyles';
15
+ import {platformNativeColor} from '../helpers/colorHelpers';
16
+ import {localization} from '../localization/localization';
17
+
18
+ interface IProps {
19
+ onPress?: () => void;
20
+ errorText?: string | null;
21
+ }
22
+
23
+ export const TryAgain: FC<IProps> = memo(
24
+ ({onPress, errorText = localization.errors.unknownErrorHasOccurred}) => {
25
+ return (
26
+ <View
27
+ style={{...CommonStyles.flexCenter, backgroundColor: 'transparent'}}>
28
+ <Text style={styles.title}>{errorText}</Text>
29
+ {onPress != null && (
30
+ <TouchableOpacity onPress={onPress}>
31
+ <Text style={styles.description}>
32
+ {localization.errors.tryAgain}
33
+ </Text>
34
+ </TouchableOpacity>
35
+ )}
36
+ </View>
37
+ );
38
+ },
39
+ );
40
+
41
+ const styles = StyleSheet.create({
42
+ title: {
43
+ ...CommonStyles.normalText,
44
+ textAlign: 'center',
45
+ marginBottom: CommonSizes.spacing.extraSmall,
46
+ } as TextStyle,
47
+ description: {
48
+ ...CommonStyles.normalText,
49
+ color: platformNativeColor(
50
+ PlatformColorsIOS.systemBlue,
51
+ PlatformColorsAndroid.primary,
52
+ ),
53
+ textAlign: 'center',
54
+ textDecorationLine: 'underline',
55
+ } as TextStyle,
56
+ });
@@ -0,0 +1,29 @@
1
+ export function getItemIndex<T, V>(
2
+ data: T[],
3
+ comparisonParam: keyof T,
4
+ comparisonValue: V,
5
+ ) {
6
+ const index = data.findIndex(
7
+ item => item[comparisonParam] == comparisonValue,
8
+ );
9
+
10
+ const itemExists = index > -1;
11
+
12
+ return {index, itemExists};
13
+ }
14
+
15
+ export function filterBySearch<T>(
16
+ data: T[],
17
+ param: keyof T,
18
+ searchText: string,
19
+ ): T[] {
20
+ if (searchText != '') {
21
+ const lowerCaseSearch = searchText.toLowerCase();
22
+
23
+ return data.filter(item =>
24
+ (item[param] as string).toLowerCase().includes(lowerCaseSearch),
25
+ );
26
+ } else {
27
+ return data;
28
+ }
29
+ }
@@ -0,0 +1,16 @@
1
+ export const DEFAULT_PAGE_SIZE = 20;
2
+
3
+ export function calculatePage(
4
+ count: number,
5
+ pageSize: number = DEFAULT_PAGE_SIZE,
6
+ ): number {
7
+ if (count < 0) {
8
+ throw new Error("Count can't be negative");
9
+ }
10
+
11
+ if (pageSize < 1) {
12
+ throw new Error("Page size can't be 0 or negative");
13
+ }
14
+
15
+ return Math.trunc(count / pageSize) + 1;
16
+ }
@@ -0,0 +1,34 @@
1
+ import {isIos} from '../../core/theme/commonConsts';
2
+ import {
3
+ Colors,
4
+ PlatformColorsAndroid,
5
+ PlatformColorsIOS,
6
+ } from '../../core/theme/colors';
7
+
8
+ export function platformNativeColor(
9
+ iosColor?: PlatformColorsIOS,
10
+ androidColor?: PlatformColorsAndroid,
11
+ ) {
12
+ const selectedColor = isIos ? iosColor : androidColor;
13
+
14
+ return selectedColor != null ? 'black' : undefined;
15
+ }
16
+
17
+ export function platformLocalColor(iosColor?: Colors, androidColor?: Colors) {
18
+ return isIos ? iosColor : androidColor;
19
+ }
20
+
21
+ export function platformMixedColor(
22
+ iosColor?: Colors | PlatformColorsIOS,
23
+ androidColor?: Colors | PlatformColorsAndroid,
24
+ ) {
25
+ const selectedColor = iosColor;
26
+
27
+ if (selectedColor != null) {
28
+ return Object.values(Colors).includes(selectedColor as Colors)
29
+ ? (selectedColor as Colors)
30
+ : 'black';
31
+ } else {
32
+ return undefined;
33
+ }
34
+ }
@@ -0,0 +1,5 @@
1
+ export function defaultKeyIdExtractor<T extends {id: string | number}>(
2
+ item: T,
3
+ ): string {
4
+ return item?._id;
5
+ }