@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,23 @@
1
+ import React from "react";
2
+ import { ActivityIndicator, StyleSheet, View } from "react-native";
3
+ import { THEME } from "../../theme";
4
+
5
+ interface LoaderProps {
6
+ size?: "small" | "large";
7
+ color?: string;
8
+ }
9
+
10
+ const Loader: React.FC<LoaderProps> = ({
11
+ size = "large",
12
+ color = THEME.primary,
13
+ }) => (
14
+ <View style={styles.center}>
15
+ <ActivityIndicator size={size} color={color} />
16
+ </View>
17
+ );
18
+
19
+ export default Loader;
20
+
21
+ const styles = StyleSheet.create({
22
+ center: { flex: 1, alignItems: "center", justifyContent: "center" },
23
+ });
@@ -0,0 +1,103 @@
1
+ import React, { useCallback, useRef } from "react";
2
+ import { Animated, StyleSheet, TouchableWithoutFeedback, View } from "react-native";
3
+ import Svg, { Path } from "react-native-svg";
4
+ import { moderateScale } from "react-native-size-matters";
5
+ import { THEME } from "../../theme";
6
+
7
+ /** Five-pointed star outline path on a 24x24 grid. */
8
+ const STAR_PATH =
9
+ "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";
10
+
11
+ interface RatingStarsProps {
12
+ /** Currently selected rating (0 - `count`). */
13
+ rating: number;
14
+ /** Fired with the new rating (1 - `count`) when a star is tapped. */
15
+ onChange?: (value: number) => void;
16
+ count?: number;
17
+ size?: number;
18
+ /** Fill colour used for selected stars. */
19
+ color?: string;
20
+ /** Outline colour used for unselected stars. */
21
+ emptyColor?: string;
22
+ }
23
+
24
+ /**
25
+ * Animated, tappable star rating. Each star "pops" with a spring when selected,
26
+ * keeping the rating interaction smooth and premium. Reusable across the app.
27
+ */
28
+ const RatingStars: React.FC<RatingStarsProps> = ({
29
+ rating,
30
+ onChange,
31
+ count = 5,
32
+ size = moderateScale(34),
33
+ color = THEME.primary,
34
+ emptyColor = THEME.primaryLight,
35
+ }) => {
36
+ const scales = useRef(
37
+ Array.from({ length: count }, () => new Animated.Value(1)),
38
+ ).current;
39
+
40
+ const handlePress = useCallback(
41
+ (index: number) => {
42
+ if (!onChange) return;
43
+ Animated.sequence([
44
+ Animated.spring(scales[index], {
45
+ toValue: 1.3,
46
+ useNativeDriver: true,
47
+ speed: 60,
48
+ bounciness: 14,
49
+ }),
50
+ Animated.spring(scales[index], {
51
+ toValue: 1,
52
+ useNativeDriver: true,
53
+ speed: 20,
54
+ bounciness: 10,
55
+ }),
56
+ ]).start();
57
+ onChange(index + 1);
58
+ },
59
+ [onChange, scales],
60
+ );
61
+
62
+ return (
63
+ <View style={styles.row}>
64
+ {Array.from({ length: count }).map((_, i) => {
65
+ const filled = i < rating;
66
+ return (
67
+ <TouchableWithoutFeedback
68
+ key={i}
69
+ disabled={!onChange}
70
+ onPress={() => handlePress(i)}
71
+ >
72
+ <Animated.View
73
+ style={[styles.star, { transform: [{ scale: scales[i] }] }]}
74
+ >
75
+ <Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
76
+ <Path
77
+ d={STAR_PATH}
78
+ fill={filled ? color : "none"}
79
+ stroke={filled ? color : emptyColor}
80
+ strokeWidth={filled ? 0 : 1.6}
81
+ strokeLinejoin="round"
82
+ />
83
+ </Svg>
84
+ </Animated.View>
85
+ </TouchableWithoutFeedback>
86
+ );
87
+ })}
88
+ </View>
89
+ );
90
+ };
91
+
92
+ export default RatingStars;
93
+
94
+ const styles = StyleSheet.create({
95
+ row: {
96
+ flexDirection: "row",
97
+ alignItems: "center",
98
+ justifyContent: "center",
99
+ },
100
+ star: {
101
+ marginHorizontal: moderateScale(6),
102
+ },
103
+ });
@@ -0,0 +1,98 @@
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
+ interface RoutePoint {
8
+ time?: string;
9
+ city: string;
10
+ area?: string;
11
+ }
12
+
13
+ interface RouteDotsProps {
14
+ from: RoutePoint;
15
+ to: RoutePoint;
16
+ compact?: boolean;
17
+ }
18
+
19
+ /** Two-point timeline used on trip cards & detail pages */
20
+ const RouteDots: React.FC<RouteDotsProps> = ({ from, to, compact }) => (
21
+ <View style={styles.wrap}>
22
+ <View style={styles.timeline}>
23
+ <View style={[styles.dot, styles.dotOutline]} />
24
+ <View style={styles.line} />
25
+ <View style={[styles.dot, styles.dotFilled]} />
26
+ </View>
27
+ <View style={[styles.col, compact && { gap: moderateScale(8) }]}>
28
+ <View>
29
+ {from.time ? (
30
+ <RNText size={12} color={THEME.textMuted}>
31
+ {from.time}
32
+ </RNText>
33
+ ) : null}
34
+ <RNText font="semibold" size={14} color={THEME.text}>
35
+ {from.city}
36
+ </RNText>
37
+ {from.area ? (
38
+ <RNText size={12} color={THEME.textMuted}>
39
+ {from.area}
40
+ </RNText>
41
+ ) : null}
42
+ </View>
43
+ <View>
44
+ {to.time ? (
45
+ <RNText size={12} color={THEME.textMuted}>
46
+ {to.time}
47
+ </RNText>
48
+ ) : null}
49
+ <RNText font="semibold" size={14} color={THEME.text}>
50
+ {to.city}
51
+ </RNText>
52
+ {to.area ? (
53
+ <RNText size={12} color={THEME.textMuted}>
54
+ {to.area}
55
+ </RNText>
56
+ ) : null}
57
+ </View>
58
+ </View>
59
+ </View>
60
+ );
61
+
62
+ export default RouteDots;
63
+
64
+ const styles = StyleSheet.create({
65
+ wrap: {
66
+ flexDirection: "row",
67
+ alignItems: "stretch",
68
+ gap: SPACING.md,
69
+ },
70
+ timeline: {
71
+ alignItems: "center",
72
+ paddingVertical: moderateScale(4),
73
+ },
74
+ dot: {
75
+ width: moderateScale(10),
76
+ height: moderateScale(10),
77
+ borderRadius: moderateScale(5),
78
+ },
79
+ dotOutline: {
80
+ borderWidth: 2,
81
+ borderColor: THEME.primary,
82
+ backgroundColor: THEME.surface,
83
+ },
84
+ dotFilled: {
85
+ backgroundColor: THEME.primary,
86
+ },
87
+ line: {
88
+ flex: 1,
89
+ width: 1.5,
90
+ backgroundColor: THEME.primary,
91
+ marginVertical: moderateScale(2),
92
+ },
93
+ col: {
94
+ flex: 1,
95
+ justifyContent: "space-between",
96
+ gap: moderateScale(14),
97
+ },
98
+ });
@@ -0,0 +1,126 @@
1
+ import React from "react";
2
+ import {
3
+ Pressable,
4
+ StyleSheet,
5
+ View,
6
+ StyleProp,
7
+ ViewStyle,
8
+ } from "react-native";
9
+ import { moderateScale } from "react-native-size-matters";
10
+ import { SPACING, THEME } from "../../theme";
11
+ import RNText from "../Text/RNText";
12
+
13
+ export interface SegmentedTab {
14
+ key: string;
15
+ label: string;
16
+ }
17
+
18
+ interface SegmentedControlProps {
19
+ tabs: SegmentedTab[];
20
+ value: string;
21
+ onChange: (key: string) => void;
22
+ style?: StyleProp<ViewStyle>;
23
+ variant?: "pill" | "underline";
24
+ }
25
+
26
+ const SegmentedControl: React.FC<SegmentedControlProps> = ({
27
+ tabs,
28
+ value,
29
+ onChange,
30
+ style,
31
+ variant = "pill",
32
+ }) => {
33
+ if (variant === "underline") {
34
+ return (
35
+ <View style={[styles.underlineContainer, style]}>
36
+ {tabs.map((t) => {
37
+ const active = t.key === value;
38
+ return (
39
+ <Pressable
40
+ key={t.key}
41
+ onPress={() => onChange(t.key)}
42
+ style={styles.underlineTab}
43
+ >
44
+ <RNText
45
+ font={active ? "semibold" : "regular"}
46
+ size={14}
47
+ color={active ? THEME.primary : THEME.textSecondary}
48
+ >
49
+ {t.label}
50
+ </RNText>
51
+ <View
52
+ style={[
53
+ styles.underline,
54
+ { backgroundColor: active ? THEME.primary : "transparent" },
55
+ ]}
56
+ />
57
+ </Pressable>
58
+ );
59
+ })}
60
+ </View>
61
+ );
62
+ }
63
+
64
+ return (
65
+ <View style={[styles.container, style]}>
66
+ {tabs.map((t) => {
67
+ const active = t.key === value;
68
+ return (
69
+ <Pressable
70
+ key={t.key}
71
+ onPress={() => onChange(t.key)}
72
+ style={[
73
+ styles.pill,
74
+ {
75
+ backgroundColor: active ? THEME.primary : "transparent",
76
+ },
77
+ ]}
78
+ >
79
+ <RNText
80
+ font={active ? "semibold" : "medium"}
81
+ size={13}
82
+ color={active ? THEME.textOnPrimary : THEME.textSecondary}
83
+ >
84
+ {t.label}
85
+ </RNText>
86
+ </Pressable>
87
+ );
88
+ })}
89
+ </View>
90
+ );
91
+ };
92
+
93
+ export default SegmentedControl;
94
+
95
+ const styles = StyleSheet.create({
96
+ container: {
97
+ flexDirection: "row",
98
+ backgroundColor: THEME.surface,
99
+ borderRadius: SPACING.radiusPill,
100
+ gap: moderateScale(4),
101
+ padding: moderateScale(4),
102
+ },
103
+ pill: {
104
+ flex: 1,
105
+ height: moderateScale(38),
106
+ borderRadius: SPACING.radiusPill,
107
+ alignItems: "center",
108
+ justifyContent: "center",
109
+ },
110
+ underlineContainer: {
111
+ flexDirection: "row",
112
+ borderBottomWidth: 1,
113
+ borderBottomColor: THEME.border,
114
+ },
115
+ underlineTab: {
116
+ flex: 1,
117
+ alignItems: "center",
118
+ paddingVertical: moderateScale(12),
119
+ gap: moderateScale(8),
120
+ },
121
+ underline: {
122
+ height: moderateScale(2),
123
+ width: "60%",
124
+ borderRadius: moderateScale(2),
125
+ },
126
+ });
@@ -0,0 +1,80 @@
1
+ import React, { useEffect, useRef } from "react";
2
+ import { Animated, Easing, StyleSheet } from "react-native";
3
+ import { moderateScale } from "react-native-size-matters";
4
+ import { THEME } from "../../theme";
5
+ import RNText from "../Text/RNText";
6
+
7
+ interface SosButtonProps {
8
+ /** Diameter of the button. Defaults to a header-friendly 38. */
9
+ size?: number;
10
+ }
11
+
12
+ /**
13
+ * Discreet, presentational SOS pill for the header. The press is owned by the
14
+ * parent (e.g. Header `onRightPress`) so it can sit inside the header's touch
15
+ * target. A subtle "breathing" pulse keeps it noticeable without being loud.
16
+ */
17
+ const SosButton: React.FC<SosButtonProps> = ({ size = moderateScale(30) }) => {
18
+ const pulse = useRef(new Animated.Value(0)).current;
19
+
20
+ useEffect(() => {
21
+ const loop = Animated.loop(
22
+ Animated.sequence([
23
+ Animated.timing(pulse, {
24
+ toValue: 1,
25
+ duration: 900,
26
+ easing: Easing.inOut(Easing.ease),
27
+ useNativeDriver: true,
28
+ }),
29
+ Animated.timing(pulse, {
30
+ toValue: 0,
31
+ duration: 900,
32
+ easing: Easing.inOut(Easing.ease),
33
+ useNativeDriver: true,
34
+ }),
35
+ ]),
36
+ );
37
+ loop.start();
38
+ return () => loop.stop();
39
+ }, [pulse]);
40
+
41
+ const scale = pulse.interpolate({
42
+ inputRange: [0, 1],
43
+ outputRange: [1, 1.07],
44
+ });
45
+
46
+ return (
47
+ <Animated.View
48
+ style={[
49
+ styles.core,
50
+ {
51
+ width: size,
52
+ height: size,
53
+ borderRadius: size / 2,
54
+ transform: [{ scale }],
55
+ },
56
+ ]}
57
+ >
58
+ <RNText font="bold" size={9} color={THEME.textOnPrimary} letterSpacing={0.5}>
59
+ SOS
60
+ </RNText>
61
+ </Animated.View>
62
+ );
63
+ };
64
+
65
+ export default SosButton;
66
+
67
+ const styles = StyleSheet.create({
68
+ core: {
69
+ alignItems: "center",
70
+ justifyContent: "center",
71
+ backgroundColor: THEME.danger,
72
+ borderWidth: moderateScale(2),
73
+ borderColor: "rgba(255,255,255,0.85)",
74
+ shadowColor: THEME.danger,
75
+ shadowOffset: { width: 0, height: moderateScale(3) },
76
+ shadowOpacity: 0.35,
77
+ shadowRadius: moderateScale(6),
78
+ elevation: 4,
79
+ },
80
+ });