@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.
- package/.vscode/settings.json +7 -0
- package/README.md +269 -0
- package/package.json +36 -0
- package/template/.bundle/config +2 -0
- package/template/.env.development +5 -0
- package/template/.env.production +5 -0
- package/template/.env.staging +5 -0
- package/template/.eslintrc.js +4 -0
- package/template/.prettierrc.js +7 -0
- package/template/.watchmanconfig +1 -0
- package/template/App.tsx +34 -0
- package/template/Gemfile +9 -0
- package/template/Gemfile.lock +117 -0
- package/template/README.md +79 -0
- package/template/__tests__/App.test.tsx +17 -0
- package/template/android/app/build.gradle +128 -0
- package/template/android/app/debug.keystore +0 -0
- package/template/android/app/proguard-rules.pro +10 -0
- package/template/android/app/src/debug/AndroidManifest.xml +9 -0
- package/template/android/app/src/main/AndroidManifest.xml +26 -0
- package/template/android/app/src/main/java/com/reactnativemagic/MainActivity.kt +22 -0
- package/template/android/app/src/main/java/com/reactnativemagic/MainApplication.kt +44 -0
- package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
- package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- package/template/android/app/src/main/res/values/strings.xml +3 -0
- package/template/android/app/src/main/res/values/styles.xml +9 -0
- package/template/android/build.gradle +21 -0
- package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/template/android/gradle.properties +39 -0
- package/template/android/gradlew +252 -0
- package/template/android/gradlew.bat +94 -0
- package/template/android/settings.gradle +6 -0
- package/template/app.json +4 -0
- package/template/babel.config.js +3 -0
- package/template/index.js +9 -0
- package/template/install-dev.sh +1 -0
- package/template/install.sh +1 -0
- package/template/ios/.xcode.env +11 -0
- package/template/ios/Podfile +42 -0
- package/template/ios/Podfile.lock +2461 -0
- package/template/ios/reactnativemagic/AppDelegate.h +6 -0
- package/template/ios/reactnativemagic/AppDelegate.mm +31 -0
- package/template/ios/reactnativemagic/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
- package/template/ios/reactnativemagic/Images.xcassets/Contents.json +6 -0
- package/template/ios/reactnativemagic/Info.plist +52 -0
- package/template/ios/reactnativemagic/LaunchScreen.storyboard +47 -0
- package/template/ios/reactnativemagic/PrivacyInfo.xcprivacy +46 -0
- package/template/ios/reactnativemagic/main.m +10 -0
- package/template/ios/reactnativemagic copy-Info.plist +52 -0
- package/template/ios/reactnativemagic.xcodeproj/project.pbxproj +836 -0
- package/template/ios/reactnativemagic.xcodeproj/xcshareddata/xcschemes/reactnativemagic.xcscheme +88 -0
- package/template/ios/reactnativemagic.xcworkspace/contents.xcworkspacedata +10 -0
- package/template/ios/reactnativemagic.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +8 -0
- package/template/ios/reactnativemagicTests/Info.plist +24 -0
- package/template/ios/reactnativemagicTests/reactnativemagicTests.m +66 -0
- package/template/ios/tmp.xcconfig +2 -0
- package/template/jest.config.js +3 -0
- package/template/metro.config.js +11 -0
- package/template/package-lock.json +18315 -0
- package/template/package.json +125 -0
- package/template/resources/symbols/SFSymbols.ts +2614 -0
- package/template/src/common/ImageResources.g.ts +14 -0
- package/template/src/common/components/Background.tsx +34 -0
- package/template/src/common/components/EmptyView.tsx +31 -0
- package/template/src/common/components/FlatListWrapper.tsx +66 -0
- package/template/src/common/components/IconPlatform.tsx +17 -0
- package/template/src/common/components/ImageCropPickerButton.tsx +108 -0
- package/template/src/common/components/LoadingComponent.tsx +16 -0
- package/template/src/common/components/PhotoTakingButton.tsx +99 -0
- package/template/src/common/components/PrimaryButton.tsx +305 -0
- package/template/src/common/components/PrimaryTextInput.tsx +287 -0
- package/template/src/common/components/RadioButton.tsx +73 -0
- package/template/src/common/components/RadioIcon.tsx +63 -0
- package/template/src/common/components/Separator.tsx +39 -0
- package/template/src/common/components/Svg.tsx +25 -0
- package/template/src/common/components/TouchablePlatform.tsx +70 -0
- package/template/src/common/components/TryAgain.tsx +56 -0
- package/template/src/common/helpers/arrayHelpers.ts +29 -0
- package/template/src/common/helpers/calculatePage.ts +16 -0
- package/template/src/common/helpers/colorHelpers.ts +34 -0
- package/template/src/common/helpers/defaultKeyIdExtractor.ts +5 -0
- package/template/src/common/helpers/dialogsHelpers.ts +66 -0
- package/template/src/common/helpers/imageHelpers.ts +5 -0
- package/template/src/common/helpers/inAppReviewHelper.ts +31 -0
- package/template/src/common/helpers/netInfoHelpers.ts +42 -0
- package/template/src/common/helpers/orientationHelpers.ts +25 -0
- package/template/src/common/helpers/regexHelpers.ts +7 -0
- package/template/src/common/helpers/shareHelpers.ts +47 -0
- package/template/src/common/helpers/stringsHelpers.ts +15 -0
- package/template/src/common/hooks/useBackHandler.ts +10 -0
- package/template/src/common/hooks/useDebounce.ts +17 -0
- package/template/src/common/hooks/useEventRegister.ts +50 -0
- package/template/src/common/hooks/useFlatListActions.ts +31 -0
- package/template/src/common/hooks/usePrevious.ts +11 -0
- package/template/src/common/hooks/useWhyDidYouUpdate.ts +27 -0
- package/template/src/common/localization/dateFormatter.ts +108 -0
- package/template/src/common/localization/intlFormatter.ts +37 -0
- package/template/src/common/localization/localization.ts +51 -0
- package/template/src/common/localization/translations/commonLocalization.ts +29 -0
- package/template/src/common/localization/translations/emptyLocalization.ts +6 -0
- package/template/src/common/localization/translations/errorsLocalization.ts +22 -0
- package/template/src/common/localization/translations/homeLocalization.ts +5 -0
- package/template/src/common/localization/translations/loginLocalization.ts +14 -0
- package/template/src/common/localization/translations/onboardingLocalization.ts +13 -0
- package/template/src/common/localization/translations/pagesLocalization.ts +14 -0
- package/template/src/common/localization/translations/profileLocalization.ts +6 -0
- package/template/src/common/urls/baseUrlOpener.ts +31 -0
- package/template/src/common/urls/emailUrl.ts +20 -0
- package/template/src/common/urls/httpUrl.ts +19 -0
- package/template/src/common/urls/mapUrl.ts +22 -0
- package/template/src/common/urls/phoneUrl.ts +16 -0
- package/template/src/common/utils/createPerfectSize.ts +15 -0
- package/template/src/common/utils/listHandlers.ts +30 -0
- package/template/src/common/utils/newState.ts +5 -0
- package/template/src/common/utils/serializeQueryParams.ts +10 -0
- package/template/src/common/validations/authValidations.ts +15 -0
- package/template/src/common/validations/commonValidations.ts +39 -0
- package/template/src/common/validations/errorValidations.ts +72 -0
- package/template/src/common/validations/hooks/useDatesError.ts +40 -0
- package/template/src/common/validations/hooks/useInputError.ts +30 -0
- package/template/src/common/validations/profileValidations.ts +30 -0
- package/template/src/common/validations/validationConstants.ts +20 -0
- package/template/src/core/api/responseHandlers.ts +43 -0
- package/template/src/core/api/serverHeaders.ts +39 -0
- package/template/src/core/store/app/appSlice.ts +12 -0
- package/template/src/core/store/app/appState.ts +3 -0
- package/template/src/core/store/reduxHelpers.ts +11 -0
- package/template/src/core/store/rootReducer.ts +10 -0
- package/template/src/core/store/store.tsx +41 -0
- package/template/src/core/store/user/userActions.ts +31 -0
- package/template/src/core/store/user/userSlice.ts +62 -0
- package/template/src/core/store/user/userState.ts +44 -0
- package/template/src/core/theme/colors.ts +117 -0
- package/template/src/core/theme/commonConsts.ts +45 -0
- package/template/src/core/theme/commonSizes.ts +70 -0
- package/template/src/core/theme/commonStyles.ts +228 -0
- package/template/src/core/theme/fonts.ts +12 -0
- package/template/src/navigation/AuthStack.tsx +39 -0
- package/template/src/navigation/HeaderComponents.tsx +104 -0
- package/template/src/navigation/MainNavigation.tsx +55 -0
- package/template/src/navigation/MainStack.tsx +99 -0
- package/template/src/navigation/RootNavigation.tsx +33 -0
- package/template/src/navigation/TabBar.tsx +94 -0
- package/template/src/navigation/TopTabBar.tsx +75 -0
- package/template/src/navigation/types.ts +5 -0
- package/template/src/screens/Login/Login.tsx +114 -0
- package/template/src/screens/Settings/Settings.tsx +5 -0
- package/template/src/screens/main/Main.tsx +5 -0
- package/template/src/screens/profile/Profile.tsx +5 -0
- package/template/src/screens/splash/Splash.tsx +19 -0
- package/template/src/sheetManager/sheets.tsx +14 -0
- package/template/tsconfig.json +3 -0
- package/template/types/index.ts +108 -0
- package/template/types/react-native-config.d.ts +19 -0
- 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
|
+
}
|