create-gufran-expo-app 2.0.0 → 2.0.2

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 (266) hide show
  1. package/lib/createApp.js +7 -2
  2. package/package.json +1 -1
  3. package/template/App.tsx +118 -0
  4. package/template/ReactotronConfig.js +5 -0
  5. package/template/android/app/build.gradle +184 -0
  6. package/template/android/app/debug.keystore +0 -0
  7. package/template/android/app/google-services.json +29 -0
  8. package/template/android/app/proguard-rules.pro +14 -0
  9. package/template/android/app/src/debug/AndroidManifest.xml +7 -0
  10. package/template/android/app/src/debugOptimized/AndroidManifest.xml +7 -0
  11. package/template/android/app/src/main/AndroidManifest.xml +28 -0
  12. package/template/android/app/src/main/assets/fonts/Outfit-Bold.ttf +0 -0
  13. package/template/android/app/src/main/assets/fonts/Outfit-Light.ttf +0 -0
  14. package/template/android/app/src/main/assets/fonts/Outfit-Medium.ttf +0 -0
  15. package/template/android/app/src/main/assets/fonts/Outfit-Regular.ttf +0 -0
  16. package/template/android/app/src/main/assets/fonts/Outfit-SemiBold.ttf +0 -0
  17. package/template/android/app/src/main/java/com/club/yakka/MainActivity.kt +61 -0
  18. package/template/android/app/src/main/java/com/club/yakka/MainApplication.kt +60 -0
  19. package/template/android/app/src/main/res/drawable/ic_launcher_background.xml +6 -0
  20. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  21. package/template/android/app/src/main/res/drawable-hdpi/splashscreen_logo.png +0 -0
  22. package/template/android/app/src/main/res/drawable-mdpi/splashscreen_logo.png +0 -0
  23. package/template/android/app/src/main/res/drawable-xhdpi/splashscreen_logo.png +0 -0
  24. package/template/android/app/src/main/res/drawable-xxhdpi/splashscreen_logo.png +0 -0
  25. package/template/android/app/src/main/res/drawable-xxxhdpi/splashscreen_logo.png +0 -0
  26. package/template/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  27. package/template/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  28. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
  29. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp +0 -0
  30. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
  31. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
  32. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp +0 -0
  33. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
  34. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
  35. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp +0 -0
  36. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
  37. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
  38. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp +0 -0
  39. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
  40. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
  41. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp +0 -0
  42. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
  43. package/template/android/app/src/main/res/values/colors.xml +6 -0
  44. package/template/android/app/src/main/res/values/strings.xml +5 -0
  45. package/template/android/app/src/main/res/values/styles.xml +14 -0
  46. package/template/android/app/src/main/res/values-night/colors.xml +1 -0
  47. package/template/android/build.gradle +33 -0
  48. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  49. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  50. package/template/android/gradle.properties +65 -0
  51. package/template/android/gradlew +251 -0
  52. package/template/android/gradlew.bat +94 -0
  53. package/template/android/settings.gradle +39 -0
  54. package/template/app.json +69 -0
  55. package/template/assets/adaptive-icon.png +0 -0
  56. package/template/assets/adaptive-icon1.png +0 -0
  57. package/template/assets/app_icon.png +0 -0
  58. package/template/assets/favicon.png +0 -0
  59. package/template/assets/icon.png +0 -0
  60. package/template/assets/splash-icon.png +0 -0
  61. package/template/babel-plugin-disable-font-scaling.js +41 -0
  62. package/template/babel.config.js +28 -0
  63. package/template/firebase.json +5 -0
  64. package/template/index.ts +24 -0
  65. package/template/ios/.xcode.env +11 -0
  66. package/template/ios/ClubYakka/AppDelegate.swift +74 -0
  67. package/template/ios/ClubYakka/ClubYakka-Bridging-Header.h +3 -0
  68. package/template/ios/ClubYakka/ClubYakka.entitlements +8 -0
  69. package/template/ios/ClubYakka/GoogleService-Info.plist +30 -0
  70. package/template/ios/ClubYakka/Images.xcassets/AppIcon.appiconset/App-Icon-1024x1024@1x.png +0 -0
  71. package/template/ios/ClubYakka/Images.xcassets/AppIcon.appiconset/Contents.json +14 -0
  72. package/template/ios/ClubYakka/Images.xcassets/Contents.json +6 -0
  73. package/template/ios/ClubYakka/Images.xcassets/SplashScreenBackground.colorset/Contents.json +20 -0
  74. package/template/ios/ClubYakka/Images.xcassets/SplashScreenLegacy.imageset/Contents.json +23 -0
  75. package/template/ios/ClubYakka/Images.xcassets/SplashScreenLegacy.imageset/image.png +0 -0
  76. package/template/ios/ClubYakka/Images.xcassets/SplashScreenLegacy.imageset/image@2x.png +0 -0
  77. package/template/ios/ClubYakka/Images.xcassets/SplashScreenLegacy.imageset/image@3x.png +0 -0
  78. package/template/ios/ClubYakka/Info.plist +101 -0
  79. package/template/ios/ClubYakka/PrivacyInfo.xcprivacy +50 -0
  80. package/template/ios/ClubYakka/SplashScreen.storyboard +48 -0
  81. package/template/ios/ClubYakka/Supporting/Expo.plist +12 -0
  82. package/template/ios/ClubYakka.xcodeproj/project.pbxproj +669 -0
  83. package/template/ios/ClubYakka.xcodeproj/xcshareddata/xcschemes/ClubYakka.xcscheme +88 -0
  84. package/template/ios/ClubYakka.xcworkspace/contents.xcworkspacedata +10 -0
  85. package/template/ios/ClubYakka.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +5 -0
  86. package/template/ios/Podfile +84 -0
  87. package/template/ios/Podfile.lock +2698 -0
  88. package/template/ios/Podfile.properties.json +8 -0
  89. package/template/metro.config.js +17 -0
  90. package/template/package.json +70 -0
  91. package/template/patches/react-native-background-upload+6.6.0.patch +704 -0
  92. package/template/react-native.config.js +7 -0
  93. package/template/src/assets/fonts/Outfit-Bold.ttf +0 -0
  94. package/template/src/assets/fonts/Outfit-Light.ttf +0 -0
  95. package/template/src/assets/fonts/Outfit-Medium.ttf +0 -0
  96. package/template/src/assets/fonts/Outfit-Regular.ttf +0 -0
  97. package/template/src/assets/fonts/Outfit-SemiBold.ttf +0 -0
  98. package/template/src/assets/icons/BG.svg +33 -0
  99. package/template/src/assets/icons/Ic_Users.svg +6 -0
  100. package/template/src/assets/icons/arrow-left-white.svg +4 -0
  101. package/template/src/assets/icons/arrow-left.svg +4 -0
  102. package/template/src/assets/icons/bell.svg +4 -0
  103. package/template/src/assets/icons/bottomSheetIcone.svg +3 -0
  104. package/template/src/assets/icons/call.svg +4 -0
  105. package/template/src/assets/icons/camera.svg +0 -0
  106. package/template/src/assets/icons/chatAppleGreenBG.svg +22 -0
  107. package/template/src/assets/icons/check.svg +4 -0
  108. package/template/src/assets/icons/check_Radio.svg +4 -0
  109. package/template/src/assets/icons/chevron-right.svg +3 -0
  110. package/template/src/assets/icons/clubDefauldImage.png +0 -0
  111. package/template/src/assets/icons/curvBackgroundView.svg +3 -0
  112. package/template/src/assets/icons/defaultClub.png +0 -0
  113. package/template/src/assets/icons/email.svg +3 -0
  114. package/template/src/assets/icons/emptyUser.svg +5 -0
  115. package/template/src/assets/icons/eye-Hide.svg +8 -0
  116. package/template/src/assets/icons/eye.svg +4 -0
  117. package/template/src/assets/icons/gallery.svg +4 -0
  118. package/template/src/assets/icons/home.svg +4 -0
  119. package/template/src/assets/icons/ic_Calendar.svg +14 -0
  120. package/template/src/assets/icons/ic_Calendar_blue.svg +12 -0
  121. package/template/src/assets/icons/ic_Calendar_white.svg +12 -0
  122. package/template/src/assets/icons/ic_Chat.svg +14 -0
  123. package/template/src/assets/icons/ic_ChatAppleGreen.svg +21 -0
  124. package/template/src/assets/icons/ic_ChatAppleWhite.svg +21 -0
  125. package/template/src/assets/icons/ic_Download.svg +6 -0
  126. package/template/src/assets/icons/ic_Events.svg +6 -0
  127. package/template/src/assets/icons/ic_HeadCoachIcon.svg +3 -0
  128. package/template/src/assets/icons/ic_Membership.svg +10 -0
  129. package/template/src/assets/icons/ic_Notification.svg +6 -0
  130. package/template/src/assets/icons/ic_Raffles.svg +14 -0
  131. package/template/src/assets/icons/ic_Referral_Members.svg +12 -0
  132. package/template/src/assets/icons/ic_Shop.svg +13 -0
  133. package/template/src/assets/icons/ic_Teams.svg +8 -0
  134. package/template/src/assets/icons/ic_Volunteer.svg +9 -0
  135. package/template/src/assets/icons/ic_add.svg +3 -0
  136. package/template/src/assets/icons/ic_addCircle.svg +5 -0
  137. package/template/src/assets/icons/ic_chatSend.svg +4 -0
  138. package/template/src/assets/icons/ic_chat_blue_bg.svg +22 -0
  139. package/template/src/assets/icons/ic_clock_blue.svg +4 -0
  140. package/template/src/assets/icons/ic_delete.svg +8 -0
  141. package/template/src/assets/icons/ic_more.svg +5 -0
  142. package/template/src/assets/icons/ic_mute.svg +10 -0
  143. package/template/src/assets/icons/ic_pdf.svg +3 -0
  144. package/template/src/assets/icons/ic_pending_AppleGreen.svg +11 -0
  145. package/template/src/assets/icons/ic_right_appleGreen.svg +11 -0
  146. package/template/src/assets/icons/ic_unread_chat_blue_bg.svg +23 -0
  147. package/template/src/assets/icons/ic_volunteer_Member.svg +8 -0
  148. package/template/src/assets/icons/index.ts +144 -0
  149. package/template/src/assets/icons/location-blue.svg +4 -0
  150. package/template/src/assets/icons/location-white.svg +4 -0
  151. package/template/src/assets/icons/location.svg +4 -0
  152. package/template/src/assets/icons/lock.svg +5 -0
  153. package/template/src/assets/icons/log-out.svg +5 -0
  154. package/template/src/assets/icons/login_logo.svg +9 -0
  155. package/template/src/assets/icons/mail.svg +4 -0
  156. package/template/src/assets/icons/or_saprater.svg +5 -0
  157. package/template/src/assets/icons/password.svg +4 -0
  158. package/template/src/assets/icons/profile-appleGreen.svg +6 -0
  159. package/template/src/assets/icons/search.svg +3 -0
  160. package/template/src/assets/icons/settings.svg +4 -0
  161. package/template/src/assets/icons/success.svg +4 -0
  162. package/template/src/assets/icons/unCheck_Radio.svg +3 -0
  163. package/template/src/assets/icons/uncheck.svg +3 -0
  164. package/template/src/assets/icons/upload_Image.svg +6 -0
  165. package/template/src/assets/icons/upload_Image_Member.svg +6 -0
  166. package/template/src/assets/icons/user.svg +4 -0
  167. package/template/src/assets/icons/wifi.svg +1 -0
  168. package/template/src/assets/images/Splash.png +0 -0
  169. package/template/src/assets/images/SplashLogo.png +0 -0
  170. package/template/src/assets/images/background.png +0 -0
  171. package/template/src/assets/images/clubDefauldImage.png +0 -0
  172. package/template/src/assets/images/index.tsx +9 -0
  173. package/template/src/assets/index.ts +1 -0
  174. package/template/src/components/common/AddMemberModal.tsx +543 -0
  175. package/template/src/components/common/AppLoader.tsx +91 -0
  176. package/template/src/components/common/Button.tsx +173 -0
  177. package/template/src/components/common/ClubCard.tsx +248 -0
  178. package/template/src/components/common/Icon.tsx +93 -0
  179. package/template/src/components/common/IconAlt.tsx +65 -0
  180. package/template/src/components/common/IconButton.tsx +92 -0
  181. package/template/src/components/common/ImagePicker.tsx +451 -0
  182. package/template/src/components/common/LoadingSpinner.tsx +30 -0
  183. package/template/src/components/common/OTPInput.tsx +128 -0
  184. package/template/src/components/common/ReminderCalendar.tsx +129 -0
  185. package/template/src/components/common/ReminderCardItem.tsx +91 -0
  186. package/template/src/components/common/SafeAreaWrapper.tsx +27 -0
  187. package/template/src/components/common/SetReminderModal.tsx +308 -0
  188. package/template/src/components/common/SlowInternet.js +57 -0
  189. package/template/src/components/common/TeamCard.tsx +297 -0
  190. package/template/src/components/common/TextInput.tsx +227 -0
  191. package/template/src/components/common/ToastConfig.tsx +103 -0
  192. package/template/src/components/common/ToastManager.ts +86 -0
  193. package/template/src/components/common/UploadProgressModal.tsx +284 -0
  194. package/template/src/components/common/WrapperContainer.tsx +39 -0
  195. package/template/src/components/common/index.ts +19 -0
  196. package/template/src/constants/Constants.tsx +7 -0
  197. package/template/src/constants/Fonts.tsx +30 -0
  198. package/template/src/constants/index.ts +45 -0
  199. package/template/src/constants/strings.ts +211 -0
  200. package/template/src/constants/theme.ts +72 -0
  201. package/template/src/contexts/AuthContext.tsx +268 -0
  202. package/template/src/contexts/index.ts +2 -0
  203. package/template/src/hooks/index.ts +3 -0
  204. package/template/src/hooks/useImageUpload.ts +199 -0
  205. package/template/src/index.ts +8 -0
  206. package/template/src/navigation/AuthStack.tsx +67 -0
  207. package/template/src/navigation/MainStack.tsx +183 -0
  208. package/template/src/navigation/MiddleStack.tsx +35 -0
  209. package/template/src/navigation/RootNavigator.tsx +101 -0
  210. package/template/src/navigation/index.ts +5 -0
  211. package/template/src/navigation/navigationRef.ts +5 -0
  212. package/template/src/providers/QueryProvider.tsx +30 -0
  213. package/template/src/screens/DetailsScreen.tsx +271 -0
  214. package/template/src/screens/HomeScreen.tsx +736 -0
  215. package/template/src/screens/ProfileScreen.tsx +202 -0
  216. package/template/src/screens/SettingsScreen.tsx +253 -0
  217. package/template/src/screens/SportHubScreen.tsx +280 -0
  218. package/template/src/screens/auth/AddMamber.tsx +428 -0
  219. package/template/src/screens/auth/ForgotPasswordScreen.tsx +176 -0
  220. package/template/src/screens/auth/LoginScreen.tsx +286 -0
  221. package/template/src/screens/auth/OTPVerifyScreen.tsx +359 -0
  222. package/template/src/screens/auth/RegisterScreen.tsx +430 -0
  223. package/template/src/screens/auth/SuccessScreen.tsx +201 -0
  224. package/template/src/screens/auth/WalcomeScreen.tsx +274 -0
  225. package/template/src/screens/auth/index.ts +8 -0
  226. package/template/src/screens/chat/ChatScreen.tsx +1819 -0
  227. package/template/src/screens/chat/ChatThreadsScreen.tsx +360 -0
  228. package/template/src/screens/chat/ReportMessageScreen.tsx +238 -0
  229. package/template/src/screens/clubs/Announcements.tsx +426 -0
  230. package/template/src/screens/clubs/BuyRaffleTicketsScreen.tsx +568 -0
  231. package/template/src/screens/clubs/ClubDeteils.tsx +497 -0
  232. package/template/src/screens/clubs/JoinClub.tsx +841 -0
  233. package/template/src/screens/events/EventScreen.tsx +460 -0
  234. package/template/src/screens/index.ts +42 -0
  235. package/template/src/screens/raffles/MyReferralMembersScreen.tsx +758 -0
  236. package/template/src/screens/raffles/RaffleDetailsScreen.tsx +762 -0
  237. package/template/src/screens/raffles/RafflesScreen.tsx +495 -0
  238. package/template/src/screens/raffles/SetRaffleReminderScreen.tsx +390 -0
  239. package/template/src/screens/teams/JoinTeamScreen.tsx +464 -0
  240. package/template/src/screens/teams/MyTeamDetailsScreen.tsx +979 -0
  241. package/template/src/screens/teams/MyTeamScreen.tsx +568 -0
  242. package/template/src/screens/teams/PendingRequestsScreen.tsx +426 -0
  243. package/template/src/screens/volunteerOpportunities/SetReminderScreen.tsx +631 -0
  244. package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesDetailsScreen.tsx +1049 -0
  245. package/template/src/screens/volunteerOpportunities/VolunteerOpportunitiesScreen.tsx +608 -0
  246. package/template/src/services/api.ts +167 -0
  247. package/template/src/services/authService.ts +422 -0
  248. package/template/src/services/index.ts +5 -0
  249. package/template/src/services/mainServices.ts +1963 -0
  250. package/template/src/stores/authStore.ts +159 -0
  251. package/template/src/stores/index.ts +2 -0
  252. package/template/src/types/index.ts +85 -0
  253. package/template/src/types/navigation.ts +206 -0
  254. package/template/src/utils/AzureUploaderService.ts +371 -0
  255. package/template/src/utils/ClubSearchManager.ts +222 -0
  256. package/template/src/utils/NotificationManager.ts +503 -0
  257. package/template/src/utils/UploadDebugUtil.ts +107 -0
  258. package/template/src/utils/imagePicker.ts +321 -0
  259. package/template/src/utils/index.ts +111 -0
  260. package/template/src/utils/permissions.ts +277 -0
  261. package/template/src/utils/scaling.ts +14 -0
  262. package/template/src/utils/storage.ts +247 -0
  263. package/template/src/utils/usePermissions.ts +275 -0
  264. package/template/src/utils/validation.ts +340 -0
  265. package/template/tsconfig.json +50 -0
  266. package/template/types/svg.d.ts +6 -0
