@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,362 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import {
3
+ ActivityIndicator,
4
+ FlatList,
5
+ StyleSheet,
6
+ TouchableOpacity,
7
+ View,
8
+ } from "react-native";
9
+ import { useNavigation, useRoute, RouteProp } from "@react-navigation/native";
10
+ import { useDispatch } from "react-redux";
11
+ import { moderateScale } from "react-native-size-matters";
12
+ import Animated, { FadeIn, FadeInDown } from "react-native-reanimated";
13
+ import GetLocation from "react-native-get-location";
14
+ import {
15
+ EmptyState,
16
+ Header,
17
+ MainContainer,
18
+ RNInput,
19
+ RNText,
20
+ } from "../../components";
21
+ import {
22
+ CircleXIcon,
23
+ LocateIcon,
24
+ PinIcon,
25
+ SearchIcon,
26
+ } from "../../components/Icon/SvgIcons";
27
+ import { SPACING, THEME } from "../../theme";
28
+ import {
29
+ autocompletePlaces,
30
+ getPlaceDetails,
31
+ newSessionToken,
32
+ reverseGeocode,
33
+ PlaceSuggestion,
34
+ } from "../../services/places";
35
+ import { showToast } from "../../utils/functions";
36
+ import { updateDraft } from "../../redux/slice/ride";
37
+ import { DriverStackParamList } from "../../navigation/paramLists";
38
+ import RouteKey from "../../navigation/RouteKey";
39
+ import { useLanguage } from "../../localization";
40
+
41
+ const DEBOUNCE_MS = 300;
42
+
43
+ const LocationSearch: React.FC = () => {
44
+ const nav = useNavigation<any>();
45
+ const dispatch = useDispatch();
46
+ const { t } = useLanguage();
47
+ const { params } =
48
+ useRoute<RouteProp<DriverStackParamList, RouteKey.LocationSearch>>();
49
+ const field = params?.field ?? "pickup";
50
+
51
+ const [query, setQuery] = useState("");
52
+ const [results, setResults] = useState<PlaceSuggestion[]>([]);
53
+ const [searching, setSearching] = useState(false);
54
+ const [resolving, setResolving] = useState(false);
55
+
56
+ const abortRef = useRef<AbortController | null>(null);
57
+ // Device coordinates used only to bias nearby cities to the top of results.
58
+ const biasRef = useRef<{ latitude: number; longitude: number } | null>(null);
59
+
60
+ // Open a fresh autocomplete billing session whenever the screen mounts.
61
+ useEffect(() => {
62
+ newSessionToken();
63
+ }, []);
64
+
65
+ // Best-effort, silent location fetch to prioritise nearby cities. Any
66
+ // failure / denied permission simply falls back to a global-only search.
67
+ useEffect(() => {
68
+ let active = true;
69
+ GetLocation.getCurrentPosition({ enableHighAccuracy: false, timeout: 8000 })
70
+ .then((pos) => {
71
+ if (active) {
72
+ biasRef.current = {
73
+ latitude: pos.latitude,
74
+ longitude: pos.longitude,
75
+ };
76
+ }
77
+ })
78
+ .catch(() => {
79
+ /* no bias — global search only */
80
+ });
81
+ return () => {
82
+ active = false;
83
+ };
84
+ }, []);
85
+
86
+ // Debounced live search.
87
+ useEffect(() => {
88
+ const text = query.trim();
89
+ abortRef.current?.abort();
90
+
91
+ if (text.length < 2) {
92
+ setResults([]);
93
+ setSearching(false);
94
+ return;
95
+ }
96
+
97
+ setSearching(true);
98
+ const controller = new AbortController();
99
+ abortRef.current = controller;
100
+
101
+ const timer = setTimeout(async () => {
102
+ try {
103
+ const list = await autocompletePlaces(
104
+ text,
105
+ controller.signal,
106
+ biasRef.current ?? undefined,
107
+ );
108
+ setResults(list);
109
+ } catch (err: any) {
110
+ if (err?.name !== "CanceledError" && err?.code !== "ERR_CANCELED") {
111
+ setResults([]);
112
+ }
113
+ } finally {
114
+ if (!controller.signal.aborted) setSearching(false);
115
+ }
116
+ }, DEBOUNCE_MS);
117
+
118
+ return () => {
119
+ clearTimeout(timer);
120
+ controller.abort();
121
+ };
122
+ }, [query]);
123
+
124
+ const commit = useCallback(
125
+ (loc: { latitude: number; longitude: number; address: string }) => {
126
+ // Callers managing their own state (e.g. the Home From/To fields) receive
127
+ // the location directly; otherwise fall back to the ride-draft flow.
128
+ if (params?.onSelect) {
129
+ params.onSelect(loc);
130
+ } else if (field === "pickup") {
131
+ dispatch(updateDraft({ from: loc.address, fromLocation: loc }));
132
+ } else {
133
+ dispatch(updateDraft({ to: loc.address, toLocation: loc }));
134
+ }
135
+ nav.goBack();
136
+ },
137
+ [dispatch, field, nav, params],
138
+ );
139
+
140
+ const onSelect = useCallback(
141
+ async (item: PlaceSuggestion) => {
142
+ try {
143
+ setResolving(true);
144
+ const detail = await getPlaceDetails(item.placeId);
145
+ commit(detail);
146
+ } catch {
147
+ showToast(t("location.loadError"), "danger");
148
+ setResolving(false);
149
+ }
150
+ },
151
+ [commit, t],
152
+ );
153
+
154
+ const onUseCurrentLocation = useCallback(async () => {
155
+ try {
156
+ setResolving(true);
157
+ const position = await GetLocation.getCurrentPosition({
158
+ enableHighAccuracy: true,
159
+ timeout: 15000,
160
+ });
161
+ const detail = await reverseGeocode(
162
+ position.latitude,
163
+ position.longitude,
164
+ );
165
+ commit(detail);
166
+ } catch {
167
+ showToast(t("location.currentLocationError"), "danger");
168
+ setResolving(false);
169
+ }
170
+ }, [commit, t]);
171
+
172
+ const renderItem = useCallback(
173
+ ({ item, index }: { item: PlaceSuggestion; index: number }) => (
174
+ <Animated.View entering={FadeInDown.delay(index * 30).duration(240)}>
175
+ <TouchableOpacity
176
+ style={styles.row}
177
+ activeOpacity={0.7}
178
+ onPress={() => onSelect(item)}
179
+ >
180
+ <View style={styles.rowIcon}>
181
+ <PinIcon size={moderateScale(18)} color={THEME.primary} />
182
+ </View>
183
+ <View style={styles.rowText}>
184
+ <RNText font="semibold" size={14} color={THEME.text} numberOfLines={1}>
185
+ {item.primaryText}
186
+ </RNText>
187
+ {item.secondaryText ? (
188
+ <RNText
189
+ size={12}
190
+ color={THEME.textMuted}
191
+ numberOfLines={1}
192
+ style={styles.rowSub}
193
+ >
194
+ {item.secondaryText}
195
+ </RNText>
196
+ ) : null}
197
+ </View>
198
+ </TouchableOpacity>
199
+ </Animated.View>
200
+ ),
201
+ [onSelect],
202
+ );
203
+
204
+ const headerTitle =
205
+ params?.title ??
206
+ (field === "pickup" ? t("location.pickupTitle") : t("location.dropTitle"));
207
+
208
+ return (
209
+ <MainContainer gradient statusBarStyle="dark-content">
210
+ <Header title={headerTitle} safeArea={false} />
211
+
212
+ <View style={styles.searchWrap}>
213
+ <RNInput
214
+ value={query}
215
+ onChangeText={setQuery}
216
+ placeholder={t("location.searchPlaceholder")}
217
+ autoFocus
218
+ returnKeyType="search"
219
+ leftIcon={
220
+ <SearchIcon size={moderateScale(18)} color={THEME.textMuted} />
221
+ }
222
+ rightIcon={
223
+ query ? (
224
+ <CircleXIcon size={moderateScale(16)} color={THEME.primary} />
225
+ ) : null
226
+ }
227
+ onPressRightIcon={() => setQuery("")}
228
+ />
229
+ </View>
230
+
231
+ <TouchableOpacity
232
+ style={styles.currentRow}
233
+ activeOpacity={0.7}
234
+ onPress={onUseCurrentLocation}
235
+ >
236
+ <View style={styles.currentIcon}>
237
+ <LocateIcon size={moderateScale(18)} color={THEME.primary} />
238
+ </View>
239
+ <RNText font="medium" size={14} color={THEME.primary} style={styles.currentText}>
240
+ {t("location.currentLocation")}
241
+ </RNText>
242
+ </TouchableOpacity>
243
+
244
+ <View style={styles.listWrap}>
245
+ {searching ? (
246
+ <View style={styles.center}>
247
+ <ActivityIndicator size="small" color={THEME.primary} />
248
+ <RNText size={12} color={THEME.textMuted} style={styles.searchingText}>
249
+ {t("location.searching")}
250
+ </RNText>
251
+ </View>
252
+ ) : results.length ? (
253
+ <FlatList
254
+ data={results}
255
+ keyExtractor={(item) => item.placeId}
256
+ renderItem={renderItem}
257
+ keyboardShouldPersistTaps="handled"
258
+ showsVerticalScrollIndicator={false}
259
+ contentContainerStyle={styles.listContent}
260
+ />
261
+ ) : query.trim().length >= 2 ? (
262
+ <EmptyState
263
+ icon={<SearchIcon size={moderateScale(34)} color={THEME.textMuted} />}
264
+ title={t("location.noResults")}
265
+ description={t("location.noResultsSubtitle")}
266
+ />
267
+ ) : (
268
+ <EmptyState
269
+ icon={<PinIcon size={moderateScale(34)} color={THEME.primary} />}
270
+ title={t("location.whereToTitle")}
271
+ description={t("location.searchHint")}
272
+ />
273
+ )}
274
+ </View>
275
+
276
+ {resolving ? (
277
+ <Animated.View
278
+ entering={FadeIn.duration(150)}
279
+ style={styles.resolveOverlay}
280
+ >
281
+ <View style={styles.resolveCard}>
282
+ <ActivityIndicator size="large" color={THEME.primary} />
283
+ <RNText size={13} color={THEME.text} style={styles.resolveText}>
284
+ {t("common.loading")}
285
+ </RNText>
286
+ </View>
287
+ </Animated.View>
288
+ ) : null}
289
+ </MainContainer>
290
+ );
291
+ };
292
+
293
+ export default LocationSearch;
294
+
295
+ const styles = StyleSheet.create({
296
+ searchWrap: {
297
+ paddingHorizontal: SPACING.xl,
298
+ paddingTop: SPACING.sm,
299
+ },
300
+ currentRow: {
301
+ flexDirection: "row",
302
+ alignItems: "center",
303
+ paddingHorizontal: SPACING.xl,
304
+ paddingVertical: SPACING.md,
305
+ marginTop: SPACING.sm,
306
+ },
307
+ currentIcon: {
308
+ width: moderateScale(36),
309
+ height: moderateScale(36),
310
+ borderRadius: moderateScale(18),
311
+ backgroundColor: THEME.primaryFaint,
312
+ alignItems: "center",
313
+ justifyContent: "center",
314
+ },
315
+ currentText: { marginLeft: SPACING.md },
316
+ listWrap: { flex: 1 },
317
+ listContent: {
318
+ paddingHorizontal: SPACING.xl,
319
+ paddingBottom: SPACING.huge,
320
+ },
321
+ row: {
322
+ flexDirection: "row",
323
+ alignItems: "center",
324
+ paddingVertical: SPACING.md,
325
+ borderBottomWidth: 1,
326
+ borderBottomColor: THEME.divider,
327
+ },
328
+ rowIcon: {
329
+ width: moderateScale(38),
330
+ height: moderateScale(38),
331
+ borderRadius: moderateScale(10),
332
+ backgroundColor: THEME.primaryFaint,
333
+ alignItems: "center",
334
+ justifyContent: "center",
335
+ },
336
+ rowText: { flex: 1, marginLeft: SPACING.md },
337
+ rowSub: { marginTop: moderateScale(2) },
338
+ center: {
339
+ flex: 1,
340
+ alignItems: "center",
341
+ justifyContent: "center",
342
+ },
343
+ searchingText: { marginTop: SPACING.sm },
344
+ resolveOverlay: {
345
+ position: "absolute",
346
+ top: 0,
347
+ left: 0,
348
+ right: 0,
349
+ bottom: 0,
350
+ backgroundColor: THEME.overlay,
351
+ alignItems: "center",
352
+ justifyContent: "center",
353
+ },
354
+ resolveCard: {
355
+ paddingHorizontal: SPACING.xxl,
356
+ paddingVertical: SPACING.xl,
357
+ borderRadius: SPACING.radiusLg,
358
+ backgroundColor: THEME.surface,
359
+ alignItems: "center",
360
+ },
361
+ resolveText: { marginTop: SPACING.md },
362
+ });
@@ -0,0 +1,115 @@
1
+ import React from "react";
2
+ import { FlatList, StyleSheet, TouchableOpacity, View } from "react-native";
3
+ import { useNavigation } from "@react-navigation/native";
4
+ import { useSelector } from "react-redux";
5
+ import { moderateScale } from "react-native-size-matters";
6
+ import {
7
+ Avatar,
8
+ Header,
9
+ MainContainer,
10
+ RNText,
11
+ Divider,
12
+ } from "../../components";
13
+ import { ArrowRightIcon } from "../../components/Icon/SvgIcons";
14
+ import { THEME } from "../../theme";
15
+ import { RootState } from "../../redux/store";
16
+ import RouteKey from "../../navigation/RouteKey";
17
+ import { useLanguage } from "../../localization";
18
+
19
+ const Messages: React.FC = () => {
20
+ const nav = useNavigation<any>();
21
+ const { t } = useLanguage();
22
+ const conversations = useSelector((s: RootState) => s.chat.conversations);
23
+
24
+ return (
25
+ <MainContainer gradient>
26
+ <Header safeArea={false} title={t("messages.title")} showBack={false} />
27
+ <FlatList
28
+ data={conversations}
29
+ keyExtractor={(c) => c.id}
30
+ contentContainerStyle={styles.list}
31
+ ItemSeparatorComponent={() => <Divider style={styles.separator} />}
32
+ renderItem={({ item }) => (
33
+ <TouchableOpacity
34
+ activeOpacity={0.7}
35
+ style={styles.row}
36
+ onPress={() =>
37
+ nav.navigate(RouteKey.Chat, {
38
+ conversationId: item.id,
39
+ title: item.name,
40
+ })
41
+ }
42
+ >
43
+ <Avatar name={item.name} size={moderateScale(56)} />
44
+ <View style={styles.info}>
45
+ <RNText font="semibold" size={16} color={THEME.text}>
46
+ {item.name}
47
+ </RNText>
48
+ <View style={styles.routeRow}>
49
+ <RNText size={14} color={THEME.text}>
50
+ {item.route.from}
51
+ </RNText>
52
+ <ArrowRightIcon
53
+ size={moderateScale(14)}
54
+ color={THEME.text}
55
+ />
56
+ <RNText size={14} color={THEME.text}>
57
+ {item.route.to}
58
+ </RNText>
59
+ </View>
60
+ <RNText size={12} color={THEME.labelBrown} style={styles.date}>
61
+ {item.lastTime}
62
+ </RNText>
63
+ </View>
64
+ {item.unread ? (
65
+ <View style={styles.badge}>
66
+ <RNText size={10} color="#fff" font="bold">
67
+ {item.unread}
68
+ </RNText>
69
+ </View>
70
+ ) : null}
71
+ </TouchableOpacity>
72
+ )}
73
+ />
74
+ </MainContainer>
75
+ );
76
+ };
77
+
78
+ export default Messages;
79
+
80
+ const styles = StyleSheet.create({
81
+ list: {
82
+ paddingHorizontal: moderateScale(20),
83
+ paddingTop: moderateScale(8),
84
+ paddingBottom: moderateScale(100),
85
+ },
86
+ separator: {
87
+ marginVertical: moderateScale(14),
88
+ },
89
+ row: {
90
+ flexDirection: "row",
91
+ alignItems: "center",
92
+ },
93
+ info: {
94
+ flex: 1,
95
+ marginLeft: moderateScale(14),
96
+ },
97
+ routeRow: {
98
+ flexDirection: "row",
99
+ alignItems: "center",
100
+ marginTop: moderateScale(2),
101
+ gap: moderateScale(6),
102
+ },
103
+ date: {
104
+ marginTop: moderateScale(4),
105
+ },
106
+ badge: {
107
+ minWidth: moderateScale(20),
108
+ height: moderateScale(20),
109
+ borderRadius: moderateScale(10),
110
+ paddingHorizontal: moderateScale(5),
111
+ alignItems: "center",
112
+ justifyContent: "center",
113
+ backgroundColor: THEME.primary,
114
+ },
115
+ });
@@ -0,0 +1,86 @@
1
+ import React from 'react';
2
+ import { ScrollView, StyleSheet, View } from 'react-native';
3
+ import { useDispatch, useSelector } from 'react-redux';
4
+ import {
5
+ Card,
6
+ Divider,
7
+ Header,
8
+ MainContainer,
9
+ RNText,
10
+ Toggle,
11
+ } from '../../components';
12
+ import { moderateScale } from 'react-native-size-matters';
13
+ import { THEME, SPACING, FONT_SIZE } from '../../theme';
14
+ import { RootState } from '../../redux/store';
15
+ import { setNotificationPref } from '../../redux/slice/app';
16
+ import { useLanguage } from '../../localization';
17
+
18
+ const Notifications: React.FC = () => {
19
+ const dispatch = useDispatch();
20
+ const { t } = useLanguage();
21
+ const prefs = useSelector((s: RootState) => s.app.notificationsEnabled);
22
+ return (
23
+ <MainContainer gradient statusBarStyle="dark-content">
24
+ <Header title={t('notifications.title')} safeArea={false} />
25
+ <ScrollView contentContainerStyle={styles.scroll}>
26
+ <Card padding={0}>
27
+ <Row
28
+ label={t('notifications.push')}
29
+ value={prefs.push}
30
+ onChange={v => dispatch(setNotificationPref({ push: v }))}
31
+ />
32
+ <Divider />
33
+ <Row
34
+ label={t('notifications.email')}
35
+ value={prefs.email}
36
+ onChange={v => dispatch(setNotificationPref({ email: v }))}
37
+ />
38
+ <Divider />
39
+ <Row
40
+ label={t('notifications.sms')}
41
+ value={prefs.sms}
42
+ onChange={v => dispatch(setNotificationPref({ sms: v }))}
43
+ />
44
+ </Card>
45
+ </ScrollView>
46
+ </MainContainer>
47
+ );
48
+ };
49
+
50
+ const Row = ({
51
+ label,
52
+ value,
53
+ onChange,
54
+ }: {
55
+ label: string;
56
+ value: boolean;
57
+ onChange: (v: boolean) => void;
58
+ }) => (
59
+ <View style={styles.row}>
60
+ <RNText
61
+ font="medium"
62
+ size={FONT_SIZE.base}
63
+ color={THEME.text}
64
+ style={styles.rowLabel}
65
+ >
66
+ {label}
67
+ </RNText>
68
+ <Toggle value={value} onChange={onChange} />
69
+ </View>
70
+ );
71
+
72
+ export default Notifications;
73
+
74
+ const styles = StyleSheet.create({
75
+ scroll: {
76
+ paddingHorizontal: SPACING.hPadding,
77
+ paddingBottom: moderateScale(60),
78
+ },
79
+ row: {
80
+ flexDirection: 'row',
81
+ alignItems: 'center',
82
+ paddingHorizontal: SPACING.lg,
83
+ paddingVertical: SPACING.lg,
84
+ },
85
+ rowLabel: { flex: 1 },
86
+ });