@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.
- package/README.md +276 -0
- package/dist/__tests__/e2e.test.d.ts +7 -0
- package/dist/__tests__/e2e.test.js +472 -0
- package/dist/api/client.d.ts +11 -0
- package/dist/api/client.js +61 -0
- package/dist/api/mutations/admin.d.ts +167 -0
- package/dist/api/mutations/admin.js +326 -0
- package/dist/api/mutations/ambassadors.d.ts +52 -0
- package/dist/api/mutations/ambassadors.js +148 -0
- package/dist/api/mutations/auth.d.ts +267 -0
- package/dist/api/mutations/auth.js +332 -0
- package/dist/api/mutations/bookings.d.ts +59 -0
- package/dist/api/mutations/bookings.js +143 -0
- package/dist/api/mutations/event-chat.d.ts +35 -0
- package/dist/api/mutations/event-chat.js +147 -0
- package/dist/api/mutations/events.d.ts +87 -0
- package/dist/api/mutations/events.js +205 -0
- package/dist/api/mutations/grow90.d.ts +36 -0
- package/dist/api/mutations/grow90.js +132 -0
- package/dist/api/mutations/hubs.d.ts +111 -0
- package/dist/api/mutations/hubs.js +240 -0
- package/dist/api/mutations/index.d.ts +22 -0
- package/dist/api/mutations/index.js +39 -0
- package/dist/api/mutations/jack.d.ts +61 -0
- package/dist/api/mutations/jack.js +104 -0
- package/dist/api/mutations/library.d.ts +67 -0
- package/dist/api/mutations/library.js +168 -0
- package/dist/api/mutations/map.d.ts +153 -0
- package/dist/api/mutations/map.js +181 -0
- package/dist/api/mutations/matching.d.ts +130 -0
- package/dist/api/mutations/matching.js +204 -0
- package/dist/api/mutations/notifications.d.ts +63 -0
- package/dist/api/mutations/notifications.js +106 -0
- package/dist/api/mutations/offers.d.ts +26 -0
- package/dist/api/mutations/offers.js +47 -0
- package/dist/api/mutations/subscriptions.d.ts +127 -0
- package/dist/api/mutations/subscriptions.js +140 -0
- package/dist/api/mutations/support.d.ts +165 -0
- package/dist/api/mutations/support.js +307 -0
- package/dist/api/mutations/users.d.ts +211 -0
- package/dist/api/mutations/users.js +261 -0
- package/dist/api/queries/admin.d.ts +257 -0
- package/dist/api/queries/admin.js +320 -0
- package/dist/api/queries/ambassadors.d.ts +53 -0
- package/dist/api/queries/ambassadors.js +98 -0
- package/dist/api/queries/auth.d.ts +16 -0
- package/dist/api/queries/auth.js +25 -0
- package/dist/api/queries/bookings.d.ts +91 -0
- package/dist/api/queries/bookings.js +102 -0
- package/dist/api/queries/businesses.d.ts +212 -0
- package/dist/api/queries/businesses.js +154 -0
- package/dist/api/queries/event-chat.d.ts +19 -0
- package/dist/api/queries/event-chat.js +75 -0
- package/dist/api/queries/events.d.ts +322 -0
- package/dist/api/queries/events.js +221 -0
- package/dist/api/queries/grow90.d.ts +26 -0
- package/dist/api/queries/grow90.js +85 -0
- package/dist/api/queries/hubs.d.ts +165 -0
- package/dist/api/queries/hubs.js +143 -0
- package/dist/api/queries/index.d.ts +23 -0
- package/dist/api/queries/index.js +40 -0
- package/dist/api/queries/jack.d.ts +63 -0
- package/dist/api/queries/jack.js +92 -0
- package/dist/api/queries/library.d.ts +132 -0
- package/dist/api/queries/library.js +120 -0
- package/dist/api/queries/map.d.ts +216 -0
- package/dist/api/queries/map.js +278 -0
- package/dist/api/queries/matching.d.ts +136 -0
- package/dist/api/queries/matching.js +161 -0
- package/dist/api/queries/notifications.d.ts +78 -0
- package/dist/api/queries/notifications.js +88 -0
- package/dist/api/queries/offers.d.ts +91 -0
- package/dist/api/queries/offers.js +103 -0
- package/dist/api/queries/subscriptions.d.ts +56 -0
- package/dist/api/queries/subscriptions.js +73 -0
- package/dist/api/queries/support.d.ts +106 -0
- package/dist/api/queries/support.js +202 -0
- package/dist/api/queries/users.d.ts +293 -0
- package/dist/api/queries/users.js +370 -0
- package/dist/api/types.d.ts +464 -0
- package/dist/api/types.js +9 -0
- package/dist/hooks/useAuth.d.ts +5 -0
- package/dist/hooks/useAuth.js +39 -0
- package/dist/hooks/useUser.d.ts +43 -0
- package/dist/hooks/useUser.js +44 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +67 -0
- package/package.json +62 -0
- package/src/__tests__/e2e.test.ts +502 -0
- package/src/api/client.ts +71 -0
- package/src/api/mutations/admin.ts +531 -0
- package/src/api/mutations/ambassadors.ts +185 -0
- package/src/api/mutations/auth.ts +350 -0
- package/src/api/mutations/bookings.ts +190 -0
- package/src/api/mutations/event-chat.ts +177 -0
- package/src/api/mutations/events.ts +273 -0
- package/src/api/mutations/grow90.ts +169 -0
- package/src/api/mutations/hubs.ts +385 -0
- package/src/api/mutations/index.ts +23 -0
- package/src/api/mutations/jack.ts +130 -0
- package/src/api/mutations/library.ts +212 -0
- package/src/api/mutations/map.ts +230 -0
- package/src/api/mutations/matching.ts +271 -0
- package/src/api/mutations/notifications.ts +114 -0
- package/src/api/mutations/offers.ts +73 -0
- package/src/api/mutations/subscriptions.ts +162 -0
- package/src/api/mutations/support.ts +390 -0
- package/src/api/mutations/users.ts +271 -0
- package/src/api/queries/admin.ts +480 -0
- package/src/api/queries/ambassadors.ts +139 -0
- package/src/api/queries/auth.ts +24 -0
- package/src/api/queries/bookings.ts +135 -0
- package/src/api/queries/businesses.ts +203 -0
- package/src/api/queries/event-chat.ts +78 -0
- package/src/api/queries/events.ts +272 -0
- package/src/api/queries/grow90.ts +98 -0
- package/src/api/queries/hubs.ts +211 -0
- package/src/api/queries/index.ts +24 -0
- package/src/api/queries/jack.ts +127 -0
- package/src/api/queries/library.ts +166 -0
- package/src/api/queries/map.ts +331 -0
- package/src/api/queries/matching.ts +238 -0
- package/src/api/queries/notifications.ts +103 -0
- package/src/api/queries/offers.ts +136 -0
- package/src/api/queries/subscriptions.ts +91 -0
- package/src/api/queries/support.ts +235 -0
- package/src/api/queries/users.ts +393 -0
- package/src/api/types.ts +596 -0
- package/src/index.ts +57 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type { BookingResponse } from '../types';
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// QUERY KEY FACTORY
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
export const bookingKeys = {
|
|
10
|
+
all: ['bookings'] as const,
|
|
11
|
+
lists: () => [...bookingKeys.all, 'list'] as const,
|
|
12
|
+
list: (filters?: BookingFilters) => [...bookingKeys.lists(), filters] as const,
|
|
13
|
+
details: () => [...bookingKeys.all, 'detail'] as const,
|
|
14
|
+
detail: (id: string) => [...bookingKeys.details(), id] as const,
|
|
15
|
+
mine: (filters?: BookingFilters) => [...bookingKeys.all, 'mine', filters] as const,
|
|
16
|
+
qrCode: (id: string) => [...bookingKeys.detail(id), 'qr'] as const,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// TYPES
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export interface BookingFilters {
|
|
24
|
+
page?: number;
|
|
25
|
+
limit?: number;
|
|
26
|
+
status?: 'CONFIRMED' | 'WAITLISTED' | 'CANCELLED';
|
|
27
|
+
eventId?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PaginatedBookingsResponse {
|
|
31
|
+
bookings: BookingResponse[];
|
|
32
|
+
total: number;
|
|
33
|
+
page: number;
|
|
34
|
+
limit: number;
|
|
35
|
+
totalPages: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface QrCodeResponse {
|
|
39
|
+
qrCode: string;
|
|
40
|
+
bookingId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// QUERY HOOKS
|
|
45
|
+
// ============================================================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get a single booking by ID
|
|
49
|
+
*
|
|
50
|
+
* @param id - Booking ID
|
|
51
|
+
* @param options - TanStack Query options
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```tsx
|
|
55
|
+
* const { data, isLoading } = useBooking('booking-123');
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function useBooking(
|
|
59
|
+
id: string,
|
|
60
|
+
options?: Omit<UseQueryOptions<BookingResponse>, 'queryKey' | 'queryFn'>
|
|
61
|
+
) {
|
|
62
|
+
return useQuery({
|
|
63
|
+
queryKey: bookingKeys.detail(id),
|
|
64
|
+
queryFn: async (): Promise<BookingResponse> => {
|
|
65
|
+
const client = getApiClient();
|
|
66
|
+
const response = await client.get(`/api/v1/bookings/${id}`);
|
|
67
|
+
return response.data;
|
|
68
|
+
},
|
|
69
|
+
enabled: !!id,
|
|
70
|
+
...options,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get current user's bookings with optional filters
|
|
76
|
+
*
|
|
77
|
+
* @param filters - Query parameters for filtering and pagination
|
|
78
|
+
* @param options - TanStack Query options
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```tsx
|
|
82
|
+
* const { data, isLoading } = useMyBookings({
|
|
83
|
+
* page: 1,
|
|
84
|
+
* limit: 20,
|
|
85
|
+
* status: 'CONFIRMED',
|
|
86
|
+
* eventId: 'event-123'
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function useMyBookings(
|
|
91
|
+
filters?: BookingFilters,
|
|
92
|
+
options?: Omit<UseQueryOptions<PaginatedBookingsResponse>, 'queryKey' | 'queryFn'>
|
|
93
|
+
) {
|
|
94
|
+
return useQuery({
|
|
95
|
+
queryKey: bookingKeys.mine(filters),
|
|
96
|
+
queryFn: async (): Promise<PaginatedBookingsResponse> => {
|
|
97
|
+
const client = getApiClient();
|
|
98
|
+
// Use /users/me/bookings - the existing API endpoint
|
|
99
|
+
const response = await client.get('/api/v1/users/me/bookings', {
|
|
100
|
+
params: filters,
|
|
101
|
+
});
|
|
102
|
+
// API returns { data: { bookings: [...] }, meta: {...} }
|
|
103
|
+
return response.data.data || response.data;
|
|
104
|
+
},
|
|
105
|
+
...options,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get QR code for a specific booking
|
|
111
|
+
*
|
|
112
|
+
* @param id - Booking ID
|
|
113
|
+
* @param options - TanStack Query options
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```tsx
|
|
117
|
+
* const { data, isLoading } = useBookingQrCode('booking-123');
|
|
118
|
+
* // data.qrCode contains the QR code string for display
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function useBookingQrCode(
|
|
122
|
+
id: string,
|
|
123
|
+
options?: Omit<UseQueryOptions<QrCodeResponse>, 'queryKey' | 'queryFn'>
|
|
124
|
+
) {
|
|
125
|
+
return useQuery({
|
|
126
|
+
queryKey: bookingKeys.qrCode(id),
|
|
127
|
+
queryFn: async (): Promise<QrCodeResponse> => {
|
|
128
|
+
const client = getApiClient();
|
|
129
|
+
const response = await client.get(`/api/v1/bookings/${id}/qr`);
|
|
130
|
+
return response.data;
|
|
131
|
+
},
|
|
132
|
+
enabled: !!id,
|
|
133
|
+
...options,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type { BusinessResponse, OfferResponse } from '../types';
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// QUERY KEY FACTORY
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
export const businessKeys = {
|
|
10
|
+
all: ['businesses'] as const,
|
|
11
|
+
lists: () => [...businessKeys.all, 'list'] as const,
|
|
12
|
+
list: (filters?: BusinessFilters) => [...businessKeys.lists(), filters] as const,
|
|
13
|
+
details: () => [...businessKeys.all, 'detail'] as const,
|
|
14
|
+
detail: (id: string) => [...businessKeys.details(), id] as const,
|
|
15
|
+
featured: () => [...businessKeys.all, 'featured'] as const,
|
|
16
|
+
nearby: (params?: NearbyBusinessParams) => [...businessKeys.all, 'nearby', params] as const,
|
|
17
|
+
offers: (businessId: string) => [...businessKeys.detail(businessId), 'offers'] as const,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// TYPES
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
export interface BusinessFilters {
|
|
25
|
+
page?: number;
|
|
26
|
+
limit?: number;
|
|
27
|
+
search?: string;
|
|
28
|
+
cityId?: string;
|
|
29
|
+
type?: string;
|
|
30
|
+
hasAfDrinks?: boolean;
|
|
31
|
+
isAfVenue?: boolean;
|
|
32
|
+
isFeatured?: boolean;
|
|
33
|
+
isPartner?: boolean;
|
|
34
|
+
lat?: number;
|
|
35
|
+
long?: number;
|
|
36
|
+
radius?: number;
|
|
37
|
+
sortBy?: string;
|
|
38
|
+
sortOrder?: 'asc' | 'desc';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface NearbyBusinessParams {
|
|
42
|
+
lat: number;
|
|
43
|
+
long: number;
|
|
44
|
+
radius?: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface PaginatedBusinessesResponse {
|
|
48
|
+
businesses: BusinessResponse[];
|
|
49
|
+
total: number;
|
|
50
|
+
page: number;
|
|
51
|
+
limit: number;
|
|
52
|
+
totalPages: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ============================================================================
|
|
56
|
+
// QUERY HOOKS
|
|
57
|
+
// ============================================================================
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get paginated list of businesses with optional filters
|
|
61
|
+
*
|
|
62
|
+
* @param filters - Query parameters for filtering and pagination
|
|
63
|
+
* @param options - TanStack Query options
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```tsx
|
|
67
|
+
* const { data, isLoading } = useBusinesses({
|
|
68
|
+
* page: 1,
|
|
69
|
+
* limit: 20,
|
|
70
|
+
* cityId: 'city-123',
|
|
71
|
+
* hasAfDrinks: true,
|
|
72
|
+
* sortBy: 'name',
|
|
73
|
+
* sortOrder: 'asc'
|
|
74
|
+
* });
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export function useBusinesses(
|
|
78
|
+
filters?: BusinessFilters,
|
|
79
|
+
options?: Omit<UseQueryOptions<PaginatedBusinessesResponse>, 'queryKey' | 'queryFn'>
|
|
80
|
+
) {
|
|
81
|
+
return useQuery({
|
|
82
|
+
queryKey: businessKeys.list(filters),
|
|
83
|
+
queryFn: async (): Promise<PaginatedBusinessesResponse> => {
|
|
84
|
+
const client = getApiClient();
|
|
85
|
+
const response = await client.get('/api/v1/businesses', {
|
|
86
|
+
params: filters,
|
|
87
|
+
});
|
|
88
|
+
return response.data;
|
|
89
|
+
},
|
|
90
|
+
...options,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get featured businesses
|
|
96
|
+
*
|
|
97
|
+
* @param options - TanStack Query options
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* const { data, isLoading } = useFeaturedBusinesses();
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function useFeaturedBusinesses(
|
|
105
|
+
options?: Omit<UseQueryOptions<BusinessResponse[]>, 'queryKey' | 'queryFn'>
|
|
106
|
+
) {
|
|
107
|
+
return useQuery({
|
|
108
|
+
queryKey: businessKeys.featured(),
|
|
109
|
+
queryFn: async (): Promise<BusinessResponse[]> => {
|
|
110
|
+
const client = getApiClient();
|
|
111
|
+
const response = await client.get('/api/v1/businesses/featured');
|
|
112
|
+
return response.data;
|
|
113
|
+
},
|
|
114
|
+
...options,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get nearby businesses based on location
|
|
120
|
+
*
|
|
121
|
+
* @param params - Location parameters (latitude, longitude, radius)
|
|
122
|
+
* @param options - TanStack Query options
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```tsx
|
|
126
|
+
* const { data, isLoading } = useNearbyBusinesses({
|
|
127
|
+
* lat: 51.5074,
|
|
128
|
+
* long: -0.1278,
|
|
129
|
+
* radius: 5000 // 5km radius
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function useNearbyBusinesses(
|
|
134
|
+
params: NearbyBusinessParams,
|
|
135
|
+
options?: Omit<UseQueryOptions<BusinessResponse[]>, 'queryKey' | 'queryFn'>
|
|
136
|
+
) {
|
|
137
|
+
return useQuery({
|
|
138
|
+
queryKey: businessKeys.nearby(params),
|
|
139
|
+
queryFn: async (): Promise<BusinessResponse[]> => {
|
|
140
|
+
const client = getApiClient();
|
|
141
|
+
const response = await client.get('/api/v1/businesses/nearby', {
|
|
142
|
+
params,
|
|
143
|
+
});
|
|
144
|
+
return response.data;
|
|
145
|
+
},
|
|
146
|
+
enabled: !!params.lat && !!params.long,
|
|
147
|
+
...options,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get a single business by ID
|
|
153
|
+
*
|
|
154
|
+
* @param id - Business ID
|
|
155
|
+
* @param options - TanStack Query options
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```tsx
|
|
159
|
+
* const { data, isLoading } = useBusiness('business-123');
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
export function useBusiness(
|
|
163
|
+
id: string,
|
|
164
|
+
options?: Omit<UseQueryOptions<BusinessResponse>, 'queryKey' | 'queryFn'>
|
|
165
|
+
) {
|
|
166
|
+
return useQuery({
|
|
167
|
+
queryKey: businessKeys.detail(id),
|
|
168
|
+
queryFn: async (): Promise<BusinessResponse> => {
|
|
169
|
+
const client = getApiClient();
|
|
170
|
+
const response = await client.get(`/api/v1/businesses/${id}`);
|
|
171
|
+
return response.data;
|
|
172
|
+
},
|
|
173
|
+
enabled: !!id,
|
|
174
|
+
...options,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get all offers for a specific business
|
|
180
|
+
*
|
|
181
|
+
* @param businessId - Business ID
|
|
182
|
+
* @param options - TanStack Query options
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```tsx
|
|
186
|
+
* const { data, isLoading } = useBusinessOffers('business-123');
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export function useBusinessOffers(
|
|
190
|
+
businessId: string,
|
|
191
|
+
options?: Omit<UseQueryOptions<OfferResponse[]>, 'queryKey' | 'queryFn'>
|
|
192
|
+
) {
|
|
193
|
+
return useQuery({
|
|
194
|
+
queryKey: businessKeys.offers(businessId),
|
|
195
|
+
queryFn: async (): Promise<OfferResponse[]> => {
|
|
196
|
+
const client = getApiClient();
|
|
197
|
+
const response = await client.get(`/api/v1/businesses/${businessId}/offers`);
|
|
198
|
+
return response.data;
|
|
199
|
+
},
|
|
200
|
+
enabled: !!businessId,
|
|
201
|
+
...options,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useQuery, useInfiniteQuery } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type {
|
|
4
|
+
EventChatResponse,
|
|
5
|
+
ChatMemberResponse,
|
|
6
|
+
PaginatedMessagesResponse,
|
|
7
|
+
} from '../types';
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// QUERY KEYS
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
export const eventChatKeys = {
|
|
14
|
+
all: ['event-chat'] as const,
|
|
15
|
+
chat: (eventId: string) => [...eventChatKeys.all, 'chat', eventId] as const,
|
|
16
|
+
members: (eventId: string) => [...eventChatKeys.all, 'members', eventId] as const,
|
|
17
|
+
messages: (eventId: string) => [...eventChatKeys.all, 'messages', eventId] as const,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// ============================================================================
|
|
21
|
+
// HOOKS
|
|
22
|
+
// ============================================================================
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get or create chat for an event
|
|
26
|
+
*/
|
|
27
|
+
export function useEventChat(eventId: string | undefined) {
|
|
28
|
+
return useQuery({
|
|
29
|
+
queryKey: eventChatKeys.chat(eventId || ''),
|
|
30
|
+
queryFn: async () => {
|
|
31
|
+
if (!eventId) throw new Error('Event ID is required');
|
|
32
|
+
const client = getApiClient();
|
|
33
|
+
const response = await client.get<EventChatResponse>(`/events/${eventId}/chat`);
|
|
34
|
+
return response.data;
|
|
35
|
+
},
|
|
36
|
+
enabled: !!eventId,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get chat members
|
|
42
|
+
*/
|
|
43
|
+
export function useEventChatMembers(eventId: string | undefined) {
|
|
44
|
+
return useQuery({
|
|
45
|
+
queryKey: eventChatKeys.members(eventId || ''),
|
|
46
|
+
queryFn: async () => {
|
|
47
|
+
if (!eventId) throw new Error('Event ID is required');
|
|
48
|
+
const client = getApiClient();
|
|
49
|
+
const response = await client.get<ChatMemberResponse[]>(`/events/${eventId}/chat/members`);
|
|
50
|
+
return response.data;
|
|
51
|
+
},
|
|
52
|
+
enabled: !!eventId,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get chat messages with infinite scroll pagination
|
|
58
|
+
*/
|
|
59
|
+
export function useEventChatMessages(eventId: string | undefined, limit = 50) {
|
|
60
|
+
return useInfiniteQuery({
|
|
61
|
+
queryKey: eventChatKeys.messages(eventId || ''),
|
|
62
|
+
queryFn: async ({ pageParam }) => {
|
|
63
|
+
if (!eventId) throw new Error('Event ID is required');
|
|
64
|
+
const client = getApiClient();
|
|
65
|
+
const params = new URLSearchParams({ limit: String(limit) });
|
|
66
|
+
if (pageParam) {
|
|
67
|
+
params.append('cursor', pageParam);
|
|
68
|
+
}
|
|
69
|
+
const response = await client.get<PaginatedMessagesResponse>(
|
|
70
|
+
`/events/${eventId}/chat/messages?${params.toString()}`
|
|
71
|
+
);
|
|
72
|
+
return response.data;
|
|
73
|
+
},
|
|
74
|
+
initialPageParam: undefined as string | undefined,
|
|
75
|
+
getNextPageParam: (lastPage) => lastPage.nextCursor,
|
|
76
|
+
enabled: !!eventId,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type { EventResponse } from '../types';
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// QUERY KEY FACTORY
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
export const eventKeys = {
|
|
10
|
+
all: ['events'] as const,
|
|
11
|
+
lists: () => [...eventKeys.all, 'list'] as const,
|
|
12
|
+
list: (filters?: EventFilters) => [...eventKeys.lists(), filters] as const,
|
|
13
|
+
details: () => [...eventKeys.all, 'detail'] as const,
|
|
14
|
+
detail: (id: string) => [...eventKeys.details(), id] as const,
|
|
15
|
+
detailBySlug: (slug: string) => [...eventKeys.details(), 'slug', slug] as const,
|
|
16
|
+
upcoming: (limit?: number) => [...eventKeys.all, 'upcoming', limit] as const,
|
|
17
|
+
featured: (limit?: number) => [...eventKeys.all, 'featured', limit] as const,
|
|
18
|
+
ambient: (filters?: AmbientEventFilters) => [...eventKeys.all, 'ambient', filters] as const,
|
|
19
|
+
bookings: (eventId: string) => [...eventKeys.detail(eventId), 'bookings'] as const,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// TYPES
|
|
24
|
+
// ============================================================================
|
|
25
|
+
|
|
26
|
+
export interface EventFilters {
|
|
27
|
+
page?: number;
|
|
28
|
+
limit?: number;
|
|
29
|
+
hubId?: string;
|
|
30
|
+
cityId?: string;
|
|
31
|
+
eventType?: string;
|
|
32
|
+
status?: 'DRAFT' | 'PUBLISHED' | 'CANCELLED';
|
|
33
|
+
startAfter?: string;
|
|
34
|
+
startBefore?: string;
|
|
35
|
+
isFeatured?: boolean;
|
|
36
|
+
isAmbient?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface AmbientEventFilters {
|
|
40
|
+
limit?: number;
|
|
41
|
+
cityId?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PaginatedEventsResponse {
|
|
45
|
+
events: EventResponse[];
|
|
46
|
+
total: number;
|
|
47
|
+
page: number;
|
|
48
|
+
limit: number;
|
|
49
|
+
totalPages: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// QUERY HOOKS
|
|
54
|
+
// ============================================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get paginated list of events with optional filters
|
|
58
|
+
*
|
|
59
|
+
* @param filters - Query parameters for filtering and pagination
|
|
60
|
+
* @param options - TanStack Query options
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const { data, isLoading } = useEvents({
|
|
65
|
+
* page: 1,
|
|
66
|
+
* limit: 20,
|
|
67
|
+
* hubId: 'hub-123',
|
|
68
|
+
* isFeatured: true
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export function useEvents(
|
|
73
|
+
filters?: EventFilters,
|
|
74
|
+
options?: Omit<UseQueryOptions<PaginatedEventsResponse>, 'queryKey' | 'queryFn'>
|
|
75
|
+
) {
|
|
76
|
+
return useQuery({
|
|
77
|
+
queryKey: eventKeys.list(filters),
|
|
78
|
+
queryFn: async (): Promise<PaginatedEventsResponse> => {
|
|
79
|
+
const client = getApiClient();
|
|
80
|
+
const response = await client.get('/api/v1/events', {
|
|
81
|
+
params: filters,
|
|
82
|
+
});
|
|
83
|
+
return response.data;
|
|
84
|
+
},
|
|
85
|
+
...options,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get a single event by ID
|
|
91
|
+
*
|
|
92
|
+
* @param id - Event ID
|
|
93
|
+
* @param options - TanStack Query options
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```tsx
|
|
97
|
+
* const { data, isLoading } = useEvent('event-123');
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function useEvent(
|
|
101
|
+
id: string,
|
|
102
|
+
options?: Omit<UseQueryOptions<EventResponse>, 'queryKey' | 'queryFn'>
|
|
103
|
+
) {
|
|
104
|
+
return useQuery({
|
|
105
|
+
queryKey: eventKeys.detail(id),
|
|
106
|
+
queryFn: async (): Promise<EventResponse> => {
|
|
107
|
+
const client = getApiClient();
|
|
108
|
+
const response = await client.get(`/api/v1/events/${id}`);
|
|
109
|
+
return response.data;
|
|
110
|
+
},
|
|
111
|
+
enabled: !!id,
|
|
112
|
+
...options,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Get a single event by slug
|
|
118
|
+
*
|
|
119
|
+
* @param slug - Event slug
|
|
120
|
+
* @param options - TanStack Query options
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const { data, isLoading } = useEventBySlug('yoga-in-the-park');
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export function useEventBySlug(
|
|
128
|
+
slug: string,
|
|
129
|
+
options?: Omit<UseQueryOptions<EventResponse>, 'queryKey' | 'queryFn'>
|
|
130
|
+
) {
|
|
131
|
+
return useQuery({
|
|
132
|
+
queryKey: eventKeys.detailBySlug(slug),
|
|
133
|
+
queryFn: async (): Promise<EventResponse> => {
|
|
134
|
+
const client = getApiClient();
|
|
135
|
+
const response = await client.get(`/api/v1/events/slug/${slug}`);
|
|
136
|
+
return response.data;
|
|
137
|
+
},
|
|
138
|
+
enabled: !!slug,
|
|
139
|
+
...options,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get upcoming events
|
|
145
|
+
*
|
|
146
|
+
* @param limit - Maximum number of events to return (default: 10)
|
|
147
|
+
* @param options - TanStack Query options
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```tsx
|
|
151
|
+
* const { data, isLoading } = useUpcomingEvents(20);
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export function useUpcomingEvents(
|
|
155
|
+
limit?: number,
|
|
156
|
+
options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
|
|
157
|
+
) {
|
|
158
|
+
return useQuery({
|
|
159
|
+
queryKey: eventKeys.upcoming(limit),
|
|
160
|
+
queryFn: async (): Promise<EventResponse[]> => {
|
|
161
|
+
const client = getApiClient();
|
|
162
|
+
const response = await client.get('/api/v1/events/upcoming', {
|
|
163
|
+
params: { limit },
|
|
164
|
+
});
|
|
165
|
+
return response.data;
|
|
166
|
+
},
|
|
167
|
+
...options,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Get featured events
|
|
173
|
+
*
|
|
174
|
+
* Note: This uses the main events endpoint with isFeatured filter
|
|
175
|
+
*
|
|
176
|
+
* @param limit - Maximum number of events to return (default: 10)
|
|
177
|
+
* @param options - TanStack Query options
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```tsx
|
|
181
|
+
* const { data, isLoading } = useFeaturedEvents(5);
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export function useFeaturedEvents(
|
|
185
|
+
limit: number = 10,
|
|
186
|
+
options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
|
|
187
|
+
) {
|
|
188
|
+
return useQuery({
|
|
189
|
+
queryKey: eventKeys.featured(limit),
|
|
190
|
+
queryFn: async (): Promise<EventResponse[]> => {
|
|
191
|
+
const client = getApiClient();
|
|
192
|
+
const response = await client.get('/api/v1/events', {
|
|
193
|
+
params: {
|
|
194
|
+
isFeatured: true,
|
|
195
|
+
limit,
|
|
196
|
+
page: 1,
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
return response.data.events || response.data;
|
|
200
|
+
},
|
|
201
|
+
...options,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get ambient events (auto-generated social activities)
|
|
207
|
+
*
|
|
208
|
+
* @param filters - Optional filters (limit, cityId)
|
|
209
|
+
* @param options - TanStack Query options
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```tsx
|
|
213
|
+
* const { data, isLoading } = useAmbientEvents({ limit: 10 });
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
export function useAmbientEvents(
|
|
217
|
+
filters?: AmbientEventFilters,
|
|
218
|
+
options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
|
|
219
|
+
) {
|
|
220
|
+
return useQuery({
|
|
221
|
+
queryKey: eventKeys.ambient(filters),
|
|
222
|
+
queryFn: async (): Promise<EventResponse[]> => {
|
|
223
|
+
const client = getApiClient();
|
|
224
|
+
const response = await client.get('/api/v1/events', {
|
|
225
|
+
params: {
|
|
226
|
+
isAmbient: true,
|
|
227
|
+
limit: filters?.limit || 20,
|
|
228
|
+
cityId: filters?.cityId,
|
|
229
|
+
startFrom: new Date().toISOString(),
|
|
230
|
+
sortBy: 'startDate',
|
|
231
|
+
sortOrder: 'asc',
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
// API returns { data: { events: [...], meta: {...} }, meta: {...} }
|
|
235
|
+
return response.data.data?.events || response.data.events || response.data;
|
|
236
|
+
},
|
|
237
|
+
...options,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get bookings for a specific event
|
|
243
|
+
*
|
|
244
|
+
* Note: This endpoint may not be available in the current API.
|
|
245
|
+
* Consider using admin endpoints or user bookings endpoints instead.
|
|
246
|
+
* This hook is provided for future compatibility.
|
|
247
|
+
*
|
|
248
|
+
* @param eventId - Event ID
|
|
249
|
+
* @param options - TanStack Query options
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* ```tsx
|
|
253
|
+
* const { data, isLoading } = useEventBookings('event-123');
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
export function useEventBookings(
|
|
257
|
+
eventId: string,
|
|
258
|
+
options?: Omit<UseQueryOptions<any[]>, 'queryKey' | 'queryFn'>
|
|
259
|
+
) {
|
|
260
|
+
return useQuery({
|
|
261
|
+
queryKey: eventKeys.bookings(eventId),
|
|
262
|
+
queryFn: async (): Promise<any[]> => {
|
|
263
|
+
const client = getApiClient();
|
|
264
|
+
// Note: This endpoint may not exist in the current API
|
|
265
|
+
// Adjust the path based on your actual API implementation
|
|
266
|
+
const response = await client.get(`/api/v1/events/${eventId}/bookings`);
|
|
267
|
+
return response.data;
|
|
268
|
+
},
|
|
269
|
+
enabled: !!eventId,
|
|
270
|
+
...options,
|
|
271
|
+
});
|
|
272
|
+
}
|