@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,308 @@
|
|
|
1
|
+
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import type {
|
|
4
|
+
CreatorResponse,
|
|
5
|
+
CreatorAvailabilityResponse,
|
|
6
|
+
EventResponse,
|
|
7
|
+
LibraryContentResponse,
|
|
8
|
+
} from '../types';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// QUERY KEY FACTORY
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export const creatorKeys = {
|
|
15
|
+
all: ['creators'] as const,
|
|
16
|
+
lists: () => [...creatorKeys.all, 'list'] as const,
|
|
17
|
+
list: (filters?: CreatorFilters) => [...creatorKeys.lists(), filters] as const,
|
|
18
|
+
details: () => [...creatorKeys.all, 'detail'] as const,
|
|
19
|
+
detail: (id: string) => [...creatorKeys.details(), id] as const,
|
|
20
|
+
slug: (slug: string) => [...creatorKeys.all, 'slug', slug] as const,
|
|
21
|
+
byUser: (userId: string) => [...creatorKeys.all, 'user', userId] as const,
|
|
22
|
+
me: () => [...creatorKeys.all, 'me'] as const,
|
|
23
|
+
availability: (creatorId: string) => [...creatorKeys.detail(creatorId), 'availability'] as const,
|
|
24
|
+
content: (creatorId: string) => [...creatorKeys.detail(creatorId), 'content'] as const,
|
|
25
|
+
allContent: (creatorId: string) => [...creatorKeys.detail(creatorId), 'content', 'all'] as const,
|
|
26
|
+
events: (creatorId: string) => [...creatorKeys.detail(creatorId), 'events'] as const,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// TYPES
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
export interface CreatorFilters {
|
|
34
|
+
page?: number;
|
|
35
|
+
limit?: number;
|
|
36
|
+
search?: string;
|
|
37
|
+
cityId?: string;
|
|
38
|
+
canFacilitate?: boolean;
|
|
39
|
+
canCreateContent?: boolean;
|
|
40
|
+
isInfluencer?: boolean;
|
|
41
|
+
isVerified?: boolean;
|
|
42
|
+
sortBy?: string;
|
|
43
|
+
sortOrder?: 'asc' | 'desc';
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface PaginatedCreatorsResponse {
|
|
47
|
+
creators: CreatorResponse[];
|
|
48
|
+
meta: {
|
|
49
|
+
total: number;
|
|
50
|
+
page: number;
|
|
51
|
+
limit: number;
|
|
52
|
+
totalPages: number;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// QUERY HOOKS
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get paginated list of creators with optional filters
|
|
62
|
+
*
|
|
63
|
+
* @param filters - Query parameters for filtering and pagination
|
|
64
|
+
* @param options - TanStack Query options
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```tsx
|
|
68
|
+
* const { data, isLoading } = useCreators({
|
|
69
|
+
* page: 1,
|
|
70
|
+
* limit: 20,
|
|
71
|
+
* canFacilitate: true,
|
|
72
|
+
* });
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function useCreators(
|
|
76
|
+
filters?: CreatorFilters,
|
|
77
|
+
options?: Omit<UseQueryOptions<PaginatedCreatorsResponse>, 'queryKey' | 'queryFn'>
|
|
78
|
+
) {
|
|
79
|
+
return useQuery({
|
|
80
|
+
queryKey: creatorKeys.list(filters),
|
|
81
|
+
queryFn: async (): Promise<PaginatedCreatorsResponse> => {
|
|
82
|
+
const client = getApiClient();
|
|
83
|
+
const response = await client.get('/api/v1/creators', {
|
|
84
|
+
params: filters,
|
|
85
|
+
});
|
|
86
|
+
return response.data;
|
|
87
|
+
},
|
|
88
|
+
...options,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get a single creator by ID
|
|
94
|
+
*
|
|
95
|
+
* @param id - Creator ID
|
|
96
|
+
* @param options - TanStack Query options
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```tsx
|
|
100
|
+
* const { data, isLoading } = useCreator('creator-123');
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export function useCreator(
|
|
104
|
+
id: string,
|
|
105
|
+
options?: Omit<UseQueryOptions<CreatorResponse>, 'queryKey' | 'queryFn'>
|
|
106
|
+
) {
|
|
107
|
+
return useQuery({
|
|
108
|
+
queryKey: creatorKeys.detail(id),
|
|
109
|
+
queryFn: async (): Promise<CreatorResponse> => {
|
|
110
|
+
const client = getApiClient();
|
|
111
|
+
const response = await client.get(`/api/v1/creators/${id}`);
|
|
112
|
+
return response.data;
|
|
113
|
+
},
|
|
114
|
+
enabled: !!id,
|
|
115
|
+
...options,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Get a creator by their slug
|
|
121
|
+
*
|
|
122
|
+
* @param slug - Creator slug
|
|
123
|
+
* @param options - TanStack Query options
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```tsx
|
|
127
|
+
* const { data, isLoading } = useCreatorBySlug('john-doe');
|
|
128
|
+
* ```
|
|
129
|
+
*/
|
|
130
|
+
export function useCreatorBySlug(
|
|
131
|
+
slug: string,
|
|
132
|
+
options?: Omit<UseQueryOptions<CreatorResponse>, 'queryKey' | 'queryFn'>
|
|
133
|
+
) {
|
|
134
|
+
return useQuery({
|
|
135
|
+
queryKey: creatorKeys.slug(slug),
|
|
136
|
+
queryFn: async (): Promise<CreatorResponse> => {
|
|
137
|
+
const client = getApiClient();
|
|
138
|
+
const response = await client.get(`/api/v1/creators/slug/${slug}`);
|
|
139
|
+
return response.data;
|
|
140
|
+
},
|
|
141
|
+
enabled: !!slug,
|
|
142
|
+
...options,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get a creator profile by user ID
|
|
148
|
+
*
|
|
149
|
+
* @param userId - User ID
|
|
150
|
+
* @param options - TanStack Query options
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```tsx
|
|
154
|
+
* const { data, isLoading } = useCreatorByUser('user-123');
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export function useCreatorByUser(
|
|
158
|
+
userId: string,
|
|
159
|
+
options?: Omit<UseQueryOptions<CreatorResponse | null>, 'queryKey' | 'queryFn'>
|
|
160
|
+
) {
|
|
161
|
+
return useQuery({
|
|
162
|
+
queryKey: creatorKeys.byUser(userId),
|
|
163
|
+
queryFn: async (): Promise<CreatorResponse | null> => {
|
|
164
|
+
const client = getApiClient();
|
|
165
|
+
const response = await client.get(`/api/v1/creators/user/${userId}`);
|
|
166
|
+
return response.data;
|
|
167
|
+
},
|
|
168
|
+
enabled: !!userId,
|
|
169
|
+
...options,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get the current user's creator profile
|
|
175
|
+
*
|
|
176
|
+
* @param options - TanStack Query options
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```tsx
|
|
180
|
+
* const { data, isLoading } = useMyCreatorProfile();
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
export function useMyCreatorProfile(
|
|
184
|
+
options?: Omit<UseQueryOptions<CreatorResponse | null>, 'queryKey' | 'queryFn'>
|
|
185
|
+
) {
|
|
186
|
+
return useQuery({
|
|
187
|
+
queryKey: creatorKeys.me(),
|
|
188
|
+
queryFn: async (): Promise<CreatorResponse | null> => {
|
|
189
|
+
const client = getApiClient();
|
|
190
|
+
const response = await client.get('/api/v1/creators/me');
|
|
191
|
+
return response.data;
|
|
192
|
+
},
|
|
193
|
+
...options,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get creator availability slots
|
|
199
|
+
*
|
|
200
|
+
* @param creatorId - Creator ID
|
|
201
|
+
* @param options - TanStack Query options
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```tsx
|
|
205
|
+
* const { data, isLoading } = useCreatorAvailability('creator-123');
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function useCreatorAvailability(
|
|
209
|
+
creatorId: string,
|
|
210
|
+
options?: Omit<UseQueryOptions<CreatorAvailabilityResponse[]>, 'queryKey' | 'queryFn'>
|
|
211
|
+
) {
|
|
212
|
+
return useQuery({
|
|
213
|
+
queryKey: creatorKeys.availability(creatorId),
|
|
214
|
+
queryFn: async (): Promise<CreatorAvailabilityResponse[]> => {
|
|
215
|
+
const client = getApiClient();
|
|
216
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/availability`);
|
|
217
|
+
return response.data;
|
|
218
|
+
},
|
|
219
|
+
enabled: !!creatorId,
|
|
220
|
+
...options,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get a creator's published library content
|
|
226
|
+
*
|
|
227
|
+
* @param creatorId - Creator ID
|
|
228
|
+
* @param options - TanStack Query options
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* ```tsx
|
|
232
|
+
* const { data, isLoading } = useCreatorContent('creator-123');
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export function useCreatorContent(
|
|
236
|
+
creatorId: string,
|
|
237
|
+
options?: Omit<UseQueryOptions<LibraryContentResponse[]>, 'queryKey' | 'queryFn'>
|
|
238
|
+
) {
|
|
239
|
+
return useQuery({
|
|
240
|
+
queryKey: creatorKeys.content(creatorId),
|
|
241
|
+
queryFn: async (): Promise<LibraryContentResponse[]> => {
|
|
242
|
+
const client = getApiClient();
|
|
243
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/content`);
|
|
244
|
+
return response.data;
|
|
245
|
+
},
|
|
246
|
+
enabled: !!creatorId,
|
|
247
|
+
...options,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Get all of a creator's content including unpublished (owner only)
|
|
253
|
+
*
|
|
254
|
+
* @param creatorId - Creator ID
|
|
255
|
+
* @param options - TanStack Query options
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```tsx
|
|
259
|
+
* // For creator dashboard - shows all content statuses
|
|
260
|
+
* const { data, isLoading } = useCreatorAllContent('creator-123');
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
263
|
+
export function useCreatorAllContent(
|
|
264
|
+
creatorId: string,
|
|
265
|
+
options?: Omit<UseQueryOptions<LibraryContentResponse[]>, 'queryKey' | 'queryFn'>
|
|
266
|
+
) {
|
|
267
|
+
return useQuery({
|
|
268
|
+
queryKey: creatorKeys.allContent(creatorId),
|
|
269
|
+
queryFn: async (): Promise<LibraryContentResponse[]> => {
|
|
270
|
+
const client = getApiClient();
|
|
271
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/content/all`);
|
|
272
|
+
return response.data;
|
|
273
|
+
},
|
|
274
|
+
enabled: !!creatorId,
|
|
275
|
+
...options,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Get a creator's upcoming events
|
|
281
|
+
*
|
|
282
|
+
* @param creatorId - Creator ID
|
|
283
|
+
* @param upcoming - Whether to filter to upcoming events only (default: true)
|
|
284
|
+
* @param options - TanStack Query options
|
|
285
|
+
*
|
|
286
|
+
* @example
|
|
287
|
+
* ```tsx
|
|
288
|
+
* const { data, isLoading } = useCreatorEvents('creator-123');
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
export function useCreatorEvents(
|
|
292
|
+
creatorId: string,
|
|
293
|
+
upcoming = true,
|
|
294
|
+
options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
|
|
295
|
+
) {
|
|
296
|
+
return useQuery({
|
|
297
|
+
queryKey: creatorKeys.events(creatorId),
|
|
298
|
+
queryFn: async (): Promise<EventResponse[]> => {
|
|
299
|
+
const client = getApiClient();
|
|
300
|
+
const response = await client.get(`/api/v1/creators/${creatorId}/events`, {
|
|
301
|
+
params: { upcoming },
|
|
302
|
+
});
|
|
303
|
+
return response.data;
|
|
304
|
+
},
|
|
305
|
+
enabled: !!creatorId,
|
|
306
|
+
...options,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
@@ -30,7 +30,7 @@ export function useEventChat(eventId: string | undefined) {
|
|
|
30
30
|
queryFn: async () => {
|
|
31
31
|
if (!eventId) throw new Error('Event ID is required');
|
|
32
32
|
const client = getApiClient();
|
|
33
|
-
const response = await client.get<EventChatResponse>(`/events/${eventId}/chat`);
|
|
33
|
+
const response = await client.get<EventChatResponse>(`/api/v1/events/${eventId}/chat`);
|
|
34
34
|
return response.data;
|
|
35
35
|
},
|
|
36
36
|
enabled: !!eventId,
|
|
@@ -46,7 +46,7 @@ export function useEventChatMembers(eventId: string | undefined) {
|
|
|
46
46
|
queryFn: async () => {
|
|
47
47
|
if (!eventId) throw new Error('Event ID is required');
|
|
48
48
|
const client = getApiClient();
|
|
49
|
-
const response = await client.get<ChatMemberResponse[]>(`/events/${eventId}/chat/members`);
|
|
49
|
+
const response = await client.get<ChatMemberResponse[]>(`/api/v1/events/${eventId}/chat/members`);
|
|
50
50
|
return response.data;
|
|
51
51
|
},
|
|
52
52
|
enabled: !!eventId,
|
|
@@ -67,7 +67,7 @@ export function useEventChatMessages(eventId: string | undefined, limit = 50) {
|
|
|
67
67
|
params.append('cursor', pageParam);
|
|
68
68
|
}
|
|
69
69
|
const response = await client.get<PaginatedMessagesResponse>(
|
|
70
|
-
`/events/${eventId}/chat/messages?${params.toString()}`
|
|
70
|
+
`/api/v1/events/${eventId}/chat/messages?${params.toString()}`
|
|
71
71
|
);
|
|
72
72
|
return response.data;
|
|
73
73
|
},
|
package/src/api/queries/index.ts
CHANGED
|
@@ -24,3 +24,8 @@ export * from './grow90';
|
|
|
24
24
|
export * from './matching';
|
|
25
25
|
export * from './event-chat';
|
|
26
26
|
export * from './user-pins';
|
|
27
|
+
export * from './badges';
|
|
28
|
+
export * from './venues';
|
|
29
|
+
export * from './creators';
|
|
30
|
+
export * from './brands';
|
|
31
|
+
export * from './products';
|
package/src/api/queries/jack.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
|
|
1
|
+
import { useQuery, useInfiniteQuery, UseQueryOptions, UseInfiniteQueryOptions } from '@tanstack/react-query';
|
|
2
2
|
import { getApiClient } from '../client';
|
|
3
3
|
|
|
4
4
|
// ============================================================================
|
|
@@ -10,6 +10,8 @@ export const jackKeys = {
|
|
|
10
10
|
conversations: () => [...jackKeys.all, 'conversations'] as const,
|
|
11
11
|
conversation: (id: string) => [...jackKeys.all, 'conversation', id] as const,
|
|
12
12
|
history: () => [...jackKeys.all, 'history'] as const,
|
|
13
|
+
timeline: (cursor?: string) => [...jackKeys.all, 'timeline', cursor] as const,
|
|
14
|
+
stats: (days?: number) => [...jackKeys.all, 'stats', days] as const,
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
// ============================================================================
|
|
@@ -36,6 +38,42 @@ export interface JackMessage {
|
|
|
36
38
|
createdAt: string;
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
export type JackEntryType =
|
|
42
|
+
| 'MESSAGE'
|
|
43
|
+
| 'CHECK_IN'
|
|
44
|
+
| 'REFLECTION'
|
|
45
|
+
| 'MOOD_LOG'
|
|
46
|
+
| 'WIN'
|
|
47
|
+
| 'JOURNAL'
|
|
48
|
+
| 'HABIT';
|
|
49
|
+
|
|
50
|
+
export interface JackTimelineEntry {
|
|
51
|
+
id: string;
|
|
52
|
+
role: string;
|
|
53
|
+
content: string;
|
|
54
|
+
entryType: JackEntryType;
|
|
55
|
+
metadata: Record<string, any> | null;
|
|
56
|
+
createdAt: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface JackTimelineResponse {
|
|
60
|
+
entries: JackTimelineEntry[];
|
|
61
|
+
hasMore: boolean;
|
|
62
|
+
nextCursor?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface JackStats {
|
|
66
|
+
totalMessages: number;
|
|
67
|
+
checkInsCount: number;
|
|
68
|
+
reflectionsCount: number;
|
|
69
|
+
moodLogsCount: number;
|
|
70
|
+
winsCount: number;
|
|
71
|
+
journalsCount: number;
|
|
72
|
+
habitsCount: number;
|
|
73
|
+
checkInStreak: number;
|
|
74
|
+
lastCheckInDate: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
39
77
|
export interface JackConversationWithMessages extends JackConversation {
|
|
40
78
|
messages: JackMessage[];
|
|
41
79
|
}
|
|
@@ -125,3 +163,103 @@ export function useJackHistory(
|
|
|
125
163
|
...options,
|
|
126
164
|
});
|
|
127
165
|
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Get paginated timeline entries (messages, check-ins, reflections, etc.)
|
|
169
|
+
*
|
|
170
|
+
* @param limit - Number of entries to return (default: 20)
|
|
171
|
+
* @param before - Cursor for pagination (entry ID to fetch before)
|
|
172
|
+
* @param options - TanStack Query options
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```tsx
|
|
176
|
+
* const { data: timeline, fetchNextPage } = useJackTimeline();
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export function useJackTimeline(
|
|
180
|
+
limit = 20,
|
|
181
|
+
before?: string,
|
|
182
|
+
options?: Omit<UseQueryOptions<JackTimelineResponse>, 'queryKey' | 'queryFn'>
|
|
183
|
+
) {
|
|
184
|
+
return useQuery({
|
|
185
|
+
queryKey: jackKeys.timeline(before),
|
|
186
|
+
queryFn: async (): Promise<JackTimelineResponse> => {
|
|
187
|
+
const client = getApiClient();
|
|
188
|
+
const params: Record<string, any> = { limit };
|
|
189
|
+
if (before) params.before = before;
|
|
190
|
+
const response = await client.get('/api/v1/support/jack/timeline', { params });
|
|
191
|
+
return response.data?.data || response.data;
|
|
192
|
+
},
|
|
193
|
+
...options,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get paginated timeline entries with infinite scroll support
|
|
199
|
+
*
|
|
200
|
+
* @param limit - Number of entries per page (default: 20)
|
|
201
|
+
* @param options - TanStack Query infinite query options
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* ```tsx
|
|
205
|
+
* const {
|
|
206
|
+
* data,
|
|
207
|
+
* fetchNextPage,
|
|
208
|
+
* hasNextPage,
|
|
209
|
+
* isFetchingNextPage,
|
|
210
|
+
* } = useInfiniteJackTimeline(20);
|
|
211
|
+
*
|
|
212
|
+
* // Flatten all pages into single array
|
|
213
|
+
* const entries = data?.pages.flatMap(page => page.entries) ?? [];
|
|
214
|
+
*
|
|
215
|
+
* // Load more when user scrolls to top
|
|
216
|
+
* const onEndReached = () => {
|
|
217
|
+
* if (hasNextPage && !isFetchingNextPage) {
|
|
218
|
+
* fetchNextPage();
|
|
219
|
+
* }
|
|
220
|
+
* };
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function useInfiniteJackTimeline(limit = 20) {
|
|
224
|
+
return useInfiniteQuery({
|
|
225
|
+
queryKey: [...jackKeys.all, 'timeline-infinite', limit] as const,
|
|
226
|
+
queryFn: async ({ pageParam }: { pageParam: string | undefined }): Promise<JackTimelineResponse> => {
|
|
227
|
+
const client = getApiClient();
|
|
228
|
+
const params: Record<string, any> = { limit };
|
|
229
|
+
if (pageParam) params.before = pageParam;
|
|
230
|
+
const response = await client.get('/api/v1/support/jack/timeline', { params });
|
|
231
|
+
return response.data?.data || response.data;
|
|
232
|
+
},
|
|
233
|
+
initialPageParam: undefined as string | undefined,
|
|
234
|
+
getNextPageParam: (lastPage: JackTimelineResponse) => lastPage.hasMore ? lastPage.nextCursor : undefined,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Get stats for rewards tracking
|
|
240
|
+
*
|
|
241
|
+
* @param days - Number of days to include in stats (default: 30)
|
|
242
|
+
* @param options - TanStack Query options
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```tsx
|
|
246
|
+
* const { data: stats } = useJackStats();
|
|
247
|
+
* console.log('Check-in streak:', stats?.checkInStreak);
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export function useJackStats(
|
|
251
|
+
days = 30,
|
|
252
|
+
options?: Omit<UseQueryOptions<JackStats>, 'queryKey' | 'queryFn'>
|
|
253
|
+
) {
|
|
254
|
+
return useQuery({
|
|
255
|
+
queryKey: jackKeys.stats(days),
|
|
256
|
+
queryFn: async (): Promise<JackStats> => {
|
|
257
|
+
const client = getApiClient();
|
|
258
|
+
const response = await client.get('/api/v1/support/jack/stats', {
|
|
259
|
+
params: { days },
|
|
260
|
+
});
|
|
261
|
+
return response.data?.data || response.data;
|
|
262
|
+
},
|
|
263
|
+
...options,
|
|
264
|
+
});
|
|
265
|
+
}
|