@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,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
  },
@@ -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';
@@ -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
+ }