@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.
- package/dist/__tests__/e2e.test.d.ts +30 -0
- package/dist/__tests__/e2e.test.js +959 -63
- package/dist/api/mutations/badges.d.ts +116 -0
- package/dist/api/mutations/badges.js +177 -0
- package/dist/api/mutations/brands.d.ts +251 -0
- package/dist/api/mutations/brands.js +242 -0
- package/dist/api/mutations/creators.d.ts +131 -0
- package/dist/api/mutations/creators.js +129 -0
- package/dist/api/mutations/event-chat.d.ts +2 -2
- package/dist/api/mutations/event-chat.js +9 -9
- package/dist/api/mutations/index.d.ts +4 -0
- package/dist/api/mutations/index.js +5 -1
- package/dist/api/mutations/jack.d.ts +29 -0
- package/dist/api/mutations/jack.js +41 -1
- package/dist/api/mutations/products.d.ts +175 -0
- package/dist/api/mutations/products.js +226 -0
- package/dist/api/mutations/support.d.ts +20 -1
- package/dist/api/mutations/support.js +36 -1
- package/dist/api/queries/badges.d.ts +221 -0
- package/dist/api/queries/badges.js +290 -0
- package/dist/api/queries/bookings.d.ts +1 -1
- package/dist/api/queries/brands.d.ts +248 -0
- package/dist/api/queries/brands.js +226 -0
- package/dist/api/queries/businesses.d.ts +61 -1
- package/dist/api/queries/businesses.js +27 -1
- package/dist/api/queries/creators.d.ts +332 -0
- package/dist/api/queries/creators.js +249 -0
- package/dist/api/queries/event-chat.d.ts +1 -1
- package/dist/api/queries/event-chat.js +4 -4
- package/dist/api/queries/events.d.ts +45 -0
- package/dist/api/queries/index.d.ts +5 -0
- package/dist/api/queries/index.js +6 -1
- package/dist/api/queries/jack.d.ts +80 -0
- package/dist/api/queries/jack.js +98 -1
- package/dist/api/queries/library.d.ts +8 -0
- package/dist/api/queries/products.d.ts +185 -0
- package/dist/api/queries/products.js +203 -0
- package/dist/api/queries/support.d.ts +46 -1
- package/dist/api/queries/support.js +48 -1
- package/dist/api/queries/venues.d.ts +304 -0
- package/dist/api/queries/venues.js +211 -0
- package/dist/api/types.d.ts +245 -0
- package/dist/api/types.js +6 -1
- package/dist/api/utils/eventGrouping.d.ts +104 -0
- package/dist/api/utils/eventGrouping.js +155 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/package.json +5 -2
- package/src/__tests__/e2e.test.ts +996 -64
- package/src/api/mutations/badges.ts +228 -0
- package/src/api/mutations/brands.ts +376 -0
- package/src/api/mutations/creators.ts +171 -0
- package/src/api/mutations/event-chat.ts +8 -8
- package/src/api/mutations/index.ts +4 -0
- package/src/api/mutations/jack.ts +50 -1
- package/src/api/mutations/products.ts +336 -0
- package/src/api/mutations/support.ts +44 -0
- package/src/api/queries/badges.ts +385 -0
- package/src/api/queries/brands.ts +281 -0
- package/src/api/queries/businesses.ts +30 -1
- package/src/api/queries/creators.ts +308 -0
- package/src/api/queries/event-chat.ts +3 -3
- package/src/api/queries/index.ts +5 -0
- package/src/api/queries/jack.ts +139 -1
- package/src/api/queries/products.ts +312 -0
- package/src/api/queries/support.ts +54 -0
- package/src/api/queries/venues.ts +271 -0
- package/src/api/types.ts +317 -1
- package/src/api/utils/eventGrouping.ts +181 -0
- package/src/index.ts +6 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// TYPES
|
|
6
|
+
// ============================================================================
|
|
7
|
+
|
|
8
|
+
export type ProductType = 'SESSION_1ON1' | 'SESSION_GROUP' | 'PACKAGE' | 'WORKSHOP' | 'CONSULTATION';
|
|
9
|
+
export type DeliveryMethod = 'VIDEO_CALL' | 'PHONE_CALL' | 'IN_PERSON' | 'HYBRID';
|
|
10
|
+
export type BookingStatus = 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED';
|
|
11
|
+
export type PaymentStatus = 'PENDING' | 'PAID' | 'REFUNDED' | 'FAILED';
|
|
12
|
+
|
|
13
|
+
export interface CreatorProductResponse {
|
|
14
|
+
id: string;
|
|
15
|
+
creatorId: string;
|
|
16
|
+
title: string;
|
|
17
|
+
slug: string;
|
|
18
|
+
description: string | null;
|
|
19
|
+
imageUrl: string | null;
|
|
20
|
+
type: ProductType;
|
|
21
|
+
price: number;
|
|
22
|
+
currency: string;
|
|
23
|
+
durationMinutes: number;
|
|
24
|
+
maxParticipants: number;
|
|
25
|
+
deliveryMethod: DeliveryMethod;
|
|
26
|
+
locationDetails: string | null;
|
|
27
|
+
isActive: boolean;
|
|
28
|
+
isFeatured: boolean;
|
|
29
|
+
createdAt: string;
|
|
30
|
+
updatedAt: string;
|
|
31
|
+
creator?: {
|
|
32
|
+
id: string;
|
|
33
|
+
displayName: string;
|
|
34
|
+
slug: string;
|
|
35
|
+
avatarUrl: string | null;
|
|
36
|
+
specialties?: string[];
|
|
37
|
+
certifications?: string[];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ProductBookingResponse {
|
|
42
|
+
id: string;
|
|
43
|
+
productId: string;
|
|
44
|
+
userId: string;
|
|
45
|
+
scheduledAt: string;
|
|
46
|
+
timezone: string;
|
|
47
|
+
status: BookingStatus;
|
|
48
|
+
paymentStatus: PaymentStatus | null;
|
|
49
|
+
stripePaymentIntentId: string | null;
|
|
50
|
+
amountPaid: number | null;
|
|
51
|
+
currency: string;
|
|
52
|
+
clientNotes: string | null;
|
|
53
|
+
creatorNotes: string | null;
|
|
54
|
+
meetingLink: string | null;
|
|
55
|
+
isCompleted: boolean;
|
|
56
|
+
completedAt: string | null;
|
|
57
|
+
isCancelled: boolean;
|
|
58
|
+
cancelledAt: string | null;
|
|
59
|
+
cancelledBy: string | null;
|
|
60
|
+
cancellationReason: string | null;
|
|
61
|
+
createdAt: string;
|
|
62
|
+
updatedAt: string;
|
|
63
|
+
product?: CreatorProductResponse;
|
|
64
|
+
user?: {
|
|
65
|
+
id: string;
|
|
66
|
+
name: string;
|
|
67
|
+
profileImage: string | null;
|
|
68
|
+
email: string;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface ProductFilters {
|
|
73
|
+
page?: number;
|
|
74
|
+
limit?: number;
|
|
75
|
+
type?: ProductType;
|
|
76
|
+
deliveryMethod?: DeliveryMethod;
|
|
77
|
+
minPrice?: number;
|
|
78
|
+
maxPrice?: number;
|
|
79
|
+
isActive?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface PaginatedProductsResponse {
|
|
83
|
+
products: CreatorProductResponse[];
|
|
84
|
+
meta: {
|
|
85
|
+
total: number;
|
|
86
|
+
page: number;
|
|
87
|
+
limit: number;
|
|
88
|
+
totalPages: number;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// QUERY KEY FACTORY
|
|
94
|
+
// ============================================================================
|
|
95
|
+
|
|
96
|
+
export const productKeys = {
|
|
97
|
+
all: ['products'] as const,
|
|
98
|
+
lists: () => [...productKeys.all, 'list'] as const,
|
|
99
|
+
list: (filters?: ProductFilters) => [...productKeys.lists(), filters] as const,
|
|
100
|
+
details: () => [...productKeys.all, 'detail'] as const,
|
|
101
|
+
detail: (id: string) => [...productKeys.details(), id] as const,
|
|
102
|
+
slug: (slug: string) => [...productKeys.all, 'slug', slug] as const,
|
|
103
|
+
byCreator: (creatorId: string, filters?: ProductFilters) =>
|
|
104
|
+
[...productKeys.all, 'creator', creatorId, filters] as const,
|
|
105
|
+
bookings: () => [...productKeys.all, 'bookings'] as const,
|
|
106
|
+
myBookings: () => [...productKeys.bookings(), 'me'] as const,
|
|
107
|
+
creatorBookings: (creatorId: string) => [...productKeys.bookings(), 'creator', creatorId] as const,
|
|
108
|
+
bookingDetail: (bookingId: string) => [...productKeys.bookings(), 'detail', bookingId] as const,
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// QUERY HOOKS
|
|
113
|
+
// ============================================================================
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get paginated list of all active products
|
|
117
|
+
*
|
|
118
|
+
* @param filters - Query parameters for filtering and pagination
|
|
119
|
+
* @param options - TanStack Query options
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```tsx
|
|
123
|
+
* const { data, isLoading } = useProducts({
|
|
124
|
+
* page: 1,
|
|
125
|
+
* limit: 20,
|
|
126
|
+
* type: 'SESSION_1ON1',
|
|
127
|
+
* });
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function useProducts(
|
|
131
|
+
filters?: ProductFilters,
|
|
132
|
+
options?: Omit<UseQueryOptions<PaginatedProductsResponse>, 'queryKey' | 'queryFn'>
|
|
133
|
+
) {
|
|
134
|
+
return useQuery({
|
|
135
|
+
queryKey: productKeys.list(filters),
|
|
136
|
+
queryFn: async (): Promise<PaginatedProductsResponse> => {
|
|
137
|
+
const client = getApiClient();
|
|
138
|
+
const response = await client.get('/api/v1/products', {
|
|
139
|
+
params: filters,
|
|
140
|
+
});
|
|
141
|
+
return response.data;
|
|
142
|
+
},
|
|
143
|
+
...options,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get a single product by ID
|
|
149
|
+
*
|
|
150
|
+
* @param id - Product ID
|
|
151
|
+
* @param options - TanStack Query options
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```tsx
|
|
155
|
+
* const { data, isLoading } = useProduct('product-123');
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export function useProduct(
|
|
159
|
+
id: string,
|
|
160
|
+
options?: Omit<UseQueryOptions<CreatorProductResponse>, 'queryKey' | 'queryFn'>
|
|
161
|
+
) {
|
|
162
|
+
return useQuery({
|
|
163
|
+
queryKey: productKeys.detail(id),
|
|
164
|
+
queryFn: async (): Promise<CreatorProductResponse> => {
|
|
165
|
+
const client = getApiClient();
|
|
166
|
+
const response = await client.get(`/api/v1/products/${id}`);
|
|
167
|
+
return response.data;
|
|
168
|
+
},
|
|
169
|
+
enabled: !!id,
|
|
170
|
+
...options,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get a product by its slug
|
|
176
|
+
*
|
|
177
|
+
* @param slug - Product slug
|
|
178
|
+
* @param options - TanStack Query options
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```tsx
|
|
182
|
+
* const { data, isLoading } = useProductBySlug('1-on-1-coaching-abc123');
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export function useProductBySlug(
|
|
186
|
+
slug: string,
|
|
187
|
+
options?: Omit<UseQueryOptions<CreatorProductResponse>, 'queryKey' | 'queryFn'>
|
|
188
|
+
) {
|
|
189
|
+
return useQuery({
|
|
190
|
+
queryKey: productKeys.slug(slug),
|
|
191
|
+
queryFn: async (): Promise<CreatorProductResponse> => {
|
|
192
|
+
const client = getApiClient();
|
|
193
|
+
const response = await client.get(`/api/v1/products/slug/${slug}`);
|
|
194
|
+
return response.data;
|
|
195
|
+
},
|
|
196
|
+
enabled: !!slug,
|
|
197
|
+
...options,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Get products for a specific creator
|
|
203
|
+
*
|
|
204
|
+
* @param creatorId - Creator ID
|
|
205
|
+
* @param filters - Query parameters for filtering
|
|
206
|
+
* @param options - TanStack Query options
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```tsx
|
|
210
|
+
* const { data, isLoading } = useCreatorProducts('creator-123', {
|
|
211
|
+
* type: 'SESSION_1ON1',
|
|
212
|
+
* isActive: true,
|
|
213
|
+
* });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export function useCreatorProducts(
|
|
217
|
+
creatorId: string,
|
|
218
|
+
filters?: ProductFilters,
|
|
219
|
+
options?: Omit<UseQueryOptions<PaginatedProductsResponse>, 'queryKey' | 'queryFn'>
|
|
220
|
+
) {
|
|
221
|
+
return useQuery({
|
|
222
|
+
queryKey: productKeys.byCreator(creatorId, filters),
|
|
223
|
+
queryFn: async (): Promise<PaginatedProductsResponse> => {
|
|
224
|
+
const client = getApiClient();
|
|
225
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/products`, {
|
|
226
|
+
params: filters,
|
|
227
|
+
});
|
|
228
|
+
return response.data;
|
|
229
|
+
},
|
|
230
|
+
enabled: !!creatorId,
|
|
231
|
+
...options,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get current user's product bookings
|
|
237
|
+
*
|
|
238
|
+
* @param options - TanStack Query options
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* ```tsx
|
|
242
|
+
* const { data, isLoading } = useMyProductBookings();
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
export function useMyProductBookings(
|
|
246
|
+
options?: Omit<UseQueryOptions<ProductBookingResponse[]>, 'queryKey' | 'queryFn'>
|
|
247
|
+
) {
|
|
248
|
+
return useQuery({
|
|
249
|
+
queryKey: productKeys.myBookings(),
|
|
250
|
+
queryFn: async (): Promise<ProductBookingResponse[]> => {
|
|
251
|
+
const client = getApiClient();
|
|
252
|
+
const response = await client.get('/api/v1/users/me/product-bookings');
|
|
253
|
+
return response.data;
|
|
254
|
+
},
|
|
255
|
+
...options,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get a single product booking by ID
|
|
261
|
+
*
|
|
262
|
+
* @param bookingId - Booking ID
|
|
263
|
+
* @param options - TanStack Query options
|
|
264
|
+
*
|
|
265
|
+
* @example
|
|
266
|
+
* ```tsx
|
|
267
|
+
* const { data, isLoading } = useProductBooking('booking-123');
|
|
268
|
+
* ```
|
|
269
|
+
*/
|
|
270
|
+
export function useProductBooking(
|
|
271
|
+
bookingId: string,
|
|
272
|
+
options?: Omit<UseQueryOptions<ProductBookingResponse>, 'queryKey' | 'queryFn'>
|
|
273
|
+
) {
|
|
274
|
+
return useQuery({
|
|
275
|
+
queryKey: productKeys.bookingDetail(bookingId),
|
|
276
|
+
queryFn: async (): Promise<ProductBookingResponse> => {
|
|
277
|
+
const client = getApiClient();
|
|
278
|
+
const response = await client.get(`/api/v1/users/me/product-bookings/${bookingId}`);
|
|
279
|
+
return response.data;
|
|
280
|
+
},
|
|
281
|
+
enabled: !!bookingId,
|
|
282
|
+
...options,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Get bookings for a creator's products (creator dashboard)
|
|
288
|
+
*
|
|
289
|
+
* @param creatorId - Creator ID
|
|
290
|
+
* @param options - TanStack Query options
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```tsx
|
|
294
|
+
* // For creator dashboard - see all bookings for their products
|
|
295
|
+
* const { data, isLoading } = useCreatorBookings('creator-123');
|
|
296
|
+
* ```
|
|
297
|
+
*/
|
|
298
|
+
export function useCreatorBookings(
|
|
299
|
+
creatorId: string,
|
|
300
|
+
options?: Omit<UseQueryOptions<ProductBookingResponse[]>, 'queryKey' | 'queryFn'>
|
|
301
|
+
) {
|
|
302
|
+
return useQuery({
|
|
303
|
+
queryKey: productKeys.creatorBookings(creatorId),
|
|
304
|
+
queryFn: async (): Promise<ProductBookingResponse[]> => {
|
|
305
|
+
const client = getApiClient();
|
|
306
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/products/bookings`);
|
|
307
|
+
return response.data;
|
|
308
|
+
},
|
|
309
|
+
enabled: !!creatorId,
|
|
310
|
+
...options,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
@@ -7,6 +7,8 @@ import type {
|
|
|
7
7
|
WinResponse,
|
|
8
8
|
HabitResponse,
|
|
9
9
|
ReflectionResponse,
|
|
10
|
+
CravingLogResponse,
|
|
11
|
+
CravingStatsResponse,
|
|
10
12
|
} from '../types';
|
|
11
13
|
|
|
12
14
|
// ============================================================================
|
|
@@ -19,6 +21,8 @@ export const supportKeys = {
|
|
|
19
21
|
checkInToday: () => [...supportKeys.checkIns(), 'today'] as const,
|
|
20
22
|
checkInStreak: () => [...supportKeys.checkIns(), 'streak'] as const,
|
|
21
23
|
moodLogs: () => [...supportKeys.all, 'mood'] as const,
|
|
24
|
+
cravings: () => [...supportKeys.all, 'cravings'] as const,
|
|
25
|
+
cravingStats: (days?: number) => [...supportKeys.cravings(), 'stats', days] as const,
|
|
22
26
|
wins: () => [...supportKeys.all, 'wins'] as const,
|
|
23
27
|
winsByCategory: () => [...supportKeys.wins(), 'by-category'] as const,
|
|
24
28
|
habits: () => [...supportKeys.all, 'habits'] as const,
|
|
@@ -233,3 +237,53 @@ export function useReflections(
|
|
|
233
237
|
...options,
|
|
234
238
|
});
|
|
235
239
|
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get user's craving logs
|
|
243
|
+
*
|
|
244
|
+
* @param options - TanStack Query options
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```tsx
|
|
248
|
+
* const { data, isLoading } = useCravings();
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
export function useCravings(
|
|
252
|
+
options?: Omit<UseQueryOptions<CravingLogResponse[]>, 'queryKey' | 'queryFn'>
|
|
253
|
+
) {
|
|
254
|
+
return useQuery({
|
|
255
|
+
queryKey: supportKeys.cravings(),
|
|
256
|
+
queryFn: async (): Promise<CravingLogResponse[]> => {
|
|
257
|
+
const client = getApiClient();
|
|
258
|
+
const response = await client.get('/api/v1/support/cravings');
|
|
259
|
+
return response.data;
|
|
260
|
+
},
|
|
261
|
+
...options,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get craving statistics for a given period
|
|
267
|
+
*
|
|
268
|
+
* @param days - Number of days to include (default: 30)
|
|
269
|
+
* @param options - TanStack Query options
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```tsx
|
|
273
|
+
* const { data, isLoading } = useCravingStats(30);
|
|
274
|
+
* ```
|
|
275
|
+
*/
|
|
276
|
+
export function useCravingStats(
|
|
277
|
+
days: number = 30,
|
|
278
|
+
options?: Omit<UseQueryOptions<CravingStatsResponse>, 'queryKey' | 'queryFn'>
|
|
279
|
+
) {
|
|
280
|
+
return useQuery({
|
|
281
|
+
queryKey: supportKeys.cravingStats(days),
|
|
282
|
+
queryFn: async (): Promise<CravingStatsResponse> => {
|
|
283
|
+
const client = getApiClient();
|
|
284
|
+
const response = await client.get(`/api/v1/support/cravings/stats?days=${days}`);
|
|
285
|
+
return response.data;
|
|
286
|
+
},
|
|
287
|
+
...options,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type { VenueResponse, VenueOwnerResponse, EventResponse, OfferResponse } from '../types';
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// QUERY KEY FACTORY
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
export const venueKeys = {
|
|
10
|
+
all: ['venues'] as const,
|
|
11
|
+
lists: () => [...venueKeys.all, 'list'] as const,
|
|
12
|
+
list: (filters?: VenueFilters) => [...venueKeys.lists(), filters] as const,
|
|
13
|
+
details: () => [...venueKeys.all, 'detail'] as const,
|
|
14
|
+
detail: (id: string) => [...venueKeys.details(), id] as const,
|
|
15
|
+
featured: () => [...venueKeys.all, 'featured'] as const,
|
|
16
|
+
nearby: (params?: NearbyVenueParams) => [...venueKeys.all, 'nearby', params] as const,
|
|
17
|
+
owners: (venueId: string) => [...venueKeys.detail(venueId), 'owners'] as const,
|
|
18
|
+
events: (venueId: string) => [...venueKeys.detail(venueId), 'events'] as const,
|
|
19
|
+
offers: (venueId: string) => [...venueKeys.detail(venueId), 'offers'] as const,
|
|
20
|
+
rewards: (venueId: string) => [...venueKeys.detail(venueId), 'rewards'] as const,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// TYPES
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
export interface VenueFilters {
|
|
28
|
+
page?: number;
|
|
29
|
+
limit?: number;
|
|
30
|
+
search?: string;
|
|
31
|
+
cityId?: string;
|
|
32
|
+
type?: string;
|
|
33
|
+
hasAfDrinks?: boolean;
|
|
34
|
+
isAfVenue?: boolean;
|
|
35
|
+
isFeatured?: boolean;
|
|
36
|
+
isFoundingPartner?: boolean;
|
|
37
|
+
lat?: number;
|
|
38
|
+
long?: number;
|
|
39
|
+
radius?: number;
|
|
40
|
+
sortBy?: string;
|
|
41
|
+
sortOrder?: 'asc' | 'desc';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface NearbyVenueParams {
|
|
45
|
+
lat: number;
|
|
46
|
+
long: number;
|
|
47
|
+
radius?: number;
|
|
48
|
+
limit?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface PaginatedVenuesResponse {
|
|
52
|
+
venues: VenueResponse[];
|
|
53
|
+
meta: {
|
|
54
|
+
total: number;
|
|
55
|
+
page: number;
|
|
56
|
+
limit: number;
|
|
57
|
+
totalPages: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// QUERY HOOKS
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get paginated list of venues with optional filters
|
|
67
|
+
*
|
|
68
|
+
* @param filters - Query parameters for filtering and pagination
|
|
69
|
+
* @param options - TanStack Query options
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```tsx
|
|
73
|
+
* const { data, isLoading } = useVenues({
|
|
74
|
+
* page: 1,
|
|
75
|
+
* limit: 20,
|
|
76
|
+
* cityId: 'city-123',
|
|
77
|
+
* hasAfDrinks: true,
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function useVenues(
|
|
82
|
+
filters?: VenueFilters,
|
|
83
|
+
options?: Omit<UseQueryOptions<PaginatedVenuesResponse>, 'queryKey' | 'queryFn'>
|
|
84
|
+
) {
|
|
85
|
+
return useQuery({
|
|
86
|
+
queryKey: venueKeys.list(filters),
|
|
87
|
+
queryFn: async (): Promise<PaginatedVenuesResponse> => {
|
|
88
|
+
const client = getApiClient();
|
|
89
|
+
const response = await client.get('/api/v1/venues', {
|
|
90
|
+
params: filters,
|
|
91
|
+
});
|
|
92
|
+
return response.data;
|
|
93
|
+
},
|
|
94
|
+
...options,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Get featured venues
|
|
100
|
+
*
|
|
101
|
+
* @param limit - Maximum number of venues to return
|
|
102
|
+
* @param options - TanStack Query options
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```tsx
|
|
106
|
+
* const { data, isLoading } = useFeaturedVenues(10);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function useFeaturedVenues(
|
|
110
|
+
limit?: number,
|
|
111
|
+
options?: Omit<UseQueryOptions<VenueResponse[]>, 'queryKey' | 'queryFn'>
|
|
112
|
+
) {
|
|
113
|
+
return useQuery({
|
|
114
|
+
queryKey: venueKeys.featured(),
|
|
115
|
+
queryFn: async (): Promise<VenueResponse[]> => {
|
|
116
|
+
const client = getApiClient();
|
|
117
|
+
const response = await client.get('/api/v1/venues/featured', {
|
|
118
|
+
params: { limit },
|
|
119
|
+
});
|
|
120
|
+
return response.data;
|
|
121
|
+
},
|
|
122
|
+
...options,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get nearby venues based on location
|
|
128
|
+
*
|
|
129
|
+
* @param params - Location parameters (latitude, longitude, radius)
|
|
130
|
+
* @param options - TanStack Query options
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```tsx
|
|
134
|
+
* const { data, isLoading } = useNearbyVenues({
|
|
135
|
+
* lat: 51.5074,
|
|
136
|
+
* long: -0.1278,
|
|
137
|
+
* radius: 5, // 5km radius
|
|
138
|
+
* limit: 20,
|
|
139
|
+
* });
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function useNearbyVenues(
|
|
143
|
+
params: NearbyVenueParams,
|
|
144
|
+
options?: Omit<UseQueryOptions<VenueResponse[]>, 'queryKey' | 'queryFn'>
|
|
145
|
+
) {
|
|
146
|
+
return useQuery({
|
|
147
|
+
queryKey: venueKeys.nearby(params),
|
|
148
|
+
queryFn: async (): Promise<VenueResponse[]> => {
|
|
149
|
+
const client = getApiClient();
|
|
150
|
+
const response = await client.get('/api/v1/venues/nearby', {
|
|
151
|
+
params,
|
|
152
|
+
});
|
|
153
|
+
return response.data;
|
|
154
|
+
},
|
|
155
|
+
enabled: !!params.lat && !!params.long,
|
|
156
|
+
...options,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get a single venue by ID
|
|
162
|
+
*
|
|
163
|
+
* @param id - Venue ID
|
|
164
|
+
* @param options - TanStack Query options
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```tsx
|
|
168
|
+
* const { data, isLoading } = useVenue('venue-123');
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
export function useVenue(
|
|
172
|
+
id: string,
|
|
173
|
+
options?: Omit<UseQueryOptions<VenueResponse>, 'queryKey' | 'queryFn'>
|
|
174
|
+
) {
|
|
175
|
+
return useQuery({
|
|
176
|
+
queryKey: venueKeys.detail(id),
|
|
177
|
+
queryFn: async (): Promise<VenueResponse> => {
|
|
178
|
+
const client = getApiClient();
|
|
179
|
+
const response = await client.get(`/api/v1/venues/${id}`);
|
|
180
|
+
return response.data;
|
|
181
|
+
},
|
|
182
|
+
enabled: !!id,
|
|
183
|
+
...options,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get venue owners
|
|
189
|
+
*
|
|
190
|
+
* @param venueId - Venue ID
|
|
191
|
+
* @param options - TanStack Query options
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* const { data, isLoading } = useVenueOwners('venue-123');
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
export function useVenueOwners(
|
|
199
|
+
venueId: string,
|
|
200
|
+
options?: Omit<UseQueryOptions<VenueOwnerResponse[]>, 'queryKey' | 'queryFn'>
|
|
201
|
+
) {
|
|
202
|
+
return useQuery({
|
|
203
|
+
queryKey: venueKeys.owners(venueId),
|
|
204
|
+
queryFn: async (): Promise<VenueOwnerResponse[]> => {
|
|
205
|
+
const client = getApiClient();
|
|
206
|
+
const response = await client.get(`/api/v1/venues/${venueId}/owners`);
|
|
207
|
+
return response.data;
|
|
208
|
+
},
|
|
209
|
+
enabled: !!venueId,
|
|
210
|
+
...options,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get upcoming events at a venue
|
|
216
|
+
*
|
|
217
|
+
* @param venueId - Venue ID
|
|
218
|
+
* @param limit - Maximum number of events to return
|
|
219
|
+
* @param options - TanStack Query options
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```tsx
|
|
223
|
+
* const { data, isLoading } = useVenueEvents('venue-123', 20);
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
export function useVenueEvents(
|
|
227
|
+
venueId: string,
|
|
228
|
+
limit?: number,
|
|
229
|
+
options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
|
|
230
|
+
) {
|
|
231
|
+
return useQuery({
|
|
232
|
+
queryKey: venueKeys.events(venueId),
|
|
233
|
+
queryFn: async (): Promise<EventResponse[]> => {
|
|
234
|
+
const client = getApiClient();
|
|
235
|
+
const response = await client.get(`/api/v1/venues/${venueId}/events`, {
|
|
236
|
+
params: { limit },
|
|
237
|
+
});
|
|
238
|
+
return response.data?.data || response.data || [];
|
|
239
|
+
},
|
|
240
|
+
enabled: !!venueId,
|
|
241
|
+
...options,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Get offers for a venue (from legacy Business model)
|
|
247
|
+
*
|
|
248
|
+
* @param venueId - Venue ID
|
|
249
|
+
* @param options - TanStack Query options
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```tsx
|
|
253
|
+
* const { data, isLoading } = useVenueOffers('venue-123');
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
export function useVenueOffers(
|
|
257
|
+
venueId: string,
|
|
258
|
+
options?: Omit<UseQueryOptions<OfferResponse[]>, 'queryKey' | 'queryFn'>
|
|
259
|
+
) {
|
|
260
|
+
return useQuery({
|
|
261
|
+
queryKey: venueKeys.offers(venueId),
|
|
262
|
+
queryFn: async (): Promise<OfferResponse[]> => {
|
|
263
|
+
const client = getApiClient();
|
|
264
|
+
// Use businesses endpoint for offers (legacy)
|
|
265
|
+
const response = await client.get(`/api/v1/businesses/${venueId}/offers`);
|
|
266
|
+
return response.data;
|
|
267
|
+
},
|
|
268
|
+
enabled: !!venueId,
|
|
269
|
+
...options,
|
|
270
|
+
});
|
|
271
|
+
}
|