@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,344 @@
1
+ import React, { useCallback } from "react";
2
+ import { Linking, StyleSheet, TouchableOpacity, View } from "react-native";
3
+ import { moderateScale } from "react-native-size-matters";
4
+ import BottomSheet from "../BottomSheet/BottomSheet";
5
+ import RNButton from "../Button/RNButton";
6
+ import RNText from "../Text/RNText";
7
+ import {
8
+ CloseIcon,
9
+ PhoneIcon,
10
+ PlusIcon,
11
+ ShieldCheckIcon,
12
+ UserCircleIcon,
13
+ } from "../Icon/SvgIcons";
14
+ import { THEME } from "../../theme";
15
+ import { useLanguage } from "../../localization";
16
+ import { showToast } from "../../utils/functions";
17
+
18
+ export interface EmergencyService {
19
+ id: string;
20
+ /** Localized display name. */
21
+ name: string;
22
+ /** Dialable number. */
23
+ number: string;
24
+ /** Accent color for the leading icon. */
25
+ color: string;
26
+ /** Soft background tint for the leading icon. */
27
+ tint: string;
28
+ }
29
+
30
+ export interface TrustedContact {
31
+ id: string;
32
+ name: string;
33
+ number: string;
34
+ }
35
+
36
+ interface SosSheetProps {
37
+ visible: boolean;
38
+ onClose: () => void;
39
+ /** Emergency services list — falls back to local defaults when omitted. */
40
+ services?: EmergencyService[];
41
+ trustedContacts?: TrustedContact[];
42
+ /** Number dialed by the big primary CTA. Defaults to the universal 112. */
43
+ primaryNumber?: string;
44
+ onAddTrustedContact?: () => void;
45
+ }
46
+
47
+ const sanitize = (number: string) => number.replace(/[^\d+]/g, "");
48
+
49
+ /**
50
+ * Premium emergency action sheet: emergency services with one-tap call,
51
+ * a trusted-contacts section and a prominent "call emergency" CTA.
52
+ * Reusable across screens — pass `services` / `trustedContacts` to customize.
53
+ */
54
+ const SosSheet: React.FC<SosSheetProps> = ({
55
+ visible,
56
+ onClose,
57
+ services,
58
+ trustedContacts = [],
59
+ primaryNumber = "112",
60
+ onAddTrustedContact,
61
+ }) => {
62
+ const { t } = useLanguage();
63
+
64
+ const defaultServices: EmergencyService[] = [
65
+ {
66
+ id: "police",
67
+ name: t("sos.police"),
68
+ number: "117",
69
+ color: THEME.danger,
70
+ tint: THEME.dangerLight,
71
+ },
72
+ {
73
+ id: "ambulance",
74
+ name: t("sos.ambulance"),
75
+ number: "119",
76
+ color: THEME.info,
77
+ tint: "#E8F1FF",
78
+ },
79
+ {
80
+ id: "fire",
81
+ name: t("sos.fire"),
82
+ number: "118",
83
+ color: THEME.warning,
84
+ tint: THEME.warningLight,
85
+ },
86
+ ];
87
+
88
+ const list = services ?? defaultServices;
89
+
90
+ const call = useCallback(
91
+ (number: string) => {
92
+ const url = `tel:${sanitize(number)}`;
93
+ Linking.openURL(url).catch(() => showToast(t("sos.callFailed"), "danger"));
94
+ },
95
+ [t],
96
+ );
97
+
98
+ return (
99
+ <BottomSheet visible={visible} onClose={onClose} contentStyle={styles.sheet}>
100
+ {/* Header */}
101
+ <View style={styles.headerRow}>
102
+ <View style={styles.headerBadge}>
103
+ <ShieldCheckIcon size={moderateScale(22)} color={THEME.textOnPrimary} />
104
+ </View>
105
+ <View style={styles.headerText}>
106
+ <RNText font="bold" size={18} color={THEME.text}>
107
+ {t("sos.title")}
108
+ </RNText>
109
+ <RNText size={12} color={THEME.textMuted} style={styles.headerSubtitle}>
110
+ {t("sos.subtitle")}
111
+ </RNText>
112
+ </View>
113
+ <TouchableOpacity
114
+ onPress={onClose}
115
+ hitSlop={10}
116
+ style={styles.closeBtn}
117
+ activeOpacity={0.7}
118
+ >
119
+ <CloseIcon size={moderateScale(18)} color={THEME.textMuted} />
120
+ </TouchableOpacity>
121
+ </View>
122
+
123
+ {/* Warning */}
124
+ <View style={styles.warning}>
125
+ <RNText size={12} color={THEME.danger} style={styles.warningText}>
126
+ {t("sos.warning")}
127
+ </RNText>
128
+ </View>
129
+
130
+ {/* Emergency services */}
131
+ <RNText font="semibold" size={13} color={THEME.text} style={styles.sectionLabel}>
132
+ {t("sos.emergencyServices")}
133
+ </RNText>
134
+ {list.map((s) => (
135
+ <View key={s.id} style={styles.row}>
136
+ <View style={[styles.rowIcon, { backgroundColor: s.tint }]}>
137
+ <PhoneIcon size={moderateScale(18)} color={s.color} />
138
+ </View>
139
+ <View style={styles.rowInfo}>
140
+ <RNText font="semibold" size={14} color={THEME.text}>
141
+ {s.name}
142
+ </RNText>
143
+ <RNText size={12} color={THEME.textMuted} style={styles.rowSub}>
144
+ {s.number}
145
+ </RNText>
146
+ </View>
147
+ <TouchableOpacity
148
+ onPress={() => call(s.number)}
149
+ activeOpacity={0.85}
150
+ style={styles.callPill}
151
+ >
152
+ <PhoneIcon size={moderateScale(14)} color={THEME.textOnPrimary} />
153
+ <RNText
154
+ font="semibold"
155
+ size={12}
156
+ color={THEME.textOnPrimary}
157
+ style={styles.callPillText}
158
+ >
159
+ {t("sos.call")}
160
+ </RNText>
161
+ </TouchableOpacity>
162
+ </View>
163
+ ))}
164
+
165
+ <View style={styles.divider} />
166
+
167
+ {/* Trusted contacts */}
168
+ <RNText font="semibold" size={13} color={THEME.text} style={styles.sectionLabel}>
169
+ {t("sos.trustedContacts")}
170
+ </RNText>
171
+ {trustedContacts.length > 0 ? (
172
+ trustedContacts.map((c) => (
173
+ <View key={c.id} style={styles.row}>
174
+ <View style={styles.trustedIcon}>
175
+ <UserCircleIcon size={moderateScale(22)} color={THEME.primary} />
176
+ </View>
177
+ <View style={styles.rowInfo}>
178
+ <RNText font="semibold" size={14} color={THEME.text}>
179
+ {c.name}
180
+ </RNText>
181
+ <RNText size={12} color={THEME.textMuted} style={styles.rowSub}>
182
+ {c.number}
183
+ </RNText>
184
+ </View>
185
+ <TouchableOpacity
186
+ onPress={() => call(c.number)}
187
+ activeOpacity={0.85}
188
+ style={styles.callPill}
189
+ >
190
+ <PhoneIcon size={moderateScale(14)} color={THEME.textOnPrimary} />
191
+ <RNText
192
+ font="semibold"
193
+ size={12}
194
+ color={THEME.textOnPrimary}
195
+ style={styles.callPillText}
196
+ >
197
+ {t("sos.call")}
198
+ </RNText>
199
+ </TouchableOpacity>
200
+ </View>
201
+ ))
202
+ ) : (
203
+ <RNText size={12} color={THEME.textMuted} style={styles.emptyTrusted}>
204
+ {t("sos.noTrustedContacts")}
205
+ </RNText>
206
+ )}
207
+
208
+ {/* <TouchableOpacity
209
+ onPress={onAddTrustedContact}
210
+ activeOpacity={0.8}
211
+ style={styles.addRow}
212
+ >
213
+ <View style={styles.addPlus}>
214
+ <PlusIcon size={moderateScale(15)} color={THEME.primary} />
215
+ </View>
216
+ <RNText font="semibold" size={13} color={THEME.primary}>
217
+ {t("sos.addTrustedContact")}
218
+ </RNText>
219
+ </TouchableOpacity> */}
220
+
221
+ {/* Primary CTA */}
222
+ <RNButton
223
+ title={t("sos.callEmergency", { number: primaryNumber })}
224
+ onPress={() => call(primaryNumber)}
225
+ containerStyle={styles.emergencyBtn}
226
+ leftIcon={
227
+ <PhoneIcon size={moderateScale(18)} color={THEME.textOnPrimary} />
228
+ }
229
+ />
230
+ </BottomSheet>
231
+ );
232
+ };
233
+
234
+ export default React.memo(SosSheet);
235
+
236
+ const styles = StyleSheet.create({
237
+ sheet: {
238
+ paddingBottom: moderateScale(20),
239
+ },
240
+ headerRow: {
241
+ flexDirection: "row",
242
+ alignItems: "center",
243
+ },
244
+ headerBadge: {
245
+ width: moderateScale(44),
246
+ height: moderateScale(44),
247
+ borderRadius: moderateScale(22),
248
+ backgroundColor: THEME.danger,
249
+ alignItems: "center",
250
+ justifyContent: "center",
251
+ },
252
+ headerText: {
253
+ flex: 1,
254
+ marginLeft: moderateScale(12),
255
+ },
256
+ headerSubtitle: {
257
+ marginTop: moderateScale(2),
258
+ },
259
+ closeBtn: {
260
+ width: moderateScale(32),
261
+ height: moderateScale(32),
262
+ borderRadius: moderateScale(16),
263
+ backgroundColor: THEME.surfaceMuted,
264
+ alignItems: "center",
265
+ justifyContent: "center",
266
+ },
267
+ warning: {
268
+ backgroundColor: THEME.dangerLight,
269
+ borderRadius: moderateScale(12),
270
+ padding: moderateScale(12),
271
+ marginTop: moderateScale(16),
272
+ },
273
+ warningText: {
274
+ lineHeight: moderateScale(17),
275
+ },
276
+ sectionLabel: {
277
+ marginTop: moderateScale(20),
278
+ marginBottom: moderateScale(10),
279
+ },
280
+ row: {
281
+ flexDirection: "row",
282
+ alignItems: "center",
283
+ paddingVertical: moderateScale(8),
284
+ },
285
+ rowIcon: {
286
+ width: moderateScale(40),
287
+ height: moderateScale(40),
288
+ borderRadius: moderateScale(20),
289
+ alignItems: "center",
290
+ justifyContent: "center",
291
+ },
292
+ trustedIcon: {
293
+ width: moderateScale(40),
294
+ height: moderateScale(40),
295
+ borderRadius: moderateScale(20),
296
+ backgroundColor: THEME.primaryFaint,
297
+ alignItems: "center",
298
+ justifyContent: "center",
299
+ },
300
+ rowInfo: {
301
+ flex: 1,
302
+ marginLeft: moderateScale(12),
303
+ },
304
+ rowSub: {
305
+ marginTop: moderateScale(2),
306
+ },
307
+ callPill: {
308
+ flexDirection: "row",
309
+ alignItems: "center",
310
+ backgroundColor: THEME.success,
311
+ paddingHorizontal: moderateScale(14),
312
+ paddingVertical: moderateScale(8),
313
+ borderRadius: moderateScale(999),
314
+ },
315
+ callPillText: {
316
+ marginLeft: moderateScale(6),
317
+ },
318
+ divider: {
319
+ height: 1,
320
+ backgroundColor: THEME.divider,
321
+ marginTop: moderateScale(14),
322
+ },
323
+ emptyTrusted: {
324
+ lineHeight: moderateScale(17),
325
+ },
326
+ addRow: {
327
+ flexDirection: "row",
328
+ alignItems: "center",
329
+ marginTop: moderateScale(12),
330
+ },
331
+ addPlus: {
332
+ width: moderateScale(26),
333
+ height: moderateScale(26),
334
+ borderRadius: moderateScale(13),
335
+ backgroundColor: THEME.primaryFaint,
336
+ alignItems: "center",
337
+ justifyContent: "center",
338
+ marginRight: moderateScale(8),
339
+ },
340
+ emergencyBtn: {
341
+ backgroundColor: THEME.danger,
342
+ marginTop: moderateScale(22),
343
+ },
344
+ });
@@ -0,0 +1,58 @@
1
+ import React from "react";
2
+ import { Pressable, StyleSheet, View } from "react-native";
3
+ import Svg, { Path } from "react-native-svg";
4
+ import { THEME } from "../../theme";
5
+
6
+ interface StarRatingProps {
7
+ value: number;
8
+ total?: number;
9
+ size?: number;
10
+ spacing?: number;
11
+ onChange?: (n: number) => void;
12
+ color?: string;
13
+ inactiveColor?: string;
14
+ disabled?: boolean;
15
+ }
16
+
17
+ const Star = ({ size, color }: { size: number; color: string }) => (
18
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
19
+ <Path
20
+ d="M12 2.5l2.97 6.02 6.65.97-4.81 4.69 1.14 6.62L12 17.77 6.05 20.8l1.14-6.62L2.38 9.49l6.65-.97L12 2.5Z"
21
+ fill={color}
22
+ />
23
+ </Svg>
24
+ );
25
+
26
+ const StarRating: React.FC<StarRatingProps> = ({
27
+ value,
28
+ total = 5,
29
+ size = 20,
30
+ spacing = 4,
31
+ onChange,
32
+ color = THEME.star,
33
+ inactiveColor = THEME.unselectedStar,
34
+ disabled,
35
+ }) => (
36
+ <View style={styles.row}>
37
+ {Array.from({ length: total }).map((_, i) => {
38
+ const active = i < value;
39
+ return (
40
+ <Pressable
41
+ key={i}
42
+ disabled={disabled || !onChange}
43
+ onPress={() => onChange?.(i + 1)}
44
+ style={{ marginRight: i === total - 1 ? 0 : spacing }}
45
+ hitSlop={6}
46
+ >
47
+ <Star size={size} color={active ? color : inactiveColor} />
48
+ </Pressable>
49
+ );
50
+ })}
51
+ </View>
52
+ );
53
+
54
+ export default StarRating;
55
+
56
+ const styles = StyleSheet.create({
57
+ row: { flexDirection: "row", alignItems: "center" },
58
+ });
@@ -0,0 +1,56 @@
1
+ import React from "react";
2
+ import { StyleSheet, View } from "react-native";
3
+ import { moderateScale } from "react-native-size-matters";
4
+ import { SPACING, THEME } from "../../theme";
5
+ import RNText from "../Text/RNText";
6
+
7
+ type Tone = "success" | "warning" | "danger" | "info" | "primary";
8
+
9
+ interface StatusBadgeProps {
10
+ label: string;
11
+ tone?: Tone;
12
+ dot?: boolean;
13
+ }
14
+
15
+ const PALETTE: Record<Tone, { bg: string; fg: string }> = {
16
+ success: { bg: THEME.successLight, fg: THEME.success },
17
+ warning: { bg: THEME.warningLight, fg: THEME.warning },
18
+ danger: { bg: THEME.dangerLight, fg: THEME.danger },
19
+ info: { bg: "#E6F0FF", fg: THEME.info },
20
+ primary: { bg: THEME.primaryFaint, fg: THEME.primary },
21
+ };
22
+
23
+ const StatusBadge: React.FC<StatusBadgeProps> = ({
24
+ label,
25
+ tone = "success",
26
+ dot,
27
+ }) => {
28
+ const p = PALETTE[tone];
29
+ return (
30
+ <View style={[styles.badge, { backgroundColor: p.bg }]}>
31
+ {dot ? <View style={[styles.dot, { backgroundColor: p.fg }]} /> : null}
32
+ <RNText font="medium" size={11} color={p.fg}>
33
+ {label}
34
+ </RNText>
35
+ </View>
36
+ );
37
+ };
38
+
39
+ export default StatusBadge;
40
+
41
+ const styles = StyleSheet.create({
42
+ badge: {
43
+ flexDirection: "row",
44
+ alignItems: "center",
45
+ gap: moderateScale(6),
46
+ paddingHorizontal: moderateScale(8),
47
+ paddingVertical: moderateScale(4),
48
+ borderRadius: SPACING.radiusPill,
49
+ alignSelf: "flex-start",
50
+ },
51
+ dot: {
52
+ width: moderateScale(6),
53
+ height: moderateScale(6),
54
+ borderRadius: moderateScale(3),
55
+ },
56
+ });
@@ -0,0 +1,66 @@
1
+ import React, { useEffect } from "react";
2
+ import { Pressable, StyleSheet } from "react-native";
3
+ import Animated, {
4
+ Easing,
5
+ useAnimatedStyle,
6
+ useSharedValue,
7
+ withTiming,
8
+ } from "react-native-reanimated";
9
+ import { moderateScale } from "react-native-size-matters";
10
+ import { THEME } from "../../theme";
11
+
12
+ interface ToggleProps {
13
+ value: boolean;
14
+ onChange: (v: boolean) => void;
15
+ disabled?: boolean;
16
+ }
17
+
18
+ const Toggle: React.FC<ToggleProps> = ({ value, onChange, disabled }) => {
19
+ const tx = useSharedValue(value ? moderateScale(22) : 0);
20
+
21
+ useEffect(() => {
22
+ tx.value = withTiming(value ? moderateScale(22) : 0, {
23
+ duration: 160,
24
+ easing: Easing.out(Easing.cubic),
25
+ });
26
+ }, [tx, value]);
27
+
28
+ const thumb = useAnimatedStyle(() => ({
29
+ transform: [{ translateX: tx.value }],
30
+ }));
31
+
32
+ return (
33
+ <Pressable
34
+ disabled={disabled}
35
+ onPress={() => onChange(!value)}
36
+ hitSlop={6}
37
+ style={[
38
+ styles.track,
39
+ {
40
+ backgroundColor: value ? THEME.primary : "#E2D7CB",
41
+ opacity: disabled ? 0.4 : 1,
42
+ },
43
+ ]}
44
+ >
45
+ <Animated.View style={[styles.thumb, thumb]} />
46
+ </Pressable>
47
+ );
48
+ };
49
+
50
+ export default Toggle;
51
+
52
+ const styles = StyleSheet.create({
53
+ track: {
54
+ width: moderateScale(48),
55
+ height: moderateScale(28),
56
+ borderRadius: moderateScale(14),
57
+ padding: moderateScale(3),
58
+ justifyContent: "center",
59
+ },
60
+ thumb: {
61
+ width: moderateScale(20),
62
+ height: moderateScale(20),
63
+ borderRadius: moderateScale(11),
64
+ backgroundColor: "#FFFFFF",
65
+ },
66
+ });