create-react-native-starter-kit 0.0.0-stage → 1.0.1
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/LICENSE +21 -0
- package/README.md +378 -2
- package/bin/create-react-native-starter-kit.js +95 -0
- package/lib/copy-src.js +127 -0
- package/lib/creator.js +211 -0
- package/lib/deps.js +58 -0
- package/lib/patch-configs.js +318 -0
- package/lib/patch-native.js +588 -0
- package/package.json +47 -4
- package/scripts/sync-template.js +52 -0
- package/template/.env.example +3 -0
- package/template/patches/react-native-element-dropdown+2.12.4.patch +67 -0
- package/template/src/app/App.tsx +25 -0
- package/template/src/app/navigation/root.tsx +24 -0
- package/template/src/app/navigation/stacks/app.stack.tsx +67 -0
- package/template/src/app/navigation/stacks/app.tab.tsx +72 -0
- package/template/src/app/navigation/stacks/auth.stack.tsx +56 -0
- package/template/src/app/providers.tsx +43 -0
- package/template/src/assets/fonts/InterTight-Black.ttf +0 -0
- package/template/src/assets/fonts/InterTight-BlackItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Bold.ttf +0 -0
- package/template/src/assets/fonts/InterTight-BoldItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-ExtraBold.ttf +0 -0
- package/template/src/assets/fonts/InterTight-ExtraBoldItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-ExtraLight.ttf +0 -0
- package/template/src/assets/fonts/InterTight-ExtraLightItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Italic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Light.ttf +0 -0
- package/template/src/assets/fonts/InterTight-LightItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Medium.ttf +0 -0
- package/template/src/assets/fonts/InterTight-MediumItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Regular.ttf +0 -0
- package/template/src/assets/fonts/InterTight-SemiBold.ttf +0 -0
- package/template/src/assets/fonts/InterTight-SemiBoldItalic.ttf +0 -0
- package/template/src/assets/fonts/InterTight-Thin.ttf +0 -0
- package/template/src/assets/fonts/InterTight-ThinItalic.ttf +0 -0
- package/template/src/assets/icons/back.svg +3 -0
- package/template/src/assets/icons/calendar.svg +3 -0
- package/template/src/assets/icons/claim_upload.svg +3 -0
- package/template/src/assets/icons/clock.svg +1 -0
- package/template/src/assets/icons/downArrow.svg +3 -0
- package/template/src/assets/icons/edit.svg +3 -0
- package/template/src/assets/icons/eye.svg +4 -0
- package/template/src/assets/icons/eyeClose.svg +7 -0
- package/template/src/assets/icons/folder.svg +5 -0
- package/template/src/assets/icons/home.svg +4 -0
- package/template/src/assets/icons/index.ts +35 -0
- package/template/src/assets/icons/log_out.svg +4 -0
- package/template/src/assets/icons/setting.svg +4 -0
- package/template/src/assets/icons/tabs/home/filled_dark.svg +3 -0
- package/template/src/assets/icons/tabs/home/filled_light.svg +3 -0
- package/template/src/assets/icons/tabs/home/outline.svg +4 -0
- package/template/src/assets/icons/tabs/index.ts +31 -0
- package/template/src/assets/icons/tabs/profile/filled_dark.svg +6 -0
- package/template/src/assets/icons/tabs/profile/filled_light.svg +6 -0
- package/template/src/assets/icons/tabs/profile/outline.svg +3 -0
- package/template/src/assets/icons/tooltip_dark.svg +1 -0
- package/template/src/assets/icons/tooltip_light.svg +1 -0
- package/template/src/assets/icons/upArrow.svg +3 -0
- package/template/src/assets/images/back.png +0 -0
- package/template/src/assets/images/index.ts +7 -0
- package/template/src/assets/images/placeholder/profile.png +0 -0
- package/template/src/components/shared/AppImage.tsx +190 -0
- package/template/src/components/shared/AvatarPicker.tsx +175 -0
- package/template/src/components/shared/CustomButton.tsx +273 -0
- package/template/src/components/shared/DocumentPicker.tsx +86 -0
- package/template/src/components/shared/GlobalLoader.tsx +47 -0
- package/template/src/components/shared/Icon.tsx +28 -0
- package/template/src/components/shared/PressableIcon.tsx +104 -0
- package/template/src/components/shared/bottom-sheet/BaseBottomSheet.tsx +30 -0
- package/template/src/components/shared/bottom-sheet/BaseBottomSheetModal.tsx +50 -0
- package/template/src/components/shared/bottom-sheet/sheets/ImagePickerSheet.tsx +310 -0
- package/template/src/components/shared/bottom-sheet/types.ts +4 -0
- package/template/src/components/shared/form-input/FormInput.tsx +140 -0
- package/template/src/components/shared/form-input/FormInputRenderer.tsx +82 -0
- package/template/src/components/shared/form-input/FullNameInput.tsx +243 -0
- package/template/src/components/shared/form-input/formFieldStyles.ts +43 -0
- package/template/src/components/shared/form-input/type.ts +188 -0
- package/template/src/components/shared/form-input/variants/CountryPhoneVariant.tsx +289 -0
- package/template/src/components/shared/form-input/variants/DateTimeVariant.tsx +280 -0
- package/template/src/components/shared/form-input/variants/DropdownVariant.tsx +221 -0
- package/template/src/components/shared/form-input/variants/TextInputVariant.tsx +300 -0
- package/template/src/components/shared/form-input/variants/ToggleVariant.tsx +194 -0
- package/template/src/components/shared/modal/BaseModal.tsx +83 -0
- package/template/src/components/shared/modal/common/AlertModal.tsx +173 -0
- package/template/src/components/shared/navigation/AnimatedTabIcon.tsx +37 -0
- package/template/src/components/shared/navigation/HeaderActionButton.tsx +70 -0
- package/template/src/components/shared/navigation/HeaderBackButton.tsx +38 -0
- package/template/src/components/shared/navigation/StackHeader.tsx +105 -0
- package/template/src/components/shared/navigation/tabIconRender.tsx +14 -0
- package/template/src/components/shared/offline/OfflineQueryBoundary.tsx +25 -0
- package/template/src/components/shared/offline/OfflineState.tsx +229 -0
- package/template/src/components/shared/offline/index.ts +6 -0
- package/template/src/components/shared/offline/types.ts +15 -0
- package/template/src/components/shared/offline/wifi-icon-animation/BrokenWifiAnimation.tsx +116 -0
- package/template/src/components/shared/offline/wifi-icon-animation/WifiPiece.tsx +80 -0
- package/template/src/components/shared/offline/wifi-icon-animation/geometry.ts +163 -0
- package/template/src/components/shared/offline/wifi-icon-animation/useWifiIconAnimationActive.ts +37 -0
- package/template/src/components/shared/skelton/BaseSkelton.tsx +71 -0
- package/template/src/components/shared/skelton/ShimmerHolder.ts +6 -0
- package/template/src/components/shared/skelton/holders/HomeShimmer.tsx +25 -0
- package/template/src/components/shared/skelton/holders/index.ts +1 -0
- package/template/src/components/shared/skelton/layouts/avatar.layout.ts +18 -0
- package/template/src/components/shared/skelton/layouts/home.layout.ts +16 -0
- package/template/src/components/shared/skelton/layouts/index.ts +3 -0
- package/template/src/components/shared/skelton/layouts/text.layout.ts +18 -0
- package/template/src/components/shared/text/CustomText.tsx +85 -0
- package/template/src/components/shared/text/ShimmerText.tsx +159 -0
- package/template/src/components/shared/text/types.ts +40 -0
- package/template/src/constants/device.ts +12 -0
- package/template/src/constants/endpoint.ts +11 -0
- package/template/src/constants/keyExtractor.ts +6 -0
- package/template/src/constants/limits.ts +9 -0
- package/template/src/constants/queryKey.ts +3 -0
- package/template/src/constants/regex.ts +7 -0
- package/template/src/context/NetworkContext.tsx +102 -0
- package/template/src/context/ThemeContext.tsx +56 -0
- package/template/src/hooks/app/index.ts +2 -0
- package/template/src/hooks/app/useGetProfile.ts +38 -0
- package/template/src/hooks/app/useUpdateProfile.ts +21 -0
- package/template/src/hooks/useAppDispatch.ts +6 -0
- package/template/src/hooks/useAppSelector.ts +4 -0
- package/template/src/hooks/useDebounce.ts +15 -0
- package/template/src/hooks/useDocumentPicker.ts +102 -0
- package/template/src/hooks/useImagePicker.ts +83 -0
- package/template/src/i18n/i18next.d.ts +9 -0
- package/template/src/i18n/index.ts +16 -0
- package/template/src/i18n/locales/en.json +274 -0
- package/template/src/i18n/locales/ru.json +165 -0
- package/template/src/i18n/resources.ts +11 -0
- package/template/src/redux/selectors/auth.selectors.ts +4 -0
- package/template/src/redux/slice/auth.slice.ts +23 -0
- package/template/src/redux/slice/loader.slice.ts +25 -0
- package/template/src/redux/slice/settings.slice.ts +26 -0
- package/template/src/redux/slice/user.slice.ts +25 -0
- package/template/src/screens/app/main-tab/index.tsx +73 -0
- package/template/src/screens/app/main-tab/style.ts +0 -0
- package/template/src/screens/app/profile-setup/index.tsx +162 -0
- package/template/src/screens/app/profile-setup/styles.ts +3 -0
- package/template/src/screens/auth/forgot-password/index.tsx +59 -0
- package/template/src/screens/auth/forgot-password/styles.ts +0 -0
- package/template/src/screens/auth/index.ts +4 -0
- package/template/src/screens/auth/login/index.tsx +138 -0
- package/template/src/screens/auth/login/styles.ts +3 -0
- package/template/src/screens/auth/signup/index.tsx +111 -0
- package/template/src/screens/auth/signup/styles.ts +3 -0
- package/template/src/screens/auth/verify-email/index.tsx +15 -0
- package/template/src/screens/auth/verify-email/styles.ts +3 -0
- package/template/src/screens/tab/home/index.tsx +49 -0
- package/template/src/screens/tab/home/styles.ts +3 -0
- package/template/src/screens/tab/index.ts +2 -0
- package/template/src/screens/tab/profile/index.tsx +50 -0
- package/template/src/screens/tab/profile/styles.ts +3 -0
- package/template/src/services/api/auth/auth.api.ts +22 -0
- package/template/src/services/api/auth/auth.endpoints.ts +7 -0
- package/template/src/services/api/auth/auth.types.ts +9 -0
- package/template/src/services/api/auth/index.ts +3 -0
- package/template/src/services/api/axios/axios.instance.ts +15 -0
- package/template/src/services/api/axios/axios.interceptors.ts +43 -0
- package/template/src/services/api/axios/index.ts +2 -0
- package/template/src/services/api/mock/mockAdapter.ts +97 -0
- package/template/src/services/api/user/index.ts +2 -0
- package/template/src/services/api/user/user.api.ts +67 -0
- package/template/src/services/api/user/user.endpoints.ts +0 -0
- package/template/src/services/api/user/user.types.ts +0 -0
- package/template/src/services/errors/backendErrorCodes.ts +7 -0
- package/template/src/services/errors/errorHandler.ts +94 -0
- package/template/src/services/errors/firebaseErrorMap.ts +61 -0
- package/template/src/services/errors/httpStatusMap.ts +47 -0
- package/template/src/services/errors/index.ts +4 -0
- package/template/src/services/network/index.ts +1 -0
- package/template/src/services/network/onlineManager.ts +22 -0
- package/template/src/services/query/index.ts +1 -0
- package/template/src/services/query/queryClient.ts +23 -0
- package/template/src/services/toast/ToastCard.tsx +137 -0
- package/template/src/services/toast/ToastConfig.tsx +32 -0
- package/template/src/services/toast/index.ts +3 -0
- package/template/src/services/toast/toast.ts +68 -0
- package/template/src/storage/mmkvAdapter.ts +3 -0
- package/template/src/storage/mmkvInstance.ts +16 -0
- package/template/src/store/index.ts +15 -0
- package/template/src/store/mmkv.ts +6 -0
- package/template/src/store/persist.ts +10 -0
- package/template/src/store/rootReducer.ts +26 -0
- package/template/src/theme/dark.ts +40 -0
- package/template/src/theme/fonts.ts +20 -0
- package/template/src/theme/index.ts +6 -0
- package/template/src/theme/layout.ts +23 -0
- package/template/src/theme/light.ts +41 -0
- package/template/src/theme/palette.ts +32 -0
- package/template/src/theme/spacing.ts +7 -0
- package/template/src/theme/typography.ts +80 -0
- package/template/src/types/api.types.ts +34 -0
- package/template/src/types/env.d.ts +6 -0
- package/template/src/types/index.ts +2 -0
- package/template/src/types/navigation.types.ts +94 -0
- package/template/src/utils/clearAppSession.ts +10 -0
- package/template/src/utils/date.ts +19 -0
- package/template/src/utils/documentPickerHandler.ts +96 -0
- package/template/src/utils/getFileNameFromUri.ts +18 -0
- package/template/src/utils/getInitials.ts +13 -0
- package/template/src/utils/hindiText.ts +33 -0
- package/template/src/utils/imageCompress.ts +97 -0
- package/template/src/utils/imagePickerHandler.ts +200 -0
- package/template/src/utils/maskPhone.ts +17 -0
- package/template/src/utils/normalize.ts +12 -0
- package/template/src/validation/messages.ts +11 -0
- package/template/src/validation/rules.ts +44 -0
- package/template/src/validation/schema/auth.schema.ts +53 -0
- package/template/src/validation/schema/user.schema.ts +46 -0
- package/template/src/validation/tValError.ts +13 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
{
|
|
2
|
+
"common": {
|
|
3
|
+
"loading": "Загрузка...",
|
|
4
|
+
"error": "Ошибка",
|
|
5
|
+
"success": "Успешно",
|
|
6
|
+
"cancel": "Отмена",
|
|
7
|
+
"confirm": "Подтвердить",
|
|
8
|
+
"save": "Сохранить",
|
|
9
|
+
"delete": "Удалить",
|
|
10
|
+
"edit": "Редактировать",
|
|
11
|
+
"done": "Готово",
|
|
12
|
+
"next": "Далее",
|
|
13
|
+
"back": "Назад",
|
|
14
|
+
"skip": "Пропустить",
|
|
15
|
+
"retry": "Повторить",
|
|
16
|
+
"ok": "ОК",
|
|
17
|
+
"yes": "Да",
|
|
18
|
+
"no": "Нет",
|
|
19
|
+
"close": "Закрыть",
|
|
20
|
+
"search": "Поиск",
|
|
21
|
+
"noResults": "Результаты не найдены",
|
|
22
|
+
"emptyState": "Пока ничего нет"
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
"auth": {
|
|
26
|
+
"login": "Войти",
|
|
27
|
+
"signup": "Зарегистрироваться",
|
|
28
|
+
"logout": "Выйти",
|
|
29
|
+
"email": "Электронная почта",
|
|
30
|
+
"password": "Пароль",
|
|
31
|
+
"confirmPassword": "Подтвердите пароль",
|
|
32
|
+
"forgotPassword": "Забыли пароль?",
|
|
33
|
+
"resetPassword": "Сбросить пароль",
|
|
34
|
+
"firstName": "Имя",
|
|
35
|
+
"lastName": "Фамилия",
|
|
36
|
+
"phone": "Номер телефона",
|
|
37
|
+
"rememberMe": "Запомнить меня",
|
|
38
|
+
"dontHaveAccount": "Нет аккаунта?",
|
|
39
|
+
"alreadyHaveAccount": "Уже есть аккаунт?",
|
|
40
|
+
"createAccount": "Создать аккаунт",
|
|
41
|
+
"welcomeBack": "С возвращением!",
|
|
42
|
+
"signInToContinue": "Войдите, чтобы продолжить",
|
|
43
|
+
"enterEmail": "Введите адрес электронной почты",
|
|
44
|
+
"enterPassword": "Введите пароль",
|
|
45
|
+
"enterNewPassword": "Введите новый пароль",
|
|
46
|
+
"passwordRequirements": "Пароль должен содержать не менее 8 символов",
|
|
47
|
+
"passwordsDoNotMatch": "Пароли не совпадают",
|
|
48
|
+
"invalidEmail": "Введите корректный адрес электронной почты",
|
|
49
|
+
"loginSuccess": "Вход выполнен успешно",
|
|
50
|
+
"signupSuccess": "Аккаунт успешно создан",
|
|
51
|
+
"logoutSuccess": "Вы успешно вышли из системы",
|
|
52
|
+
"resetPasswordSent": "Инструкции по сбросу пароля отправлены на вашу почту",
|
|
53
|
+
"verifyEmail": "Подтвердите email",
|
|
54
|
+
"enterVerificationCode": "Введите код подтверждения, отправленный на почту",
|
|
55
|
+
"verificationCode": "Код подтверждения",
|
|
56
|
+
"resendCode": "Отправить код повторно",
|
|
57
|
+
"didntReceiveCode": "Не получили код?",
|
|
58
|
+
"codeResent": "Код подтверждения отправлен повторно",
|
|
59
|
+
"emailVerified": "Электронная почта успешно подтверждена",
|
|
60
|
+
"setupProfile": "Настройка профиля",
|
|
61
|
+
"completeProfile": "Заполните профиль",
|
|
62
|
+
"addPhoto": "Добавить фото",
|
|
63
|
+
"bio": "О себе",
|
|
64
|
+
"tellUsAboutYourself": "Расскажите о себе"
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
"navigation": {
|
|
68
|
+
"home": "Главная",
|
|
69
|
+
"search": "Поиск",
|
|
70
|
+
"notifications": "Уведомления",
|
|
71
|
+
"profile": "Профиль",
|
|
72
|
+
"settings": "Настройки"
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
"home": {
|
|
76
|
+
"greeting": "Здравствуйте, {{name}}",
|
|
77
|
+
"welcomeBack": "С возвращением!",
|
|
78
|
+
"recentActivity": "Недавняя активность",
|
|
79
|
+
"noActivity": "Нет недавней активности",
|
|
80
|
+
"quickActions": "Быстрые действия"
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"profile": {
|
|
84
|
+
"editProfile": "Редактировать профиль",
|
|
85
|
+
"myAccount": "Мой аккаунт",
|
|
86
|
+
"preferences": "Настройки",
|
|
87
|
+
"privacy": "Конфиденциальность и безопасность",
|
|
88
|
+
"appearance": "Внешний вид",
|
|
89
|
+
"notifications": "Уведомления",
|
|
90
|
+
"help": "Помощь и поддержка",
|
|
91
|
+
"about": "О приложении",
|
|
92
|
+
"termsOfService": "Условия использования",
|
|
93
|
+
"privacyPolicy": "Политика конфиденциальности",
|
|
94
|
+
"rateApp": "Оценить приложение",
|
|
95
|
+
"version": "Версия {{version}}",
|
|
96
|
+
"updateSuccess": "Профиль успешно обновлён"
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
"settings": {
|
|
100
|
+
"general": "Общие",
|
|
101
|
+
"account": "Аккаунт",
|
|
102
|
+
"notifications": "Уведомления",
|
|
103
|
+
"privacy": "Конфиденциальность",
|
|
104
|
+
"language": "Язык",
|
|
105
|
+
"theme": "Тема",
|
|
106
|
+
"darkMode": "Тёмная тема",
|
|
107
|
+
"lightMode": "Светлая тема",
|
|
108
|
+
"systemDefault": "Системная",
|
|
109
|
+
"changePassword": "Сменить пароль",
|
|
110
|
+
"deleteAccount": "Удалить аккаунт",
|
|
111
|
+
"deleteAccountWarning": "Это действие невозможно отменить. Все данные будут удалены навсегда."
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
"errors": {
|
|
115
|
+
"generic": "Что-то пошло не так",
|
|
116
|
+
"network": "Ошибка сети. Проверьте подключение к интернету.",
|
|
117
|
+
"server": "Ошибка сервера. Пожалуйста, попробуйте позже.",
|
|
118
|
+
"unauthorized": "Сессия истекла. Пожалуйста, войдите снова.",
|
|
119
|
+
"notFound": "Ресурс не найден",
|
|
120
|
+
"validation": "Проверьте введённые данные",
|
|
121
|
+
"invalidCredentials": "Неверный email или пароль",
|
|
122
|
+
"emailExists": "Аккаунт с таким email уже существует",
|
|
123
|
+
"weakPassword": "Пароль слишком слабый",
|
|
124
|
+
"rateLimited": "Слишком много попыток. Попробуйте позже."
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
"validation": {
|
|
128
|
+
"required": "Это поле обязательно",
|
|
129
|
+
"emailInvalid": "Введите корректный email",
|
|
130
|
+
"passwordTooShort": "Пароль должен содержать не менее {{min}} символов",
|
|
131
|
+
"passwordTooWeak": "Пароль должен содержать заглавную букву, строчную букву и цифру",
|
|
132
|
+
"passwordsDoNotMatch": "Пароли не совпадают",
|
|
133
|
+
"phoneInvalid": "Введите корректный номер телефона",
|
|
134
|
+
"minLength": "Минимум {{min}} символов",
|
|
135
|
+
"maxLength": "Максимум {{max}} символов"
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
"alerts": {
|
|
139
|
+
"logoutTitle": "Выход",
|
|
140
|
+
"logoutMessage": "Вы уверены, что хотите выйти?",
|
|
141
|
+
"deleteTitle": "Удаление",
|
|
142
|
+
"deleteMessage": "Вы уверены, что хотите удалить этот элемент?",
|
|
143
|
+
"unsavedChangesTitle": "Несохранённые изменения",
|
|
144
|
+
"unsavedChangesMessage": "У вас есть несохранённые изменения. Вы уверены, что хотите выйти?"
|
|
145
|
+
},
|
|
146
|
+
"network": {
|
|
147
|
+
"unavailableTitle": "Нет подключения к интернету",
|
|
148
|
+
"unavailableMessage": "Интернет недоступен. Проверьте соединение.",
|
|
149
|
+
"unavailableBody": "Проверьте Wi-Fi или мобильные данные и попробуйте снова."
|
|
150
|
+
},
|
|
151
|
+
"imagePicker": {
|
|
152
|
+
"title": "Добавить фото",
|
|
153
|
+
"subtitle": "Выберите чёткое фото для профиля.",
|
|
154
|
+
"camera": "Сделать фото",
|
|
155
|
+
"cameraHint": "Сделайте новый снимок камерой",
|
|
156
|
+
"gallery": "Выбрать из галереи",
|
|
157
|
+
"galleryHint": "Выберите существующее фото на устройстве",
|
|
158
|
+
"docTitle": "Загрузить файл",
|
|
159
|
+
"docSubtitle": "Можно загрузить изображения, PDF и другие документы.",
|
|
160
|
+
"docCamera": "Сделать фото",
|
|
161
|
+
"docCameraHint": "Сделайте новый снимок камерой",
|
|
162
|
+
"docGallery": "Выбрать на устройстве",
|
|
163
|
+
"docGalleryHint": "Выберите изображение, PDF или другой документ"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
interface AuthState {
|
|
4
|
+
access_token: string | null;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const initialState: AuthState = {
|
|
8
|
+
access_token: null,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const authSlice = createSlice({
|
|
12
|
+
name: 'auth',
|
|
13
|
+
initialState,
|
|
14
|
+
reducers: {
|
|
15
|
+
login(state, action: PayloadAction<AuthState>) {
|
|
16
|
+
state.access_token = action.payload.access_token;
|
|
17
|
+
},
|
|
18
|
+
logout() {},
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const { login: loginAction, logout: logoutAction } = authSlice.actions;
|
|
23
|
+
export default authSlice.reducer;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
interface LoaderState {
|
|
4
|
+
isLoading: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const initialState: LoaderState = {
|
|
8
|
+
isLoading: false,
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const loaderSlice = createSlice({
|
|
12
|
+
name: 'loader',
|
|
13
|
+
initialState,
|
|
14
|
+
reducers: {
|
|
15
|
+
showLoader: state => {
|
|
16
|
+
state.isLoading = true;
|
|
17
|
+
},
|
|
18
|
+
hideLoader: state => {
|
|
19
|
+
state.isLoading = false;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const { showLoader, hideLoader } = loaderSlice.actions;
|
|
25
|
+
export default loaderSlice.reducer;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
import i18n from '@/i18n';
|
|
3
|
+
|
|
4
|
+
export type AppLanguage = 'en' | 'ru';
|
|
5
|
+
|
|
6
|
+
interface SettingsState {
|
|
7
|
+
language: AppLanguage;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const initialState: SettingsState = {
|
|
11
|
+
language: 'en',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const settingsSlice = createSlice({
|
|
15
|
+
name: 'settings',
|
|
16
|
+
initialState,
|
|
17
|
+
reducers: {
|
|
18
|
+
setLanguage(state, action: PayloadAction<AppLanguage>) {
|
|
19
|
+
state.language = action.payload;
|
|
20
|
+
void i18n.changeLanguage(action.payload);
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const { setLanguage } = settingsSlice.actions;
|
|
26
|
+
export default settingsSlice.reducer;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
|
2
|
+
|
|
3
|
+
interface UserState {
|
|
4
|
+
id: string | null;
|
|
5
|
+
isProfileSetup: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const initialState: UserState = {
|
|
9
|
+
id: null,
|
|
10
|
+
isProfileSetup: false,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const userSlice = createSlice({
|
|
14
|
+
name: 'user',
|
|
15
|
+
initialState,
|
|
16
|
+
reducers: {
|
|
17
|
+
setUser(state, action: PayloadAction<UserState>) {
|
|
18
|
+
state.id = action.payload.id;
|
|
19
|
+
state.isProfileSetup = action.payload.isProfileSetup;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const { setUser: setUserAction } = userSlice.actions;
|
|
25
|
+
export default userSlice.reducer;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import CustomButton from '@/components/shared/CustomButton';
|
|
2
|
+
import CustomText from '@/components/shared/text/CustomText';
|
|
3
|
+
import AlertModal from '@/components/shared/modal/common/AlertModal';
|
|
4
|
+
import { useAppTheme } from '@/context/ThemeContext';
|
|
5
|
+
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
|
6
|
+
import { logoutAction } from '@/redux/slice/auth.slice';
|
|
7
|
+
import { persistor } from '@/store';
|
|
8
|
+
import { layout } from '@/theme/layout';
|
|
9
|
+
import { AppStackScreenProps } from '@/types';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
import { View } from 'react-native';
|
|
12
|
+
|
|
13
|
+
type props = AppStackScreenProps<'MainTabs'>;
|
|
14
|
+
|
|
15
|
+
const MainTabs = ({ navigation }: props) => {
|
|
16
|
+
const dispatch = useAppDispatch();
|
|
17
|
+
const { color } = useAppTheme();
|
|
18
|
+
const [isAlertOpen, setIsAlertOpen] = useState<boolean>(false);
|
|
19
|
+
|
|
20
|
+
const handleLogout = async () => {
|
|
21
|
+
dispatch(logoutAction());
|
|
22
|
+
await persistor.purge();
|
|
23
|
+
};
|
|
24
|
+
const handleGoToHome = () => {
|
|
25
|
+
navigation.navigate('BottomTabs', {
|
|
26
|
+
screen: 'Home',
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View>
|
|
32
|
+
<CustomText
|
|
33
|
+
variant="header"
|
|
34
|
+
textAlign="center"
|
|
35
|
+
style={layout.marginTopMd}
|
|
36
|
+
>
|
|
37
|
+
Main Tabs Screen
|
|
38
|
+
</CustomText>
|
|
39
|
+
<CustomButton
|
|
40
|
+
onPress={handleGoToHome}
|
|
41
|
+
title="Go to Home"
|
|
42
|
+
containerStyle={layout.marginBottomMd}
|
|
43
|
+
/>
|
|
44
|
+
<CustomButton onPress={() => setIsAlertOpen(true)} title="Logout" />
|
|
45
|
+
|
|
46
|
+
<AlertModal
|
|
47
|
+
title="Are you sure want to Logout?"
|
|
48
|
+
isOpen={isAlertOpen}
|
|
49
|
+
description="This will clear all your data and you will need to login again."
|
|
50
|
+
primaryButton={{
|
|
51
|
+
title: 'Yes',
|
|
52
|
+
variant: 'primary',
|
|
53
|
+
}}
|
|
54
|
+
secondaryButton={{
|
|
55
|
+
title: 'Cancel',
|
|
56
|
+
variant: 'outline',
|
|
57
|
+
overrideVariantColor: color.border,
|
|
58
|
+
overrideVariantTextColor: color.text_secondary,
|
|
59
|
+
}}
|
|
60
|
+
icon="log_out"
|
|
61
|
+
onPressPrimaryBtn={() => {
|
|
62
|
+
setIsAlertOpen(false);
|
|
63
|
+
handleLogout();
|
|
64
|
+
}}
|
|
65
|
+
onPressSecondaryBtn={() => {
|
|
66
|
+
setIsAlertOpen(false);
|
|
67
|
+
}}
|
|
68
|
+
/>
|
|
69
|
+
</View>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default MainTabs;
|
|
File without changes
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import CustomButton from '@/components/shared/CustomButton';
|
|
2
|
+
import FormInput from '@/components/shared/form-input/FormInput';
|
|
3
|
+
import { isIOS } from '@/constants/device';
|
|
4
|
+
import { LIMITS } from '@/constants/limits';
|
|
5
|
+
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
|
6
|
+
import { setUserAction } from '@/redux/slice/user.slice';
|
|
7
|
+
import { spacing } from '@/theme';
|
|
8
|
+
import { layout } from '@/theme/layout';
|
|
9
|
+
import { AppStackScreenProps } from '@/types';
|
|
10
|
+
import { profileSetupSchema } from '@/validation/schema/user.schema';
|
|
11
|
+
import { tValError } from '@/validation/tValError';
|
|
12
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { Resolver, useForm } from 'react-hook-form';
|
|
15
|
+
import { useTranslation } from 'react-i18next';
|
|
16
|
+
import { Keyboard, KeyboardAvoidingView, ScrollView, View } from 'react-native';
|
|
17
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
18
|
+
import { InferType } from 'yup';
|
|
19
|
+
|
|
20
|
+
type Props = AppStackScreenProps<'ProfileSetup'>;
|
|
21
|
+
|
|
22
|
+
export type ProfileSetupFormType = InferType<typeof profileSetupSchema>;
|
|
23
|
+
|
|
24
|
+
const ProfileSetup = ({ navigation }: Props) => {
|
|
25
|
+
const {
|
|
26
|
+
control,
|
|
27
|
+
formState: { errors },
|
|
28
|
+
handleSubmit,
|
|
29
|
+
} = useForm<ProfileSetupFormType>({
|
|
30
|
+
defaultValues: {
|
|
31
|
+
name: '',
|
|
32
|
+
phone: '',
|
|
33
|
+
gender: '',
|
|
34
|
+
address: '',
|
|
35
|
+
dob: undefined,
|
|
36
|
+
currentTime: undefined,
|
|
37
|
+
},
|
|
38
|
+
resolver: yupResolver(profileSetupSchema) as Resolver<ProfileSetupFormType>,
|
|
39
|
+
});
|
|
40
|
+
const dispatch = useAppDispatch();
|
|
41
|
+
const { t } = useTranslation();
|
|
42
|
+
const {bottom}=useSafeAreaInsets();
|
|
43
|
+
|
|
44
|
+
const handleContinue = async (data: ProfileSetupFormType) => {
|
|
45
|
+
console.log('Profile Data:', {
|
|
46
|
+
...data,
|
|
47
|
+
dob: data.dob.toISOString(),
|
|
48
|
+
currentTime: data.currentTime.toISOString(),
|
|
49
|
+
});
|
|
50
|
+
dispatch(setUserAction({ id: 'user-id', isProfileSetup: true }));
|
|
51
|
+
navigation.replace('BottomTabs', {
|
|
52
|
+
screen: 'Home',
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
return (
|
|
56
|
+
<KeyboardAvoidingView
|
|
57
|
+
style={layout.flexContainer}
|
|
58
|
+
behavior={isIOS ? 'padding' : 'height'}
|
|
59
|
+
keyboardVerticalOffset={isIOS ? 64 : 0}
|
|
60
|
+
>
|
|
61
|
+
<ScrollView showsVerticalScrollIndicator={false}>
|
|
62
|
+
<FormInput
|
|
63
|
+
control={control}
|
|
64
|
+
name="name"
|
|
65
|
+
label={t('user.name')}
|
|
66
|
+
placeholder={t('placeholder.enterName')}
|
|
67
|
+
error={tValError(t, errors.name, {
|
|
68
|
+
field: t('user.name'),
|
|
69
|
+
...LIMITS.NAME,
|
|
70
|
+
})}
|
|
71
|
+
variant="text"
|
|
72
|
+
// leftIcon={<Icon name="downArrow" size={20} />}
|
|
73
|
+
// rightIcon={<Icon name="downArrow" size={20} />}
|
|
74
|
+
// isPassword
|
|
75
|
+
/>
|
|
76
|
+
|
|
77
|
+
<FormInput
|
|
78
|
+
control={control}
|
|
79
|
+
name="phone"
|
|
80
|
+
label={t('user.phone-number')}
|
|
81
|
+
placeholder={t('placeholder.enterPhone')}
|
|
82
|
+
error={tValError(t, errors.phone, {
|
|
83
|
+
field: t('user.phone-number'),
|
|
84
|
+
...LIMITS.PHONE,
|
|
85
|
+
})}
|
|
86
|
+
variant="country-phone"
|
|
87
|
+
// showFlag={false}
|
|
88
|
+
// onChangeSelectedCountry={country => {
|
|
89
|
+
// console.log('Country:', country);
|
|
90
|
+
// console.log('Calling code:', country.idd.root); // ← "+91"
|
|
91
|
+
// console.log('ISO code:', country.cca2); // ← "IN"
|
|
92
|
+
// }}
|
|
93
|
+
/>
|
|
94
|
+
|
|
95
|
+
<FormInput
|
|
96
|
+
control={control}
|
|
97
|
+
name="gender"
|
|
98
|
+
label={t('user.gender')}
|
|
99
|
+
error={tValError(t, errors.gender, {
|
|
100
|
+
field: t('user.gender'),
|
|
101
|
+
})}
|
|
102
|
+
variant="dropdown"
|
|
103
|
+
dropdownData={[
|
|
104
|
+
{ label: 'Male', value: 'male' },
|
|
105
|
+
{ label: 'Female', value: 'female' },
|
|
106
|
+
{ label: 'Other', value: 'other' },
|
|
107
|
+
]}
|
|
108
|
+
placeholder={t('placeholder.select-your-gender')}
|
|
109
|
+
/>
|
|
110
|
+
<FormInput
|
|
111
|
+
control={control}
|
|
112
|
+
name="dob"
|
|
113
|
+
label={t('user.date-of-birth')}
|
|
114
|
+
placeholder={t('placeholder.select-your-date-of-birth')}
|
|
115
|
+
error={tValError(t, errors.dob, {
|
|
116
|
+
field: t('user.date-of-birth'),
|
|
117
|
+
})}
|
|
118
|
+
variant="date"
|
|
119
|
+
maximumDate={new Date()}
|
|
120
|
+
// disabled
|
|
121
|
+
/>
|
|
122
|
+
|
|
123
|
+
<FormInput
|
|
124
|
+
control={control}
|
|
125
|
+
name="currentTime"
|
|
126
|
+
label={t('user.current-time')}
|
|
127
|
+
placeholder={t('placeholder.enter-your-current-time')}
|
|
128
|
+
error={tValError(t, errors.currentTime, {
|
|
129
|
+
field: t('user.current-time'),
|
|
130
|
+
})}
|
|
131
|
+
variant="time"
|
|
132
|
+
iconName="clock"
|
|
133
|
+
/>
|
|
134
|
+
<FormInput
|
|
135
|
+
control={control}
|
|
136
|
+
name="address"
|
|
137
|
+
label={t('user.address')}
|
|
138
|
+
placeholder={t('placeholder.enterAddress')}
|
|
139
|
+
error={tValError(t, errors.address, {
|
|
140
|
+
field: t('user.address'),
|
|
141
|
+
...LIMITS.ADDRESS,
|
|
142
|
+
})}
|
|
143
|
+
variant="text"
|
|
144
|
+
textInputProps={{
|
|
145
|
+
multiline: true,
|
|
146
|
+
}}
|
|
147
|
+
/>
|
|
148
|
+
|
|
149
|
+
</ScrollView>
|
|
150
|
+
{/* KeyboardAvoidingView overrides its own paddingBottom, so the inset is a margin here. */}
|
|
151
|
+
<CustomButton
|
|
152
|
+
title={t('common.continue')}
|
|
153
|
+
onPress={handleSubmit(handleContinue)}
|
|
154
|
+
variant="primary"
|
|
155
|
+
fullWidth
|
|
156
|
+
containerStyle={{ marginTop: spacing.sm, marginBottom: bottom + spacing.sm }}
|
|
157
|
+
/>
|
|
158
|
+
</KeyboardAvoidingView>
|
|
159
|
+
);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export default ProfileSetup;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import CustomButton from '@/components/shared/CustomButton';
|
|
2
|
+
import FormInput from '@/components/shared/form-input/FormInput';
|
|
3
|
+
import { AuthStackScreenProps } from '@/types';
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { useForm } from 'react-hook-form';
|
|
6
|
+
import { useTranslation } from 'react-i18next';
|
|
7
|
+
import { layout } from '@/theme/layout';
|
|
8
|
+
import { View } from 'react-native';
|
|
9
|
+
import { InferType } from 'yup';
|
|
10
|
+
import { forgotPasswordSchema } from '@/validation/schema/auth.schema';
|
|
11
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
12
|
+
import { tValError } from '@/validation/tValError';
|
|
13
|
+
|
|
14
|
+
type Props = AuthStackScreenProps<'ForgotPassword'>;
|
|
15
|
+
|
|
16
|
+
export type ForgotPasswordFormType = InferType<typeof forgotPasswordSchema>;
|
|
17
|
+
|
|
18
|
+
const ForgotPassword = ({ navigation }: Props) => {
|
|
19
|
+
const {
|
|
20
|
+
control,
|
|
21
|
+
formState: { errors },
|
|
22
|
+
handleSubmit,
|
|
23
|
+
} = useForm<ForgotPasswordFormType>({
|
|
24
|
+
resolver: yupResolver(forgotPasswordSchema),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const { t } = useTranslation();
|
|
28
|
+
|
|
29
|
+
const handleForgotPassword = () => {
|
|
30
|
+
navigation.goBack();
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<View style={layout.flexContainer}>
|
|
35
|
+
<FormInput
|
|
36
|
+
control={control}
|
|
37
|
+
name="email"
|
|
38
|
+
label={t('auth.email')}
|
|
39
|
+
placeholder={t('placeholder.enterEmail')}
|
|
40
|
+
textInputProps={{
|
|
41
|
+
keyboardType: 'email-address',
|
|
42
|
+
}}
|
|
43
|
+
error={tValError(t, errors.email, {
|
|
44
|
+
field: t('auth.email'),
|
|
45
|
+
})}
|
|
46
|
+
variant="text"
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<CustomButton
|
|
50
|
+
title={t('auth.send-now')}
|
|
51
|
+
onPress={handleSubmit(handleForgotPassword)}
|
|
52
|
+
variant="primary"
|
|
53
|
+
fullWidth
|
|
54
|
+
/>
|
|
55
|
+
</View>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default ForgotPassword;
|
|
File without changes
|