@growsober/sdk 1.0.5 → 1.0.8

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 (70) hide show
  1. package/dist/__tests__/e2e.test.d.ts +30 -0
  2. package/dist/__tests__/e2e.test.js +959 -63
  3. package/dist/api/mutations/badges.d.ts +116 -0
  4. package/dist/api/mutations/badges.js +177 -0
  5. package/dist/api/mutations/brands.d.ts +251 -0
  6. package/dist/api/mutations/brands.js +242 -0
  7. package/dist/api/mutations/creators.d.ts +131 -0
  8. package/dist/api/mutations/creators.js +129 -0
  9. package/dist/api/mutations/event-chat.d.ts +2 -2
  10. package/dist/api/mutations/event-chat.js +9 -9
  11. package/dist/api/mutations/index.d.ts +4 -0
  12. package/dist/api/mutations/index.js +5 -1
  13. package/dist/api/mutations/jack.d.ts +29 -0
  14. package/dist/api/mutations/jack.js +41 -1
  15. package/dist/api/mutations/products.d.ts +175 -0
  16. package/dist/api/mutations/products.js +226 -0
  17. package/dist/api/mutations/support.d.ts +20 -1
  18. package/dist/api/mutations/support.js +36 -1
  19. package/dist/api/queries/badges.d.ts +221 -0
  20. package/dist/api/queries/badges.js +290 -0
  21. package/dist/api/queries/bookings.d.ts +1 -1
  22. package/dist/api/queries/brands.d.ts +248 -0
  23. package/dist/api/queries/brands.js +226 -0
  24. package/dist/api/queries/businesses.d.ts +61 -1
  25. package/dist/api/queries/businesses.js +27 -1
  26. package/dist/api/queries/creators.d.ts +332 -0
  27. package/dist/api/queries/creators.js +249 -0
  28. package/dist/api/queries/event-chat.d.ts +1 -1
  29. package/dist/api/queries/event-chat.js +4 -4
  30. package/dist/api/queries/events.d.ts +45 -0
  31. package/dist/api/queries/index.d.ts +5 -0
  32. package/dist/api/queries/index.js +6 -1
  33. package/dist/api/queries/jack.d.ts +80 -0
  34. package/dist/api/queries/jack.js +98 -1
  35. package/dist/api/queries/library.d.ts +8 -0
  36. package/dist/api/queries/products.d.ts +185 -0
  37. package/dist/api/queries/products.js +203 -0
  38. package/dist/api/queries/support.d.ts +46 -1
  39. package/dist/api/queries/support.js +48 -1
  40. package/dist/api/queries/venues.d.ts +304 -0
  41. package/dist/api/queries/venues.js +211 -0
  42. package/dist/api/types.d.ts +245 -0
  43. package/dist/api/types.js +6 -1
  44. package/dist/api/utils/eventGrouping.d.ts +104 -0
  45. package/dist/api/utils/eventGrouping.js +155 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +5 -1
  48. package/package.json +5 -2
  49. package/src/__tests__/e2e.test.ts +996 -64
  50. package/src/api/mutations/badges.ts +228 -0
  51. package/src/api/mutations/brands.ts +376 -0
  52. package/src/api/mutations/creators.ts +171 -0
  53. package/src/api/mutations/event-chat.ts +8 -8
  54. package/src/api/mutations/index.ts +4 -0
  55. package/src/api/mutations/jack.ts +50 -1
  56. package/src/api/mutations/products.ts +336 -0
  57. package/src/api/mutations/support.ts +44 -0
  58. package/src/api/queries/badges.ts +385 -0
  59. package/src/api/queries/brands.ts +281 -0
  60. package/src/api/queries/businesses.ts +30 -1
  61. package/src/api/queries/creators.ts +308 -0
  62. package/src/api/queries/event-chat.ts +3 -3
  63. package/src/api/queries/index.ts +5 -0
  64. package/src/api/queries/jack.ts +139 -1
  65. package/src/api/queries/products.ts +312 -0
  66. package/src/api/queries/support.ts +54 -0
  67. package/src/api/queries/venues.ts +271 -0
  68. package/src/api/types.ts +317 -1
  69. package/src/api/utils/eventGrouping.ts +181 -0
  70. package/src/index.ts +6 -0
