@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,393 @@
1
+ import React, { useEffect, useMemo, useState } from "react";
2
+ import { Pressable, StyleSheet, TouchableOpacity, View } from "react-native";
3
+ import Animated, {
4
+ FadeIn,
5
+ FadeOut,
6
+ Layout,
7
+ } from "react-native-reanimated";
8
+ import { moderateScale } from "react-native-size-matters";
9
+ import { SPACING, THEME } from "../../theme";
10
+ import { useLanguage } from "../../localization";
11
+ import BottomSheet from "../BottomSheet/BottomSheet";
12
+ import { RNButton, RNText } from "../index";
13
+ import {
14
+ ChevronLeftIcon,
15
+ ChevronRightIcon,
16
+ } from "../Icon/SvgIcons";
17
+
18
+ interface DatePickerSheetProps {
19
+ visible: boolean;
20
+ onClose: () => void;
21
+ value?: Date | null;
22
+ minimumDate?: Date;
23
+ maximumDate?: Date;
24
+ onConfirm: (date: Date) => void;
25
+ title?: string;
26
+ }
27
+
28
+ const WEEKDAY_LABELS = ["S", "M", "T", "W", "T", "F", "S"];
29
+ const MONTH_NAMES = [
30
+ "January",
31
+ "February",
32
+ "March",
33
+ "April",
34
+ "May",
35
+ "June",
36
+ "July",
37
+ "August",
38
+ "September",
39
+ "October",
40
+ "November",
41
+ "December",
42
+ ];
43
+
44
+ const startOfDay = (d: Date) => {
45
+ const copy = new Date(d);
46
+ copy.setHours(0, 0, 0, 0);
47
+ return copy;
48
+ };
49
+
50
+ const isSameDay = (a?: Date | null, b?: Date | null) => {
51
+ if (!a || !b) return false;
52
+ return (
53
+ a.getFullYear() === b.getFullYear() &&
54
+ a.getMonth() === b.getMonth() &&
55
+ a.getDate() === b.getDate()
56
+ );
57
+ };
58
+
59
+ const buildCalendar = (year: number, month: number) => {
60
+ const firstDay = new Date(year, month, 1);
61
+ const startWeekday = firstDay.getDay();
62
+ const daysInMonth = new Date(year, month + 1, 0).getDate();
63
+ const cells: (Date | null)[] = [];
64
+ for (let i = 0; i < startWeekday; i++) cells.push(null);
65
+ for (let d = 1; d <= daysInMonth; d++) {
66
+ cells.push(new Date(year, month, d));
67
+ }
68
+ while (cells.length % 7 !== 0) cells.push(null);
69
+ return cells;
70
+ };
71
+
72
+ const DatePickerSheet: React.FC<DatePickerSheetProps> = ({
73
+ visible,
74
+ onClose,
75
+ value,
76
+ minimumDate,
77
+ maximumDate,
78
+ onConfirm,
79
+ title,
80
+ }) => {
81
+ const { t } = useLanguage();
82
+ const titleText = title ?? t("common.selectDate");
83
+ const today = useMemo(() => startOfDay(new Date()), []);
84
+ const minDate = useMemo(
85
+ () => (minimumDate ? startOfDay(minimumDate) : today),
86
+ [minimumDate, today]
87
+ );
88
+ const maxDate = useMemo(
89
+ () => (maximumDate ? startOfDay(maximumDate) : null),
90
+ [maximumDate]
91
+ );
92
+
93
+ const initial = value ? startOfDay(value) : today;
94
+ const [selected, setSelected] = useState<Date>(initial);
95
+ const [viewMonth, setViewMonth] = useState<number>(initial.getMonth());
96
+ const [viewYear, setViewYear] = useState<number>(initial.getFullYear());
97
+
98
+ useEffect(() => {
99
+ if (visible) {
100
+ const start = value ? startOfDay(value) : today;
101
+ setSelected(start);
102
+ setViewMonth(start.getMonth());
103
+ setViewYear(start.getFullYear());
104
+ }
105
+ }, [visible, value, today]);
106
+
107
+ const cells = useMemo(
108
+ () => buildCalendar(viewYear, viewMonth),
109
+ [viewYear, viewMonth]
110
+ );
111
+
112
+ const canGoPrev = useMemo(() => {
113
+ const firstOfView = new Date(viewYear, viewMonth, 1);
114
+ const firstOfMin = new Date(minDate.getFullYear(), minDate.getMonth(), 1);
115
+ return firstOfView > firstOfMin;
116
+ }, [viewYear, viewMonth, minDate]);
117
+
118
+ const canGoNext = useMemo(() => {
119
+ if (!maxDate) return true;
120
+ const firstOfView = new Date(viewYear, viewMonth, 1);
121
+ const firstOfMax = new Date(maxDate.getFullYear(), maxDate.getMonth(), 1);
122
+ return firstOfView < firstOfMax;
123
+ }, [viewYear, viewMonth, maxDate]);
124
+
125
+ const goPrev = () => {
126
+ if (!canGoPrev) return;
127
+ if (viewMonth === 0) {
128
+ setViewMonth(11);
129
+ setViewYear((y) => y - 1);
130
+ } else {
131
+ setViewMonth((m) => m - 1);
132
+ }
133
+ };
134
+
135
+ const goNext = () => {
136
+ if (!canGoNext) return;
137
+ if (viewMonth === 11) {
138
+ setViewMonth(0);
139
+ setViewYear((y) => y + 1);
140
+ } else {
141
+ setViewMonth((m) => m + 1);
142
+ }
143
+ };
144
+
145
+ const setQuick = (offsetDays: number) => {
146
+ const next = startOfDay(new Date());
147
+ next.setDate(next.getDate() + offsetDays);
148
+ setSelected(next);
149
+ setViewMonth(next.getMonth());
150
+ setViewYear(next.getFullYear());
151
+ };
152
+
153
+ const todaySelected = isSameDay(selected, today);
154
+ const tomorrow = startOfDay(new Date(today));
155
+ tomorrow.setDate(tomorrow.getDate() + 1);
156
+ const tomorrowSelected = isSameDay(selected, tomorrow);
157
+
158
+ const handleConfirm = () => {
159
+ onConfirm(selected);
160
+ onClose();
161
+ };
162
+
163
+ return (
164
+ <BottomSheet visible={visible} onClose={onClose} contentStyle={styles.sheet}>
165
+ <View style={styles.header}>
166
+ <RNText font="semibold" size={18} color={THEME.text}>
167
+ {titleText}
168
+ </RNText>
169
+ </View>
170
+
171
+ <View style={styles.quickRow}>
172
+ <QuickChip
173
+ label={t("common.today")}
174
+ active={todaySelected}
175
+ onPress={() => setQuick(0)}
176
+ />
177
+ <QuickChip
178
+ label={t("common.tomorrow")}
179
+ active={tomorrowSelected}
180
+ onPress={() => setQuick(1)}
181
+ />
182
+ </View>
183
+
184
+ <View style={styles.monthRow}>
185
+ <TouchableOpacity
186
+ onPress={goPrev}
187
+ disabled={!canGoPrev}
188
+ activeOpacity={0.7}
189
+ style={[styles.navBtn, !canGoPrev && styles.navBtnDisabled]}
190
+ hitSlop={10}
191
+ >
192
+ <ChevronLeftIcon
193
+ size={moderateScale(16)}
194
+ color={canGoPrev ? THEME.primary : THEME.textPlaceholder}
195
+ />
196
+ </TouchableOpacity>
197
+ <Animated.View
198
+ key={`${viewMonth}-${viewYear}`}
199
+ entering={FadeIn.duration(180)}
200
+ exiting={FadeOut.duration(120)}
201
+ >
202
+ <RNText font="semibold" size={16} color={THEME.text}>
203
+ {MONTH_NAMES[viewMonth]} {viewYear}
204
+ </RNText>
205
+ </Animated.View>
206
+ <TouchableOpacity
207
+ onPress={goNext}
208
+ disabled={!canGoNext}
209
+ activeOpacity={0.7}
210
+ style={[styles.navBtn, !canGoNext && styles.navBtnDisabled]}
211
+ hitSlop={10}
212
+ >
213
+ <ChevronRightIcon
214
+ size={moderateScale(16)}
215
+ color={canGoNext ? THEME.primary : THEME.textPlaceholder}
216
+ />
217
+ </TouchableOpacity>
218
+ </View>
219
+
220
+ <View style={styles.weekRow}>
221
+ {WEEKDAY_LABELS.map((d, idx) => (
222
+ <View key={idx} style={styles.weekCell}>
223
+ <RNText size={11} font="medium" color={THEME.textMuted}>
224
+ {d}
225
+ </RNText>
226
+ </View>
227
+ ))}
228
+ </View>
229
+
230
+ <Animated.View
231
+ key={`grid-${viewMonth}-${viewYear}`}
232
+ entering={FadeIn.duration(160)}
233
+ layout={Layout.duration(140)}
234
+ style={styles.grid}
235
+ >
236
+ {cells.map((date, idx) => {
237
+ if (!date) {
238
+ return <View key={`e-${idx}`} style={styles.dayCell} />;
239
+ }
240
+ const disabled =
241
+ date < minDate || (maxDate ? date > maxDate : false);
242
+ const isToday = isSameDay(date, today);
243
+ const isSelected = isSameDay(date, selected);
244
+ return (
245
+ <View key={date.toISOString()} style={styles.dayCell}>
246
+ <Pressable
247
+ onPress={() => !disabled && setSelected(date)}
248
+ disabled={disabled}
249
+ style={({ pressed }) => [
250
+ styles.dayBtn,
251
+ isSelected && styles.dayBtnSelected,
252
+ isToday && !isSelected && styles.dayBtnToday,
253
+ pressed && !disabled && !isSelected && styles.dayBtnPressed,
254
+ ]}
255
+ >
256
+ <RNText
257
+ size={14}
258
+ font={isSelected ? "semibold" : isToday ? "semibold" : "regular"}
259
+ color={
260
+ disabled
261
+ ? THEME.textPlaceholder
262
+ : isSelected
263
+ ? THEME.textOnPrimary
264
+ : isToday
265
+ ? THEME.primary
266
+ : THEME.text
267
+ }
268
+ >
269
+ {date.getDate()}
270
+ </RNText>
271
+ </Pressable>
272
+ </View>
273
+ );
274
+ })}
275
+ </Animated.View>
276
+
277
+ <RNButton
278
+ title={t("common.confirm")}
279
+ onPress={handleConfirm}
280
+ containerStyle={styles.confirmBtn}
281
+ />
282
+ </BottomSheet>
283
+ );
284
+ };
285
+
286
+ const QuickChip = ({
287
+ label,
288
+ active,
289
+ onPress,
290
+ }: {
291
+ label: string;
292
+ active: boolean;
293
+ onPress: () => void;
294
+ }) => (
295
+ <TouchableOpacity
296
+ onPress={onPress}
297
+ activeOpacity={0.8}
298
+ style={[styles.chip, active && styles.chipActive]}
299
+ >
300
+ <RNText
301
+ size={13}
302
+ font="medium"
303
+ color={active ? THEME.textOnPrimary : THEME.text}
304
+ >
305
+ {label}
306
+ </RNText>
307
+ </TouchableOpacity>
308
+ );
309
+
310
+ export default DatePickerSheet;
311
+
312
+ const styles = StyleSheet.create({
313
+ sheet: {
314
+ paddingHorizontal: SPACING.lg,
315
+ paddingBottom: SPACING.xl,
316
+ },
317
+ header: {
318
+ alignItems: "center",
319
+ marginBottom: moderateScale(12),
320
+ },
321
+ quickRow: {
322
+ flexDirection: "row",
323
+ gap: moderateScale(8),
324
+ marginBottom: moderateScale(16),
325
+ },
326
+ chip: {
327
+ paddingVertical: moderateScale(8),
328
+ paddingHorizontal: moderateScale(16),
329
+ borderRadius: moderateScale(20),
330
+ backgroundColor: THEME.primaryFaint,
331
+ borderWidth: 1,
332
+ borderColor: THEME.primaryLight,
333
+ },
334
+ chipActive: {
335
+ backgroundColor: THEME.primary,
336
+ borderColor: THEME.primary,
337
+ },
338
+ monthRow: {
339
+ flexDirection: "row",
340
+ alignItems: "center",
341
+ justifyContent: "space-between",
342
+ marginBottom: moderateScale(12),
343
+ paddingHorizontal: moderateScale(4),
344
+ },
345
+ navBtn: {
346
+ width: moderateScale(34),
347
+ height: moderateScale(34),
348
+ borderRadius: moderateScale(17),
349
+ backgroundColor: THEME.primaryFaint,
350
+ alignItems: "center",
351
+ justifyContent: "center",
352
+ },
353
+ navBtnDisabled: {
354
+ backgroundColor: THEME.surfaceMuted,
355
+ },
356
+ weekRow: {
357
+ flexDirection: "row",
358
+ marginBottom: moderateScale(6),
359
+ },
360
+ weekCell: {
361
+ flex: 1,
362
+ alignItems: "center",
363
+ paddingVertical: moderateScale(6),
364
+ },
365
+ grid: {
366
+ flexDirection: "row",
367
+ flexWrap: "wrap",
368
+ },
369
+ dayCell: {
370
+ width: `${100 / 7}%`,
371
+ aspectRatio: 1,
372
+ padding: moderateScale(3),
373
+ },
374
+ dayBtn: {
375
+ flex: 1,
376
+ borderRadius: moderateScale(999),
377
+ alignItems: "center",
378
+ justifyContent: "center",
379
+ },
380
+ dayBtnSelected: {
381
+ backgroundColor: THEME.primary,
382
+ },
383
+ dayBtnToday: {
384
+ borderWidth: 1.2,
385
+ borderColor: THEME.primary,
386
+ },
387
+ dayBtnPressed: {
388
+ backgroundColor: THEME.primaryFaint,
389
+ },
390
+ confirmBtn: {
391
+ marginTop: moderateScale(16),
392
+ },
393
+ });
@@ -0,0 +1,237 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { Pressable, StyleSheet, View } from "react-native";
3
+ import Animated, {
4
+ useAnimatedStyle,
5
+ useSharedValue,
6
+ withSpring,
7
+ } from "react-native-reanimated";
8
+ import { moderateScale } from "react-native-size-matters";
9
+ import { SPACING, THEME } from "../../theme";
10
+ import { useLanguage } from "../../localization";
11
+ import BottomSheet from "../BottomSheet/BottomSheet";
12
+ import { RNButton, RNText } from "../index";
13
+ import {
14
+ MinusIcon,
15
+ PlusIcon,
16
+ UserOutlineIcon,
17
+ } from "../Icon/SvgIcons";
18
+
19
+ interface PassengerPickerSheetProps {
20
+ visible: boolean;
21
+ onClose: () => void;
22
+ value: number;
23
+ onConfirm: (count: number) => void;
24
+ min?: number;
25
+ max?: number;
26
+ title?: string;
27
+ subtitle?: string;
28
+ }
29
+
30
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
31
+
32
+ const PassengerPickerSheet: React.FC<PassengerPickerSheetProps> = ({
33
+ visible,
34
+ onClose,
35
+ value,
36
+ onConfirm,
37
+ min = 1,
38
+ max = 8,
39
+ title,
40
+ subtitle,
41
+ }) => {
42
+ const { t } = useLanguage();
43
+ const titleText = title ?? t("home.passengers");
44
+ const subtitleText = subtitle ?? t("home.passengersSubtitle");
45
+ const [count, setCount] = useState<number>(value);
46
+
47
+ useEffect(() => {
48
+ if (visible) setCount(value);
49
+ }, [visible, value]);
50
+
51
+ const decrement = () => {
52
+ if (count <= min) return;
53
+ setCount((c) => c - 1);
54
+ };
55
+
56
+ const increment = () => {
57
+ if (count >= max) return;
58
+ setCount((c) => c + 1);
59
+ };
60
+
61
+ const handleConfirm = () => {
62
+ onConfirm(count);
63
+ onClose();
64
+ };
65
+
66
+ const decDisabled = count <= min;
67
+ const incDisabled = count >= max;
68
+
69
+ return (
70
+ <BottomSheet visible={visible} onClose={onClose} contentStyle={styles.sheet}>
71
+ <View style={styles.header}>
72
+ <RNText font="semibold" size={18} color={THEME.text}>
73
+ {titleText}
74
+ </RNText>
75
+ <RNText
76
+ size={13}
77
+ color={THEME.textMuted}
78
+ style={styles.subtitle}
79
+ textAlign="center"
80
+ >
81
+ {subtitleText}
82
+ </RNText>
83
+ </View>
84
+
85
+ <View style={styles.stepper}>
86
+ <StepperButton
87
+ icon={
88
+ <MinusIcon
89
+ size={moderateScale(20)}
90
+ color={decDisabled ? THEME.textPlaceholder : THEME.primary}
91
+ />
92
+ }
93
+ disabled={decDisabled}
94
+ onPress={decrement}
95
+ />
96
+
97
+ <View style={styles.counterWrap}>
98
+ <View style={styles.counterInner}>
99
+ <UserOutlineIcon
100
+ size={moderateScale(20)}
101
+ color={THEME.primary}
102
+ />
103
+ <RNText
104
+ font="bold"
105
+ size={36}
106
+ color={THEME.text}
107
+ style={styles.counterText}
108
+ >
109
+ {count}
110
+ </RNText>
111
+ </View>
112
+ <RNText size={12} color={THEME.textMuted} style={styles.counterLabel}>
113
+ {count === 1 ? t("role.passenger") : t("home.passengers")}
114
+ </RNText>
115
+ </View>
116
+
117
+ <StepperButton
118
+ icon={
119
+ <PlusIcon
120
+ size={moderateScale(20)}
121
+ color={incDisabled ? THEME.textPlaceholder : THEME.primary}
122
+ />
123
+ }
124
+ disabled={incDisabled}
125
+ onPress={increment}
126
+ />
127
+ </View>
128
+
129
+ <RNText
130
+ size={11}
131
+ color={THEME.textMuted}
132
+ textAlign="center"
133
+ style={styles.limitHint}
134
+ >
135
+ Min {min} · Max {max}
136
+ </RNText>
137
+
138
+ <RNButton
139
+ title={t("common.apply")}
140
+ onPress={handleConfirm}
141
+ containerStyle={styles.applyBtn}
142
+ />
143
+ </BottomSheet>
144
+ );
145
+ };
146
+
147
+ const StepperButton = ({
148
+ icon,
149
+ onPress,
150
+ disabled,
151
+ }: {
152
+ icon: React.ReactNode;
153
+ onPress: () => void;
154
+ disabled: boolean;
155
+ }) => {
156
+ const scale = useSharedValue(1);
157
+ const style = useAnimatedStyle(() => ({
158
+ transform: [{ scale: scale.value }],
159
+ }));
160
+
161
+ return (
162
+ <AnimatedPressable
163
+ onPress={onPress}
164
+ disabled={disabled}
165
+ onPressIn={() => {
166
+ if (disabled) return;
167
+ scale.value = withSpring(0.9, { mass: 0.3, damping: 12 });
168
+ }}
169
+ onPressOut={() => {
170
+ scale.value = withSpring(1, { mass: 0.3, damping: 12 });
171
+ }}
172
+ style={[
173
+ styles.stepBtn,
174
+ disabled && styles.stepBtnDisabled,
175
+ style,
176
+ ]}
177
+ >
178
+ {icon}
179
+ </AnimatedPressable>
180
+ );
181
+ };
182
+
183
+ export default PassengerPickerSheet;
184
+
185
+ const styles = StyleSheet.create({
186
+ sheet: {
187
+ paddingHorizontal: SPACING.xl,
188
+ paddingBottom: SPACING.xl,
189
+ },
190
+ header: {
191
+ alignItems: "center",
192
+ marginBottom: moderateScale(24),
193
+ },
194
+ subtitle: {
195
+ marginTop: moderateScale(6),
196
+ },
197
+ stepper: {
198
+ flexDirection: "row",
199
+ alignItems: "center",
200
+ justifyContent: "space-between",
201
+ paddingHorizontal: moderateScale(8),
202
+ },
203
+ stepBtn: {
204
+ width: moderateScale(56),
205
+ height: moderateScale(56),
206
+ borderRadius: moderateScale(28),
207
+ backgroundColor: THEME.primaryFaint,
208
+ borderWidth: 1,
209
+ borderColor: THEME.primaryLight,
210
+ alignItems: "center",
211
+ justifyContent: "center",
212
+ },
213
+ stepBtnDisabled: {
214
+ backgroundColor: THEME.surfaceMuted,
215
+ borderColor: THEME.divider,
216
+ },
217
+ counterWrap: {
218
+ flex: 1,
219
+ alignItems: "center",
220
+ },
221
+ counterInner: {
222
+ flexDirection: "row",
223
+ alignItems: "center",
224
+ },
225
+ counterText: {
226
+ marginLeft: moderateScale(8),
227
+ },
228
+ counterLabel: {
229
+ marginTop: moderateScale(4),
230
+ },
231
+ limitHint: {
232
+ marginTop: moderateScale(16),
233
+ },
234
+ applyBtn: {
235
+ marginTop: moderateScale(20),
236
+ },
237
+ });
@@ -0,0 +1,62 @@
1
+ import React from "react";
2
+ import { Text, TextProps, TextStyle, StyleProp } from "react-native";
3
+ import { moderateScale } from "react-native-size-matters";
4
+ import { FONTS, THEME } from "../../theme";
5
+
6
+ type FontKey =
7
+ | "light"
8
+ | "regular"
9
+ | "italic"
10
+ | "medium"
11
+ | "semibold"
12
+ | "bold"
13
+ | "extraBold"
14
+ | "black";
15
+
16
+ interface RNTextProps extends TextProps {
17
+ size?: number;
18
+ font?: FontKey;
19
+ color?: string;
20
+ textAlign?: TextStyle["textAlign"];
21
+ lineHeight?: number;
22
+ letterSpacing?: number;
23
+ style?: StyleProp<TextStyle>;
24
+ }
25
+
26
+ const RNText: React.FC<RNTextProps> = ({
27
+ size = 14,
28
+ font = "regular",
29
+ color = THEME.text,
30
+ textAlign,
31
+ lineHeight,
32
+ letterSpacing,
33
+ style,
34
+ children,
35
+ ...rest
36
+ }) => {
37
+ const fontSize = moderateScale(size, 0.3);
38
+ const fontFamily = FONTS[font] || FONTS.regular;
39
+
40
+ return (
41
+ <Text
42
+ allowFontScaling={false}
43
+ {...rest}
44
+ style={[
45
+ {
46
+ fontFamily,
47
+ fontSize,
48
+ color,
49
+ textAlign,
50
+ lineHeight,
51
+ letterSpacing,
52
+ },
53
+ style,
54
+ ]}
55
+ >
56
+ {children}
57
+ </Text>
58
+ );
59
+ };
60
+
61
+ export default RNText;
62
+ export type { RNTextProps };
@@ -0,0 +1 @@
1
+ export {default as RNText} from "./RNText"