@growsober/sdk 1.0.0

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 (129) hide show
  1. package/README.md +276 -0
  2. package/dist/__tests__/e2e.test.d.ts +7 -0
  3. package/dist/__tests__/e2e.test.js +472 -0
  4. package/dist/api/client.d.ts +11 -0
  5. package/dist/api/client.js +61 -0
  6. package/dist/api/mutations/admin.d.ts +167 -0
  7. package/dist/api/mutations/admin.js +326 -0
  8. package/dist/api/mutations/ambassadors.d.ts +52 -0
  9. package/dist/api/mutations/ambassadors.js +148 -0
  10. package/dist/api/mutations/auth.d.ts +267 -0
  11. package/dist/api/mutations/auth.js +332 -0
  12. package/dist/api/mutations/bookings.d.ts +59 -0
  13. package/dist/api/mutations/bookings.js +143 -0
  14. package/dist/api/mutations/event-chat.d.ts +35 -0
  15. package/dist/api/mutations/event-chat.js +147 -0
  16. package/dist/api/mutations/events.d.ts +87 -0
  17. package/dist/api/mutations/events.js +205 -0
  18. package/dist/api/mutations/grow90.d.ts +36 -0
  19. package/dist/api/mutations/grow90.js +132 -0
  20. package/dist/api/mutations/hubs.d.ts +111 -0
  21. package/dist/api/mutations/hubs.js +240 -0
  22. package/dist/api/mutations/index.d.ts +22 -0
  23. package/dist/api/mutations/index.js +39 -0
  24. package/dist/api/mutations/jack.d.ts +61 -0
  25. package/dist/api/mutations/jack.js +104 -0
  26. package/dist/api/mutations/library.d.ts +67 -0
  27. package/dist/api/mutations/library.js +168 -0
  28. package/dist/api/mutations/map.d.ts +153 -0
  29. package/dist/api/mutations/map.js +181 -0
  30. package/dist/api/mutations/matching.d.ts +130 -0
  31. package/dist/api/mutations/matching.js +204 -0
  32. package/dist/api/mutations/notifications.d.ts +63 -0
  33. package/dist/api/mutations/notifications.js +106 -0
  34. package/dist/api/mutations/offers.d.ts +26 -0
  35. package/dist/api/mutations/offers.js +47 -0
  36. package/dist/api/mutations/subscriptions.d.ts +127 -0
  37. package/dist/api/mutations/subscriptions.js +140 -0
  38. package/dist/api/mutations/support.d.ts +165 -0
  39. package/dist/api/mutations/support.js +307 -0
  40. package/dist/api/mutations/users.d.ts +211 -0
  41. package/dist/api/mutations/users.js +261 -0
  42. package/dist/api/queries/admin.d.ts +257 -0
  43. package/dist/api/queries/admin.js +320 -0
  44. package/dist/api/queries/ambassadors.d.ts +53 -0
  45. package/dist/api/queries/ambassadors.js +98 -0
  46. package/dist/api/queries/auth.d.ts +16 -0
  47. package/dist/api/queries/auth.js +25 -0
  48. package/dist/api/queries/bookings.d.ts +91 -0
  49. package/dist/api/queries/bookings.js +102 -0
  50. package/dist/api/queries/businesses.d.ts +212 -0
  51. package/dist/api/queries/businesses.js +154 -0
  52. package/dist/api/queries/event-chat.d.ts +19 -0
  53. package/dist/api/queries/event-chat.js +75 -0
  54. package/dist/api/queries/events.d.ts +322 -0
  55. package/dist/api/queries/events.js +221 -0
  56. package/dist/api/queries/grow90.d.ts +26 -0
  57. package/dist/api/queries/grow90.js +85 -0
  58. package/dist/api/queries/hubs.d.ts +165 -0
  59. package/dist/api/queries/hubs.js +143 -0
  60. package/dist/api/queries/index.d.ts +23 -0
  61. package/dist/api/queries/index.js +40 -0
  62. package/dist/api/queries/jack.d.ts +63 -0
  63. package/dist/api/queries/jack.js +92 -0
  64. package/dist/api/queries/library.d.ts +132 -0
  65. package/dist/api/queries/library.js +120 -0
  66. package/dist/api/queries/map.d.ts +216 -0
  67. package/dist/api/queries/map.js +278 -0
  68. package/dist/api/queries/matching.d.ts +136 -0
  69. package/dist/api/queries/matching.js +161 -0
  70. package/dist/api/queries/notifications.d.ts +78 -0
  71. package/dist/api/queries/notifications.js +88 -0
  72. package/dist/api/queries/offers.d.ts +91 -0
  73. package/dist/api/queries/offers.js +103 -0
  74. package/dist/api/queries/subscriptions.d.ts +56 -0
  75. package/dist/api/queries/subscriptions.js +73 -0
  76. package/dist/api/queries/support.d.ts +106 -0
  77. package/dist/api/queries/support.js +202 -0
  78. package/dist/api/queries/users.d.ts +293 -0
  79. package/dist/api/queries/users.js +370 -0
  80. package/dist/api/types.d.ts +464 -0
  81. package/dist/api/types.js +9 -0
  82. package/dist/hooks/useAuth.d.ts +5 -0
  83. package/dist/hooks/useAuth.js +39 -0
  84. package/dist/hooks/useUser.d.ts +43 -0
  85. package/dist/hooks/useUser.js +44 -0
  86. package/dist/index.d.ts +36 -0
  87. package/dist/index.js +67 -0
  88. package/package.json +62 -0
  89. package/src/__tests__/e2e.test.ts +502 -0
  90. package/src/api/client.ts +71 -0
  91. package/src/api/mutations/admin.ts +531 -0
  92. package/src/api/mutations/ambassadors.ts +185 -0
  93. package/src/api/mutations/auth.ts +350 -0
  94. package/src/api/mutations/bookings.ts +190 -0
  95. package/src/api/mutations/event-chat.ts +177 -0
  96. package/src/api/mutations/events.ts +273 -0
  97. package/src/api/mutations/grow90.ts +169 -0
  98. package/src/api/mutations/hubs.ts +385 -0
  99. package/src/api/mutations/index.ts +23 -0
  100. package/src/api/mutations/jack.ts +130 -0
  101. package/src/api/mutations/library.ts +212 -0
  102. package/src/api/mutations/map.ts +230 -0
  103. package/src/api/mutations/matching.ts +271 -0
  104. package/src/api/mutations/notifications.ts +114 -0
  105. package/src/api/mutations/offers.ts +73 -0
  106. package/src/api/mutations/subscriptions.ts +162 -0
  107. package/src/api/mutations/support.ts +390 -0
  108. package/src/api/mutations/users.ts +271 -0
  109. package/src/api/queries/admin.ts +480 -0
  110. package/src/api/queries/ambassadors.ts +139 -0
  111. package/src/api/queries/auth.ts +24 -0
  112. package/src/api/queries/bookings.ts +135 -0
  113. package/src/api/queries/businesses.ts +203 -0
  114. package/src/api/queries/event-chat.ts +78 -0
  115. package/src/api/queries/events.ts +272 -0
  116. package/src/api/queries/grow90.ts +98 -0
  117. package/src/api/queries/hubs.ts +211 -0
  118. package/src/api/queries/index.ts +24 -0
  119. package/src/api/queries/jack.ts +127 -0
  120. package/src/api/queries/library.ts +166 -0
  121. package/src/api/queries/map.ts +331 -0
  122. package/src/api/queries/matching.ts +238 -0
  123. package/src/api/queries/notifications.ts +103 -0
  124. package/src/api/queries/offers.ts +136 -0
  125. package/src/api/queries/subscriptions.ts +91 -0
  126. package/src/api/queries/support.ts +235 -0
  127. package/src/api/queries/users.ts +393 -0
  128. package/src/api/types.ts +596 -0
  129. package/src/index.ts +57 -0