@@ -0,0 +1,228 @@
1
+ import { useMutation, useQueryClient, UseMutationOptions } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+ import { badgeKeys, rewardKeys } from '../queries/badges';
4
+ import type {
5
+ PartnerRewardResponse,
6
+ PartnerRewardRedemptionResponse,
7
+ CreatePartnerRewardRequest,
8
+ } from '../types';
9
+
10
+ // ============================================================================
11
+ // REWARD MUTATION HOOKS
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Redeem a partner reward
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * const redeemReward = useRedeemReward();
20
+ *
21
+ * const handleRedeem = async (rewardId: string) => {
22
+ * await redeemReward.mutateAsync(rewardId);
23
+ * // Show success message
24
+ * };
25
+ * ```
26
+ */
27
+ export function useRedeemReward(
28
+ options?: Omit<UseMutationOptions<PartnerRewardRedemptionResponse, Error, string>, 'mutationFn'>
29
+ ) {
30
+ const queryClient = useQueryClient();
31
+
32
+ return useMutation({
33
+ mutationFn: async (rewardId: string): Promise<PartnerRewardRedemptionResponse> => {
34
+ const client = getApiClient();
35
+ const response = await client.post(`/api/v1/rewards/${rewardId}/redeem`);
36
+ return response.data?.data || response.data;
37
+ },
38
+ onSuccess: () => {
39
+ // Invalidate wallet, available and redeemed rewards
40
+ queryClient.invalidateQueries({ queryKey: rewardKeys.wallet() });
41
+ queryClient.invalidateQueries({ queryKey: rewardKeys.available() });
42
+ queryClient.invalidateQueries({ queryKey: rewardKeys.redeemed() });
43
+ },
44
+ ...options,
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Create a partner reward (for business dashboard)
50
+ *
51
+ * @param businessId - Business ID creating the reward
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * const createReward = useCreatePartnerReward('business-123');
56
+ *
57
+ * const handleCreate = async () => {
58
+ * await createReward.mutateAsync({
59
+ * badgeId: 'badge-week-warrior',
60
+ * title: 'Free Coffee',
61
+ * description: 'Show your badge for a free coffee',
62
+ * });
63
+ * };
64
+ * ```
65
+ */
66
+ export function useCreatePartnerReward(
67
+ businessId: string,
68
+ options?: Omit<UseMutationOptions<PartnerRewardResponse, Error, CreatePartnerRewardRequest>, 'mutationFn'>
69
+ ) {
70
+ const queryClient = useQueryClient();
71
+
72
+ return useMutation({
73
+ mutationFn: async (data: CreatePartnerRewardRequest): Promise<PartnerRewardResponse> => {
74
+ const client = getApiClient();
75
+ const response = await client.post(`/api/v1/businesses/${businessId}/rewards`, data);
76
+ return response.data?.data || response.data;
77
+ },
78
+ onSuccess: () => {
79
+ queryClient.invalidateQueries({ queryKey: rewardKeys.forBusiness(businessId) });
80
+ },
81
+ ...options,
82
+ });
83
+ }
84
+
85
+ // ============================================================================
86
+ // UNIFIED REWARD MUTATIONS (Venue & Brand)
87
+ // ============================================================================
88
+
89
+ interface CreateRewardRequest {
90
+ badgeId: string;
91
+ title: string;
92
+ description?: string;
93
+ code?: string;
94
+ redeemType?: 'IN_PERSON' | 'ONLINE' | 'BOTH';
95
+ maxRedemptions?: number;
96
+ perUserLimit?: number;
97
+ validFrom?: string;
98
+ validUntil?: string;
99
+ }
100
+
101
+ /**
102
+ * Create a reward for a venue
103
+ *
104
+ * @param venueId - Venue ID
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * const createReward = useCreateVenueReward('venue-123');
109
+ *
110
+ * const handleCreate = async () => {
111
+ * await createReward.mutateAsync({
112
+ * badgeId: 'badge-week-warrior',
113
+ * title: 'Free Coffee',
114
+ * description: 'Show your badge for a free coffee',
115
+ * redeemType: 'IN_PERSON',
116
+ * });
117
+ * };
118
+ * ```
119
+ */
120
+ export function useCreateVenueReward(
121
+ venueId: string,
122
+ options?: Omit<UseMutationOptions<unknown, Error, CreateRewardRequest>, 'mutationFn'>
123
+ ) {
124
+ const queryClient = useQueryClient();
125
+
126
+ return useMutation({
127
+ mutationFn: async (data: CreateRewardRequest) => {
128
+ const client = getApiClient();
129
+ const response = await client.post(`/api/v1/venues/${venueId}/rewards`, data);
130
+ return response.data?.data || response.data;
131
+ },
132
+ onSuccess: () => {
133
+ queryClient.invalidateQueries({ queryKey: rewardKeys.forVenue(venueId) });
134
+ queryClient.invalidateQueries({ queryKey: rewardKeys.available() });
135
+ },
136
+ ...options,
137
+ });
138
+ }
139
+
140
+ /**
141
+ * Create a reward for a brand
142
+ *
143
+ * @param brandId - Brand ID
144
+ *
145
+ * @example
146
+ * ```tsx
147
+ * const createReward = useCreateBrandReward('brand-123');
148
+ *
149
+ * const handleCreate = async () => {
150
+ * await createReward.mutateAsync({
151
+ * badgeId: 'badge-week-warrior',
152
+ * title: '10% Off',
153
+ * description: 'Use code at checkout',
154
+ * code: 'SOBER10',
155
+ * redeemType: 'ONLINE',
156
+ * });
157
+ * };
158
+ * ```
159
+ */
160
+ export function useCreateBrandReward(
161
+ brandId: string,
162
+ options?: Omit<UseMutationOptions<unknown, Error, CreateRewardRequest>, 'mutationFn'>
163
+ ) {
164
+ const queryClient = useQueryClient();
165
+
166
+ return useMutation({
167
+ mutationFn: async (data: CreateRewardRequest) => {
168
+ const client = getApiClient();
169
+ const response = await client.post(`/api/v1/brands/${brandId}/rewards`, data);
170
+ return response.data?.data || response.data;
171
+ },
172
+ onSuccess: () => {
173
+ queryClient.invalidateQueries({ queryKey: rewardKeys.forBrand(brandId) });
174
+ queryClient.invalidateQueries({ queryKey: rewardKeys.available() });
175
+ },
176
+ ...options,
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Update a partner reward (for business dashboard)
182
+ *
183
+ * @param businessId - Business ID
184
+ *
185
+ * @example
186
+ * ```tsx
187
+ * const updateReward = useUpdatePartnerReward('business-123');
188
+ *
189
+ * const handleUpdate = async (rewardId: string) => {
190
+ * await updateReward.mutateAsync({
191
+ * id: rewardId,
192
+ * data: { title: 'Updated Title', isActive: false },
193
+ * });
194
+ * };
195
+ * ```
196
+ */
197
+ export function useUpdatePartnerReward(
198
+ businessId: string,
199
+ options?: Omit<
200
+ UseMutationOptions<
201
+ PartnerRewardResponse,
202
+ Error,
203
+ { id: string; data: Partial<CreatePartnerRewardRequest & { isActive: boolean }> }
204
+ >,
205
+ 'mutationFn'
206
+ >
207
+ ) {
208
+ const queryClient = useQueryClient();
209
+
210
+ return useMutation({
211
+ mutationFn: async ({
212
+ id,
213
+ data,
214
+ }: {
215
+ id: string;
216
+ data: Partial<CreatePartnerRewardRequest & { isActive: boolean }>;
217
+ }): Promise<PartnerRewardResponse> => {
218
+ const client = getApiClient();
219
+ const response = await client.patch(`/api/v1/businesses/${businessId}/rewards/${id}`, data);
220
+ return response.data?.data || response.data;
221
+ },
222
+ onSuccess: () => {
223
+ queryClient.invalidateQueries({ queryKey: rewardKeys.forBusiness(businessId) });
224
+ queryClient.invalidateQueries({ queryKey: rewardKeys.available() });
225
+ },
226
+ ...options,
227
+ });
228
+ }
@@ -0,0 +1,376 @@
1
+ import { useMutation, useQueryClient, UseMutationOptions } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+ import { brandKeys } from '../queries/brands';
4
+ import type {
5
+ BrandResponse,
6
+ BrandOwnerResponse,
7
+ BrandCreatorResponse,
8
+ BrandOwnerRole,
9
+ CreateBrandRequest,
10
+ UpdateBrandRequest,
11
+ } from '../types';
12
+
13
+ // ============================================================================
14
+ // MUTATION HOOKS
15
+ // ============================================================================
16
+
17
+ /**
18
+ * Create a new brand
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const { mutateAsync: createBrand } = useCreateBrand();
23
+ *
24
+ * await createBrand({
25
+ * slug: 'wellness-co',
26
+ * name: 'Wellness Co',
27
+ * description: 'A wellness brand',
28
+ * });
29
+ * ```
30
+ */
31
+ export function useCreateBrand(
32
+ options?: Omit<UseMutationOptions<BrandResponse, Error, CreateBrandRequest>, 'mutationFn'>
33
+ ) {
34
+ const queryClient = useQueryClient();
35
+
36
+ return useMutation({
37
+ mutationFn: async (data: CreateBrandRequest): Promise<BrandResponse> => {
38
+ const client = getApiClient();
39
+ const response = await client.post('/api/v1/brands', data);
40
+ return response.data;
41
+ },
42
+ onSuccess: () => {
43
+ queryClient.invalidateQueries({ queryKey: brandKeys.all });
44
+ },
45
+ ...options,
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Update a brand
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * const { mutateAsync: updateBrand } = useUpdateBrand();
55
+ *
56
+ * await updateBrand({
57
+ * id: 'brand-123',
58
+ * data: { description: 'Updated description' },
59
+ * });
60
+ * ```
61
+ */
62
+ export function useUpdateBrand(
63
+ options?: Omit<
64
+ UseMutationOptions<BrandResponse, Error, { id: string; data: UpdateBrandRequest }>,
65
+ 'mutationFn'
66
+ >
67
+ ) {
68
+ const queryClient = useQueryClient();
69
+
70
+ return useMutation({
71
+ mutationFn: async ({ id, data }: { id: string; data: UpdateBrandRequest }): Promise<BrandResponse> => {
72
+ const client = getApiClient();
73
+ const response = await client.patch(`/api/v1/brands/${id}`, data);
74
+ return response.data;
75
+ },
76
+ onSuccess: (_, variables) => {
77
+ queryClient.invalidateQueries({ queryKey: brandKeys.detail(variables.id) });
78
+ },
79
+ ...options,
80
+ });
81
+ }
82
+
83
+ /**
84
+ * Add a brand owner
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * const { mutateAsync: addOwner } = useAddBrandOwner();
89
+ *
90
+ * await addOwner({
91
+ * brandId: 'brand-123',
92
+ * userId: 'user-456',
93
+ * role: 'MANAGER',
94
+ * });
95
+ * ```
96
+ */
97
+ export function useAddBrandOwner(
98
+ options?: Omit<
99
+ UseMutationOptions<
100
+ BrandOwnerResponse,
101
+ Error,
102
+ { brandId: string; userId: string; role: BrandOwnerRole }
103
+ >,
104
+ 'mutationFn'
105
+ >
106
+ ) {
107
+ const queryClient = useQueryClient();
108
+
109
+ return useMutation({
110
+ mutationFn: async ({
111
+ brandId,
112
+ userId,
113
+ role,
114
+ }: {
115
+ brandId: string;
116
+ userId: string;
117
+ role: BrandOwnerRole;
118
+ }): Promise<BrandOwnerResponse> => {
119
+ const client = getApiClient();
120
+ const response = await client.post(`/api/v1/brands/${brandId}/owners`, { userId, role });
121
+ return response.data;
122
+ },
123
+ onSuccess: (_, variables) => {
124
+ queryClient.invalidateQueries({ queryKey: brandKeys.owners(variables.brandId) });
125
+ },
126
+ ...options,
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Update a brand owner's role
132
+ *
133
+ * @example
134
+ * ```tsx
135
+ * const { mutateAsync: updateOwnerRole } = useUpdateBrandOwnerRole();
136
+ *
137
+ * await updateOwnerRole({
138
+ * brandId: 'brand-123',
139
+ * userId: 'user-456',
140
+ * role: 'OWNER',
141
+ * });
142
+ * ```
143
+ */
144
+ export function useUpdateBrandOwnerRole(
145
+ options?: Omit<
146
+ UseMutationOptions<
147
+ BrandOwnerResponse,
148
+ Error,
149
+ { brandId: string; userId: string; role: BrandOwnerRole }
150
+ >,
151
+ 'mutationFn'
152
+ >
153
+ ) {
154
+ const queryClient = useQueryClient();
155
+
156
+ return useMutation({
157
+ mutationFn: async ({
158
+ brandId,
159
+ userId,
160
+ role,
161
+ }: {
162
+ brandId: string;
163
+ userId: string;
164
+ role: BrandOwnerRole;
165
+ }): Promise<BrandOwnerResponse> => {
166
+ const client = getApiClient();
167
+ const response = await client.patch(`/api/v1/brands/${brandId}/owners/${userId}`, { role });
168
+ return response.data;
169
+ },
170
+ onSuccess: (_, variables) => {
171
+ queryClient.invalidateQueries({ queryKey: brandKeys.owners(variables.brandId) });
172
+ },
173
+ ...options,
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Remove a brand owner
179
+ *
180
+ * @example
181
+ * ```tsx
182
+ * const { mutateAsync: removeOwner } = useRemoveBrandOwner();
183
+ *
184
+ * await removeOwner({
185
+ * brandId: 'brand-123',
186
+ * userId: 'user-456',
187
+ * });
188
+ * ```
189
+ */
190
+ export function useRemoveBrandOwner(
191
+ options?: Omit<
192
+ UseMutationOptions<void, Error, { brandId: string; userId: string }>,
193
+ 'mutationFn'
194
+ >
195
+ ) {
196
+ const queryClient = useQueryClient();
197
+
198
+ return useMutation({
199
+ mutationFn: async ({
200
+ brandId,
201
+ userId,
202
+ }: {
203
+ brandId: string;
204
+ userId: string;
205
+ }): Promise<void> => {
206
+ const client = getApiClient();
207
+ await client.delete(`/api/v1/brands/${brandId}/owners/${userId}`);
208
+ },
209
+ onSuccess: (_, variables) => {
210
+ queryClient.invalidateQueries({ queryKey: brandKeys.owners(variables.brandId) });
211
+ },
212
+ ...options,
213
+ });
214
+ }
215
+
216
+ /**
217
+ * Add a creator partnership to a brand
218
+ *
219
+ * @example
220
+ * ```tsx
221
+ * const { mutateAsync: addCreator } = useAddBrandCreator();
222
+ *
223
+ * await addCreator({
224
+ * brandId: 'brand-123',
225
+ * creatorId: 'creator-456',
226
+ * commissionRate: 0.15,
227
+ * });
228
+ * ```
229
+ */
230
+ export function useAddBrandCreator(
231
+ options?: Omit<
232
+ UseMutationOptions<
233
+ BrandCreatorResponse,
234
+ Error,
235
+ {
236
+ brandId: string;
237
+ creatorId: string;
238
+ startDate?: string;
239
+ endDate?: string;
240
+ commissionRate?: number;
241
+ isActive?: boolean;
242
+ }
243
+ >,
244
+ 'mutationFn'
245
+ >
246
+ ) {
247
+ const queryClient = useQueryClient();
248
+
249
+ return useMutation({
250
+ mutationFn: async ({
251
+ brandId,
252
+ creatorId,
253
+ startDate,
254
+ endDate,
255
+ commissionRate,
256
+ isActive,
257
+ }: {
258
+ brandId: string;
259
+ creatorId: string;
260
+ startDate?: string;
261
+ endDate?: string;
262
+ commissionRate?: number;
263
+ isActive?: boolean;
264
+ }): Promise<BrandCreatorResponse> => {
265
+ const client = getApiClient();
266
+ const response = await client.post(`/api/v1/brands/${brandId}/creators`, {
267
+ creatorId,
268
+ startDate,
269
+ endDate,
270
+ commissionRate,
271
+ isActive,
272
+ });
273
+ return response.data;
274
+ },
275
+ onSuccess: (_, variables) => {
276
+ queryClient.invalidateQueries({ queryKey: brandKeys.creators(variables.brandId) });
277
+ },
278
+ ...options,
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Update a creator partnership
284
+ *
285
+ * @example
286
+ * ```tsx
287
+ * const { mutateAsync: updateCreator } = useUpdateBrandCreator();
288
+ *
289
+ * await updateCreator({
290
+ * brandId: 'brand-123',
291
+ * creatorId: 'creator-456',
292
+ * isActive: false,
293
+ * });
294
+ * ```
295
+ */
296
+ export function useUpdateBrandCreator(
297
+ options?: Omit<
298
+ UseMutationOptions<
299
+ BrandCreatorResponse,
300
+ Error,
301
+ {
302
+ brandId: string;
303
+ creatorId: string;
304
+ startDate?: string;
305
+ endDate?: string;
306
+ commissionRate?: number;
307
+ isActive?: boolean;
308
+ }
309
+ >,
310
+ 'mutationFn'
311
+ >
312
+ ) {
313
+ const queryClient = useQueryClient();
314
+
315
+ return useMutation({
316
+ mutationFn: async ({
317
+ brandId,
318
+ creatorId,
319
+ ...data
320
+ }: {
321
+ brandId: string;
322
+ creatorId: string;
323
+ startDate?: string;
324
+ endDate?: string;
325
+ commissionRate?: number;
326
+ isActive?: boolean;
327
+ }): Promise<BrandCreatorResponse> => {
328
+ const client = getApiClient();
329
+ const response = await client.patch(`/api/v1/brands/${brandId}/creators/${creatorId}`, data);
330
+ return response.data;
331
+ },
332
+ onSuccess: (_, variables) => {
333
+ queryClient.invalidateQueries({ queryKey: brandKeys.creators(variables.brandId) });
334
+ },
335
+ ...options,
336
+ });
337
+ }
338
+
339
+ /**
340
+ * Remove a creator partnership from a brand
341
+ *
342
+ * @example
343
+ * ```tsx
344
+ * const { mutateAsync: removeCreator } = useRemoveBrandCreator();
345
+ *
346
+ * await removeCreator({
347
+ * brandId: 'brand-123',
348
+ * creatorId: 'creator-456',
349
+ * });
350
+ * ```
351
+ */
352
+ export function useRemoveBrandCreator(
353
+ options?: Omit<
354
+ UseMutationOptions<void, Error, { brandId: string; creatorId: string }>,
355
+ 'mutationFn'
356
+ >
357
+ ) {
358
+ const queryClient = useQueryClient();
359
+
360
+ return useMutation({
361
+ mutationFn: async ({
362
+ brandId,
363
+ creatorId,
364
+ }: {
365
+ brandId: string;
366
+ creatorId: string;
367
+ }): Promise<void> => {
368
+ const client = getApiClient();
369
+ await client.delete(`/api/v1/brands/${brandId}/creators/${creatorId}`);
370
+ },
371
+ onSuccess: (_, variables) => {
372
+ queryClient.invalidateQueries({ queryKey: brandKeys.creators(variables.brandId) });
373
+ },
374
+ ...options,
375
+ });
376
+ }