@@ -0,0 +1,1049 @@
1
+ import React, { useMemo, useRef, useState } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ StyleSheet,
6
+ StatusBar,
7
+ Platform,
8
+ TouchableOpacity,
9
+ Image,
10
+ ScrollView,
11
+ Dimensions,
12
+ Animated,
13
+ Modal,
14
+ PanResponder,
15
+ ActivityIndicator,
16
+ FlatList,
17
+ RefreshControl,
18
+ } from 'react-native';
19
+ import { SafeAreaView } from 'react-native-safe-area-context';
20
+ import { VolunteerOpportunitiesDetailsScreenProps } from '../../types/navigation';
21
+ import { theme } from '../../constants';
22
+ import { moderateScale } from '../../utils/scaling';
23
+ import { Fonts } from '../../constants/Fonts';
24
+ import SVG from '../../assets/icons';
25
+ import {
26
+ useVolunteerOpportunityDetails,
27
+ useVolunteerOpportunityVolunteers,
28
+ useJoinVolunteerOpportunity,
29
+ useVolunteerSlots,
30
+ useCancelVolunteerRequest,
31
+ VolunteerOpportunitySlot,
32
+ } from '../../services/mainServices';
33
+ import { Button } from '../../components/common';
34
+ import ToastManager from '../../components/common/ToastManager';
35
+ import { useFocusEffect } from '@react-navigation/native';
36
+
37
+ // Helper: Extract nested arrays from various data structures
38
+ const getFirstPopulatedArray = (...candidates: unknown[]): any[] => {
39
+ for (const candidate of candidates) {
40
+ if (Array.isArray(candidate) && candidate.length > 0) {
41
+ return candidate;
42
+ }
43
+
44
+ if (candidate && typeof candidate === 'object') {
45
+ const casted = candidate as Record<string, unknown>;
46
+ const nestedSlots =
47
+ casted.slots ??
48
+ casted.lstSlots ??
49
+ casted.data ??
50
+ casted.items ??
51
+ casted.list;
52
+
53
+ if (Array.isArray(nestedSlots) && nestedSlots.length > 0) {
54
+ return nestedSlots;
55
+ }
56
+ }
57
+ }
58
+
59
+ return [];
60
+ };
61
+
62
+ export const VolunteerOpportunitiesDetailsScreen: React.FC<
63
+ VolunteerOpportunitiesDetailsScreenProps
64
+ > = ({ navigation, route }) => {
65
+ const { selectedClub, item: itemDetails } = route?.params ?? {};
66
+
67
+ // Extract identifiers
68
+ const teamId = selectedClub?.id;
69
+ const team = selectedClub;
70
+ const opportunityId = itemDetails?.id;
71
+ const opportunityType = itemDetails?.opportunityType;
72
+ const clubId = selectedClub?.id;
73
+ const memberId = selectedClub?.selectedMember?.id;
74
+
75
+ // Mutations
76
+ const joinOpportunityMutation = useJoinVolunteerOpportunity();
77
+ const cancelVolunteerRequestMutation = useCancelVolunteerRequest();
78
+
79
+ // State
80
+ const [selectedSlot, setSelectedSlot] = useState<VolunteerOpportunitySlot | null>(null);
81
+ const [isSlotModalVisible, setIsSlotModalVisible] = useState(false);
82
+ const [isRefetching, setIsRefetching] = useState(false);
83
+ const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false);
84
+
85
+ // Bottom sheet animation
86
+ const screenHeight = Dimensions.get('window').height;
87
+ const bottomSheetHeight = screenHeight * 0.45;
88
+ const bottomSheetTranslateY = useRef(new Animated.Value(bottomSheetHeight)).current;
89
+
90
+
91
+
92
+
93
+ // Queries
94
+ const {
95
+ data: volunteersResponse,
96
+ isLoading: isVolunteersLoading,
97
+ refetch: refetchVolunteers,
98
+ } = useVolunteerOpportunityVolunteers(opportunityId, selectedSlot?.slotId);
99
+ const {
100
+ data: opportunityResponse,
101
+ isLoading,
102
+ error,
103
+ refetch: refetchOpportunity,
104
+ } = useVolunteerOpportunityDetails(opportunityId);
105
+ const {
106
+ data: slotsResponse,
107
+ isLoading: isSlotsLoading,
108
+ error: slotsError,
109
+ refetch: refetchSlots,
110
+ } = useVolunteerSlots(opportunityId, memberId);
111
+
112
+ // Computed values
113
+ const opportunityDetails = opportunityResponse?.data?.data;
114
+ const details = useMemo(
115
+ () => opportunityDetails ?? itemDetails ?? {},
116
+ [opportunityDetails, itemDetails]
117
+ );
118
+
119
+
120
+ useFocusEffect(
121
+ React.useCallback(() => {
122
+ handleRefetchAllData();
123
+ }, [])
124
+ );
125
+
126
+
127
+ // Process slots
128
+ const slots = slotsResponse?.data?.data|| [];
129
+
130
+ // Process volunteers
131
+ const volunteersDetails = volunteersResponse?.data?.data || [];
132
+
133
+
134
+ // Navigation helper
135
+ const createNavigationData = () => ({
136
+ selectedClub,
137
+ selectedMember: selectedClub?.selectedMember,
138
+ item: itemDetails,
139
+ });
140
+
141
+ // Handler: Join opportunity
142
+ const handleJoinVolunteerOpportunity = async (volunteer: any) => {
143
+ const slotId = Number(volunteer?.slotId ?? 0);
144
+ const opType = Number(itemDetails?.opportunityType ?? 1);
145
+
146
+ if (!opportunityId || Number.isNaN(opportunityId)) {
147
+ ToastManager.error('Opportunity ID is missing');
148
+ return;
149
+ }
150
+
151
+ try {
152
+ const response = await joinOpportunityMutation.mutateAsync({
153
+ opportunityId,
154
+ slotId,
155
+ opportunityType: opType,
156
+ memberId,
157
+ });
158
+
159
+ ToastManager.success(
160
+ response.data?.message || 'Successfully joined volunteer opportunity'
161
+ );
162
+ await handleRefreshAllData();
163
+ } catch (error: any) {
164
+ const errorMessage =
165
+ error?.response?.data?.message ||
166
+ error?.message ||
167
+ 'Failed to join opportunity';
168
+ ToastManager.error(errorMessage);
169
+ }
170
+ };
171
+
172
+ // Handler: Cancel request
173
+ const handleCancelVolunteerRequest = async (volunteer: any) => {
174
+ const slotId = Number(volunteer?.slotId ?? 0);
175
+
176
+ if (!opportunityId || Number.isNaN(opportunityId)) {
177
+ ToastManager.error('Opportunity ID is missing');
178
+ return;
179
+ }
180
+
181
+ if (!memberId || Number.isNaN(memberId)) {
182
+ ToastManager.error('Member ID is missing');
183
+ return;
184
+ }
185
+
186
+ if (!slotId || Number.isNaN(slotId)) {
187
+ ToastManager.error('Slot ID is missing');
188
+ return;
189
+ }
190
+
191
+ try {
192
+ const response = await cancelVolunteerRequestMutation.mutateAsync({
193
+ opportunityId,
194
+ memberId,
195
+ slotId,
196
+ });
197
+
198
+ ToastManager.success(
199
+ response.data?.message || 'Volunteer request cancelled successfully'
200
+ );
201
+ await refetchSlots();
202
+ } catch (error: any) {
203
+ const errorMessage =
204
+ error?.response?.data?.message ||
205
+ error?.message ||
206
+ 'Failed to cancel volunteer request';
207
+ ToastManager.error(errorMessage);
208
+ console.error('Cancel volunteer request error:', error);
209
+ }
210
+ };
211
+
212
+ // Modal: Close sheet
213
+ const closeSlotSelectionSheet = () => {
214
+ Animated.timing(bottomSheetTranslateY, {
215
+ toValue: bottomSheetHeight,
216
+ duration: 300,
217
+ useNativeDriver: true,
218
+ }).start(() => {
219
+ setIsSlotModalVisible(false);
220
+ setSelectedSlot(null);
221
+ bottomSheetTranslateY.setValue(bottomSheetHeight);
222
+ });
223
+ };
224
+
225
+ // Modal: Open sheet
226
+ const openSlotSelectionSheet = (volunteer: any) => {
227
+ setSelectedSlot(volunteer ?? null);
228
+ setIsSlotModalVisible(true);
229
+ refetchVolunteers()
230
+ bottomSheetTranslateY.setValue(bottomSheetHeight);
231
+ Animated.timing(bottomSheetTranslateY, {
232
+ toValue: 0,
233
+ duration: 300,
234
+ useNativeDriver: true,
235
+ }).start();
236
+ };
237
+
238
+ // PanResponder: Swipe gestures
239
+ const slotSelectionPanResponder = useRef(
240
+ PanResponder.create({
241
+ onMoveShouldSetPanResponder: (_, gestureState) =>
242
+ Math.abs(gestureState.dy) > 5,
243
+ onPanResponderGrant: () => {
244
+ bottomSheetTranslateY.extractOffset();
245
+ },
246
+ onPanResponderMove: (_, gestureState) => {
247
+ if (gestureState.dy > 0) {
248
+ bottomSheetTranslateY.setValue(gestureState.dy);
249
+ }
250
+ },
251
+ onPanResponderRelease: (_, gestureState) => {
252
+ bottomSheetTranslateY.flattenOffset();
253
+
254
+ if (gestureState.dy > 100 || gestureState.vy > 0.5) {
255
+ closeSlotSelectionSheet();
256
+ } else {
257
+ Animated.spring(bottomSheetTranslateY, {
258
+ toValue: 0,
259
+ useNativeDriver: true,
260
+ tension: 100,
261
+ friction: 8,
262
+ }).start();
263
+ }
264
+ },
265
+ })
266
+ ).current;
267
+
268
+ // Render volunteer item
269
+ const renderSlotItem = ({ item }: { item: any }) => (
270
+ <View style={styles.volunteerItemContainer}>
271
+ <View style={styles.volunteerAvatarSection}>
272
+ {item?.profileImage ? (
273
+ <Image
274
+ source={{ uri: item?.profileImage }}
275
+ style={styles.volunteerModalAvatar}
276
+ resizeMode="cover"
277
+ />
278
+ ) : (
279
+ <SVG.emptyUser style={{ marginBottom: theme.spacing.xs }} width={moderateScale(50)} height={moderateScale(50)} />
280
+ )}
281
+ </View>
282
+ <Text style={styles.volunteerName}>{item?.memberName}</Text>
283
+ </View>
284
+ );
285
+
286
+ // Refresh all data
287
+ const handleRefreshAllData = async () => {
288
+ setIsRefetching(true);
289
+ try {
290
+ await Promise.all([refetchSlots(), refetchOpportunity(), refetchVolunteers()]);
291
+ } catch (error: any) {
292
+ const message =
293
+ error?.response?.data?.message ||
294
+ error?.message ||
295
+ 'Failed to refresh data';
296
+ ToastManager.error('Refresh Error', message);
297
+ console.error('Error refreshing all data:', error);
298
+ } finally {
299
+ setIsRefetching(false);
300
+ }
301
+ };
302
+
303
+ const handleRefetchAllData = async () => {
304
+ try {
305
+ await Promise.all([refetchSlots(), refetchOpportunity(), refetchVolunteers()]);
306
+ } catch (error: any) {
307
+ const message =
308
+ error?.response?.data?.message ||
309
+ error?.message ||
310
+ 'Failed to refresh data';
311
+ ToastManager.error('Refresh Error', message);
312
+ console.error('Error refreshing all data:', error);
313
+ }
314
+
315
+ };
316
+
317
+ // Refresh slots only
318
+ const handleRefreshSlots = async () => {
319
+ setIsRefetching(true);
320
+ try {
321
+ await refetchSlots();
322
+ } catch (error: any) {
323
+ const message =
324
+ error?.response?.data?.message ||
325
+ error?.message ||
326
+ 'Failed to refresh slots';
327
+ ToastManager.error('Refresh Error', message);
328
+ console.error('Error refreshing slots:', error);
329
+ } finally {
330
+ setIsRefetching(false);
331
+ }
332
+ };
333
+
334
+ const descriptionText = opportunityDetails?.description || 'No description available for this opportunity yet.';
335
+ const shouldShowReadMore = descriptionText.length > 200;
336
+
337
+ return (
338
+ <View style={styles.container}>
339
+ <StatusBar
340
+ barStyle="light-content"
341
+ backgroundColor={theme.colors.blue}
342
+ translucent={Platform.OS === 'android'}
343
+ />
344
+ {Platform.OS === 'ios' && <View style={styles.statusBarBackground} />}
345
+ <SafeAreaView style={styles.safeArea}>
346
+ <View style={styles.header}>
347
+ <View style={styles.navRow}>
348
+ <TouchableOpacity
349
+ onPress={() => navigation.goBack()}
350
+ hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
351
+ >
352
+ <SVG.arrowLeft_white
353
+ width={moderateScale(25)}
354
+ height={moderateScale(25)}
355
+ />
356
+ </TouchableOpacity>
357
+ <View style={styles.clubInfoContainer}>
358
+ <View style={styles.userConSty}>
359
+ {selectedClub?.clubImage ? (
360
+ <Image
361
+ source={{ uri: selectedClub.clubImage }}
362
+ style={styles.userDetailsSty}
363
+ resizeMode="cover"
364
+ />
365
+ ) : (
366
+ <View style={styles.placeholderLogoHeader}>
367
+ <SVG.UsersIcon
368
+ width={moderateScale(20)}
369
+ height={moderateScale(20)}
370
+ />
371
+ </View>
372
+ )}
373
+ </View>
374
+ <Text style={styles.userNameSty}>
375
+ {details?.clubName ?? 'Unknown Team'}
376
+ </Text>
377
+ </View>
378
+ </View>
379
+ <View style={styles.headerMain}>
380
+ <Text style={styles.headerTitle}>
381
+ {details?.title ?? 'Volunteer Opportunity'}
382
+ </Text>
383
+ <View style={styles.opMetaRow}>
384
+ <SVG.locationWhite
385
+ width={moderateScale(18)}
386
+ height={moderateScale(18)}
387
+ />
388
+ <Text style={styles.opMetaText}>{details?.address}</Text>
389
+ </View>
390
+ {itemDetails?.scheduleDate && (
391
+ <View style={styles.opMetaRow}>
392
+ <SVG.CalendarWhite
393
+ width={moderateScale(18)}
394
+ height={moderateScale(18)}
395
+ />
396
+ <Text style={styles.opMetaText}>
397
+ {itemDetails.scheduleDate}
398
+ </Text>
399
+ </View>
400
+ )}
401
+ </View>
402
+ </View>
403
+
404
+ <View style={styles.content}>
405
+ {isLoading ? (
406
+ <View style={styles.loadingContainer}>
407
+ <Text style={styles.emptyText}>
408
+ Loading opportunity details...
409
+ </Text>
410
+ </View>
411
+ ) : error ? (
412
+ <View style={styles.loadingContainer}>
413
+ <Text style={styles.errorText}>
414
+ Error loading opportunity details.
415
+ </Text>
416
+ </View>
417
+ ) : (
418
+ <ScrollView
419
+ style={styles.scrollView}
420
+ contentContainerStyle={styles.scrollContent}
421
+ showsVerticalScrollIndicator={false}
422
+ refreshControl={
423
+ <RefreshControl
424
+ refreshing={isRefetching}
425
+ onRefresh={handleRefreshAllData}
426
+ tintColor={theme.colors.blue}
427
+ progressBackgroundColor={theme.colors.background}
428
+ />
429
+ }
430
+ >
431
+ <View style={styles.section}>
432
+ <Text style={styles.sectionTitle}>Description</Text>
433
+ <Text style={styles.descriptionText}>
434
+ {isDescriptionExpanded ? descriptionText : descriptionText.slice(0, 200) + (shouldShowReadMore ? '...' : '')}
435
+ {shouldShowReadMore && (
436
+ <Text
437
+ onPress={() => setIsDescriptionExpanded(!isDescriptionExpanded)}
438
+ style={{ color: theme.colors.blue, fontFamily: Fonts.outfitMedium }}
439
+ >
440
+ {isDescriptionExpanded ? ' Show Less' : ' Show More'}
441
+ </Text>
442
+ )}
443
+ </Text>
444
+ </View>
445
+
446
+ {details?.isExpired ? null : (
447
+
448
+
449
+ <View style={styles.section}>
450
+ <Text style={styles.sectionTitle}>Quick Actions</Text>
451
+ <View style={styles.quickActionsRow}>
452
+ <Button
453
+ title="Manage Reminders"
454
+ onPress={() => {
455
+ navigation.navigate('SetReminder', createNavigationData());
456
+ }}
457
+ variant="outline"
458
+ textStyle={styles.setReminderButtonText}
459
+ size="small"
460
+ />
461
+ </View>
462
+ </View>
463
+ )}
464
+
465
+ <View style={styles.section}>
466
+ <View style={styles.sectionHeaderRow}>
467
+ <Text style={styles.listTitle}>Volunteers</Text>
468
+ </View>
469
+ <View style={styles.volunteerList}>
470
+ {isSlotsLoading ? (
471
+ <View style={styles.loadingContainer}>
472
+ <Text style={styles.emptyStateText}>
473
+ Loading slots...
474
+ </Text>
475
+ <ActivityIndicator
476
+ size="small"
477
+ color={theme.colors.primary}
478
+ />
479
+ </View>
480
+ ) : slotsError ? (
481
+ <View style={styles.loadingContainer}>
482
+ <Text style={styles.errorText}>
483
+ Failed to load slots. Please try again.
484
+ </Text>
485
+ <TouchableOpacity
486
+ onPress={handleRefreshSlots}
487
+ style={styles.retryButtonContainer}
488
+ >
489
+ <Text style={styles.retryButtonText}>Retry</Text>
490
+ </TouchableOpacity>
491
+ </View>
492
+ ) : slots.length > 0 ? (
493
+ slots.map((volunteer: any) => (
494
+ <View key={volunteer.id} style={styles.volunteerCard}>
495
+ <View style={styles.slotHeaderRow}>
496
+ <Text style={styles.volunteerSlot}>
497
+ {volunteer?.slotStartTime} -{' '}
498
+ {volunteer?.slotEndTime}
499
+ </Text>
500
+ {volunteer?.applicationStatus === 1 ? (
501
+ <SVG.rightAppleGreen
502
+ style={styles.statusIconMargin}
503
+ width={moderateScale(25)}
504
+ height={moderateScale(25)}
505
+ />
506
+ ) : volunteer?.applicationStatus === 2 ? (
507
+ <SVG.PendingAppleGreen
508
+ style={styles.statusIconMargin}
509
+ width={moderateScale(20)}
510
+ height={moderateScale(20)}
511
+ />
512
+ ) : null}
513
+ </View>
514
+ <View style={styles.volunteerActionRow}>
515
+ {opportunityType === 1 ? (
516
+ <>
517
+ {volunteer?.applicationStatus === 3 ? (
518
+ <>
519
+ {!volunteer?.isExpired && (
520
+ <TouchableOpacity
521
+ disabled={
522
+ volunteer?.isExpired
523
+ }
524
+ onPress={() =>
525
+ handleJoinVolunteerOpportunity(volunteer)
526
+ }
527
+ style={styles.joinButton}
528
+ >
529
+ <Text style={styles.joinButtonText}>
530
+ Join
531
+ </Text>
532
+ </TouchableOpacity>
533
+ )}
534
+ </>
535
+ ) : (
536
+ <TouchableOpacity
537
+ onPress={() => {
538
+ navigation.navigate('ChatScreen', {
539
+ itemDetails: volunteer,
540
+ memberId,
541
+ teamId: volunteer?.opportunityId, //this is opportunityId
542
+ team,
543
+ userType: 'volunteer',
544
+ });
545
+ }}
546
+ >
547
+ {volunteer?.unreadMessageCount > 0 ? (
548
+ <SVG.UNREAD_CHAT_BLUE_BG width={30} height={30} />
549
+ ) : (
550
+ <SVG.chatBlueBG width={30} height={30} />
551
+ )}
552
+ </TouchableOpacity>
553
+ )}
554
+ </>
555
+ ) : (
556
+ <>
557
+ {volunteer?.applicationStatus === 3 ? (
558
+ <>
559
+ {!volunteer?.isExpired && (
560
+ <TouchableOpacity
561
+ disabled={
562
+ volunteer?.isExpired
563
+ }
564
+ onPress={() =>
565
+ handleJoinVolunteerOpportunity(volunteer)
566
+ }
567
+ style={styles.joinButton}
568
+ >
569
+ <Text style={styles.joinButtonText}>
570
+ Join
571
+ </Text>
572
+ </TouchableOpacity>
573
+ )}
574
+ </>
575
+ ) : volunteer?.applicationStatus === 2 ? (
576
+ <>
577
+ {volunteer?.isExpired ? null : (
578
+ <TouchableOpacity
579
+ onPress={() =>
580
+ handleCancelVolunteerRequest(volunteer)
581
+ }
582
+ disabled={
583
+ volunteer?.isExpired
584
+ }
585
+ style={[
586
+ styles.cancelButton,
587
+ cancelVolunteerRequestMutation.isPending &&
588
+ styles.cancelButtonDisabled,
589
+ ]}
590
+ >
591
+ <Text
592
+ style={[
593
+ styles.cancelButtonText,
594
+ cancelVolunteerRequestMutation.isPending &&
595
+ styles.cancelButtonTextDisabled,
596
+ ]}
597
+ >
598
+ {cancelVolunteerRequestMutation.isPending
599
+ ? 'Canceling...'
600
+ : 'Cancel'}
601
+ </Text>
602
+ </TouchableOpacity>
603
+ )}
604
+ </>
605
+ ) : (
606
+ <TouchableOpacity
607
+ onPress={() => {
608
+ navigation.navigate('ChatScreen', {
609
+ itemDetails: volunteer,
610
+ memberId,
611
+ teamId: volunteer?.opportunityId, //this is opportunityId
612
+ team,
613
+ userType: 'volunteer',
614
+ });
615
+ }}
616
+ >
617
+ {volunteer?.unreadMessageCount > 0 ? (
618
+ <SVG.UNREAD_CHAT_BLUE_BG width={30} height={30} />
619
+ ) : (
620
+ <SVG.chatBlueBG width={30} height={30} />
621
+ )}
622
+ </TouchableOpacity>
623
+ )}
624
+ </>
625
+ )}
626
+ <TouchableOpacity
627
+ onPress={() =>
628
+ openSlotSelectionSheet(volunteer)
629
+ }
630
+ >
631
+ <SVG.volunteerMember
632
+ style={styles.volunteerMemberIconMargin}
633
+ width={moderateScale(30)}
634
+ height={moderateScale(30)}
635
+ />
636
+ </TouchableOpacity>
637
+ </View>
638
+ </View>
639
+ ))
640
+ ) : (
641
+ <View style={styles.emptyState}>
642
+ <Text style={styles.emptyStateText}>
643
+ No slots available for this opportunity yet.
644
+ </Text>
645
+ </View>
646
+ )}
647
+ </View>
648
+ </View>
649
+ </ScrollView>
650
+ )}
651
+ </View>
652
+
653
+ {/* Volunteer Members Modal */}
654
+ <Modal
655
+ visible={isSlotModalVisible}
656
+ animationType="fade"
657
+ transparent
658
+ onRequestClose={closeSlotSelectionSheet}
659
+ >
660
+ <View style={styles.modalOverlay}>
661
+ <TouchableOpacity
662
+ style={styles.modalBackdrop}
663
+ activeOpacity={1}
664
+ onPress={closeSlotSelectionSheet}
665
+ />
666
+ <Animated.View
667
+ style={[
668
+ styles.modalContainer,
669
+ {
670
+ transform: [{ translateY: bottomSheetTranslateY }],
671
+ },
672
+ ]}
673
+ >
674
+ <View
675
+ style={styles.dragHandle}
676
+ {...slotSelectionPanResponder.panHandlers}
677
+ />
678
+ {isVolunteersLoading ? (
679
+ <View style={styles.slotLoadingContainer}>
680
+ <ActivityIndicator
681
+ size="small"
682
+ color={theme.colors.primary}
683
+ />
684
+ </View>
685
+ ) : (
686
+ <FlatList
687
+ data={volunteersDetails}
688
+ renderItem={renderSlotItem}
689
+ style={styles.membersList}
690
+ showsVerticalScrollIndicator={false}
691
+ ListHeaderComponent={() => (
692
+ <View style={styles.headerContainer}>
693
+ <Text style={styles.mamberHeaderTitle}>
694
+ Joined Volunteers
695
+ </Text>
696
+ <View style={styles.slotTimeRow}>
697
+ <SVG.Clock_Blue
698
+ width={moderateScale(28)}
699
+ height={moderateScale(28)}
700
+ />
701
+ <Text style={styles.slotTimeHeaderText}>
702
+ {selectedSlot?.slotStartTime} -{' '}
703
+ {selectedSlot?.slotEndTime}
704
+ </Text>
705
+ </View>
706
+ </View>
707
+ )}
708
+ ListEmptyComponent={() => (
709
+ <View style={styles.emptyContainer}>
710
+ <Text style={styles.emptyText}>
711
+ No volunteers available
712
+ </Text>
713
+ </View>
714
+ )}
715
+ keyExtractor={(item) => `volunteer-${item.id}`}
716
+ />
717
+ )}
718
+ </Animated.View>
719
+ </View>
720
+ </Modal>
721
+ </SafeAreaView>
722
+ </View>
723
+ );
724
+ };
725
+
726
+ const styles = StyleSheet.create({
727
+ container: {
728
+ flex: 1,
729
+ backgroundColor: theme.colors.blue,
730
+ },
731
+ statusBarBackground: {
732
+ position: 'absolute',
733
+ top: 0,
734
+ left: 0,
735
+ right: 0,
736
+ height: Platform.OS === 'ios' ? 44 : 0,
737
+ backgroundColor: theme.colors.blue,
738
+ zIndex: 1000,
739
+ },
740
+ safeArea: {
741
+ flex: 1,
742
+ backgroundColor: theme.colors.blue,
743
+ },
744
+ header: {
745
+ paddingBottom: theme.spacing.lg,
746
+ backgroundColor: theme.colors.blue,
747
+ },
748
+ navRow: {
749
+ flexDirection: 'row',
750
+ alignItems: 'center',
751
+ paddingHorizontal: theme.spacing.lg,
752
+ },
753
+ clubInfoContainer: {
754
+ flexDirection: 'row',
755
+ alignItems: 'center',
756
+ },
757
+ userConSty: {
758
+ marginHorizontal: moderateScale(10),
759
+ width: moderateScale(30),
760
+ height: moderateScale(30),
761
+ borderRadius: moderateScale(15),
762
+ borderWidth: 1.5,
763
+ borderColor: theme.colors.imageBorder,
764
+ backgroundColor: theme.colors.background,
765
+ alignItems: 'center',
766
+ justifyContent: 'center',
767
+ },
768
+ placeholderLogoHeader: {
769
+ width: moderateScale(24),
770
+ height: moderateScale(24),
771
+ borderRadius: moderateScale(12),
772
+ alignItems: 'center',
773
+ justifyContent: 'center',
774
+ },
775
+ userDetailsSty: {
776
+ width: moderateScale(30),
777
+ height: moderateScale(30),
778
+ borderRadius: moderateScale(15),
779
+ resizeMode: 'cover',
780
+ },
781
+ userNameSty: {
782
+ color: theme.colors.white,
783
+ fontFamily: Fonts.outfitMedium,
784
+ fontSize: moderateScale(15),
785
+ },
786
+ headerMain: {
787
+ paddingHorizontal: theme.spacing.lg,
788
+ marginTop: theme.spacing.sm,
789
+ },
790
+ headerTitle: {
791
+ fontFamily: Fonts.outfitSemiBold,
792
+ fontSize: moderateScale(24),
793
+ color: theme.colors.white,
794
+ marginBottom: theme.spacing.sm,
795
+ },
796
+ opMetaRow: {
797
+ flexDirection: 'row',
798
+ alignItems: 'center',
799
+ marginBottom: theme.spacing.xs,
800
+ },
801
+ opMetaText: {
802
+ marginLeft: theme.spacing.xs,
803
+ fontFamily: Fonts.outfitRegular,
804
+ fontSize: theme.typography.fontSize.xs,
805
+ color: 'rgba(255, 255, 255, 0.85)',
806
+ },
807
+ content: {
808
+ flex: 1,
809
+ backgroundColor: theme.colors.background,
810
+ borderTopLeftRadius: moderateScale(28),
811
+ borderTopRightRadius: moderateScale(28),
812
+ paddingTop: theme.spacing.lg,
813
+ },
814
+ scrollView: {
815
+ flex: 1,
816
+ },
817
+ scrollContent: {
818
+ paddingHorizontal: theme.spacing.lg,
819
+ paddingBottom: theme.spacing.xl,
820
+ },
821
+ section: {
822
+ marginBottom: theme.spacing.lg,
823
+ },
824
+ sectionHeaderRow: {
825
+ flexDirection: 'row',
826
+ alignItems: 'center',
827
+ justifyContent: 'space-between',
828
+ marginBottom: theme.spacing.sm,
829
+ },
830
+ sectionTitle: {
831
+ fontFamily: Fonts.outfitSemiBold,
832
+ fontSize: theme.typography.fontSize.sm,
833
+ color: theme.colors.black,
834
+ },
835
+ listTitle: {
836
+ fontFamily: Fonts.outfitSemiBold,
837
+ fontSize: theme.typography.fontSize.sm,
838
+ color: theme.colors.blue,
839
+ },
840
+ descriptionText: {
841
+ marginTop: theme.spacing.xs,
842
+ fontFamily: Fonts.outfitRegular,
843
+ fontSize: theme.typography.fontSize.sm,
844
+ color: theme.colors.paraText,
845
+ lineHeight: moderateScale(22),
846
+ },
847
+ quickActionsRow: {
848
+ marginTop: theme.spacing.sm,
849
+ gap: theme.spacing.md,
850
+ },
851
+ setReminderButtonText: {
852
+ color: theme.colors.appleGreen,
853
+ fontWeight: theme.typography.fontWeight.semibold,
854
+ },
855
+ volunteerList: {},
856
+ volunteerCard: {
857
+ flexDirection: 'row',
858
+ alignItems: 'center',
859
+ justifyContent: 'space-between',
860
+ borderRadius: moderateScale(18),
861
+ paddingHorizontal: theme.spacing.sm,
862
+ paddingVertical: theme.spacing.sm,
863
+ marginBottom: theme.spacing.sm,
864
+ backgroundColor: theme.colors.lightLavenderGray,
865
+ },
866
+ slotHeaderRow: {
867
+ flexDirection: 'row',
868
+ alignItems: 'center',
869
+ },
870
+ volunteerSlot: {
871
+ fontFamily: Fonts.outfitMedium,
872
+ fontSize: theme.typography.fontSize.sm,
873
+ color: theme.colors.black,
874
+ },
875
+ statusIconMargin: {
876
+ marginLeft: theme.spacing.xs,
877
+ },
878
+ volunteerActionRow: {
879
+ alignItems: 'center',
880
+ flexDirection: 'row',
881
+ justifyContent: 'flex-end',
882
+ },
883
+ joinButton: {
884
+ alignItems: 'center',
885
+ justifyContent: 'center',
886
+ borderWidth: 1,
887
+ borderColor: theme.colors.appleGreen,
888
+ borderRadius: theme.borderRadius.xxl,
889
+ paddingHorizontal: theme.spacing.md,
890
+ paddingVertical: theme.spacing.xs,
891
+ },
892
+ joinButtonText: {
893
+ color: theme.colors.appleGreen,
894
+ fontFamily: Fonts.outfitMedium,
895
+ fontSize: theme.typography.fontSize.xs,
896
+ },
897
+ cancelButton: {
898
+ alignItems: 'center',
899
+ justifyContent: 'center',
900
+ borderWidth: 1,
901
+ borderColor: theme.colors.red,
902
+ borderRadius: theme.borderRadius.xxl,
903
+ paddingHorizontal: theme.spacing.md,
904
+ paddingVertical: theme.spacing.xs,
905
+ },
906
+ cancelButtonDisabled: {
907
+ borderColor: theme.colors.DarkGray,
908
+ opacity: 0.6,
909
+ },
910
+ cancelButtonText: {
911
+ color: theme.colors.red,
912
+ fontFamily: Fonts.outfitMedium,
913
+ fontSize: theme.typography.fontSize.xs,
914
+ },
915
+ cancelButtonTextDisabled: {
916
+ color: theme.colors.DarkGray,
917
+ },
918
+ volunteerMemberIconMargin: {
919
+ marginLeft: theme.spacing.xs,
920
+ marginTop: moderateScale(2),
921
+ },
922
+ retryButtonContainer: {
923
+ marginTop: theme.spacing.sm,
924
+ },
925
+ retryButtonText: {
926
+ color: theme.colors.blue,
927
+ textDecorationLine: 'underline',
928
+ },
929
+ emptyState: {
930
+ paddingVertical: theme.spacing.lg,
931
+ alignItems: 'center',
932
+ justifyContent: 'center',
933
+ },
934
+ emptyStateText: {
935
+ fontFamily: Fonts.outfitMedium,
936
+ fontSize: theme.typography.fontSize.sm,
937
+ color: theme.colors.DarkGray,
938
+ marginBottom: theme.spacing.sm,
939
+ },
940
+ loadingContainer: {
941
+ flex: 1,
942
+ justifyContent: 'center',
943
+ alignItems: 'center',
944
+ paddingHorizontal: theme.spacing.lg,
945
+ },
946
+ emptyText: {
947
+ fontFamily: Fonts.outfitMedium,
948
+ fontSize: theme.typography.fontSize.md,
949
+ color: theme.colors.DarkGray,
950
+ textAlign: 'center',
951
+ },
952
+ errorText: {
953
+ fontFamily: Fonts.outfitMedium,
954
+ fontSize: theme.typography.fontSize.md,
955
+ color: theme.colors.cancelButton,
956
+ marginTop: theme.spacing.md,
957
+ textAlign: 'center',
958
+ },
959
+ modalOverlay: {
960
+ flex: 1,
961
+ justifyContent: 'flex-end',
962
+ },
963
+ modalBackdrop: {
964
+ position: 'absolute',
965
+ top: 0,
966
+ left: 0,
967
+ right: 0,
968
+ bottom: 0,
969
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
970
+ },
971
+ modalContainer: {
972
+ backgroundColor: theme.colors.white,
973
+ borderTopLeftRadius: moderateScale(20),
974
+ borderTopRightRadius: moderateScale(20),
975
+ paddingHorizontal: theme.spacing.lg,
976
+ paddingTop: theme.spacing.sm,
977
+ paddingBottom: theme.spacing.xl,
978
+ height: '45%',
979
+ maxHeight: '45%',
980
+ },
981
+ dragHandle: {
982
+ width: moderateScale(40),
983
+ height: moderateScale(4),
984
+ backgroundColor: theme.colors.border,
985
+ borderRadius: moderateScale(2),
986
+ alignSelf: 'center',
987
+ marginBottom: theme.spacing.sm,
988
+ },
989
+ slotLoadingContainer: {
990
+ flex: 1,
991
+ justifyContent: 'center',
992
+ alignItems: 'center',
993
+ paddingVertical: theme.spacing.lg,
994
+ },
995
+ membersList: {
996
+ flex: 1,
997
+ },
998
+ headerContainer: {
999
+ paddingVertical: theme.spacing.xs,
1000
+ borderBottomColor: theme.colors.lightLavenderGray,
1001
+ marginBottom: theme.spacing.sm,
1002
+ },
1003
+ mamberHeaderTitle: {
1004
+ fontFamily: Fonts.outfitBold,
1005
+ fontSize: moderateScale(18),
1006
+ color: theme.colors.text,
1007
+ marginBottom: theme.spacing.xs,
1008
+ },
1009
+ slotTimeRow: {
1010
+ flexDirection: 'row',
1011
+ alignItems: 'center',
1012
+ },
1013
+ slotTimeHeaderText: {
1014
+ color: theme.colors.black,
1015
+ marginLeft: theme.spacing.sm,
1016
+ fontFamily: Fonts.outfitMedium,
1017
+ fontSize: theme.typography.fontSize.md,
1018
+ },
1019
+ volunteerItemContainer: {
1020
+ backgroundColor: theme.colors.white,
1021
+ flexDirection: 'row',
1022
+ alignItems: 'center',
1023
+ borderBottomWidth: 1,
1024
+ borderBottomColor: theme.colors.border,
1025
+ paddingBottom: theme.spacing.xs,
1026
+ paddingTop: theme.spacing.sm,
1027
+ },
1028
+ volunteerAvatarSection: {
1029
+ alignItems: 'center',
1030
+ marginRight: theme.spacing.md,
1031
+ },
1032
+ volunteerModalAvatar: {
1033
+ width: moderateScale(50),
1034
+ height: moderateScale(50),
1035
+ borderRadius: moderateScale(25),
1036
+ marginBottom: theme.spacing.xs,
1037
+ },
1038
+ volunteerName: {
1039
+ fontFamily: Fonts.outfitSemiBold,
1040
+ fontSize: theme.typography.fontSize.md,
1041
+ color: theme.colors.text,
1042
+ flex: 1,
1043
+ },
1044
+ emptyContainer: {
1045
+ paddingVertical: theme.spacing.xl,
1046
+ alignItems: 'center',
1047
+ marginTop: theme.spacing.xl,
1048
+ },
1049
+ });