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,1963 @@
1
+ import { useMutation, useQuery, useInfiniteQuery } from '@tanstack/react-query';
2
+ import { apiClient, API_ENDPOINTS } from '../services/api';
3
+ import { User } from '../stores/authStore';
4
+
5
+ // Types for API requests and responses
6
+ export interface ApiResponse<T = any> {
7
+ data: T;
8
+ status: number;
9
+ statusText: string;
10
+ headers: any;
11
+ }
12
+
13
+ export interface ClubSearchResponse {
14
+ apiName: string;
15
+ data: any[];
16
+ message: string;
17
+ success: boolean;
18
+ }
19
+ export interface TeamSearchResponse {
20
+ apiName: string;
21
+ data: any[];
22
+ message: string;
23
+ success: boolean;
24
+ }
25
+ export interface ApiClubSearchResponse {
26
+ data: ClubSearchResponse;
27
+ status: number;
28
+ statusText: string;
29
+ headers: any;
30
+ }
31
+
32
+ export interface ClubSearchRequest {
33
+ pageNumber: number;
34
+ pageSize: number;
35
+ search: string;
36
+ }
37
+ export interface ApiTeamSearchResponse {
38
+ data: TeamSearchResponse;
39
+ status: number;
40
+ statusText: string;
41
+ headers: any;
42
+ }
43
+
44
+ export interface TeamSearchRequest {
45
+ pageNumber: number;
46
+ pageSize: number;
47
+ search: string;
48
+ clubId: number;
49
+ memberId?: number;
50
+ }
51
+
52
+ export interface MyClubsRequest {
53
+ pageNumber: number;
54
+ pageSize: number;
55
+ search: string;
56
+ }
57
+
58
+ export interface MyClubsResponse {
59
+
60
+ apiName: string;
61
+ data: any[];
62
+ message: string;
63
+ success: boolean;
64
+ }
65
+
66
+ export interface JoinClubRequest {
67
+ clubId: number;
68
+ memberId: number;
69
+ }
70
+ export interface JoinTeamRequest {
71
+ clubId: number;
72
+ memberId: number;
73
+ teamId: number;
74
+ }
75
+
76
+ export interface JoinClubResponse {
77
+ apiName: string;
78
+ data: any;
79
+ message: string;
80
+ success: boolean;
81
+ }
82
+
83
+ export interface ClubMembersRequest {
84
+ clubId: number;
85
+ }
86
+
87
+ export interface ClubMembersResponse {
88
+ apiName: string;
89
+ data: any[];
90
+ message: string;
91
+ success: boolean;
92
+ }
93
+
94
+ export interface MyTeamsRequest {
95
+ memberId: number;
96
+ pageNumber: number;
97
+ pageSize: number;
98
+ }
99
+
100
+ export interface MyTeamsResponse {
101
+ apiName: string;
102
+ data: {
103
+ members: any[];
104
+ pendingRequest: number;
105
+ totalRecord: number;
106
+ };
107
+ message: string;
108
+ success: boolean;
109
+ }
110
+
111
+ export interface PendingTeamRequestsRequest {
112
+ memberId: number;
113
+ PageNumber: number;
114
+ PageSize: number;
115
+ }
116
+
117
+ export interface PendingTeamRequest {
118
+ id: number;
119
+ teamName: string;
120
+ teamImageUrl?: string;
121
+ requestDate: string;
122
+ status: string;
123
+ clubId?: number;
124
+ teamId?: number;
125
+ memberId?: number;
126
+ totalRecord?: number;
127
+ }
128
+
129
+ export interface PendingTeamRequestsResponse {
130
+ apiName: string;
131
+ data: PendingTeamRequest[];
132
+ message: string;
133
+ success: boolean;
134
+ }
135
+
136
+ export interface TeamDetailsRequest {
137
+ teamId: number;
138
+ }
139
+
140
+ export interface TeamMember {
141
+ id: number;
142
+ name: string;
143
+ profileImage?: string;
144
+ position?: string;
145
+ birthDate?: string;
146
+ relation?: string;
147
+ isOwner?: boolean;
148
+ }
149
+
150
+ export interface Coach {
151
+ id: number;
152
+ name: string;
153
+ profileImage?: string;
154
+ title: string;
155
+ experienceYears?: number;
156
+ joinedDate?: string;
157
+ }
158
+
159
+ export interface TeamDetails {
160
+ id: number;
161
+ name: string;
162
+ clubId: number;
163
+ clubName: string;
164
+ clubImage?: string;
165
+ teamImage?: string;
166
+ description?: string;
167
+ totalMembers: number;
168
+ members: TeamMember[];
169
+ coach?: Coach;
170
+ createdDate: string;
171
+ isActive: boolean;
172
+ }
173
+
174
+ export interface TeamDetailsResponse {
175
+ apiName: string;
176
+ data: TeamDetails;
177
+ message: string;
178
+ success: boolean;
179
+ }
180
+
181
+ export interface TeamThreadsRequest {
182
+ teamId: number;
183
+ memberId: number;
184
+ }
185
+
186
+ export interface ChatThread {
187
+ id: number;
188
+ threadName: string;
189
+ lastMessage?: string;
190
+ lastMessageSentAt?: string;
191
+ unreadMessageCount: number;
192
+ isMute: boolean;
193
+ participants: number;
194
+ threadImage?: string;
195
+ isActive: boolean;
196
+ createdDate: string;
197
+ lastMessageText?: string;
198
+ }
199
+
200
+ export interface TeamThreadsResponse {
201
+ apiName: string;
202
+ data: ChatThread[];
203
+ message: string;
204
+ success: boolean;
205
+ }
206
+
207
+ // Add message-related types
208
+ export interface ChatMessage {
209
+ messageId: number;
210
+ threadId: number;
211
+ senderId: number;
212
+ message: string;
213
+ image?: string;
214
+ senderName: string;
215
+ senderImage?: string;
216
+ sentAt: string;
217
+ userTypeId?: number;
218
+ userType?: string;
219
+ profileImage?: string;
220
+ isMute?: boolean;
221
+ }
222
+
223
+ export interface TeamChatMessagesRequest {
224
+ teamId: number;
225
+ memberId: number;
226
+ threadId: number;
227
+ pageNumber: number;
228
+ }
229
+
230
+ export interface TeamChatMessagesData {
231
+ lstMessages: ChatMessage[];
232
+ totalRecords: number;
233
+ currentPage: number;
234
+ hasMorePages: boolean;
235
+ isMute?: boolean;
236
+ }
237
+
238
+ export interface TeamChatMessagesResponse {
239
+ apiName: string;
240
+ data: TeamChatMessagesData;
241
+ message: string;
242
+ success: boolean;
243
+ }
244
+
245
+ export interface AnnouncementsRequest {
246
+ clubId: number;
247
+ pageNumber: number;
248
+ pageSize: number;
249
+ }
250
+
251
+ export interface Announcement {
252
+ message: string;
253
+ image: string | null;
254
+ sentOn: string;
255
+ }
256
+
257
+ export interface AnnouncementsResponse {
258
+ apiName: string;
259
+ data: {
260
+ announcements?: Announcement[];
261
+ totalRecord?: number;
262
+ } | Announcement[];
263
+ message: string;
264
+ success: boolean;
265
+ totalRecord?: number;
266
+ }
267
+
268
+ export interface PaymentRequest {
269
+ nonce: string;
270
+ amount: number;
271
+ clubId: number;
272
+ token: string;
273
+ memberId: number;
274
+ metadata: {
275
+ orderTypeId: number;
276
+ id: number;
277
+ referralCode: string;
278
+ };
279
+ }
280
+
281
+ export interface PaymentResponse {
282
+ apiName: string;
283
+ data: {
284
+ transactionId: string;
285
+ status: string;
286
+ };
287
+ message: string;
288
+ success: boolean;
289
+ }
290
+
291
+ export interface VolunteerHoursDetailsRequest {
292
+ memberId: number;
293
+ clubId: number;
294
+ }
295
+
296
+ export interface VolunteerHoursDetailsResponse {
297
+ apiName?: string;
298
+ data?: any;
299
+ message?: string;
300
+ success?: boolean;
301
+ // Keep it flexible until backend schema is finalized
302
+ }
303
+
304
+ // Volunteer: Opportunities
305
+ export interface VolunteerOpportunitiesRequest {
306
+ memberId: number;
307
+ clubId: number;
308
+ requestType: number; // Tab ID: 1=Upcoming, 2=Requested, 3=Ongoing, 4=Past
309
+ pageNo: number;
310
+ pageSize: number;
311
+ }
312
+
313
+ export interface VolunteerOpportunity {
314
+ id: number;
315
+ title: string;
316
+ location?: string;
317
+ dateLabel?: string;
318
+ ctaType?: 'join' | 'request';
319
+ // Add other fields as needed based on API response
320
+ [key: string]: any;
321
+ }
322
+
323
+ export interface VolunteerOpportunitiesData {
324
+ opportunities?: VolunteerOpportunity[];
325
+ totalRecord?: number;
326
+ currentPage?: number;
327
+ hasMorePages?: boolean;
328
+ }
329
+
330
+ export interface VolunteerOpportunitiesResponse {
331
+ apiName?: string;
332
+ data?: VolunteerOpportunitiesData | VolunteerOpportunity[];
333
+ message?: string;
334
+ success?: boolean;
335
+ totalRecord?: number;
336
+ }
337
+
338
+ export interface VolunteerOpportunitySlot {
339
+ slotId?: number;
340
+ id?: number;
341
+ slotName?: string;
342
+ [key: string]: any;
343
+ }
344
+
345
+ export interface VolunteerOpportunitySlotsResponse {
346
+ apiName?: string;
347
+ data?: VolunteerOpportunitySlot[] | {
348
+ slots?: VolunteerOpportunitySlot[];
349
+ lstSlots?: VolunteerOpportunitySlot[];
350
+ data?: VolunteerOpportunitySlot[];
351
+ [key: string]: any;
352
+ };
353
+ message?: string;
354
+ success?: boolean;
355
+ }
356
+
357
+ // Volunteer: Join Opportunity
358
+ export interface JoinVolunteerOpportunityRequest {
359
+ opportunityId: number;
360
+ slotId: number;
361
+ opportunityType: number;
362
+ memberId: number;
363
+ }
364
+
365
+ export interface JoinVolunteerOpportunityResponse {
366
+ apiName?: string;
367
+ data?: any;
368
+ message?: string;
369
+ success?: boolean;
370
+ }
371
+
372
+ // Volunteer: Cancel Request
373
+ export interface CancelVolunteerRequestRequest {
374
+ opportunityId: number;
375
+ memberId: number;
376
+ slotId: number;
377
+ }
378
+
379
+ export interface CancelVolunteerRequestResponse {
380
+ apiName?: string;
381
+ data?: any;
382
+ message?: string;
383
+ success?: boolean;
384
+ }
385
+
386
+ // Volunteer: Set Reminder
387
+ export interface SetVolunteerReminderRequest {
388
+ reminderDateTime: string;
389
+ opportunityId: number;
390
+ memberId: number;
391
+ clubId: number;
392
+ }
393
+
394
+ export interface SetVolunteerReminderResponse {
395
+ apiName?: string;
396
+ data?: any;
397
+ message?: string;
398
+ success?: boolean;
399
+ }
400
+
401
+ // Volunteer: Get Reminder
402
+ export interface GetVolunteerReminderRequest {
403
+ opportunityId: number;
404
+ clubId: number;
405
+ memberId: number;
406
+ }
407
+
408
+ export interface VolunteerReminder {
409
+ id?: number;
410
+ reminderId?: number;
411
+ reminderDateTime: string;
412
+ opportunityId: number;
413
+ memberId: number;
414
+ clubId: number;
415
+ createdDate?: string;
416
+ [key: string]: any;
417
+ }
418
+
419
+ export interface GetVolunteerReminderResponse {
420
+ apiName?: string;
421
+ data?: {
422
+ scheduledDate?: string;
423
+ opportunityReminders?: VolunteerReminder[];
424
+ };
425
+ message?: string;
426
+ success?: boolean;
427
+ }
428
+
429
+ // Raffle: Set Reminder
430
+ export interface SetRaffleReminderRequest {
431
+ reminderDateTime: string;
432
+ raffleId: number;
433
+ memberId: number;
434
+ clubId: number;
435
+ }
436
+
437
+ export interface SetRaffleReminderResponse {
438
+ apiName?: string;
439
+ data?: any;
440
+ message?: string;
441
+ success?: boolean;
442
+ }
443
+
444
+ // Raffle: Get Reminder
445
+ export interface GetRaffleReminderRequest {
446
+
447
+ raffleId: number;
448
+ clubId: number;
449
+ memberId: number;
450
+ }
451
+
452
+ export interface RaffleReminder {
453
+ id?: number;
454
+ reminderId?: number;
455
+ reminderDateTime: string;
456
+ raffleId: number;
457
+ memberId: number;
458
+ clubId: number;
459
+ createdDate?: string;
460
+ [key: string]: any;
461
+ }
462
+
463
+ export interface GetRaffleReminderResponse {
464
+ apiName?: string;
465
+ data?: {
466
+ raffleDrawDate: string;
467
+ raffleReminders: RaffleReminder[];
468
+ }
469
+ message?: string;
470
+ success?: boolean;
471
+ }
472
+
473
+ export interface VolunteerOpportunityDetailsRequest {
474
+ opportunityId: number;
475
+ }
476
+
477
+ export interface VolunteerOpportunityDetailsResponse {
478
+ apiName?: string;
479
+ data?: VolunteerOpportunity; // Reusing VolunteerOpportunity type
480
+ message?: string;
481
+ success?: boolean;
482
+ }
483
+
484
+ export interface VolunteerOpportunityVolunteer {
485
+ id?: number | string;
486
+ memberId?: number;
487
+ volunteerId?: number;
488
+ userId?: number;
489
+ participantId?: number;
490
+ name?: string;
491
+ fullName?: string;
492
+ volunteerName?: string;
493
+ memberName?: string;
494
+ displayName?: string;
495
+ profileImage?: string;
496
+ image?: string;
497
+ avatar?: string;
498
+ profileImageUrl?: string;
499
+ photoUrl?: string;
500
+ memberImage?: string;
501
+ slotId?: number;
502
+ slotName?: string;
503
+ slotLabel?: string;
504
+ assignedSlotId?: number;
505
+ [key: string]: any;
506
+ }
507
+
508
+ export interface VolunteerOpportunityVolunteersRequest {
509
+ opportunityId: number;
510
+ slotId?: number | null;
511
+ }
512
+
513
+ export interface VolunteerOpportunityVolunteersResponse {
514
+ apiName?: string;
515
+ data?:
516
+ | VolunteerOpportunityVolunteer[]
517
+ | {
518
+ volunteers?: VolunteerOpportunityVolunteer[];
519
+ lstVolunteers?: VolunteerOpportunityVolunteer[];
520
+ data?: VolunteerOpportunityVolunteer[];
521
+ items?: VolunteerOpportunityVolunteer[];
522
+ list?: VolunteerOpportunityVolunteer[];
523
+ [key: string]: any;
524
+ };
525
+ message?: string;
526
+ success?: boolean;
527
+ totalRecord?: number;
528
+ }
529
+
530
+ // Raffle Details Types
531
+ export interface RafflePrizePool {
532
+ id: number;
533
+ raffleId: number;
534
+ title: string;
535
+ prizeTitle: string;
536
+ description: string;
537
+ bannerImageUrl: string | null;
538
+ prizeRank: number;
539
+ prizeAmount: number;
540
+ }
541
+
542
+ export interface RaffleTicketOption {
543
+ id: number;
544
+ raffleId: number;
545
+ ticketCount: number;
546
+ totalAmount: number;
547
+ perTicketAmount: number;
548
+ }
549
+
550
+ export interface RaffleDetailsData {
551
+ raffleId: number;
552
+ raffleTitle: string;
553
+ bannerImageUrl: string | null;
554
+ description: string;
555
+ totalPricePoolAmount: number;
556
+ drawDate: string;
557
+ drawTime: string;
558
+ purchaseEndDate: string;
559
+ termsAndConditionFileUrl: string | null;
560
+ latitude: number;
561
+ longitude: number;
562
+ locationAddress: string;
563
+ pricePools: RafflePrizePool[];
564
+ ticketOptions: RaffleTicketOption[];
565
+ }
566
+
567
+ export interface RaffleDetailsResponse {
568
+ data: RaffleDetailsData;
569
+ message: string;
570
+ apiName: string;
571
+ }
572
+
573
+ // Referrer Member Sales Types
574
+ export interface ReferrerMember {
575
+ id: number;
576
+ memberId: number;
577
+ name?: string;
578
+ memberName?: string;
579
+ profileImage?: string;
580
+ profileImageUrl?: string;
581
+ ticketCount?: number;
582
+ ticketsSold?: number;
583
+ totalTickets?: number;
584
+ purchasedTicketCount?: number;
585
+ }
586
+
587
+ export interface ReferrerMemberSalesRequest {
588
+ raffleId: number;
589
+ memberId: number;
590
+ pageNumber: number;
591
+ pageSize: number;
592
+ }
593
+
594
+ export interface ReferrerMemberSalesData {
595
+ salesList?: ReferrerMember[];
596
+ members?: ReferrerMember[];
597
+ referralMembers?: ReferrerMember[];
598
+ data?: {
599
+ salesList?: ReferrerMember[];
600
+ totalPurchasedTicketCount?: number;
601
+ pageNumber?: number;
602
+ pageSize?: number;
603
+ totalRecords?: number;
604
+ };
605
+ totalPurchasedTicketCount?: number;
606
+ totalRecord?: number;
607
+ totalRecords?: number;
608
+ totalSales?: number;
609
+ pageNumber?: number;
610
+ pageSize?: number;
611
+ currentPage?: number;
612
+ hasMorePages?: boolean;
613
+ }
614
+
615
+ export interface ReferrerMemberSalesResponse {
616
+ apiName: string;
617
+ data: ReferrerMemberSalesData;
618
+ message: string;
619
+ success?: boolean;
620
+ totalRecord?: number;
621
+ }
622
+
623
+ // Referral Code Types
624
+ export interface ReferralCodeRequest {
625
+ raffleId: number;
626
+ memberId: number;
627
+ }
628
+
629
+ export interface ReferralCodeResponse {
630
+ apiName?: string;
631
+ data?: {
632
+ referralCode: string;
633
+ clubId?: number;
634
+ clubCode?: string;
635
+ clubName?: string;
636
+ raffleTitle?: string;
637
+ };
638
+ message?: string;
639
+ success?: boolean;
640
+ }
641
+
642
+ export interface VerifyReferralCodeRequest {
643
+ raffleId: number;
644
+ clubId: number;
645
+ memberId: number;
646
+ referralCode: string;
647
+ }
648
+
649
+ export interface VerifyReferralCodeResponse {
650
+ apiName: string;
651
+ data: any;
652
+ message: string;
653
+ success: boolean;
654
+ }
655
+
656
+ // Ticket Details Types
657
+ export interface TicketDetailsRequest {
658
+ raffleId: number;
659
+ memberId: number;
660
+ purchasedMemberId: number;
661
+ }
662
+
663
+ export interface TicketDetailsResponse {
664
+ apiName: string;
665
+ data: {
666
+ id: number;
667
+ orderId: number;
668
+ ticketNumber: number[];
669
+ memberId?: string;
670
+ };
671
+ message: string;
672
+ }
673
+
674
+
675
+ export const MainService = {
676
+ clubSearch: async (params: ClubSearchRequest): Promise<ApiResponse<ClubSearchResponse>> => {
677
+ const response = await apiClient.get(API_ENDPOINTS.CLUB.SEARCH, {
678
+ params: params,
679
+ });
680
+ return {
681
+ data: response.data,
682
+ status: response.status,
683
+ statusText: response.statusText,
684
+ headers: response.headers
685
+ };
686
+ },
687
+ }
688
+
689
+ // API service functions
690
+ export const mainService = {
691
+ // Raffles: list with pagination
692
+ getRaffles: async (params: { clubId: number; memberId: number; PageNumber: number; PageSize: number; Search?: string }) => {
693
+ const response = await apiClient.get('Raffles', {
694
+ params,
695
+ });
696
+ return {
697
+ data: response.data,
698
+ status: response.status,
699
+ statusText: response.statusText,
700
+ headers: response.headers
701
+ };
702
+ },
703
+
704
+ // Raffle Details: Get single raffle by ID
705
+ getRaffleDetails: async (raffleId: number): Promise<ApiResponse<RaffleDetailsResponse>> => {
706
+ const response = await apiClient.get(`Raffles/${raffleId}`);
707
+ return {
708
+ data: response.data,
709
+ status: response.status,
710
+ statusText: response.statusText,
711
+ headers: response.headers
712
+ };
713
+ },
714
+
715
+ // Get Referral Code for raffle
716
+ getReferralCode: async (params: ReferralCodeRequest): Promise<ApiResponse<ReferralCodeResponse>> => {
717
+ const response = await apiClient.get(API_ENDPOINTS.RAFFLE.GET_REFEREE_CODE, {
718
+ params: {
719
+ raffleId: params.raffleId,
720
+ memberId: params.memberId,
721
+ },
722
+ });
723
+ return {
724
+ data: response.data,
725
+ status: response.status,
726
+ statusText: response.statusText,
727
+ headers: response.headers
728
+ };
729
+ },
730
+
731
+ // Verify Referral Code
732
+ verifyReferralCode: async (params: VerifyReferralCodeRequest): Promise<ApiResponse<VerifyReferralCodeResponse>> => {
733
+ const response = await apiClient.post(API_ENDPOINTS.RAFFLE.VERIFY_REFERRAL_CODE, params);
734
+ return {
735
+ data: response.data,
736
+ status: response.status,
737
+ statusText: response.statusText,
738
+ headers: response.headers
739
+ };
740
+ },
741
+
742
+ clubSearch: async (params: ClubSearchRequest): Promise<ApiResponse<ClubSearchResponse>> => {
743
+ const response = await apiClient.get(API_ENDPOINTS.CLUB.SEARCH, {
744
+ params: params,
745
+ });
746
+ return {
747
+ data: response.data,
748
+ status: response.status,
749
+ statusText: response.statusText,
750
+ headers: response.headers
751
+ };
752
+ },
753
+
754
+ myTeam: async (params: MyTeamsRequest): Promise<ApiResponse<MyTeamsResponse>> => {
755
+ const endpoint = API_ENDPOINTS.TEAM.MY_TEAMS.replace('{memberId}', params?.memberId.toString());
756
+ const queryParams: Record<string, any> = {
757
+ PageNumber: params.pageNumber,
758
+ PageSize: params.pageSize,
759
+ };
760
+ const response = await apiClient.get(endpoint, { params: queryParams });
761
+ return {
762
+ data: response.data,
763
+ status: response.status,
764
+ statusText: response.statusText,
765
+ headers: response.headers
766
+ };
767
+ },
768
+
769
+ teamSearch: async (params: TeamSearchRequest): Promise<ApiResponse<TeamSearchResponse>> => {
770
+ const endpoint = API_ENDPOINTS.TEAM.SERCH_JOIN_TEAMS
771
+ .replace('{clubId}', params.clubId.toString());
772
+ const { pageNumber, pageSize, search, memberId } = params;
773
+ const queryParams: Record<string, any> = {
774
+ PageNumber: pageNumber,
775
+ PageSize: pageSize,
776
+ };
777
+ if (typeof search === 'string' && search.trim().length > 0) {
778
+ queryParams.search = search.trim();
779
+ }
780
+ if (memberId) {
781
+ queryParams.memberId = memberId;
782
+ }
783
+ const response = await apiClient.get(endpoint, { params: queryParams });
784
+ return {
785
+ data: response.data,
786
+ status: response.status,
787
+ statusText: response.statusText,
788
+ headers: response.headers
789
+ };
790
+ },
791
+ getUser: async (): Promise<ApiResponse<User>> => {
792
+ const response = await apiClient.get(API_ENDPOINTS.USER.MEMBERS);
793
+ return {
794
+ data: response.data,
795
+ status: response.status,
796
+ statusText: response.statusText,
797
+ headers: response.headers
798
+ };
799
+ },
800
+ myClubs: async (params: MyClubsRequest): Promise<ApiResponse<MyClubsResponse>> => {
801
+ const response = await apiClient.get(API_ENDPOINTS.CLUB.SEARCH_MY_CLUBS, {
802
+ params: params,
803
+ });
804
+ return {
805
+ data: response.data,
806
+ status: response.status,
807
+ statusText: response.statusText,
808
+ headers: response.headers
809
+ };
810
+ },
811
+ joinClub: async (params: JoinClubRequest): Promise<ApiResponse<JoinClubResponse>> => {
812
+ const endpoint = API_ENDPOINTS.CLUB.JOIN
813
+ .replace('{clubId}', params.clubId.toString())
814
+ .replace('{memberId}', params.memberId.toString());
815
+ const response = await apiClient.post(endpoint);
816
+ return {
817
+ data: response.data,
818
+ status: response.status,
819
+ statusText: response.statusText,
820
+ headers: response.headers
821
+ };
822
+ },
823
+ getClubMembers: async (params: ClubMembersRequest): Promise<ApiResponse<ClubMembersResponse>> => {
824
+ const endpoint = API_ENDPOINTS.CLUB.MEMBERS
825
+ .replace('{clubId}', params.clubId.toString());
826
+ const response = await apiClient.get(endpoint);
827
+ return {
828
+ data: response.data,
829
+ status: response.status,
830
+ statusText: response.statusText,
831
+ headers: response.headers
832
+ };
833
+ },
834
+ joinTeam: async (params: JoinTeamRequest): Promise<ApiResponse<JoinClubResponse>> => {
835
+ const endpoint = API_ENDPOINTS.TEAM.JOIN_TEAM;
836
+ const response = await apiClient.post(endpoint, params);
837
+ return {
838
+ data: response.data,
839
+ status: response.status,
840
+ statusText: response.statusText,
841
+ headers: response.headers
842
+ };
843
+ },
844
+
845
+ cancelRequestTeam: async (params: JoinTeamRequest): Promise<ApiResponse<JoinClubResponse>> => {
846
+ const endpoint = API_ENDPOINTS.TEAM.CANCEL_PENDING_REQUEST;
847
+ const response = await apiClient.post(endpoint, params);
848
+ return {
849
+ data: response.data,
850
+ status: response.status,
851
+ statusText: response.statusText,
852
+ headers: response.headers
853
+ };
854
+ },
855
+
856
+ getPendingTeamRequests: async (params: PendingTeamRequestsRequest): Promise<ApiResponse<PendingTeamRequestsResponse>> => {
857
+ const response = await apiClient.get(API_ENDPOINTS.TEAM.PENDING_REQUEST, {
858
+ params: params,
859
+ });
860
+ return {
861
+ data: response.data,
862
+ status: response.status,
863
+ statusText: response.statusText,
864
+ headers: response.headers
865
+ };
866
+ },
867
+
868
+ getTeamDetails: async (params: TeamDetailsRequest): Promise<ApiResponse<TeamDetailsResponse>> => {
869
+ const endpoint = API_ENDPOINTS.TEAM.TEAM_DETAILS.replace('{teamId}', params.teamId.toString());
870
+ const response = await apiClient.get(endpoint);
871
+ return {
872
+ data: response.data,
873
+ status: response.status,
874
+ statusText: response.statusText,
875
+ headers: response.headers
876
+ };
877
+ },
878
+
879
+ getTeamThreads: async (params: TeamThreadsRequest): Promise<ApiResponse<TeamThreadsResponse>> => {
880
+ const endpoint = API_ENDPOINTS.TEAM.TEAM_THREADS
881
+ .replace('{teamId}', params.teamId.toString())
882
+ .replace('{memberId}', params.memberId.toString());
883
+
884
+ const response = await apiClient.get(endpoint);
885
+ return {
886
+ data: response.data,
887
+ status: response.status,
888
+ statusText: response.statusText,
889
+ headers: response.headers
890
+ };
891
+ },
892
+
893
+ // Add service function for fetching chat messages with pagination
894
+ getTeamChatMessages: async (params: TeamChatMessagesRequest): Promise<ApiResponse<TeamChatMessagesResponse>> => {
895
+ const endpoint = API_ENDPOINTS.TEAM.TEAM_CHAT
896
+ .replace('{teamId}', params.teamId.toString())
897
+ .replace('{memberId}', params.memberId.toString())
898
+ .replace('{threadId}', params.threadId.toString())
899
+ .replace('{pageNumber}', params.pageNumber.toString());
900
+
901
+ const response = await apiClient.get(endpoint);
902
+ return {
903
+ data: response.data,
904
+ status: response.status,
905
+ statusText: response.statusText,
906
+ headers: response.headers
907
+ };
908
+ },
909
+
910
+ // New service function for fetching chat messages with userType condition
911
+ getChatMessages: async (params: TeamChatMessagesRequest & { userType?: string }): Promise<ApiResponse<TeamChatMessagesResponse>> => {
912
+ let endpoint: string;
913
+
914
+ // Check userType and use appropriate API endpoint
915
+ if (params?.userType === 'volunteer') {
916
+ endpoint = API_ENDPOINTS?.VOLUNTEER?.VOLUNTEER_CHAT;
917
+ console.log('🔄 Using VOLUNTEER_CHAT endpoint:', endpoint);
918
+ } else {
919
+ // Default to team chat for 'teams' userType or if userType is not provided
920
+ endpoint = API_ENDPOINTS?.TEAM?.TEAM_CHAT;
921
+ console.log('🔄 Using TEAM_CHAT endpoint:', endpoint);
922
+ }
923
+
924
+ // Replace parameters based on userType
925
+ let finalEndpoint: string;
926
+ if (params?.userType === 'volunteer') {
927
+ // For volunteer endpoint, don't replace {teamId}
928
+ finalEndpoint = endpoint
929
+ .replace('{memberId}', params?.memberId.toString())
930
+ .replace('{threadId}', params?.threadId.toString())
931
+ .replace('{pageNumber}', params?.pageNumber.toString());
932
+ } else {
933
+ // For team endpoint, replace all parameters including {teamId}
934
+ finalEndpoint = endpoint
935
+ .replace('{teamId}', params?.teamId.toString())
936
+ .replace('{memberId}', params?.memberId.toString())
937
+ .replace('{threadId}', params?.threadId.toString())
938
+ .replace('{pageNumber}', params?.pageNumber.toString());
939
+ }
940
+
941
+
942
+ const response = await apiClient.get(finalEndpoint);
943
+ return {
944
+ data: response.data,
945
+ status: response.status,
946
+ statusText: response.statusText,
947
+ headers: response.headers
948
+ };
949
+ },
950
+
951
+ getAnnouncements: async (params: AnnouncementsRequest): Promise<ApiResponse<AnnouncementsResponse>> => {
952
+ const endpoint = API_ENDPOINTS.CLUB.ANNOUNCEMENTS.replace('{clubId}', params.clubId.toString());
953
+ const queryParams: Record<string, any> = {
954
+ PageNumber: params.pageNumber,
955
+ PageSize: params.pageSize,
956
+ };
957
+ const response = await apiClient.get(endpoint, { params: queryParams });
958
+ return {
959
+ data: response.data,
960
+ status: response.status,
961
+ statusText: response.statusText,
962
+ headers: response.headers
963
+ };
964
+ },
965
+
966
+ // New: Update Chat Mute Status (POST)
967
+ updateChatMuteStatus: async ({ teamId, memberId, threadId, isMute, chatTypeId }: { teamId: number; memberId: number; threadId: number; isMute: boolean; chatTypeId: number }): Promise<ApiResponse<any>> => {
968
+ const endpoint = `Teams/UpdateChatMuteStatus?teamId=${teamId}&memberId=${memberId}&threadId=${threadId}&isMute=${isMute}&chatTypeId=${chatTypeId}`;
969
+ // POST with empty body as per API style
970
+ const response = await apiClient.post(endpoint, {});
971
+ return {
972
+ data: response.data,
973
+ status: response.status,
974
+ statusText: response.statusText,
975
+ headers: response.headers
976
+ };
977
+ },
978
+
979
+ processPayment: async (payload: PaymentRequest): Promise<ApiResponse<PaymentResponse>> => {
980
+ const response = await apiClient.post(API_ENDPOINTS.PAYMENT.PROCESS, payload);
981
+ return {
982
+ data: response.data,
983
+ status: response.status,
984
+ statusText: response.statusText,
985
+ headers: response.headers
986
+ };
987
+ },
988
+
989
+ getVolunteerHoursDetails: async (params: VolunteerHoursDetailsRequest): Promise<ApiResponse<VolunteerHoursDetailsResponse>> => {
990
+ const response = await apiClient.get(API_ENDPOINTS.VOLUNTEER.HOURS_DETAILS, {
991
+ params: {
992
+ memberId: params.memberId,
993
+ clubId: params.clubId,
994
+ },
995
+ });
996
+ return {
997
+ data: response.data,
998
+ status: response.status,
999
+ statusText: response.statusText,
1000
+ headers: response.headers
1001
+ };
1002
+ },
1003
+
1004
+ // Volunteer: Get Opportunities with pagination
1005
+ getVolunteerOpportunities: async (params: VolunteerOpportunitiesRequest): Promise<ApiResponse<VolunteerOpportunitiesResponse>> => {
1006
+ const response = await apiClient.get(API_ENDPOINTS.VOLUNTEER.OPPORTUNITIES, {
1007
+ params: {
1008
+ memberId: params.memberId,
1009
+ clubId: params.clubId,
1010
+ requestType: params.requestType,
1011
+ pageNo: params.pageNo,
1012
+ pageSize: params.pageSize,
1013
+ },
1014
+ });
1015
+ return {
1016
+ data: response.data,
1017
+ status: response.status,
1018
+ statusText: response.statusText,
1019
+ headers: response.headers
1020
+ };
1021
+ },
1022
+
1023
+ // Volunteer: Get Single Opportunity Details by ID
1024
+ getVolunteerOpportunityDetails: async (
1025
+ params: VolunteerOpportunityDetailsRequest
1026
+ ): Promise<ApiResponse<VolunteerOpportunityDetailsResponse>> => {
1027
+ const endpoint = API_ENDPOINTS.VOLUNTEER.OPPORTUNITIES_BY_ID.replace(
1028
+ '{opportunityId}',
1029
+ params.opportunityId.toString()
1030
+ );
1031
+ const response = await apiClient.get(endpoint);
1032
+ return {
1033
+ data: response.data,
1034
+ status: response.status,
1035
+ statusText: response.statusText,
1036
+ headers: response.headers,
1037
+ };
1038
+ },
1039
+
1040
+ // Volunteer: Join Opportunity
1041
+ joinVolunteerOpportunity: async (params: JoinVolunteerOpportunityRequest): Promise<ApiResponse<JoinVolunteerOpportunityResponse>> => {
1042
+ const response = await apiClient.post(API_ENDPOINTS.VOLUNTEER.JOIN, {
1043
+ opportunityId: params.opportunityId,
1044
+ slotId: params.slotId,
1045
+ opportunityType: params.opportunityType,
1046
+ memberId: params.memberId,
1047
+ });
1048
+ return {
1049
+ data: response.data,
1050
+ status: response.status,
1051
+ statusText: response.statusText,
1052
+ headers: response.headers
1053
+ };
1054
+ },
1055
+
1056
+ // Volunteer: Cancel Request
1057
+ cancelVolunteerRequest: async (params: CancelVolunteerRequestRequest): Promise<ApiResponse<CancelVolunteerRequestResponse>> => {
1058
+ const endpoint = API_ENDPOINTS.VOLUNTEER.CANCEL_REQUEST;
1059
+ const response = await apiClient.post(endpoint, {
1060
+ opportunityId: params.opportunityId,
1061
+ memberId: params.memberId,
1062
+ slotId: params.slotId,
1063
+ });
1064
+ return {
1065
+ data: response.data,
1066
+ status: response.status,
1067
+ statusText: response.statusText,
1068
+ headers: response.headers
1069
+ };
1070
+ },
1071
+
1072
+ // Volunteer: Get Slots By Opportunity
1073
+ getVolunteerSlots: async (opportunityId: number, memberId: number): Promise<ApiResponse<VolunteerOpportunitySlotsResponse>> => {
1074
+ const response = await apiClient.get(API_ENDPOINTS.VOLUNTEER.SLOTS_BY_OPPORTUNITY, {
1075
+ params: { opportunityId, memberId },
1076
+ });
1077
+ return {
1078
+ data: response.data,
1079
+ status: response.status,
1080
+ statusText: response.statusText,
1081
+ headers: response.headers,
1082
+ };
1083
+ },
1084
+
1085
+ getVolunteerOpportunityVolunteers: async (
1086
+ params: VolunteerOpportunityVolunteersRequest
1087
+ ): Promise<ApiResponse<VolunteerOpportunityVolunteersResponse>> => {
1088
+ const { opportunityId, slotId } = params;
1089
+ const queryParams: Record<string, any> = {
1090
+ opportunityId,
1091
+ slotId: typeof slotId === 'number' && !Number.isNaN(slotId) ? slotId : 0,
1092
+ };
1093
+
1094
+ const response = await apiClient.get(API_ENDPOINTS.VOLUNTEER.OPPORTUNITY_VOLUNTEERS, {
1095
+ params: queryParams,
1096
+ });
1097
+
1098
+ return {
1099
+ data: response.data,
1100
+ status: response.status,
1101
+ statusText: response.statusText,
1102
+ headers: response.headers,
1103
+ };
1104
+ },
1105
+
1106
+ // Volunteer: Set Reminder
1107
+ setVolunteerReminder: async (params: SetVolunteerReminderRequest): Promise<ApiResponse<SetVolunteerReminderResponse>> => {
1108
+ const response = await apiClient.post(API_ENDPOINTS.VOLUNTEER.REMINDER, {
1109
+ reminderDateTime: params.reminderDateTime,
1110
+ opportunityId: params.opportunityId,
1111
+ memberId: params.memberId,
1112
+ clubId: params.clubId,
1113
+ });
1114
+ return {
1115
+ data: response.data,
1116
+ status: response.status,
1117
+ statusText: response.statusText,
1118
+ headers: response.headers,
1119
+ };
1120
+ },
1121
+
1122
+ // Volunteer: Get Reminder
1123
+ getVolunteerReminder: async (params: GetVolunteerReminderRequest): Promise<ApiResponse<GetVolunteerReminderResponse>> => {
1124
+ const endpoint = API_ENDPOINTS.VOLUNTEER.GET_REMINDER.replace(
1125
+ '{opportunityId}',
1126
+ params.opportunityId.toString()
1127
+ );
1128
+ const response = await apiClient.get(endpoint, {
1129
+ params: {
1130
+ clubId: params.clubId,
1131
+ memberId: params.memberId,
1132
+ },
1133
+ });
1134
+ return {
1135
+ data: response.data,
1136
+ status: response.status,
1137
+ statusText: response.statusText,
1138
+ headers: response.headers,
1139
+ };
1140
+ },
1141
+
1142
+ // Volunteer: Delete Reminder
1143
+ deleteVolunteerReminder: async (opportunityId: number, reminderId: number, clubId?: number, memberId?: number): Promise<ApiResponse<any>> => {
1144
+ let endpoint = API_ENDPOINTS.VOLUNTEER.DELETE_REMINDER
1145
+ .replace('{opportunityId}', opportunityId.toString())
1146
+ .replace('{reminderId}', reminderId.toString());
1147
+
1148
+ const params: Record<string, any> = {};
1149
+ if (clubId) params.clubId = clubId;
1150
+ if (memberId) params.memberId = memberId;
1151
+
1152
+ const response = await apiClient.delete(endpoint, { params });
1153
+ return {
1154
+ data: response.data,
1155
+ status: response.status,
1156
+ statusText: response.statusText,
1157
+ headers: response.headers,
1158
+ };
1159
+ },
1160
+
1161
+ // Raffle: Set Reminder
1162
+ setRaffleReminder: async (params: SetRaffleReminderRequest): Promise<ApiResponse<SetRaffleReminderResponse>> => {
1163
+ const response = await apiClient.post(API_ENDPOINTS.RAFFLE.REMINDER, {
1164
+ reminderDateTime: params.reminderDateTime,
1165
+ raffleId: params.raffleId,
1166
+ memberId: params.memberId,
1167
+ clubId: params.clubId,
1168
+ });
1169
+ return {
1170
+ data: response.data,
1171
+ status: response.status,
1172
+ statusText: response.statusText,
1173
+ headers: response.headers,
1174
+ };
1175
+ },
1176
+
1177
+ // Raffle: Get Reminder
1178
+ getRaffleReminder: async (params: GetRaffleReminderRequest): Promise<ApiResponse<GetRaffleReminderResponse>> => {
1179
+ const endpoint = API_ENDPOINTS.RAFFLE.GET_REMINDER.replace(
1180
+ '{raffleId}',
1181
+ params.raffleId.toString()
1182
+ );
1183
+ const response = await apiClient.get(endpoint, {
1184
+ params: {
1185
+ clubId: params.clubId,
1186
+ memberId: params.memberId,
1187
+ },
1188
+ });
1189
+ return {
1190
+ data: response.data,
1191
+ status: response.status,
1192
+ statusText: response.statusText,
1193
+ headers: response.headers,
1194
+ };
1195
+ },
1196
+
1197
+ // Raffle: Delete Reminder
1198
+ deleteRaffleReminder: async (raffleId: number, reminderId: number, clubId?: number, memberId?: number): Promise<ApiResponse<any>> => {
1199
+ let endpoint = API_ENDPOINTS.RAFFLE.DELETE_REMINDER
1200
+ .replace('{reminderId}', reminderId.toString());
1201
+
1202
+ const params: Record<string, any> = {};
1203
+ if (clubId) params.clubId = clubId;
1204
+ if (memberId) params.memberId = memberId;
1205
+ if (raffleId) params.raffleId = raffleId;
1206
+
1207
+ const response = await apiClient.delete(endpoint, { params });
1208
+ return {
1209
+ data: response.data,
1210
+ status: response.status,
1211
+ statusText: response.statusText,
1212
+ headers: response.headers,
1213
+ };
1214
+ },
1215
+
1216
+ // Get Referrer Member Sales
1217
+ getReferrerMemberSales: async (params: ReferrerMemberSalesRequest): Promise<ApiResponse<ReferrerMemberSalesResponse>> => {
1218
+ const response = await apiClient.get('ReferrerMemberSales', {
1219
+ params: {
1220
+ raffleId: params.raffleId,
1221
+ memberId: params.memberId,
1222
+ pageNumber: params.pageNumber,
1223
+ pageSize: params.pageSize,
1224
+ },
1225
+ });
1226
+ return {
1227
+ data: response.data,
1228
+ status: response.status,
1229
+ statusText: response.statusText,
1230
+ headers: response.headers,
1231
+ };
1232
+ },
1233
+
1234
+ // Get Ticket Details
1235
+ getTicketDetails: async (params: TicketDetailsRequest): Promise<ApiResponse<TicketDetailsResponse>> => {
1236
+ const response = await apiClient.get(API_ENDPOINTS.RAFFLE.GET_TICKET_DETAILS, {
1237
+ params: {
1238
+ raffleId: params.raffleId,
1239
+ memberId: params.memberId,
1240
+ },
1241
+ });
1242
+ return {
1243
+ data: response.data,
1244
+ status: response.status,
1245
+ statusText: response.statusText,
1246
+ headers: response.headers,
1247
+ };
1248
+ },
1249
+ }
1250
+
1251
+ export const useClubSearch = (params: ClubSearchRequest) => {
1252
+ return useQuery({
1253
+ queryKey: ['clubSearch', params],
1254
+ queryFn: () => mainService.clubSearch(params),
1255
+ });
1256
+ };
1257
+
1258
+ // Volunteer hooks
1259
+ export const useVolunteerHoursDetails = (memberId?: number, clubId?: number) => {
1260
+ return useQuery({
1261
+ queryKey: ['volunteerHoursDetails', memberId, clubId],
1262
+ queryFn: () => mainService.getVolunteerHoursDetails({ memberId: memberId as number, clubId: clubId as number }),
1263
+ enabled: !!memberId && memberId > 0 && !!clubId && clubId > 0,
1264
+ staleTime: 5 * 60 * 1000,
1265
+ });
1266
+ };
1267
+
1268
+ // Volunteer: Infinite Query for Opportunities with pagination
1269
+ export const useInfiniteVolunteerOpportunities = (
1270
+ memberId: number,
1271
+ clubId: number,
1272
+ requestType: number,
1273
+ pageSize: number = 10
1274
+ ) => {
1275
+ return useInfiniteQuery({
1276
+ queryKey: ['infiniteVolunteerOpportunities', memberId, clubId, requestType, pageSize],
1277
+ queryFn: ({ pageParam = 1 }) =>
1278
+ mainService.getVolunteerOpportunities({
1279
+ memberId,
1280
+ clubId,
1281
+ requestType,
1282
+ pageNo: pageParam,
1283
+ pageSize,
1284
+ }),
1285
+ getNextPageParam: (lastPage, allPages) => {
1286
+ // Check if we have valid data structure
1287
+ if (!lastPage?.data?.data) {
1288
+ return undefined;
1289
+ }
1290
+
1291
+ const pageData = lastPage.data.data;
1292
+ let opportunities: VolunteerOpportunity[] = [];
1293
+ let totalRecords = 0;
1294
+
1295
+ // Handle both structures: { opportunities: [], totalRecord: number } or []
1296
+ if (Array.isArray(pageData)) {
1297
+ opportunities = pageData;
1298
+ totalRecords = lastPage?.data?.totalRecord || 0;
1299
+ } else if (pageData && typeof pageData === 'object' && 'opportunities' in pageData) {
1300
+ opportunities = pageData.opportunities || [];
1301
+ totalRecords = pageData.totalRecord || lastPage?.data?.totalRecord || 0;
1302
+ }
1303
+
1304
+ // If no items returned, no more pages
1305
+ if (opportunities.length === 0) {
1306
+ return undefined;
1307
+ }
1308
+
1309
+ // If fewer items than pageSize, we've reached the end
1310
+ if (opportunities.length < pageSize) {
1311
+ return undefined;
1312
+ }
1313
+
1314
+ // If totalRecord is available, use it for pagination
1315
+ if (totalRecords > 0) {
1316
+ const totalPages = Math.ceil(totalRecords / pageSize);
1317
+ const currentPage = allPages.length;
1318
+ return currentPage < totalPages ? currentPage + 1 : undefined;
1319
+ }
1320
+
1321
+ // Fallback: if we got a full page of items, assume there might be more
1322
+ return opportunities.length === pageSize ? allPages.length + 1 : undefined;
1323
+ },
1324
+ initialPageParam: 1,
1325
+ enabled: !!memberId && memberId > 0 && !!clubId && clubId > 0 && !!requestType && requestType > 0,
1326
+ staleTime: 2 * 60 * 1000, // Cache for 2 minutes
1327
+ gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
1328
+ refetchOnWindowFocus: false,
1329
+ });
1330
+ };
1331
+
1332
+ // Infinite query for Raffles with pagination
1333
+ export const useInfiniteRaffles = (memberId: number | undefined, clubId: number | undefined, pageSize: number = 10, search?: string) => {
1334
+ return useInfiniteQuery({
1335
+ queryKey: ['infiniteRaffles', memberId, clubId, pageSize, search],
1336
+ queryFn: ({ pageParam = 0 }) =>
1337
+ mainService.getRaffles({
1338
+ clubId: clubId as number,
1339
+ memberId: memberId as number,
1340
+ PageNumber: pageParam,
1341
+ PageSize: pageSize,
1342
+ Search: search ? search : "",
1343
+ }),
1344
+ getNextPageParam: (lastPage, allPages) => {
1345
+ // Expect either { data: { data: [], totalRecord? } } or { data: [] }
1346
+ const payload = lastPage?.data;
1347
+ const list = Array.isArray(payload?.data) ? payload.data : Array.isArray(payload) ? payload : [];
1348
+ const totalRecord = typeof payload?.totalRecord === 'number' ? payload.totalRecord : undefined;
1349
+ const currentCount = allPages.reduce((acc, p) => {
1350
+ const pp = p?.data;
1351
+ const arr = Array.isArray(pp?.data) ? pp.data : Array.isArray(pp) ? pp : [];
1352
+ return acc + arr.length;
1353
+ }, 0);
1354
+ if (list.length === 0) return undefined;
1355
+ if (totalRecord && currentCount >= totalRecord) return undefined;
1356
+ if (list.length < pageSize) return undefined;
1357
+ return (allPages.length); // next PageNumber (0-based)
1358
+ },
1359
+ initialPageParam: 0,
1360
+ enabled: !!memberId && memberId > 0 && !!clubId && clubId > 0,
1361
+ refetchOnWindowFocus: false,
1362
+ staleTime: 2 * 60 * 1000,
1363
+ gcTime: 5 * 60 * 1000,
1364
+ });
1365
+ };
1366
+
1367
+ // Volunteer: Join Opportunity Mutation Hook
1368
+ export const useJoinVolunteerOpportunity = () => {
1369
+ return useMutation({
1370
+ mutationFn: mainService.joinVolunteerOpportunity,
1371
+ onSuccess: (response) => {
1372
+ console.log('Join volunteer opportunity successful:', response.data);
1373
+ },
1374
+ });
1375
+ };
1376
+
1377
+ // Volunteer: Cancel Request Mutation Hook
1378
+ export const useCancelVolunteerRequest = () => {
1379
+ return useMutation({
1380
+ mutationFn: mainService.cancelVolunteerRequest,
1381
+ onSuccess: (response) => {
1382
+ console.log('Cancel volunteer request successful:', response.data);
1383
+ },
1384
+ onError: (error) => {
1385
+ console.error('Cancel volunteer request failed:', error);
1386
+ },
1387
+ });
1388
+ };
1389
+
1390
+ // Volunteer: Set Reminder Mutation Hook
1391
+ export const useSetVolunteerReminder = () => {
1392
+ return useMutation({
1393
+ mutationFn: mainService.setVolunteerReminder,
1394
+ onSuccess: (response) => {
1395
+ console.log('Set reminder successful:', response.data);
1396
+ },
1397
+ onError: (error) => {
1398
+ console.error('Set reminder failed:', error);
1399
+ },
1400
+ });
1401
+ };
1402
+
1403
+ // Volunteer: Delete Reminder Mutation Hook
1404
+ export const useDeleteVolunteerReminder = () => {
1405
+ return useMutation({
1406
+ mutationFn: ({ opportunityId, reminderId, clubId, memberId }: { opportunityId: number; reminderId: number; clubId?: number; memberId?: number }) =>
1407
+ mainService.deleteVolunteerReminder(opportunityId, reminderId, clubId, memberId),
1408
+ onSuccess: (response) => {
1409
+ console.log('Delete reminder successful:', response.data);
1410
+ },
1411
+ onError: (error) => {
1412
+ console.error('Delete reminder failed:', error);
1413
+ },
1414
+ });
1415
+ };
1416
+
1417
+ // Raffle: Set Reminder Mutation Hook
1418
+ export const useSetRaffleReminder = () => {
1419
+ return useMutation({
1420
+ mutationFn: mainService.setRaffleReminder,
1421
+ onSuccess: (response) => {
1422
+ console.log('Set raffle reminder successful:', response.data);
1423
+ },
1424
+ onError: (error) => {
1425
+ console.error('Set raffle reminder failed:', error);
1426
+ },
1427
+ });
1428
+ };
1429
+
1430
+ // Raffle: Delete Reminder Mutation Hook
1431
+ export const useDeleteRaffleReminder = () => {
1432
+ return useMutation({
1433
+ mutationFn: ({ raffleId, reminderId, clubId, memberId }: { raffleId: number; reminderId: number; clubId?: number; memberId?: number }) =>
1434
+ mainService.deleteRaffleReminder(raffleId, reminderId, clubId, memberId),
1435
+ onSuccess: (response) => {
1436
+ console.log('Delete raffle reminder successful:', response.data);
1437
+ },
1438
+ onError: (error) => {
1439
+ console.error('Delete raffle reminder failed:', error);
1440
+ },
1441
+ });
1442
+ };
1443
+
1444
+ // Raffle: Get Reminder Hook
1445
+ export const useRaffleReminder = (raffleId?: number, clubId?: number, memberId?: number) => {
1446
+ return useQuery({
1447
+ queryKey: ['raffleReminder', raffleId, clubId, memberId],
1448
+ queryFn: () => mainService.getRaffleReminder({
1449
+ raffleId: raffleId as number,
1450
+ clubId: clubId as number,
1451
+ memberId: memberId as number,
1452
+ }),
1453
+ enabled: !!raffleId && raffleId > 0 && !!clubId && clubId > 0 && !!memberId && memberId > 0,
1454
+ staleTime: 60 * 1000, // Cache for 1 minute
1455
+ refetchOnWindowFocus: false,
1456
+ });
1457
+ };
1458
+
1459
+ // Volunteer: Get Reminder Hook
1460
+ export const useVolunteerReminder = (opportunityId?: number, clubId?: number, memberId?: number) => {
1461
+ return useQuery({
1462
+ queryKey: ['volunteerReminder', opportunityId, clubId, memberId],
1463
+ queryFn: () => mainService.getVolunteerReminder({
1464
+ opportunityId: opportunityId as number,
1465
+ clubId: clubId as number,
1466
+ memberId: memberId as number,
1467
+ }),
1468
+ enabled: !!opportunityId && opportunityId > 0 && !!clubId && clubId > 0 && !!memberId && memberId > 0,
1469
+ staleTime: 60 * 1000, // Cache for 1 minute
1470
+ refetchOnWindowFocus: false,
1471
+ });
1472
+ };
1473
+
1474
+ // Volunteer: Get Single Opportunity Details Hook
1475
+ export const useVolunteerOpportunityDetails = (opportunityId?: number) => {
1476
+ return useQuery({
1477
+ queryKey: ['volunteerOpportunityDetails', opportunityId],
1478
+ queryFn: () => mainService.getVolunteerOpportunityDetails({ opportunityId: opportunityId as number }),
1479
+ enabled: !!opportunityId && opportunityId > 0,
1480
+ staleTime: 0
1481
+ });
1482
+ };
1483
+
1484
+ // Raffle Details Hook
1485
+ export const useRaffleDetails = (raffleId?: number) => {
1486
+ return useQuery({
1487
+ queryKey: ['raffleDetails', raffleId],
1488
+ queryFn: () => mainService.getRaffleDetails(raffleId as number),
1489
+ enabled: !!raffleId && raffleId > 0,
1490
+ staleTime: 5 * 60 * 1000, // Cache for 5 minutes
1491
+ refetchOnWindowFocus: false,
1492
+ });
1493
+ };
1494
+
1495
+ // Volunteer: Get Slots Hook
1496
+ export const useVolunteerSlots = (opportunityId?: number, memberId?: number) => {
1497
+ return useQuery({
1498
+ queryKey: ['volunteerSlots', opportunityId, memberId],
1499
+ queryFn: () => mainService.getVolunteerSlots(opportunityId as number, memberId as number),
1500
+ enabled: !!opportunityId && opportunityId > 0,
1501
+ staleTime: 60 * 1000, // Cache for 1 minute
1502
+ refetchOnWindowFocus: false,
1503
+ });
1504
+ };
1505
+
1506
+ export const useVolunteerOpportunityVolunteers = (opportunityId?: number, slotId?: number | null) => {
1507
+ const slotQueryValue = typeof slotId === 'number' && !Number.isNaN(slotId) ? slotId : 0;
1508
+ return useQuery({
1509
+ queryKey: ['volunteerOpportunityVolunteers', opportunityId, slotQueryValue],
1510
+ queryFn: () =>
1511
+ mainService.getVolunteerOpportunityVolunteers({
1512
+ opportunityId: opportunityId as number,
1513
+ slotId: slotQueryValue,
1514
+ }),
1515
+ enabled: typeof opportunityId === 'number' && opportunityId > 0,
1516
+ staleTime: 60 * 1000,
1517
+ refetchOnWindowFocus: false,
1518
+ });
1519
+ };
1520
+
1521
+ export const useInfiniteClubSearch = (search: string, pageSize: number) => {
1522
+ return useInfiniteQuery({
1523
+ queryKey: ['infiniteClubSearch', search, pageSize],
1524
+ queryFn: ({ pageParam = 0 }) =>
1525
+ mainService.clubSearch({
1526
+ search,
1527
+ pageNumber: pageParam,
1528
+ pageSize
1529
+ }),
1530
+ getNextPageParam: (lastPage, allPages) => {
1531
+ const currentPage = allPages.length - 1;
1532
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1533
+ const totalPages = Math.ceil(totalRecords / pageSize);
1534
+
1535
+ // Return next page number if there are more pages
1536
+ return currentPage < totalPages - 1 ? currentPage + 1 : undefined;
1537
+ },
1538
+ initialPageParam: 0,
1539
+ });
1540
+ };
1541
+
1542
+ export const useInfiniteTeamSearch = (search: string, pageSize: number, clubId: number, memberId?: number) => {
1543
+ return useInfiniteQuery({
1544
+ queryKey: ['infiniteTeamSearch', search, pageSize, clubId, memberId],
1545
+ queryFn: ({ pageParam = 0 }) =>
1546
+ mainService.teamSearch({
1547
+ search,
1548
+ pageNumber: pageParam,
1549
+ pageSize,
1550
+ clubId,
1551
+ memberId,
1552
+ }),
1553
+ getNextPageParam: (lastPage, allPages) => {
1554
+ const currentPage = allPages.length - 1;
1555
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1556
+ const totalPages = Math.ceil(totalRecords / pageSize);
1557
+
1558
+ // Return next page number if there are more pages
1559
+ return currentPage < totalPages - 1 ? currentPage + 1 : undefined;
1560
+ },
1561
+ initialPageParam: 0,
1562
+ });
1563
+ };
1564
+
1565
+ export const useInfiniteMyClubs = (search: string, pageSize: number) => {
1566
+ return useInfiniteQuery({
1567
+ queryKey: ['infiniteMyClubs', search, pageSize],
1568
+ queryFn: ({ pageParam = 0 }) =>
1569
+ mainService.myClubs({
1570
+ search: '',
1571
+ pageNumber: pageParam,
1572
+ pageSize
1573
+ }),
1574
+ getNextPageParam: (lastPage, allPages) => {
1575
+ const currentPage = allPages.length - 1;
1576
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1577
+ const totalPages = Math.ceil(totalRecords / pageSize);
1578
+
1579
+ // Return next page number if there are more pages
1580
+ return currentPage < totalPages - 1 ? currentPage + 1 : undefined;
1581
+ },
1582
+ initialPageParam: 0,
1583
+ });
1584
+ };
1585
+
1586
+ export const useInfiniteMyTams = (search: string, pageSize: number, clubId: number) => {
1587
+ return useInfiniteQuery({
1588
+ queryKey: ['infiniteMyTeams', search, pageSize, clubId],
1589
+ queryFn: ({ pageParam = 0 }) =>
1590
+ mainService.teamSearch({
1591
+ search,
1592
+ pageNumber: pageParam,
1593
+ pageSize,
1594
+ clubId
1595
+ }),
1596
+ getNextPageParam: (lastPage, allPages) => {
1597
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1598
+ const totalPages = Math.ceil(totalRecords / pageSize);
1599
+ const nextPage = allPages.length; // zero-based next page index
1600
+ return nextPage < totalPages ? nextPage : undefined;
1601
+ },
1602
+ initialPageParam: 0,
1603
+ });
1604
+ };
1605
+
1606
+ export const useJoinClub = () => {
1607
+ return useMutation({
1608
+ mutationFn: mainService.joinClub,
1609
+ onSuccess: (response) => {
1610
+ console.log('Join club successful:', response.data);
1611
+ },
1612
+ onError: (error) => {
1613
+ console.error('Join club failed:', error);
1614
+ },
1615
+ });
1616
+ };
1617
+
1618
+ export const useClubMembers = (clubId: number) => {
1619
+ return useQuery({
1620
+ queryKey: ['clubMembers', clubId],
1621
+ queryFn: () => mainService.getClubMembers({ clubId }),
1622
+ enabled: !!clubId, // Only run query if clubId is provided
1623
+ });
1624
+ };
1625
+
1626
+
1627
+ // Teams
1628
+
1629
+ export const useInfiniteMyTeams = (memberId: number, pageSize: number) => {
1630
+ return useInfiniteQuery({
1631
+ queryKey: ['infiniteMyTeams', memberId, pageSize],
1632
+ queryFn: ({ pageParam = 0 }) =>
1633
+ mainService.myTeam({
1634
+ memberId,
1635
+ pageNumber: pageParam,
1636
+ pageSize
1637
+ }),
1638
+ getNextPageParam: (lastPage, allPages) => {
1639
+ const currentPage = allPages.length - 1;
1640
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1641
+ const totalPages = Math.ceil(totalRecords / pageSize);
1642
+
1643
+ // Return next page number if there are more pages
1644
+ return currentPage < totalPages - 1 ? currentPage + 1 : undefined;
1645
+ },
1646
+ initialPageParam: 0,
1647
+ enabled: !!memberId, // Only run query if teamId is provided
1648
+ });
1649
+ };
1650
+
1651
+ export const useVerifyReferralCode = () => {
1652
+ return useMutation({
1653
+ mutationFn: mainService.verifyReferralCode,
1654
+ });
1655
+ };
1656
+
1657
+ export const useJoinTeam = () => {
1658
+ return useMutation({
1659
+ mutationFn: mainService.joinTeam,
1660
+ onSuccess: (response) => {
1661
+ console.log('Join club successful:', response.data);
1662
+ },
1663
+ onError: (error) => {
1664
+ console.error('Join club failed:', error);
1665
+ },
1666
+ });
1667
+ };
1668
+
1669
+ export const useCancelRequestTeam = () => {
1670
+ return useMutation({
1671
+ mutationFn: mainService.cancelRequestTeam,
1672
+ onSuccess: (response) => {
1673
+ console.log('Join club successful:', response.data);
1674
+ },
1675
+ onError: (error) => {
1676
+ console.error('Join club failed:', error);
1677
+ },
1678
+ });
1679
+ };
1680
+
1681
+ export const useInfinitePendingTeamRequests = (memberId: number, pageSize: number) => {
1682
+ return useInfiniteQuery({
1683
+ queryKey: ['infinitePendingTeamRequests', memberId, pageSize],
1684
+ queryFn: ({ pageParam = 1 }) =>
1685
+ mainService.getPendingTeamRequests({
1686
+ memberId,
1687
+ PageNumber: pageParam,
1688
+ PageSize: pageSize
1689
+ }),
1690
+ getNextPageParam: (lastPage, allPages) => {
1691
+ const currentPage = allPages.length;
1692
+ const totalRecords = lastPage?.data?.data?.[0]?.totalRecord || 0;
1693
+ const totalPages = Math.ceil(totalRecords / pageSize);
1694
+
1695
+ // Return next page number if there are more pages
1696
+ return currentPage < totalPages ? currentPage + 1 : undefined;
1697
+ },
1698
+ initialPageParam: 0,
1699
+ enabled: !!memberId && memberId > 0, // Only run query if memberId is provided
1700
+ });
1701
+ };
1702
+
1703
+ export const useTeamDetails = (teamId: number) => {
1704
+ return useQuery({
1705
+ queryKey: ['teamDetails', teamId],
1706
+ queryFn: () => mainService.getTeamDetails({ teamId }),
1707
+ enabled: !!teamId && teamId > 0, // Only run query if teamId is provided
1708
+ staleTime: 5 * 60 * 1000, // Data stays fresh for 5 minutes
1709
+ gcTime: 10 * 60 * 1000, // Cache for 10 minutes
1710
+ });
1711
+ };
1712
+
1713
+ export const useTeamThreads = (teamId: number, memberId: number) => {
1714
+ return useQuery({
1715
+ queryKey: ['teamThreads', teamId, memberId],
1716
+ queryFn: () => mainService.getTeamThreads({ teamId, memberId }),
1717
+ enabled: !!teamId && teamId > 0 && !!memberId && memberId > 0, // Only run query if both IDs are provided
1718
+ staleTime: 30 * 1000, // Data stays fresh for 30 seconds (chat data should be more frequently updated)
1719
+ gcTime: 5 * 60 * 1000, // Cache for 5 minutes
1720
+ });
1721
+ };
1722
+
1723
+ // Add React Query hook for infinite chat messages with pagination
1724
+ export const useInfiniteTeamChatMessages = (teamId: number, memberId: number, threadId: number) => {
1725
+ return useInfiniteQuery({
1726
+ queryKey: ['infiniteTeamChatMessages', teamId, memberId, threadId],
1727
+ queryFn: ({ pageParam = 0 }) =>
1728
+ mainService.getTeamChatMessages({
1729
+ teamId,
1730
+ memberId,
1731
+ threadId,
1732
+ pageNumber: pageParam
1733
+ }),
1734
+ getNextPageParam: (lastPage, allPages) => {
1735
+ // Check if we have valid data structure
1736
+ if (!lastPage?.data?.data?.lstMessages) {
1737
+ console.log('No valid message data structure found');
1738
+ return undefined;
1739
+ }
1740
+
1741
+ const { lstMessages, totalRecords, hasMorePages } = lastPage.data.data;
1742
+
1743
+ // If hasMorePages is explicitly provided, use it
1744
+ if (typeof hasMorePages === 'boolean') {
1745
+ return hasMorePages ? allPages.length : undefined;
1746
+ }
1747
+
1748
+ // Fallback: check if we have messages and calculate based on total records
1749
+ const currentMessagesCount = allPages.reduce((total, page) => {
1750
+ return total + (page?.data?.data?.lstMessages?.length || 0);
1751
+ }, 0);
1752
+
1753
+ // If we have totalRecords, use it to determine if there are more pages
1754
+ if (typeof totalRecords === 'number' && totalRecords > 0) {
1755
+ return currentMessagesCount < totalRecords ? allPages.length : undefined;
1756
+ }
1757
+
1758
+ // Final fallback: if we got messages in the last response, assume there might be more
1759
+ const hasMessages = lstMessages && lstMessages.length > 0;
1760
+ return hasMessages ? allPages.length : undefined;
1761
+ },
1762
+ initialPageParam: 0,
1763
+ enabled: !!teamId && teamId > 0 && !!memberId && memberId > 0 && !!threadId && threadId > 0,
1764
+ staleTime: 0, // Chat messages should always be fresh
1765
+ gcTime: 2 * 60 * 1000, // Cache for 2 minutes (updated property name)
1766
+ refetchOnWindowFocus: false, // Don't refetch when window gains focus (better for chat UX)
1767
+ });
1768
+ };
1769
+
1770
+ // New React Query hook for infinite chat messages with userType support
1771
+ export const useInfiniteChatMessages = (teamId: number, memberId: number, threadId: number, userType?: string) => {
1772
+ return useInfiniteQuery({
1773
+ queryKey: ['infiniteChatMessages', teamId, memberId, threadId, userType],
1774
+ queryFn: ({ pageParam = 0 }) =>
1775
+ mainService.getChatMessages({
1776
+ teamId,
1777
+ memberId,
1778
+ threadId,
1779
+ pageNumber: pageParam,
1780
+ userType
1781
+ }),
1782
+ getNextPageParam: (lastPage, allPages) => {
1783
+ // Check if we have valid data structure
1784
+ if (!lastPage?.data?.data?.lstMessages) {
1785
+ console.log('No valid message data structure found');
1786
+ return undefined;
1787
+ }
1788
+
1789
+ const { lstMessages, totalRecords, hasMorePages } = lastPage.data.data;
1790
+
1791
+ // If hasMorePages is explicitly provided, use it
1792
+ if (typeof hasMorePages === 'boolean') {
1793
+ return hasMorePages ? allPages.length : undefined;
1794
+ }
1795
+
1796
+ // Fallback: check if we have messages and calculate based on total records
1797
+ const currentMessagesCount = allPages.reduce((total, page) => {
1798
+ return total + (page?.data?.data?.lstMessages?.length || 0);
1799
+ }, 0);
1800
+
1801
+ // If we have totalRecords, use it to determine if there are more pages
1802
+ if (typeof totalRecords === 'number' && totalRecords > 0) {
1803
+ return currentMessagesCount < totalRecords ? allPages.length : undefined;
1804
+ }
1805
+
1806
+ // Final fallback: if we got messages in the last response, assume there might be more
1807
+ const hasMessages = lstMessages && lstMessages.length > 0;
1808
+ return hasMessages ? allPages.length : undefined;
1809
+ },
1810
+ initialPageParam: 0,
1811
+ enabled: !!teamId && teamId > 0 && !!memberId && memberId > 0 && !!threadId && threadId > 0,
1812
+ staleTime: 0, // Chat messages should always be fresh
1813
+ gcTime: 2 * 60 * 1000, // Cache for 2 minutes (updated property name)
1814
+ refetchOnWindowFocus: false, // Don't refetch when window gains focus (better for chat UX)
1815
+ });
1816
+ };
1817
+
1818
+ // Add React Query hook for infinite announcements with pagination
1819
+ export const useInfiniteAnnouncements = (clubId: number, pageSize: number) => {
1820
+ return useInfiniteQuery({
1821
+ queryKey: ['infiniteAnnouncements', clubId, pageSize],
1822
+ queryFn: ({ pageParam = 0 }) =>
1823
+ mainService.getAnnouncements({
1824
+ clubId,
1825
+ pageNumber: pageParam,
1826
+ pageSize
1827
+ }),
1828
+ getNextPageParam: (lastPage, allPages) => {
1829
+ // Check if we have valid data structure
1830
+ if (!lastPage?.data?.data) {
1831
+ console.log('getNextPageParam: No data found');
1832
+ return undefined;
1833
+ }
1834
+
1835
+ const pageData = lastPage.data.data;
1836
+ let announcements: Announcement[] = [];
1837
+ let totalRecords = 0;
1838
+
1839
+ // Handle both structures: { announcements: [], totalRecord: number } or []
1840
+ if (Array.isArray(pageData)) {
1841
+ announcements = pageData;
1842
+ totalRecords = lastPage?.data?.totalRecord || 0;
1843
+ } else if (pageData && typeof pageData === 'object' && 'announcements' in pageData) {
1844
+ announcements = pageData.announcements || [];
1845
+ totalRecords = pageData.totalRecord || lastPage?.data?.totalRecord || 0;
1846
+ }
1847
+
1848
+ // If no items returned, no more pages
1849
+ if (announcements.length === 0) {
1850
+ console.log('getNextPageParam: No items, returning undefined');
1851
+ return undefined;
1852
+ }
1853
+
1854
+ // If fewer items than pageSize, we've reached the end
1855
+ if (announcements.length < pageSize) {
1856
+ console.log('getNextPageParam: Fewer items than pageSize, returning undefined');
1857
+ return undefined;
1858
+ }
1859
+
1860
+ // If totalRecord is available, use it for pagination
1861
+ if (totalRecords > 0) {
1862
+ const totalPages = Math.ceil(totalRecords / pageSize);
1863
+ const currentPage = allPages.length;
1864
+ const nextPage = currentPage < totalPages ? currentPage : undefined;
1865
+ console.log('getNextPageParam: Using totalRecord - totalPages:', totalPages, 'currentPage:', currentPage, 'nextPage:', nextPage);
1866
+ // Return next page number if there are more pages (0-indexed)
1867
+ return nextPage;
1868
+ }
1869
+
1870
+ // Fallback: if we got a full page of items, assume there might be more
1871
+ // (This is less reliable but works if totalRecord is not provided)
1872
+ const currentPage = allPages.length;
1873
+ const nextPage = announcements.length === pageSize ? currentPage : undefined;
1874
+ console.log('getNextPageParam: Using fallback - nextPage:', nextPage);
1875
+ return nextPage;
1876
+ },
1877
+ initialPageParam: 0,
1878
+ enabled: !!clubId && clubId > 0 && pageSize > 0,
1879
+ staleTime: 5 * 60 * 1000, // Cache for 5 minutes
1880
+ gcTime: 0, // Keep in cache for 10 minutes
1881
+ refetchOnWindowFocus: false,
1882
+ });
1883
+ };
1884
+
1885
+ // Infinite query for Referrer Member Sales with pagination
1886
+ export const useInfiniteReferrerMemberSales = (raffleId?: number, memberId?: number, pageSize?: number) => {
1887
+ return useInfiniteQuery({
1888
+ queryKey: ['infiniteReferrerMemberSales', raffleId, memberId, pageSize],
1889
+ queryFn: ({ pageParam = 1 }) =>
1890
+ mainService.getReferrerMemberSales({
1891
+ raffleId: raffleId as number,
1892
+ memberId: memberId as number,
1893
+ pageNumber: pageParam,
1894
+ pageSize,
1895
+ }),
1896
+ getNextPageParam: (lastPage, allPages) => {
1897
+ // Check if we have valid data structure
1898
+ if (!lastPage?.data?.data) {
1899
+ return undefined;
1900
+ }
1901
+
1902
+ const responseData = lastPage.data.data;
1903
+ let members: ReferrerMember[] = [];
1904
+ let totalRecords = 0;
1905
+ let currentPageNumber = 1;
1906
+
1907
+ // Handle the actual API structure: data.data.salesList
1908
+ if (responseData && typeof responseData === 'object') {
1909
+ // Check for nested data.data structure
1910
+ if ('data' in responseData && responseData.data && typeof responseData.data === 'object') {
1911
+ const nestedData = responseData.data;
1912
+ if ('salesList' in nestedData && Array.isArray(nestedData.salesList)) {
1913
+ members = nestedData.salesList;
1914
+ }
1915
+ totalRecords = nestedData.totalRecords || 0;
1916
+ currentPageNumber = nestedData.pageNumber || 1;
1917
+ }
1918
+ // Fallback to direct salesList
1919
+ else if ('salesList' in responseData && Array.isArray(responseData.salesList)) {
1920
+ members = responseData.salesList;
1921
+ totalRecords = responseData.totalRecords || responseData.totalRecord || 0;
1922
+ currentPageNumber = responseData.pageNumber || 1;
1923
+ }
1924
+ // Other possible structures
1925
+ else if ('members' in responseData && Array.isArray(responseData.members)) {
1926
+ members = responseData.members;
1927
+ totalRecords = responseData.totalRecords || responseData.totalRecord || 0;
1928
+ } else if ('referralMembers' in responseData && Array.isArray(responseData.referralMembers)) {
1929
+ members = responseData.referralMembers;
1930
+ totalRecords = responseData.totalRecords || responseData.totalRecord || 0;
1931
+ } else if (Array.isArray(responseData)) {
1932
+ members = responseData;
1933
+ totalRecords = lastPage?.data?.totalRecord || 0;
1934
+ }
1935
+ }
1936
+
1937
+ // If no items returned, no more pages
1938
+ if (members.length === 0) {
1939
+ return undefined;
1940
+ }
1941
+
1942
+ // If fewer items than pageSize, we've reached the end
1943
+ if (members.length < pageSize) {
1944
+ return undefined;
1945
+ }
1946
+
1947
+ // If totalRecords is available, use it for pagination
1948
+ if (totalRecords > 0) {
1949
+ const totalPages = Math.ceil(totalRecords / pageSize);
1950
+ const nextPage = currentPageNumber + 1;
1951
+ return nextPage <= totalPages ? nextPage : undefined;
1952
+ }
1953
+
1954
+ // Fallback: if we got a full page of items, assume there might be more
1955
+ return members.length === pageSize ? allPages.length + 1 : undefined;
1956
+ },
1957
+ initialPageParam: 1,
1958
+ enabled: !!raffleId && raffleId > 0,
1959
+ staleTime: 2 * 60 * 1000, // Cache for 2 minutes
1960
+ gcTime: 5 * 60 * 1000, // Keep in cache for 5 minutes
1961
+ refetchOnWindowFocus: false,
1962
+ });
1963
+ };