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.
Files changed (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +378 -2
  3. package/bin/create-react-native-starter-kit.js +95 -0
  4. package/lib/copy-src.js +127 -0
  5. package/lib/creator.js +211 -0
  6. package/lib/deps.js +58 -0
  7. package/lib/patch-configs.js +318 -0
  8. package/lib/patch-native.js +588 -0
  9. package/package.json +47 -4
  10. package/scripts/sync-template.js +52 -0
  11. package/template/.env.example +3 -0
  12. package/template/patches/react-native-element-dropdown+2.12.4.patch +67 -0
  13. package/template/src/app/App.tsx +25 -0
  14. package/template/src/app/navigation/root.tsx +24 -0
  15. package/template/src/app/navigation/stacks/app.stack.tsx +67 -0
  16. package/template/src/app/navigation/stacks/app.tab.tsx +72 -0
  17. package/template/src/app/navigation/stacks/auth.stack.tsx +56 -0
  18. package/template/src/app/providers.tsx +43 -0
  19. package/template/src/assets/fonts/InterTight-Black.ttf +0 -0
  20. package/template/src/assets/fonts/InterTight-BlackItalic.ttf +0 -0
  21. package/template/src/assets/fonts/InterTight-Bold.ttf +0 -0
  22. package/template/src/assets/fonts/InterTight-BoldItalic.ttf +0 -0
  23. package/template/src/assets/fonts/InterTight-ExtraBold.ttf +0 -0
  24. package/template/src/assets/fonts/InterTight-ExtraBoldItalic.ttf +0 -0
  25. package/template/src/assets/fonts/InterTight-ExtraLight.ttf +0 -0
  26. package/template/src/assets/fonts/InterTight-ExtraLightItalic.ttf +0 -0
  27. package/template/src/assets/fonts/InterTight-Italic.ttf +0 -0
  28. package/template/src/assets/fonts/InterTight-Light.ttf +0 -0
  29. package/template/src/assets/fonts/InterTight-LightItalic.ttf +0 -0
  30. package/template/src/assets/fonts/InterTight-Medium.ttf +0 -0
  31. package/template/src/assets/fonts/InterTight-MediumItalic.ttf +0 -0
  32. package/template/src/assets/fonts/InterTight-Regular.ttf +0 -0
  33. package/template/src/assets/fonts/InterTight-SemiBold.ttf +0 -0
  34. package/template/src/assets/fonts/InterTight-SemiBoldItalic.ttf +0 -0
  35. package/template/src/assets/fonts/InterTight-Thin.ttf +0 -0
  36. package/template/src/assets/fonts/InterTight-ThinItalic.ttf +0 -0
  37. package/template/src/assets/icons/back.svg +3 -0
  38. package/template/src/assets/icons/calendar.svg +3 -0
  39. package/template/src/assets/icons/claim_upload.svg +3 -0
  40. package/template/src/assets/icons/clock.svg +1 -0
  41. package/template/src/assets/icons/downArrow.svg +3 -0
  42. package/template/src/assets/icons/edit.svg +3 -0
  43. package/template/src/assets/icons/eye.svg +4 -0
  44. package/template/src/assets/icons/eyeClose.svg +7 -0
  45. package/template/src/assets/icons/folder.svg +5 -0
  46. package/template/src/assets/icons/home.svg +4 -0
  47. package/template/src/assets/icons/index.ts +35 -0
  48. package/template/src/assets/icons/log_out.svg +4 -0
  49. package/template/src/assets/icons/setting.svg +4 -0
  50. package/template/src/assets/icons/tabs/home/filled_dark.svg +3 -0
  51. package/template/src/assets/icons/tabs/home/filled_light.svg +3 -0
  52. package/template/src/assets/icons/tabs/home/outline.svg +4 -0
  53. package/template/src/assets/icons/tabs/index.ts +31 -0
  54. package/template/src/assets/icons/tabs/profile/filled_dark.svg +6 -0
  55. package/template/src/assets/icons/tabs/profile/filled_light.svg +6 -0
  56. package/template/src/assets/icons/tabs/profile/outline.svg +3 -0
  57. package/template/src/assets/icons/tooltip_dark.svg +1 -0
  58. package/template/src/assets/icons/tooltip_light.svg +1 -0
  59. package/template/src/assets/icons/upArrow.svg +3 -0
  60. package/template/src/assets/images/back.png +0 -0
  61. package/template/src/assets/images/index.ts +7 -0
  62. package/template/src/assets/images/placeholder/profile.png +0 -0
  63. package/template/src/components/shared/AppImage.tsx +190 -0
  64. package/template/src/components/shared/AvatarPicker.tsx +175 -0
  65. package/template/src/components/shared/CustomButton.tsx +273 -0
  66. package/template/src/components/shared/DocumentPicker.tsx +86 -0
  67. package/template/src/components/shared/GlobalLoader.tsx +47 -0
  68. package/template/src/components/shared/Icon.tsx +28 -0
  69. package/template/src/components/shared/PressableIcon.tsx +104 -0
  70. package/template/src/components/shared/bottom-sheet/BaseBottomSheet.tsx +30 -0
  71. package/template/src/components/shared/bottom-sheet/BaseBottomSheetModal.tsx +50 -0
  72. package/template/src/components/shared/bottom-sheet/sheets/ImagePickerSheet.tsx +310 -0
  73. package/template/src/components/shared/bottom-sheet/types.ts +4 -0
  74. package/template/src/components/shared/form-input/FormInput.tsx +140 -0
  75. package/template/src/components/shared/form-input/FormInputRenderer.tsx +82 -0
  76. package/template/src/components/shared/form-input/FullNameInput.tsx +243 -0
  77. package/template/src/components/shared/form-input/formFieldStyles.ts +43 -0
  78. package/template/src/components/shared/form-input/type.ts +188 -0
  79. package/template/src/components/shared/form-input/variants/CountryPhoneVariant.tsx +289 -0
  80. package/template/src/components/shared/form-input/variants/DateTimeVariant.tsx +280 -0
  81. package/template/src/components/shared/form-input/variants/DropdownVariant.tsx +221 -0
  82. package/template/src/components/shared/form-input/variants/TextInputVariant.tsx +300 -0
  83. package/template/src/components/shared/form-input/variants/ToggleVariant.tsx +194 -0
  84. package/template/src/components/shared/modal/BaseModal.tsx +83 -0
  85. package/template/src/components/shared/modal/common/AlertModal.tsx +173 -0
  86. package/template/src/components/shared/navigation/AnimatedTabIcon.tsx +37 -0
  87. package/template/src/components/shared/navigation/HeaderActionButton.tsx +70 -0
  88. package/template/src/components/shared/navigation/HeaderBackButton.tsx +38 -0
  89. package/template/src/components/shared/navigation/StackHeader.tsx +105 -0
  90. package/template/src/components/shared/navigation/tabIconRender.tsx +14 -0
  91. package/template/src/components/shared/offline/OfflineQueryBoundary.tsx +25 -0
  92. package/template/src/components/shared/offline/OfflineState.tsx +229 -0
  93. package/template/src/components/shared/offline/index.ts +6 -0
  94. package/template/src/components/shared/offline/types.ts +15 -0
  95. package/template/src/components/shared/offline/wifi-icon-animation/BrokenWifiAnimation.tsx +116 -0
  96. package/template/src/components/shared/offline/wifi-icon-animation/WifiPiece.tsx +80 -0
  97. package/template/src/components/shared/offline/wifi-icon-animation/geometry.ts +163 -0
  98. package/template/src/components/shared/offline/wifi-icon-animation/useWifiIconAnimationActive.ts +37 -0
  99. package/template/src/components/shared/skelton/BaseSkelton.tsx +71 -0
  100. package/template/src/components/shared/skelton/ShimmerHolder.ts +6 -0
  101. package/template/src/components/shared/skelton/holders/HomeShimmer.tsx +25 -0
  102. package/template/src/components/shared/skelton/holders/index.ts +1 -0
  103. package/template/src/components/shared/skelton/layouts/avatar.layout.ts +18 -0
  104. package/template/src/components/shared/skelton/layouts/home.layout.ts +16 -0
  105. package/template/src/components/shared/skelton/layouts/index.ts +3 -0
  106. package/template/src/components/shared/skelton/layouts/text.layout.ts +18 -0
  107. package/template/src/components/shared/text/CustomText.tsx +85 -0
  108. package/template/src/components/shared/text/ShimmerText.tsx +159 -0
  109. package/template/src/components/shared/text/types.ts +40 -0
  110. package/template/src/constants/device.ts +12 -0
  111. package/template/src/constants/endpoint.ts +11 -0
  112. package/template/src/constants/keyExtractor.ts +6 -0
  113. package/template/src/constants/limits.ts +9 -0
  114. package/template/src/constants/queryKey.ts +3 -0
  115. package/template/src/constants/regex.ts +7 -0
  116. package/template/src/context/NetworkContext.tsx +102 -0
  117. package/template/src/context/ThemeContext.tsx +56 -0
  118. package/template/src/hooks/app/index.ts +2 -0
  119. package/template/src/hooks/app/useGetProfile.ts +38 -0
  120. package/template/src/hooks/app/useUpdateProfile.ts +21 -0
  121. package/template/src/hooks/useAppDispatch.ts +6 -0
  122. package/template/src/hooks/useAppSelector.ts +4 -0
  123. package/template/src/hooks/useDebounce.ts +15 -0
  124. package/template/src/hooks/useDocumentPicker.ts +102 -0
  125. package/template/src/hooks/useImagePicker.ts +83 -0
  126. package/template/src/i18n/i18next.d.ts +9 -0
  127. package/template/src/i18n/index.ts +16 -0
  128. package/template/src/i18n/locales/en.json +274 -0
  129. package/template/src/i18n/locales/ru.json +165 -0
  130. package/template/src/i18n/resources.ts +11 -0
  131. package/template/src/redux/selectors/auth.selectors.ts +4 -0
  132. package/template/src/redux/slice/auth.slice.ts +23 -0
  133. package/template/src/redux/slice/loader.slice.ts +25 -0
  134. package/template/src/redux/slice/settings.slice.ts +26 -0
  135. package/template/src/redux/slice/user.slice.ts +25 -0
  136. package/template/src/screens/app/main-tab/index.tsx +73 -0
  137. package/template/src/screens/app/main-tab/style.ts +0 -0
  138. package/template/src/screens/app/profile-setup/index.tsx +162 -0
  139. package/template/src/screens/app/profile-setup/styles.ts +3 -0
  140. package/template/src/screens/auth/forgot-password/index.tsx +59 -0
  141. package/template/src/screens/auth/forgot-password/styles.ts +0 -0
  142. package/template/src/screens/auth/index.ts +4 -0
  143. package/template/src/screens/auth/login/index.tsx +138 -0
  144. package/template/src/screens/auth/login/styles.ts +3 -0
  145. package/template/src/screens/auth/signup/index.tsx +111 -0
  146. package/template/src/screens/auth/signup/styles.ts +3 -0
  147. package/template/src/screens/auth/verify-email/index.tsx +15 -0
  148. package/template/src/screens/auth/verify-email/styles.ts +3 -0
  149. package/template/src/screens/tab/home/index.tsx +49 -0
  150. package/template/src/screens/tab/home/styles.ts +3 -0
  151. package/template/src/screens/tab/index.ts +2 -0
  152. package/template/src/screens/tab/profile/index.tsx +50 -0
  153. package/template/src/screens/tab/profile/styles.ts +3 -0
  154. package/template/src/services/api/auth/auth.api.ts +22 -0
  155. package/template/src/services/api/auth/auth.endpoints.ts +7 -0
  156. package/template/src/services/api/auth/auth.types.ts +9 -0
  157. package/template/src/services/api/auth/index.ts +3 -0
  158. package/template/src/services/api/axios/axios.instance.ts +15 -0
  159. package/template/src/services/api/axios/axios.interceptors.ts +43 -0
  160. package/template/src/services/api/axios/index.ts +2 -0
  161. package/template/src/services/api/mock/mockAdapter.ts +97 -0
  162. package/template/src/services/api/user/index.ts +2 -0
  163. package/template/src/services/api/user/user.api.ts +67 -0
  164. package/template/src/services/api/user/user.endpoints.ts +0 -0
  165. package/template/src/services/api/user/user.types.ts +0 -0
  166. package/template/src/services/errors/backendErrorCodes.ts +7 -0
  167. package/template/src/services/errors/errorHandler.ts +94 -0
  168. package/template/src/services/errors/firebaseErrorMap.ts +61 -0
  169. package/template/src/services/errors/httpStatusMap.ts +47 -0
  170. package/template/src/services/errors/index.ts +4 -0
  171. package/template/src/services/network/index.ts +1 -0
  172. package/template/src/services/network/onlineManager.ts +22 -0
  173. package/template/src/services/query/index.ts +1 -0
  174. package/template/src/services/query/queryClient.ts +23 -0
  175. package/template/src/services/toast/ToastCard.tsx +137 -0
  176. package/template/src/services/toast/ToastConfig.tsx +32 -0
  177. package/template/src/services/toast/index.ts +3 -0
  178. package/template/src/services/toast/toast.ts +68 -0
  179. package/template/src/storage/mmkvAdapter.ts +3 -0
  180. package/template/src/storage/mmkvInstance.ts +16 -0
  181. package/template/src/store/index.ts +15 -0
  182. package/template/src/store/mmkv.ts +6 -0
  183. package/template/src/store/persist.ts +10 -0
  184. package/template/src/store/rootReducer.ts +26 -0
  185. package/template/src/theme/dark.ts +40 -0
  186. package/template/src/theme/fonts.ts +20 -0
  187. package/template/src/theme/index.ts +6 -0
  188. package/template/src/theme/layout.ts +23 -0
  189. package/template/src/theme/light.ts +41 -0
  190. package/template/src/theme/palette.ts +32 -0
  191. package/template/src/theme/spacing.ts +7 -0
  192. package/template/src/theme/typography.ts +80 -0
  193. package/template/src/types/api.types.ts +34 -0
  194. package/template/src/types/env.d.ts +6 -0
  195. package/template/src/types/index.ts +2 -0
  196. package/template/src/types/navigation.types.ts +94 -0
  197. package/template/src/utils/clearAppSession.ts +10 -0
  198. package/template/src/utils/date.ts +19 -0
  199. package/template/src/utils/documentPickerHandler.ts +96 -0
  200. package/template/src/utils/getFileNameFromUri.ts +18 -0
  201. package/template/src/utils/getInitials.ts +13 -0
  202. package/template/src/utils/hindiText.ts +33 -0
  203. package/template/src/utils/imageCompress.ts +97 -0
  204. package/template/src/utils/imagePickerHandler.ts +200 -0
  205. package/template/src/utils/maskPhone.ts +17 -0
  206. package/template/src/utils/normalize.ts +12 -0
  207. package/template/src/validation/messages.ts +11 -0
  208. package/template/src/validation/rules.ts +44 -0
  209. package/template/src/validation/schema/auth.schema.ts +53 -0
  210. package/template/src/validation/schema/user.schema.ts +46 -0
  211. 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,11 @@
1
+ import en from './locales/en.json';
2
+ import ru from './locales/ru.json';
3
+
4
+ export const resources = {
5
+ en: {
6
+ translation: en,
7
+ },
8
+ ru: {
9
+ translation: ru,
10
+ },
11
+ } as const;
@@ -0,0 +1,4 @@
1
+ import { RootStoreState } from '@/store/rootReducer';
2
+
3
+ export const selectIsAuthenticated = (state: RootStoreState) =>
4
+ !!state.auth.access_token;
@@ -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,3 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export const styles = StyleSheet.create({});
@@ -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;
@@ -0,0 +1,4 @@
1
+ export { default as Login } from './login';
2
+ export { default as Signup } from './signup';
3
+ export { default as ForgotPassword } from './forgot-password';
4
+ export { default as VerifyEmail } from './verify-email';