@varunindiit/create-rn-starter 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 (243) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -0
  3. package/bin/index.js +270 -0
  4. package/lib/prompt.js +63 -0
  5. package/lib/rename.js +239 -0
  6. package/lib/scaffold.js +110 -0
  7. package/lib/utils.js +122 -0
  8. package/package.json +38 -0
  9. package/template/.eslintrc.js +4 -0
  10. package/template/.prettierrc.js +5 -0
  11. package/template/.watchmanconfig +1 -0
  12. package/template/App.tsx +100 -0
  13. package/template/Gemfile +17 -0
  14. package/template/README.md +97 -0
  15. package/template/__tests__/App.test.tsx +13 -0
  16. package/template/_gitignore +75 -0
  17. package/template/android/app/build.gradle +119 -0
  18. package/template/android/app/debug.keystore +0 -0
  19. package/template/android/app/proguard-rules.pro +10 -0
  20. package/template/android/app/src/main/AndroidManifest.xml +45 -0
  21. package/template/android/app/src/main/assets/fonts/MonaSans-Black.ttf +0 -0
  22. package/template/android/app/src/main/assets/fonts/MonaSans-BlackItalic.ttf +0 -0
  23. package/template/android/app/src/main/assets/fonts/MonaSans-Bold.ttf +0 -0
  24. package/template/android/app/src/main/assets/fonts/MonaSans-BoldItalic.ttf +0 -0
  25. package/template/android/app/src/main/assets/fonts/MonaSans-ExtraBold.ttf +0 -0
  26. package/template/android/app/src/main/assets/fonts/MonaSans-ExtraBoldItalic.ttf +0 -0
  27. package/template/android/app/src/main/assets/fonts/MonaSans-ExtraLight.ttf +0 -0
  28. package/template/android/app/src/main/assets/fonts/MonaSans-ExtraLightItalic.ttf +0 -0
  29. package/template/android/app/src/main/assets/fonts/MonaSans-Italic.ttf +0 -0
  30. package/template/android/app/src/main/assets/fonts/MonaSans-Light.ttf +0 -0
  31. package/template/android/app/src/main/assets/fonts/MonaSans-LightItalic.ttf +0 -0
  32. package/template/android/app/src/main/assets/fonts/MonaSans-Medium.ttf +0 -0
  33. package/template/android/app/src/main/assets/fonts/MonaSans-MediumItalic.ttf +0 -0
  34. package/template/android/app/src/main/assets/fonts/MonaSans-Regular.ttf +0 -0
  35. package/template/android/app/src/main/assets/fonts/MonaSans-SemiBold.ttf +0 -0
  36. package/template/android/app/src/main/assets/fonts/MonaSans-SemiBoldItalic.ttf +0 -0
  37. package/template/android/app/src/main/java/com/awesomeproject/MainActivity.kt +22 -0
  38. package/template/android/app/src/main/java/com/awesomeproject/MainApplication.kt +27 -0
  39. package/template/android/app/src/main/res/drawable/launch_screen.png +0 -0
  40. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  41. package/template/android/app/src/main/res/layout/launch_screen.xml +12 -0
  42. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  43. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  44. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  45. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  46. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  47. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  48. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  49. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  50. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  51. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  52. package/template/android/app/src/main/res/values/colors.xml +3 -0
  53. package/template/android/app/src/main/res/values/strings.xml +3 -0
  54. package/template/android/app/src/main/res/values/styles.xml +11 -0
  55. package/template/android/build.gradle +21 -0
  56. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  57. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  58. package/template/android/gradle.properties +44 -0
  59. package/template/android/gradlew +248 -0
  60. package/template/android/gradlew.bat +98 -0
  61. package/template/android/link-assets-manifest.json +69 -0
  62. package/template/android/settings.gradle +6 -0
  63. package/template/app.json +4 -0
  64. package/template/babel.config.js +4 -0
  65. package/template/declarations.d.ts +6 -0
  66. package/template/env.example +20 -0
  67. package/template/index.js +10 -0
  68. package/template/ios/.xcode.env +11 -0
  69. package/template/ios/.xcode.env.local +1 -0
  70. package/template/ios/AwesomeProject/AppDelegate.swift +60 -0
  71. package/template/ios/AwesomeProject/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  72. package/template/ios/AwesomeProject/Images.xcassets/Contents.json +6 -0
  73. package/template/ios/AwesomeProject/Images.xcassets/Splash.imageset/Contents.json +23 -0
  74. package/template/ios/AwesomeProject/Images.xcassets/Splash.imageset/Splash@1x.png +0 -0
  75. package/template/ios/AwesomeProject/Images.xcassets/Splash.imageset/Splash@2x.png +0 -0
  76. package/template/ios/AwesomeProject/Images.xcassets/Splash.imageset/Splash@3x.png +0 -0
  77. package/template/ios/AwesomeProject/Info.plist +89 -0
  78. package/template/ios/AwesomeProject/LaunchScreen.storyboard +40 -0
  79. package/template/ios/AwesomeProject/PrivacyInfo.xcprivacy +38 -0
  80. package/template/ios/AwesomeProject.xcodeproj/project.pbxproj +576 -0
  81. package/template/ios/AwesomeProject.xcodeproj/xcshareddata/xcschemes/AwesomeProject.xcscheme +88 -0
  82. package/template/ios/AwesomeProject.xcworkspace/contents.xcworkspacedata +10 -0
  83. package/template/ios/Podfile +68 -0
  84. package/template/ios/link-assets-manifest.json +69 -0
  85. package/template/jest.config.js +3 -0
  86. package/template/metro.config.js +24 -0
  87. package/template/package.json +68 -0
  88. package/template/react-native.config.js +7 -0
  89. package/template/src/assets/fonts/MonaSans-Black.ttf +0 -0
  90. package/template/src/assets/fonts/MonaSans-BlackItalic.ttf +0 -0
  91. package/template/src/assets/fonts/MonaSans-Bold.ttf +0 -0
  92. package/template/src/assets/fonts/MonaSans-BoldItalic.ttf +0 -0
  93. package/template/src/assets/fonts/MonaSans-ExtraBold.ttf +0 -0
  94. package/template/src/assets/fonts/MonaSans-ExtraBoldItalic.ttf +0 -0
  95. package/template/src/assets/fonts/MonaSans-ExtraLight.ttf +0 -0
  96. package/template/src/assets/fonts/MonaSans-ExtraLightItalic.ttf +0 -0
  97. package/template/src/assets/fonts/MonaSans-Italic.ttf +0 -0
  98. package/template/src/assets/fonts/MonaSans-Light.ttf +0 -0
  99. package/template/src/assets/fonts/MonaSans-LightItalic.ttf +0 -0
  100. package/template/src/assets/fonts/MonaSans-Medium.ttf +0 -0
  101. package/template/src/assets/fonts/MonaSans-MediumItalic.ttf +0 -0
  102. package/template/src/assets/fonts/MonaSans-Regular.ttf +0 -0
  103. package/template/src/assets/fonts/MonaSans-SemiBold.ttf +0 -0
  104. package/template/src/assets/fonts/MonaSans-SemiBoldItalic.ttf +0 -0
  105. package/template/src/assets/image/BackGroundAuth.png +0 -0
  106. package/template/src/assets/image/BackgroundVerification.png +0 -0
  107. package/template/src/assets/image/logo.png +0 -0
  108. package/template/src/assets/svg/add-circle.svg +5 -0
  109. package/template/src/assets/svg/airConditioning.svg +12 -0
  110. package/template/src/assets/svg/apple.svg +3 -0
  111. package/template/src/assets/svg/arrowDown.svg +3 -0
  112. package/template/src/assets/svg/back.svg +10 -0
  113. package/template/src/assets/svg/bag.svg +11 -0
  114. package/template/src/assets/svg/calender.svg +5 -0
  115. package/template/src/assets/svg/car.svg +10 -0
  116. package/template/src/assets/svg/carConfirm.svg +60 -0
  117. package/template/src/assets/svg/chatActive.svg +3 -0
  118. package/template/src/assets/svg/chatUnActive.svg +3 -0
  119. package/template/src/assets/svg/document-text.svg +6 -0
  120. package/template/src/assets/svg/gender.svg +11 -0
  121. package/template/src/assets/svg/google.svg +6 -0
  122. package/template/src/assets/svg/headphone.svg +3 -0
  123. package/template/src/assets/svg/homeActive.svg +3 -0
  124. package/template/src/assets/svg/homeUnActive.svg +3 -0
  125. package/template/src/assets/svg/logo.svg +18 -0
  126. package/template/src/assets/svg/logout.svg +5 -0
  127. package/template/src/assets/svg/maxBack.svg +4 -0
  128. package/template/src/assets/svg/message-text.svg +7 -0
  129. package/template/src/assets/svg/music.svg +5 -0
  130. package/template/src/assets/svg/noSmoking.svg +10 -0
  131. package/template/src/assets/svg/notification.svg +5 -0
  132. package/template/src/assets/svg/passenger.svg +4 -0
  133. package/template/src/assets/svg/phone.svg +3 -0
  134. package/template/src/assets/svg/rightArrow.svg +3 -0
  135. package/template/src/assets/svg/security-user.svg +5 -0
  136. package/template/src/assets/svg/star.svg +3 -0
  137. package/template/src/assets/svg/tick-circle.svg +4 -0
  138. package/template/src/assets/svg/trafficLight.svg +41 -0
  139. package/template/src/assets/svg/tripActive.svg +10 -0
  140. package/template/src/assets/svg/tripUnActive.svg +10 -0
  141. package/template/src/assets/svg/usbChargers.svg +3 -0
  142. package/template/src/assets/svg/user.svg +4 -0
  143. package/template/src/assets/svg/userActive.svg +3 -0
  144. package/template/src/assets/svg/userPlaceholder.svg +3 -0
  145. package/template/src/assets/svg/userUnActive.svg +3 -0
  146. package/template/src/components/AuthLayout/AuthLayout.tsx +170 -0
  147. package/template/src/components/AuthLayout/index.ts +1 -0
  148. package/template/src/components/BottomSheet/BottomSheet.tsx +73 -0
  149. package/template/src/components/BottomSheet/BottomSheetAlert.tsx +100 -0
  150. package/template/src/components/BottomSheet/CenterAlert.tsx +153 -0
  151. package/template/src/components/BottomSheet/index.ts +2 -0
  152. package/template/src/components/BottomTabBar/index.tsx +145 -0
  153. package/template/src/components/Button/RNButton.tsx +152 -0
  154. package/template/src/components/Button/index.ts +2 -0
  155. package/template/src/components/Common/Avatar.tsx +80 -0
  156. package/template/src/components/Common/Card.tsx +49 -0
  157. package/template/src/components/Common/CardBrandLogo.tsx +66 -0
  158. package/template/src/components/Common/Checkbox.tsx +65 -0
  159. package/template/src/components/Common/Chip.tsx +79 -0
  160. package/template/src/components/Common/CommonStyles.tsx +594 -0
  161. package/template/src/components/Common/Divider.tsx +33 -0
  162. package/template/src/components/Common/DriverTripCard.tsx +308 -0
  163. package/template/src/components/Common/Dropdown.tsx +161 -0
  164. package/template/src/components/Common/EmptyState.tsx +52 -0
  165. package/template/src/components/Common/FAB.tsx +68 -0
  166. package/template/src/components/Common/HeaderLocation.tsx +108 -0
  167. package/template/src/components/Common/Loader.tsx +23 -0
  168. package/template/src/components/Common/RatingStars.tsx +103 -0
  169. package/template/src/components/Common/RouteDots.tsx +98 -0
  170. package/template/src/components/Common/SegmentedControl.tsx +126 -0
  171. package/template/src/components/Common/SosButton.tsx +80 -0
  172. package/template/src/components/Common/SosSheet.tsx +344 -0
  173. package/template/src/components/Common/StarRating.tsx +58 -0
  174. package/template/src/components/Common/StatusBadge.tsx +56 -0
  175. package/template/src/components/Common/Toggle.tsx +66 -0
  176. package/template/src/components/Common/TripCard.tsx +247 -0
  177. package/template/src/components/Common/UploadBox.tsx +106 -0
  178. package/template/src/components/Container/MainContainer.tsx +76 -0
  179. package/template/src/components/Container/index.ts +1 -0
  180. package/template/src/components/Header/index.tsx +143 -0
  181. package/template/src/components/Icon/SvgIcons.tsx +1991 -0
  182. package/template/src/components/ImagePickerSheet/ImagePickerSheet.tsx +233 -0
  183. package/template/src/components/ImagePickerSheet/index.ts +2 -0
  184. package/template/src/components/Input/CountryDropdown.tsx +71 -0
  185. package/template/src/components/Input/OtpInput.tsx +117 -0
  186. package/template/src/components/Input/RNInput.tsx +138 -0
  187. package/template/src/components/Input/index.ts +4 -0
  188. package/template/src/components/Picker/DatePickerSheet.tsx +393 -0
  189. package/template/src/components/Picker/PassengerPickerSheet.tsx +237 -0
  190. package/template/src/components/Text/RNText.tsx +62 -0
  191. package/template/src/components/Text/index.ts +1 -0
  192. package/template/src/components/index.ts +44 -0
  193. package/template/src/hooks/useCurrentLocation.ts +72 -0
  194. package/template/src/localization/i18n.ts +29 -0
  195. package/template/src/localization/i18next.d.ts +11 -0
  196. package/template/src/localization/index.ts +4 -0
  197. package/template/src/localization/languageStorage.ts +27 -0
  198. package/template/src/localization/languages.ts +62 -0
  199. package/template/src/localization/resources/en.ts +703 -0
  200. package/template/src/localization/resources/fr.ts +703 -0
  201. package/template/src/localization/useLanguage.ts +42 -0
  202. package/template/src/navigation/AuthNavigation.tsx +23 -0
  203. package/template/src/navigation/BottomTabs.tsx +24 -0
  204. package/template/src/navigation/RootNavigation.tsx +27 -0
  205. package/template/src/navigation/RouteKey.ts +22 -0
  206. package/template/src/navigation/StackNavigation.tsx +52 -0
  207. package/template/src/navigation/paramLists.ts +25 -0
  208. package/template/src/redux/slice/app.ts +66 -0
  209. package/template/src/redux/slice/auth.ts +40 -0
  210. package/template/src/redux/slice/userProfile.ts +124 -0
  211. package/template/src/redux/store.ts +17 -0
  212. package/template/src/screen/auth/Login.tsx +69 -0
  213. package/template/src/screen/onboarding/LanguageSelection.tsx +231 -0
  214. package/template/src/screen/root/home/index.tsx +36 -0
  215. package/template/src/screen/root/profile/index.tsx +69 -0
  216. package/template/src/screen/shared/Chat.tsx +308 -0
  217. package/template/src/screen/shared/EditProfile.tsx +407 -0
  218. package/template/src/screen/shared/HelpSupport.tsx +678 -0
  219. package/template/src/screen/shared/LocationSearch.tsx +362 -0
  220. package/template/src/screen/shared/Messages.tsx +115 -0
  221. package/template/src/screen/shared/Notifications.tsx +86 -0
  222. package/template/src/screen/shared/PrivacyPolicy.tsx +297 -0
  223. package/template/src/screen/shared/Profile.tsx +118 -0
  224. package/template/src/screen/shared/Ratings.tsx +170 -0
  225. package/template/src/screen/shared/TermsConditions.tsx +315 -0
  226. package/template/src/screen/shared/profile/DriverProfile.tsx +262 -0
  227. package/template/src/screen/shared/profile/PassengerProfile.tsx +123 -0
  228. package/template/src/screen/shared/profile/ProfileParts.tsx +219 -0
  229. package/template/src/services/Config.ts +37 -0
  230. package/template/src/services/api.ts +37 -0
  231. package/template/src/services/index.ts +4 -0
  232. package/template/src/services/places.ts +320 -0
  233. package/template/src/services/storage.ts +33 -0
  234. package/template/src/theme/fonts.ts +30 -0
  235. package/template/src/theme/index.ts +3 -0
  236. package/template/src/theme/spacing.ts +66 -0
  237. package/template/src/theme/theme.ts +58 -0
  238. package/template/src/types/env.d.ts +8 -0
  239. package/template/src/types/index.ts +3 -0
  240. package/template/src/utils/card.ts +101 -0
  241. package/template/src/utils/constants.ts +39 -0
  242. package/template/src/utils/functions.ts +24 -0
  243. package/template/tsconfig.json +8 -0