@@ -0,0 +1,169 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ UseMutationResult,
6
+ } from '@tanstack/react-query';
7
+ import { getApiClient } from '../client';
8
+ import type {
9
+ Grow90EnrollmentResponse,
10
+ Grow90ProgressResponse,
11
+ EnrollGrow90Request,
12
+ UpdateGrow90ProgressRequest,
13
+ UpdateGrow90SettingsRequest,
14
+ } from '../types';
15
+ import { grow90Keys } from '../queries/grow90';
16
+
17
+ // ============================================================================
18
+ // MUTATION HOOKS
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Enroll in GROW90 program
23
+ */
24
+ export function useEnrollGrow90(
25
+ options?: Omit<
26
+ UseMutationOptions<Grow90EnrollmentResponse, Error, EnrollGrow90Request>,
27
+ 'mutationFn'
28
+ >
29
+ ): UseMutationResult<Grow90EnrollmentResponse, Error, EnrollGrow90Request> {
30
+ const queryClient = useQueryClient();
31
+
32
+ return useMutation({
33
+ mutationFn: async (data: EnrollGrow90Request): Promise<Grow90EnrollmentResponse> => {
34
+ const client = getApiClient();
35
+ const response = await client.post('/api/v1/grow90/enroll', data);
36
+ // API returns { data: {...}, meta: {...} }, extract the data
37
+ const enrollment = 'data' in response.data ? response.data.data : response.data;
38
+ return enrollment;
39
+ },
40
+ onSuccess: (enrollment) => {
41
+ queryClient.setQueryData(grow90Keys.enrollment(), enrollment);
42
+ queryClient.invalidateQueries({ queryKey: grow90Keys.today() });
43
+ queryClient.invalidateQueries({ queryKey: grow90Keys.progress() });
44
+ queryClient.invalidateQueries({ queryKey: grow90Keys.stats() });
45
+ },
46
+ ...options,
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Update progress for a specific day
52
+ */
53
+ export function useUpdateGrow90Progress(
54
+ options?: Omit<
55
+ UseMutationOptions<Grow90ProgressResponse, Error, { day: number; data: UpdateGrow90ProgressRequest }>,
56
+ 'mutationFn'
57
+ >
58
+ ): UseMutationResult<Grow90ProgressResponse, Error, { day: number; data: UpdateGrow90ProgressRequest }> {
59
+ const queryClient = useQueryClient();
60
+
61
+ return useMutation({
62
+ mutationFn: async ({ day, data }): Promise<Grow90ProgressResponse> => {
63
+ const client = getApiClient();
64
+ const response = await client.put(`/api/v1/grow90/progress/${day}`, data);
65
+ // API returns { data: {...}, meta: {...} }, extract the data
66
+ return response.data?.data || response.data;
67
+ },
68
+ onSuccess: () => {
69
+ queryClient.invalidateQueries({ queryKey: grow90Keys.today() });
70
+ queryClient.invalidateQueries({ queryKey: grow90Keys.progress() });
71
+ queryClient.invalidateQueries({ queryKey: grow90Keys.stats() });
72
+ queryClient.invalidateQueries({ queryKey: grow90Keys.enrollment() });
73
+ },
74
+ ...options,
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Update GROW90 settings
80
+ */
81
+ export function useUpdateGrow90Settings(
82
+ options?: Omit<
83
+ UseMutationOptions<Grow90EnrollmentResponse, Error, UpdateGrow90SettingsRequest>,
84
+ 'mutationFn'
85
+ >
86
+ ): UseMutationResult<Grow90EnrollmentResponse, Error, UpdateGrow90SettingsRequest> {
87
+ const queryClient = useQueryClient();
88
+
89
+ return useMutation({
90
+ mutationFn: async (data: UpdateGrow90SettingsRequest): Promise<Grow90EnrollmentResponse> => {
91
+ const client = getApiClient();
92
+ const response = await client.put('/api/v1/grow90/settings', data);
93
+ // API returns { data: {...}, meta: {...} }, extract the data
94
+ return response.data?.data || response.data;
95
+ },
96
+ onSuccess: (enrollment) => {
97
+ queryClient.setQueryData(grow90Keys.enrollment(), enrollment);
98
+ },
99
+ ...options,
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Pause GROW90 program
105
+ */
106
+ export function usePauseGrow90(
107
+ options?: Omit<UseMutationOptions<Grow90EnrollmentResponse, Error, void>, 'mutationFn'>
108
+ ): UseMutationResult<Grow90EnrollmentResponse, Error, void> {
109
+ const queryClient = useQueryClient();
110
+
111
+ return useMutation({
112
+ mutationFn: async (): Promise<Grow90EnrollmentResponse> => {
113
+ const client = getApiClient();
114
+ const response = await client.post('/api/v1/grow90/pause');
115
+ // API returns { data: {...}, meta: {...} }, extract the data
116
+ return response.data?.data || response.data;
117
+ },
118
+ onSuccess: (enrollment) => {
119
+ queryClient.setQueryData(grow90Keys.enrollment(), enrollment);
120
+ },
121
+ ...options,
122
+ });
123
+ }
124
+
125
+ /**
126
+ * Resume GROW90 program
127
+ */
128
+ export function useResumeGrow90(
129
+ options?: Omit<UseMutationOptions<Grow90EnrollmentResponse, Error, void>, 'mutationFn'>
130
+ ): UseMutationResult<Grow90EnrollmentResponse, Error, void> {
131
+ const queryClient = useQueryClient();
132
+
133
+ return useMutation({
134
+ mutationFn: async (): Promise<Grow90EnrollmentResponse> => {
135
+ const client = getApiClient();
136
+ const response = await client.post('/api/v1/grow90/resume');
137
+ // API returns { data: {...}, meta: {...} }, extract the data
138
+ return response.data?.data || response.data;
139
+ },
140
+ onSuccess: (enrollment) => {
141
+ queryClient.setQueryData(grow90Keys.enrollment(), enrollment);
142
+ queryClient.invalidateQueries({ queryKey: grow90Keys.today() });
143
+ },
144
+ ...options,
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Abandon GROW90 program
150
+ */
151
+ export function useAbandonGrow90(
152
+ options?: Omit<UseMutationOptions<{ success: boolean }, Error, void>, 'mutationFn'>
153
+ ): UseMutationResult<{ success: boolean }, Error, void> {
154
+ const queryClient = useQueryClient();
155
+
156
+ return useMutation({
157
+ mutationFn: async (): Promise<{ success: boolean }> => {
158
+ const client = getApiClient();
159
+ const response = await client.post('/api/v1/grow90/abandon');
160
+ // API returns { data: {...}, meta: {...} }, extract the data
161
+ return response.data?.data || response.data;
162
+ },
163
+ onSuccess: () => {
164
+ queryClient.setQueryData(grow90Keys.enrollment(), null);
165
+ queryClient.invalidateQueries({ queryKey: grow90Keys.all });
166
+ },
167
+ ...options,
168
+ });
169
+ }
@@ -0,0 +1,385 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ UseMutationResult,
6
+ } from '@tanstack/react-query';
7
+ import { getApiClient } from '../client';
8
+ import type { HubResponse, CreateHubRequest, UpdateHubRequest } from '../types';
9
+ import { hubKeys } from '../queries/hubs';
10
+
11
+ // ============================================================================
12
+ // TYPES
13
+ // ============================================================================
14
+
15
+ export interface UpdateMemberRoleRequest {
16
+ role: 'OWNER' | 'ADMIN' | 'MEMBER';
17
+ }
18
+
19
+ export interface JoinHubResponse {
20
+ message: string;
21
+ membership: {
22
+ id: string;
23
+ hubId: string;
24
+ userId: string;
25
+ role: 'MEMBER';
26
+ status: 'ACTIVE' | 'PENDING';
27
+ joinedAt: string;
28
+ };
29
+ }
30
+
31
+ export interface LeaveHubResponse {
32
+ message: string;
33
+ }
34
+
35
+ export interface ApproveMemberResponse {
36
+ message: string;
37
+ }
38
+
39
+ export interface UpdateMemberRoleResponse {
40
+ message: string;
41
+ role: 'OWNER' | 'ADMIN' | 'MEMBER';
42
+ }
43
+
44
+ export interface RemoveMemberResponse {
45
+ message: string;
46
+ }
47
+
48
+ // ============================================================================
49
+ // MUTATION HOOKS
50
+ // ============================================================================
51
+
52
+ /**
53
+ * Create a new hub
54
+ *
55
+ * @param options - React Query mutation options
56
+ * @returns Mutation result
57
+ */
58
+ export function useCreateHub(
59
+ options?: Omit<
60
+ UseMutationOptions<HubResponse, Error, CreateHubRequest>,
61
+ 'mutationFn'
62
+ >
63
+ ): UseMutationResult<HubResponse, Error, CreateHubRequest> {
64
+ const queryClient = useQueryClient();
65
+
66
+ return useMutation({
67
+ mutationFn: async (data: CreateHubRequest): Promise<HubResponse> => {
68
+ const client = getApiClient();
69
+ const response = await client.post('/api/v1/hubs', data);
70
+ return response.data;
71
+ },
72
+ onSuccess: (newHub, variables, context) => {
73
+ // Invalidate all hub lists to refetch with the new hub
74
+ queryClient.invalidateQueries({ queryKey: hubKeys.lists() });
75
+ // Invalidate my hubs list
76
+ queryClient.invalidateQueries({ queryKey: hubKeys.myHubs() });
77
+ // Set the new hub in the cache
78
+ queryClient.setQueryData(hubKeys.detail(newHub.id), newHub);
79
+
80
+ // Call user's onSuccess if provided
81
+ },
82
+ ...options,
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Update an existing hub
88
+ *
89
+ * @param options - React Query mutation options
90
+ * @returns Mutation result
91
+ */
92
+ export function useUpdateHub(
93
+ options?: Omit<
94
+ UseMutationOptions<HubResponse, Error, { id: string; data: UpdateHubRequest }>,
95
+ 'mutationFn'
96
+ >
97
+ ): UseMutationResult<HubResponse, Error, { id: string; data: UpdateHubRequest }> {
98
+ const queryClient = useQueryClient();
99
+
100
+ return useMutation({
101
+ mutationFn: async ({
102
+ id,
103
+ data,
104
+ }: {
105
+ id: string;
106
+ data: UpdateHubRequest;
107
+ }): Promise<HubResponse> => {
108
+ const client = getApiClient();
109
+ const response = await client.put(`/api/v1/hubs/${id}`, data);
110
+ return response.data;
111
+ },
112
+ onSuccess: (updatedHub, variables, context) => {
113
+ // Update the hub in the cache
114
+ queryClient.setQueryData(hubKeys.detail(updatedHub.id), updatedHub);
115
+ // Invalidate hub lists to refetch with updated data
116
+ queryClient.invalidateQueries({ queryKey: hubKeys.lists() });
117
+ // Invalidate my hubs list
118
+ queryClient.invalidateQueries({ queryKey: hubKeys.myHubs() });
119
+ // Invalidate slug-based query since slug might have changed
120
+ queryClient.invalidateQueries({
121
+ queryKey: hubKeys.bySlug(updatedHub.slug)
122
+ });
123
+
124
+ // Call user's onSuccess if provided
125
+ },
126
+ ...options,
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Delete a hub
132
+ *
133
+ * @param options - React Query mutation options
134
+ * @returns Mutation result
135
+ */
136
+ export function useDeleteHub(
137
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
138
+ ): UseMutationResult<void, Error, string> {
139
+ const queryClient = useQueryClient();
140
+
141
+ return useMutation({
142
+ mutationFn: async (id: string): Promise<void> => {
143
+ const client = getApiClient();
144
+ await client.delete(`/api/v1/hubs/${id}`);
145
+ },
146
+ onSuccess: (data, id, context) => {
147
+ // Remove the hub from the cache
148
+ queryClient.removeQueries({ queryKey: hubKeys.detail(id) });
149
+ // Invalidate all hub lists to refetch without the deleted hub
150
+ queryClient.invalidateQueries({ queryKey: hubKeys.lists() });
151
+ // Invalidate my hubs list
152
+ queryClient.invalidateQueries({ queryKey: hubKeys.myHubs() });
153
+
154
+ // Call user's onSuccess if provided
155
+ // User's onSuccess is handled by spreading options
156
+ },
157
+ ...options,
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Join a hub
163
+ *
164
+ * @param options - React Query mutation options
165
+ * @returns Mutation result
166
+ */
167
+ export function useJoinHub(
168
+ options?: Omit<UseMutationOptions<JoinHubResponse, Error, string>, 'mutationFn'>
169
+ ): UseMutationResult<JoinHubResponse, Error, string> {
170
+ const queryClient = useQueryClient();
171
+
172
+ return useMutation({
173
+ mutationFn: async (id: string): Promise<JoinHubResponse> => {
174
+ const client = getApiClient();
175
+ const response = await client.post(`/api/v1/hubs/${id}/join`);
176
+ return response.data;
177
+ },
178
+ onSuccess: (data, id, context) => {
179
+ // Invalidate membership status for this hub
180
+ queryClient.invalidateQueries({ queryKey: hubKeys.membership(id) });
181
+ // Invalidate my hubs list
182
+ queryClient.invalidateQueries({ queryKey: hubKeys.myHubs() });
183
+ // Invalidate hub members list
184
+ queryClient.invalidateQueries({ queryKey: hubKeys.members(id) });
185
+ // Refetch hub details to update member count
186
+ queryClient.invalidateQueries({ queryKey: hubKeys.detail(id) });
187
+
188
+ // Call user's onSuccess if provided
189
+ // User's onSuccess is handled by spreading options
190
+ },
191
+ ...options,
192
+ });
193
+ }
194
+
195
+ /**
196
+ * Leave a hub
197
+ *
198
+ * @param options - React Query mutation options
199
+ * @returns Mutation result
200
+ */
201
+ export function useLeaveHub(
202
+ options?: Omit<UseMutationOptions<LeaveHubResponse, Error, string>, 'mutationFn'>
203
+ ): UseMutationResult<LeaveHubResponse, Error, string> {
204
+ const queryClient = useQueryClient();
205
+
206
+ return useMutation({
207
+ mutationFn: async (id: string): Promise<LeaveHubResponse> => {
208
+ const client = getApiClient();
209
+ const response = await client.post(`/api/v1/hubs/${id}/leave`);
210
+ return response.data;
211
+ },
212
+ onSuccess: (data, id, context) => {
213
+ // Invalidate membership status for this hub
214
+ queryClient.invalidateQueries({ queryKey: hubKeys.membership(id) });
215
+ // Invalidate my hubs list
216
+ queryClient.invalidateQueries({ queryKey: hubKeys.myHubs() });
217
+ // Invalidate hub members list
218
+ queryClient.invalidateQueries({ queryKey: hubKeys.members(id) });
219
+ // Refetch hub details to update member count
220
+ queryClient.invalidateQueries({ queryKey: hubKeys.detail(id) });
221
+
222
+ // Call user's onSuccess if provided
223
+ // User's onSuccess is handled by spreading options
224
+ },
225
+ ...options,
226
+ });
227
+ }
228
+
229
+ /**
230
+ * Approve a pending member
231
+ *
232
+ * @param options - React Query mutation options
233
+ * @returns Mutation result
234
+ */
235
+ export function useApproveMember(
236
+ options?: Omit<
237
+ UseMutationOptions<
238
+ ApproveMemberResponse,
239
+ Error,
240
+ { hubId: string; memberId: string }
241
+ >,
242
+ 'mutationFn'
243
+ >
244
+ ): UseMutationResult<
245
+ ApproveMemberResponse,
246
+ Error,
247
+ { hubId: string; memberId: string }
248
+ > {
249
+ const queryClient = useQueryClient();
250
+
251
+ return useMutation({
252
+ mutationFn: async ({
253
+ hubId,
254
+ memberId,
255
+ }: {
256
+ hubId: string;
257
+ memberId: string;
258
+ }): Promise<ApproveMemberResponse> => {
259
+ const client = getApiClient();
260
+ const response = await client.post(
261
+ `/api/v1/hubs/${hubId}/members/${memberId}/approve`
262
+ );
263
+ return response.data;
264
+ },
265
+ onSuccess: (data, variables, context) => {
266
+ // Invalidate hub members list to refetch with updated status
267
+ queryClient.invalidateQueries({
268
+ queryKey: hubKeys.members(variables.hubId)
269
+ });
270
+ // Refetch hub details to update member count
271
+ queryClient.invalidateQueries({
272
+ queryKey: hubKeys.detail(variables.hubId)
273
+ });
274
+
275
+ // Call user's onSuccess if provided
276
+ // User's onSuccess is handled by spreading options
277
+ },
278
+ ...options,
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Update a member's role
284
+ *
285
+ * @param options - React Query mutation options
286
+ * @returns Mutation result
287
+ */
288
+ export function useUpdateMemberRole(
289
+ options?: Omit<
290
+ UseMutationOptions<
291
+ UpdateMemberRoleResponse,
292
+ Error,
293
+ { hubId: string; memberId: string; data: UpdateMemberRoleRequest }
294
+ >,
295
+ 'mutationFn'
296
+ >
297
+ ): UseMutationResult<
298
+ UpdateMemberRoleResponse,
299
+ Error,
300
+ { hubId: string; memberId: string; data: UpdateMemberRoleRequest }
301
+ > {
302
+ const queryClient = useQueryClient();
303
+
304
+ return useMutation({
305
+ mutationFn: async ({
306
+ hubId,
307
+ memberId,
308
+ data,
309
+ }: {
310
+ hubId: string;
311
+ memberId: string;
312
+ data: UpdateMemberRoleRequest;
313
+ }): Promise<UpdateMemberRoleResponse> => {
314
+ const client = getApiClient();
315
+ const response = await client.put(
316
+ `/api/v1/hubs/${hubId}/members/${memberId}/role`,
317
+ data
318
+ );
319
+ return response.data;
320
+ },
321
+ onSuccess: (data, variables, context) => {
322
+ // Invalidate hub members list to refetch with updated role
323
+ queryClient.invalidateQueries({
324
+ queryKey: hubKeys.members(variables.hubId)
325
+ });
326
+
327
+ // Call user's onSuccess if provided
328
+ // User's onSuccess is handled by spreading options
329
+ },
330
+ ...options,
331
+ });
332
+ }
333
+
334
+ /**
335
+ * Remove a member from a hub
336
+ *
337
+ * @param options - React Query mutation options
338
+ * @returns Mutation result
339
+ */
340
+ export function useRemoveMember(
341
+ options?: Omit<
342
+ UseMutationOptions<
343
+ RemoveMemberResponse,
344
+ Error,
345
+ { hubId: string; memberId: string }
346
+ >,
347
+ 'mutationFn'
348
+ >
349
+ ): UseMutationResult<
350
+ RemoveMemberResponse,
351
+ Error,
352
+ { hubId: string; memberId: string }
353
+ > {
354
+ const queryClient = useQueryClient();
355
+
356
+ return useMutation({
357
+ mutationFn: async ({
358
+ hubId,
359
+ memberId,
360
+ }: {
361
+ hubId: string;
362
+ memberId: string;
363
+ }): Promise<RemoveMemberResponse> => {
364
+ const client = getApiClient();
365
+ const response = await client.delete(
366
+ `/api/v1/hubs/${hubId}/members/${memberId}`
367
+ );
368
+ return response.data;
369
+ },
370
+ onSuccess: (data, variables, context) => {
371
+ // Invalidate hub members list to refetch without removed member
372
+ queryClient.invalidateQueries({
373
+ queryKey: hubKeys.members(variables.hubId)
374
+ });
375
+ // Refetch hub details to update member count
376
+ queryClient.invalidateQueries({
377
+ queryKey: hubKeys.detail(variables.hubId)
378
+ });
379
+
380
+ // Call user's onSuccess if provided
381
+ // User's onSuccess is handled by spreading options
382
+ },
383
+ ...options,
384
+ });
385
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Mutation Hooks
3
+ *
4
+ * Re-exports all mutation hooks for API endpoints.
5
+ */
6
+
7
+ export * from './admin';
8
+ export * from './auth';
9
+ export * from './bookings';
10
+ export * from './events';
11
+ export * from './hubs';
12
+ export * from './library';
13
+ export * from './map';
14
+ export * from './notifications';
15
+ export * from './offers';
16
+ export * from './subscriptions';
17
+ export * from './support';
18
+ export * from './users';
19
+ export * from './jack';
20
+ export * from './ambassadors';
21
+ export * from './grow90';
22
+ export * from './matching';
23
+ export * from './event-chat';
@@ -0,0 +1,130 @@
1
+ import { useMutation, useQueryClient, UseMutationOptions } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+ import { jackKeys } from '../queries/jack';
4
+
5
+ // ============================================================================
6
+ // TYPES
7
+ // ============================================================================
8
+
9
+ export interface ChatRequest {
10
+ message: string;
11
+ conversationId?: string;
12
+ }
13
+
14
+ export interface ChatResponse {
15
+ message: string;
16
+ conversationId: string;
17
+ messageId: string;
18
+ }
19
+
20
+ export interface NewConversationResponse {
21
+ conversationId: string;
22
+ }
23
+
24
+ // ============================================================================
25
+ // MUTATION HOOKS
26
+ // ============================================================================
27
+
28
+ /**
29
+ * Send a message to Jack and get a response
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * const chatMutation = useChatWithJack();
34
+ *
35
+ * const handleSend = async (message: string) => {
36
+ * const response = await chatMutation.mutateAsync({
37
+ * message,
38
+ * conversationId: currentConversationId, // optional
39
+ * });
40
+ * console.log('Jack says:', response.message);
41
+ * };
42
+ * ```
43
+ */
44
+ export function useChatWithJack(
45
+ options?: Omit<UseMutationOptions<ChatResponse, Error, ChatRequest>, 'mutationFn'>
46
+ ) {
47
+ const queryClient = useQueryClient();
48
+
49
+ return useMutation({
50
+ mutationFn: async (data: ChatRequest): Promise<ChatResponse> => {
51
+ const client = getApiClient();
52
+ const response = await client.post('/api/v1/support/jack/chat', data);
53
+ // API wraps response in { data: {...}, meta: {...} }
54
+ return response.data?.data || response.data;
55
+ },
56
+ onSuccess: (data) => {
57
+ // Invalidate conversation queries to refresh the list
58
+ queryClient.invalidateQueries({ queryKey: jackKeys.conversations() });
59
+ queryClient.invalidateQueries({ queryKey: jackKeys.history() });
60
+ if (data.conversationId) {
61
+ queryClient.invalidateQueries({ queryKey: jackKeys.conversation(data.conversationId) });
62
+ }
63
+ },
64
+ ...options,
65
+ });
66
+ }
67
+
68
+ /**
69
+ * Start a new conversation with Jack
70
+ *
71
+ * @example
72
+ * ```tsx
73
+ * const newConversation = useStartJackConversation();
74
+ *
75
+ * const handleNewChat = async () => {
76
+ * const { conversationId } = await newConversation.mutateAsync();
77
+ * setCurrentConversationId(conversationId);
78
+ * };
79
+ * ```
80
+ */
81
+ export function useStartJackConversation(
82
+ options?: Omit<UseMutationOptions<NewConversationResponse, Error, void>, 'mutationFn'>
83
+ ) {
84
+ const queryClient = useQueryClient();
85
+
86
+ return useMutation({
87
+ mutationFn: async (): Promise<NewConversationResponse> => {
88
+ const client = getApiClient();
89
+ const response = await client.post('/api/v1/support/jack/conversations/new');
90
+ // API wraps response in { data: {...}, meta: {...} }
91
+ return response.data?.data || response.data;
92
+ },
93
+ onSuccess: () => {
94
+ queryClient.invalidateQueries({ queryKey: jackKeys.conversations() });
95
+ },
96
+ ...options,
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Archive a conversation with Jack
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * const archiveConversation = useArchiveJackConversation();
106
+ *
107
+ * const handleArchive = async (conversationId: string) => {
108
+ * await archiveConversation.mutateAsync(conversationId);
109
+ * };
110
+ * ```
111
+ */
112
+ export function useArchiveJackConversation(
113
+ options?: Omit<UseMutationOptions<{ success: boolean }, Error, string>, 'mutationFn'>
114
+ ) {
115
+ const queryClient = useQueryClient();
116
+
117
+ return useMutation({
118
+ mutationFn: async (conversationId: string): Promise<{ success: boolean }> => {
119
+ const client = getApiClient();
120
+ const response = await client.delete(`/api/v1/support/jack/conversations/${conversationId}`);
121
+ // API wraps response in { data: {...}, meta: {...} }
122
+ return response.data?.data || response.data;
123
+ },
124
+ onSuccess: () => {
125
+ queryClient.invalidateQueries({ queryKey: jackKeys.conversations() });
126
+ queryClient.invalidateQueries({ queryKey: jackKeys.history() });
127
+ },
128
+ ...options,
129
+ });
130
+ }