@@ -0,0 +1,42 @@
1
+ import { useCallback } from "react";
2
+ import { useTranslation } from "react-i18next";
3
+ import { useDispatch } from "react-redux";
4
+ import { setLanguage as setLanguageAction } from "../redux/slice/app";
5
+ import {
6
+ DEFAULT_LANGUAGE,
7
+ LANGUAGES,
8
+ LanguageCode,
9
+ getLanguageOption,
10
+ } from "./languages";
11
+ import { markLanguageSelected, setStoredLanguage } from "./languageStorage";
12
+
13
+ /**
14
+ * Single source of truth for reading and changing the app language.
15
+ * Persists to MMKV, updates i18next (re-renders all `t()` usages) and Redux.
16
+ */
17
+ export const useLanguage = () => {
18
+ const { t, i18n } = useTranslation();
19
+ const dispatch = useDispatch();
20
+
21
+ const current = (i18n.language?.split("-")[0] as LanguageCode) || DEFAULT_LANGUAGE;
22
+
23
+ const changeLanguage = useCallback(
24
+ (code: LanguageCode, { markSelected = true }: { markSelected?: boolean } = {}) => {
25
+ i18n.changeLanguage(code);
26
+ setStoredLanguage(code);
27
+ if (markSelected) markLanguageSelected();
28
+ dispatch(setLanguageAction({ code, selected: markSelected }));
29
+ },
30
+ [dispatch, i18n],
31
+ );
32
+
33
+ return {
34
+ t,
35
+ current,
36
+ currentOption: getLanguageOption(current),
37
+ languages: LANGUAGES,
38
+ changeLanguage,
39
+ };
40
+ };
41
+
42
+ export default useLanguage;
@@ -0,0 +1,23 @@
1
+ import { createNativeStackNavigator } from "@react-navigation/native-stack";
2
+ import React from "react";
3
+ import Login from "../screen/auth/Login";
4
+ import { THEME } from "../theme";
5
+ import RouteKey from "./RouteKey";
6
+ import { AuthStackParamList } from "./paramLists";
7
+
8
+ const Stack = createNativeStackNavigator<AuthStackParamList>();
9
+
10
+ const AuthNavigation = () => (
11
+ <Stack.Navigator
12
+ initialRouteName={RouteKey.Login}
13
+ screenOptions={{
14
+ headerShown: false,
15
+ contentStyle: { backgroundColor: THEME.background },
16
+ animation: "slide_from_right",
17
+ }}
18
+ >
19
+ <Stack.Screen name={RouteKey.Login} component={Login} />
20
+ </Stack.Navigator>
21
+ );
22
+
23
+ export default AuthNavigation;
@@ -0,0 +1,24 @@
1
+ import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
2
+ import React from "react";
3
+ import BottomTabBar from "../components/BottomTabBar";
4
+ import Home from "../screen/root/home";
5
+ import Profile from "../screen/root/profile";
6
+ import RouteKey from "./RouteKey";
7
+ import { UserTabParamList } from "./paramLists";
8
+
9
+ const Tab = createBottomTabNavigator<UserTabParamList>();
10
+
11
+ const BottomTabs = () => (
12
+ <Tab.Navigator
13
+ screenOptions={{
14
+ headerShown: false,
15
+ sceneStyle: { backgroundColor: "transparent" },
16
+ }}
17
+ tabBar={props => <BottomTabBar {...props} />}
18
+ >
19
+ <Tab.Screen name={RouteKey.UserHome} component={Home} />
20
+ <Tab.Screen name={RouteKey.UserProfile} component={Profile} />
21
+ </Tab.Navigator>
22
+ );
23
+
24
+ export default BottomTabs;
@@ -0,0 +1,27 @@
1
+ import { createNativeStackNavigator } from "@react-navigation/native-stack";
2
+ import React from "react";
3
+ import { THEME } from "../theme";
4
+ import BottomTabs from "./BottomTabs";
5
+ import RouteKey from "./RouteKey";
6
+
7
+ const Stack = createNativeStackNavigator();
8
+
9
+ /**
10
+ * Root (authenticated) stack. Hosts the bottom tabs and is the place to add
11
+ * further app-level stack screens (details, settings, etc.) as the app grows.
12
+ */
13
+ const RootNavigation = () => {
14
+ return (
15
+ <Stack.Navigator
16
+ screenOptions={{
17
+ headerShown: false,
18
+ contentStyle: { backgroundColor: THEME.background },
19
+ animation: "slide_from_right",
20
+ }}
21
+ >
22
+ <Stack.Screen name={RouteKey.BottomTabs} component={BottomTabs} />
23
+ </Stack.Navigator>
24
+ );
25
+ };
26
+
27
+ export default RootNavigation;
@@ -0,0 +1,22 @@
1
+ /** Centralized route names for both User and Driver flows */
2
+ export enum RouteKey {
3
+ /* Onboarding */
4
+ LanguageSelection = "LanguageSelection",
5
+ LanguageSettings = "LanguageSettings",
6
+
7
+ /* Stacks */
8
+ AuthStack = "AuthStack",
9
+ AppStack = "AppStack",
10
+ UserStack = "UserStack",
11
+ DriverStack = "DriverStack",
12
+ BottomTabs = "BottomTabs",
13
+
14
+ /* Auth */
15
+ Login = "Login",
16
+
17
+ /* User Tabs */
18
+ UserHome = "Home",
19
+ UserProfile = "Profile",
20
+ }
21
+
22
+ export default RouteKey;
@@ -0,0 +1,52 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { createNativeStackNavigator } from "@react-navigation/native-stack";
3
+ import { useDispatch, useSelector } from "react-redux";
4
+ import { setIsLoggedIn } from "../redux/slice/auth";
5
+ import { RootState } from "../redux/store";
6
+ import { getStorageBoolean } from "../services/storage";
7
+ import { IS_LOGGED_IN } from "../utils/constants";
8
+ import AuthNavigation from "./AuthNavigation";
9
+ import RootNavigation from "./RootNavigation";
10
+ import RouteKey from "./RouteKey";
11
+ import { THEME } from "../theme";
12
+
13
+ const Stack = createNativeStackNavigator();
14
+
15
+ /**
16
+ * Top-level navigator and auth guard. The session flag in redux decides
17
+ * whether the Auth stack or the Root (app) stack is mounted, so toggling
18
+ * `isLoggedIn` swaps the whole tree declaratively — no imperative navigation
19
+ * needed on login/logout.
20
+ */
21
+ const StackNavigation = () => {
22
+ const isLoggedIn = useSelector((s: RootState) => s.auth.isLoggedIn);
23
+ const dispatch = useDispatch();
24
+ const [bootstrapped, setBootstrapped] = useState(false);
25
+
26
+ // Restore the persisted (dummy) session before rendering the tree.
27
+ useEffect(() => {
28
+ dispatch(setIsLoggedIn(getStorageBoolean(IS_LOGGED_IN) || false));
29
+ setBootstrapped(true);
30
+ }, [dispatch]);
31
+
32
+ if (!bootstrapped) {
33
+ return null;
34
+ }
35
+
36
+ return (
37
+ <Stack.Navigator
38
+ screenOptions={{
39
+ headerShown: false,
40
+ contentStyle: { backgroundColor: THEME.background },
41
+ }}
42
+ >
43
+ {isLoggedIn ? (
44
+ <Stack.Screen name={RouteKey.AppStack} component={RootNavigation} />
45
+ ) : (
46
+ <Stack.Screen name={RouteKey.AuthStack} component={AuthNavigation} />
47
+ )}
48
+ </Stack.Navigator>
49
+ );
50
+ };
51
+
52
+ export default StackNavigation;
@@ -0,0 +1,25 @@
1
+ import RouteKey from "./RouteKey";
2
+ import { LocationValue } from "../services/places";
3
+
4
+ /**
5
+ * Params for the shared Location Search screen.
6
+ *
7
+ * By default the selected location is written back to the ride draft based on
8
+ * `field` (the "Pickup Location" flow). Callers that manage their own state
9
+ * (e.g. the Home From/To fields) can instead pass an `onSelect` callback to
10
+ * receive the resolved location directly, keeping the screen reusable.
11
+ */
12
+ export type LocationSearchParams = {
13
+ field?: "pickup" | "drop";
14
+ title?: string;
15
+ onSelect?: (location: LocationValue) => void;
16
+ };
17
+
18
+ export type AuthStackParamList = {
19
+ [RouteKey.Login]: undefined;
20
+ };
21
+
22
+ export type UserTabParamList = {
23
+ [RouteKey.UserHome]: undefined;
24
+ [RouteKey.UserProfile]: undefined;
25
+ };
@@ -0,0 +1,66 @@
1
+ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2
+ import { LanguageCode } from "../../localization/languages";
3
+ import {
4
+ getStoredLanguage,
5
+ hasSelectedLanguage,
6
+ } from "../../localization/languageStorage";
7
+
8
+ interface AppState {
9
+ notificationsEnabled: { push: boolean; email: boolean; sms: boolean };
10
+ unreadNotificationCount: number;
11
+ driverOnline: boolean;
12
+ language: LanguageCode;
13
+ languageSelected: boolean;
14
+ }
15
+
16
+ const initialState: AppState = {
17
+ notificationsEnabled: { push: true, email: true, sms: false },
18
+ unreadNotificationCount: 2,
19
+ driverOnline: true,
20
+ language: getStoredLanguage(),
21
+ languageSelected: hasSelectedLanguage(),
22
+ };
23
+
24
+ const appSlice = createSlice({
25
+ name: "app",
26
+ initialState,
27
+ reducers: {
28
+ setNotificationPref: (
29
+ state,
30
+ action: PayloadAction<Partial<AppState["notificationsEnabled"]>>,
31
+ ) => {
32
+ state.notificationsEnabled = {
33
+ ...state.notificationsEnabled,
34
+ ...action.payload,
35
+ };
36
+ },
37
+ setUnreadNotificationCount: (state, action: PayloadAction<number>) => {
38
+ state.unreadNotificationCount = action.payload;
39
+ },
40
+ setDriverOnline: (state, action: PayloadAction<boolean>) => {
41
+ state.driverOnline = action.payload;
42
+ },
43
+ setLanguage: (
44
+ state,
45
+ action: PayloadAction<{ code: LanguageCode; selected?: boolean }>,
46
+ ) => {
47
+ state.language = action.payload.code;
48
+ if (action.payload.selected) state.languageSelected = true;
49
+ },
50
+ resetAppState: (state) => ({
51
+ ...initialState,
52
+ // Preserve language choice across logout/reset.
53
+ language: state.language,
54
+ languageSelected: state.languageSelected,
55
+ }),
56
+ },
57
+ });
58
+
59
+ export const {
60
+ setNotificationPref,
61
+ setUnreadNotificationCount,
62
+ setDriverOnline,
63
+ setLanguage,
64
+ resetAppState,
65
+ } = appSlice.actions;
66
+ export default appSlice.reducer;
@@ -0,0 +1,40 @@
1
+ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2
+
3
+ export type UserRole = "passenger" | "driver";
4
+
5
+ interface AuthState {
6
+ /** Whether the user has an active (dummy) session. */
7
+ isLoggedIn: boolean;
8
+ role: UserRole;
9
+ }
10
+
11
+ const initialState: AuthState = {
12
+ isLoggedIn: false,
13
+ role: "passenger",
14
+ };
15
+
16
+ const authSlice = createSlice({
17
+ name: "auth",
18
+ initialState,
19
+ reducers: {
20
+ /** Start a session. Optionally set the active role. */
21
+ login: (state, action: PayloadAction<UserRole | undefined>) => {
22
+ state.isLoggedIn = true;
23
+ if (action.payload) {
24
+ state.role = action.payload;
25
+ }
26
+ },
27
+ /** Clear the session and reset auth state. */
28
+ logout: () => initialState,
29
+ setIsLoggedIn: (state, action: PayloadAction<boolean>) => {
30
+ state.isLoggedIn = action.payload;
31
+ },
32
+ setRole: (state, action: PayloadAction<UserRole>) => {
33
+ state.role = action.payload;
34
+ },
35
+ },
36
+ });
37
+
38
+ export const { login, logout, setIsLoggedIn, setRole } = authSlice.actions;
39
+
40
+ export default authSlice.reducer;
@@ -0,0 +1,124 @@
1
+ import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2
+
3
+ export interface Vehicle {
4
+ id: string;
5
+ model: string;
6
+ registration: string;
7
+ type?: string;
8
+ manufacturer?: string;
9
+ color?: string;
10
+ year?: number;
11
+ seats?: number;
12
+ imageUri?: string | null;
13
+ images?: string[];
14
+ }
15
+
16
+ export interface UserProfile {
17
+ fullName: string;
18
+ email: string;
19
+ phone: string;
20
+ countryCode: string;
21
+ gender?: "Male" | "Female" | "Other";
22
+ dob?: string;
23
+ address?: string;
24
+ about?: string;
25
+ avatarUri?: string | null;
26
+ isEmailVerified?: boolean;
27
+ isPhoneVerified?: boolean;
28
+ /** Driver only */
29
+ isDriverVerified?: boolean;
30
+ licenseNumber?: string;
31
+ licenseExpiry?: string;
32
+ licenseImageUri?: string | null;
33
+ nationalIdImageUri?: string | null;
34
+ vehicles?: Vehicle[];
35
+ rating?: number;
36
+ totalTrips?: number;
37
+ since?: string;
38
+ }
39
+
40
+ export interface UserProfileState {
41
+ profile: UserProfile;
42
+ }
43
+
44
+ const initialState: UserProfileState = {
45
+ profile: {
46
+ fullName: "Justin Watson",
47
+ email: "justin785@gmail.com",
48
+ phone: "82 123 4567",
49
+ countryCode: "+27",
50
+ gender: "Male",
51
+ dob: "10/05/1989",
52
+ address: "Yaoundé, Cameroon",
53
+ about:
54
+ "Hi, I commute to Douala every weekend. I love listening to jazz and keep the car quiet. I drive a comfortable Toyota Yaris.",
55
+ avatarUri: null,
56
+ isPhoneVerified: true,
57
+ isEmailVerified: false,
58
+ isDriverVerified: true,
59
+ licenseNumber: "DLN-22988-CMR",
60
+ licenseExpiry: "12/2028",
61
+ rating: 4.8,
62
+ totalTrips: 124,
63
+ since: "2024",
64
+ vehicles: [
65
+ {
66
+ id: "v1",
67
+ model: "Maybach S680",
68
+ type: "Sedan",
69
+ registration: "HSA627272",
70
+ manufacturer: "Mercedes-Benz, S...",
71
+ color: "Black",
72
+ year: 2022,
73
+ seats: 5,
74
+ imageUri:
75
+ "https://images.unsplash.com/photo-1606664515524-ed2f786a0bd6?w=400",
76
+ },
77
+ {
78
+ id: "v2",
79
+ model: "Toyota Yaris",
80
+ type: "Sedan",
81
+ registration: "HSA627272",
82
+ manufacturer: "Mercedes-Benz, S...",
83
+ color: "Red",
84
+ year: 2020,
85
+ seats: 5,
86
+ imageUri:
87
+ "https://images.unsplash.com/photo-1494976388531-d1058494cdd8?w=400",
88
+ },
89
+ ],
90
+ },
91
+ };
92
+
93
+ const userProfileSlice = createSlice({
94
+ name: "userProfile",
95
+ initialState,
96
+ reducers: {
97
+ setProfile: (state, action: PayloadAction<Partial<UserProfile>>) => {
98
+ state.profile = { ...state.profile, ...action.payload };
99
+ },
100
+ setAvatarUri: (state, action: PayloadAction<string | null>) => {
101
+ state.profile.avatarUri = action.payload;
102
+ },
103
+ addVehicle: (state, action: PayloadAction<Vehicle>) => {
104
+ state.profile.vehicles = [
105
+ ...(state.profile.vehicles ?? []),
106
+ action.payload,
107
+ ];
108
+ },
109
+ removeVehicle: (state, action: PayloadAction<string>) => {
110
+ state.profile.vehicles =
111
+ state.profile.vehicles?.filter((v) => v.id !== action.payload) ?? [];
112
+ },
113
+ resetUserProfile: () => initialState,
114
+ },
115
+ });
116
+
117
+ export const {
118
+ setProfile,
119
+ setAvatarUri,
120
+ addVehicle,
121
+ removeVehicle,
122
+ resetUserProfile,
123
+ } = userProfileSlice.actions;
124
+ export default userProfileSlice.reducer;
@@ -0,0 +1,17 @@
1
+ import { configureStore } from "@reduxjs/toolkit";
2
+ import authSlice from "./slice/auth";
3
+ import appSlice from "./slice/app";
4
+ import userProfileSlice from "./slice/userProfile";
5
+
6
+ const store = configureStore({
7
+ reducer: {
8
+ auth: authSlice,
9
+ app: appSlice,
10
+ userProfile: userProfileSlice,
11
+ },
12
+ });
13
+
14
+ export type RootState = ReturnType<typeof store.getState>;
15
+ export type AppDispatch = typeof store.dispatch;
16
+
17
+ export default store;
@@ -0,0 +1,69 @@
1
+ import React from "react";
2
+ import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
3
+ import { SafeAreaView } from "react-native-safe-area-context";
4
+ import { moderateScale } from "react-native-size-matters";
5
+ import { useDispatch } from "react-redux";
6
+ import { login } from "../../redux/slice/auth";
7
+ import { setStorageBoolean } from "../../services/storage";
8
+ import { IS_LOGGED_IN } from "../../utils/constants";
9
+ import { FONTS } from "../../theme/fonts";
10
+ import { THEME } from "../../theme";
11
+
12
+ const Login = () => {
13
+ const dispatch = useDispatch();
14
+
15
+ const onLogin = () => {
16
+ // Persist the dummy session, then flip auth state. The top-level guard
17
+ // swaps to the Root stack automatically.
18
+ setStorageBoolean(IS_LOGGED_IN, true);
19
+ dispatch(login());
20
+ };
21
+
22
+ return (
23
+ <SafeAreaView style={styles.container}>
24
+ <View style={styles.content}>
25
+ <Text style={styles.title}>Login Screen</Text>
26
+
27
+ <TouchableOpacity
28
+ style={styles.button}
29
+ activeOpacity={0.8}
30
+ onPress={onLogin}
31
+ >
32
+ <Text style={styles.buttonText}>Login</Text>
33
+ </TouchableOpacity>
34
+ </View>
35
+ </SafeAreaView>
36
+ );
37
+ };
38
+
39
+ export default Login;
40
+
41
+ const styles = StyleSheet.create({
42
+ container: {
43
+ flex: 1,
44
+ backgroundColor: THEME.background,
45
+ },
46
+ content: {
47
+ flex: 1,
48
+ alignItems: "center",
49
+ justifyContent: "center",
50
+ paddingHorizontal: moderateScale(24),
51
+ },
52
+ title: {
53
+ fontFamily: FONTS.bold,
54
+ fontSize: moderateScale(22),
55
+ color: THEME.text,
56
+ marginBottom: moderateScale(28),
57
+ },
58
+ button: {
59
+ backgroundColor: THEME.primary,
60
+ paddingVertical: moderateScale(14),
61
+ paddingHorizontal: moderateScale(48),
62
+ borderRadius: moderateScale(12),
63
+ },
64
+ buttonText: {
65
+ fontFamily: FONTS.semibold,
66
+ fontSize: moderateScale(16),
67
+ color: THEME.textOnPrimary,
68
+ },
69
+ });