@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.
Files changed (129) hide show
  1. package/README.md +276 -0
  2. package/dist/__tests__/e2e.test.d.ts +7 -0
  3. package/dist/__tests__/e2e.test.js +472 -0
  4. package/dist/api/client.d.ts +11 -0
  5. package/dist/api/client.js +61 -0
  6. package/dist/api/mutations/admin.d.ts +167 -0
  7. package/dist/api/mutations/admin.js +326 -0
  8. package/dist/api/mutations/ambassadors.d.ts +52 -0
  9. package/dist/api/mutations/ambassadors.js +148 -0
  10. package/dist/api/mutations/auth.d.ts +267 -0
  11. package/dist/api/mutations/auth.js +332 -0
  12. package/dist/api/mutations/bookings.d.ts +59 -0
  13. package/dist/api/mutations/bookings.js +143 -0
  14. package/dist/api/mutations/event-chat.d.ts +35 -0
  15. package/dist/api/mutations/event-chat.js +147 -0
  16. package/dist/api/mutations/events.d.ts +87 -0
  17. package/dist/api/mutations/events.js +205 -0
  18. package/dist/api/mutations/grow90.d.ts +36 -0
  19. package/dist/api/mutations/grow90.js +132 -0
  20. package/dist/api/mutations/hubs.d.ts +111 -0
  21. package/dist/api/mutations/hubs.js +240 -0
  22. package/dist/api/mutations/index.d.ts +22 -0
  23. package/dist/api/mutations/index.js +39 -0
  24. package/dist/api/mutations/jack.d.ts +61 -0
  25. package/dist/api/mutations/jack.js +104 -0
  26. package/dist/api/mutations/library.d.ts +67 -0
  27. package/dist/api/mutations/library.js +168 -0
  28. package/dist/api/mutations/map.d.ts +153 -0
  29. package/dist/api/mutations/map.js +181 -0
  30. package/dist/api/mutations/matching.d.ts +130 -0
  31. package/dist/api/mutations/matching.js +204 -0
  32. package/dist/api/mutations/notifications.d.ts +63 -0
  33. package/dist/api/mutations/notifications.js +106 -0
  34. package/dist/api/mutations/offers.d.ts +26 -0
  35. package/dist/api/mutations/offers.js +47 -0
  36. package/dist/api/mutations/subscriptions.d.ts +127 -0
  37. package/dist/api/mutations/subscriptions.js +140 -0
  38. package/dist/api/mutations/support.d.ts +165 -0
  39. package/dist/api/mutations/support.js +307 -0
  40. package/dist/api/mutations/users.d.ts +211 -0
  41. package/dist/api/mutations/users.js +261 -0
  42. package/dist/api/queries/admin.d.ts +257 -0
  43. package/dist/api/queries/admin.js +320 -0
  44. package/dist/api/queries/ambassadors.d.ts +53 -0
  45. package/dist/api/queries/ambassadors.js +98 -0
  46. package/dist/api/queries/auth.d.ts +16 -0
  47. package/dist/api/queries/auth.js +25 -0
  48. package/dist/api/queries/bookings.d.ts +91 -0
  49. package/dist/api/queries/bookings.js +102 -0
  50. package/dist/api/queries/businesses.d.ts +212 -0
  51. package/dist/api/queries/businesses.js +154 -0
  52. package/dist/api/queries/event-chat.d.ts +19 -0
  53. package/dist/api/queries/event-chat.js +75 -0
  54. package/dist/api/queries/events.d.ts +322 -0
  55. package/dist/api/queries/events.js +221 -0
  56. package/dist/api/queries/grow90.d.ts +26 -0
  57. package/dist/api/queries/grow90.js +85 -0
  58. package/dist/api/queries/hubs.d.ts +165 -0
  59. package/dist/api/queries/hubs.js +143 -0
  60. package/dist/api/queries/index.d.ts +23 -0
  61. package/dist/api/queries/index.js +40 -0
  62. package/dist/api/queries/jack.d.ts +63 -0
  63. package/dist/api/queries/jack.js +92 -0
  64. package/dist/api/queries/library.d.ts +132 -0
  65. package/dist/api/queries/library.js +120 -0
  66. package/dist/api/queries/map.d.ts +216 -0
  67. package/dist/api/queries/map.js +278 -0
  68. package/dist/api/queries/matching.d.ts +136 -0
  69. package/dist/api/queries/matching.js +161 -0
  70. package/dist/api/queries/notifications.d.ts +78 -0
  71. package/dist/api/queries/notifications.js +88 -0
  72. package/dist/api/queries/offers.d.ts +91 -0
  73. package/dist/api/queries/offers.js +103 -0
  74. package/dist/api/queries/subscriptions.d.ts +56 -0
  75. package/dist/api/queries/subscriptions.js +73 -0
  76. package/dist/api/queries/support.d.ts +106 -0
  77. package/dist/api/queries/support.js +202 -0
  78. package/dist/api/queries/users.d.ts +293 -0
  79. package/dist/api/queries/users.js +370 -0
  80. package/dist/api/types.d.ts +464 -0
  81. package/dist/api/types.js +9 -0
  82. package/dist/hooks/useAuth.d.ts +5 -0
  83. package/dist/hooks/useAuth.js +39 -0
  84. package/dist/hooks/useUser.d.ts +43 -0
  85. package/dist/hooks/useUser.js +44 -0
  86. package/dist/index.d.ts +36 -0
  87. package/dist/index.js +67 -0
  88. package/package.json +62 -0
  89. package/src/__tests__/e2e.test.ts +502 -0
  90. package/src/api/client.ts +71 -0
  91. package/src/api/mutations/admin.ts +531 -0
  92. package/src/api/mutations/ambassadors.ts +185 -0
  93. package/src/api/mutations/auth.ts +350 -0
  94. package/src/api/mutations/bookings.ts +190 -0
  95. package/src/api/mutations/event-chat.ts +177 -0
  96. package/src/api/mutations/events.ts +273 -0
  97. package/src/api/mutations/grow90.ts +169 -0
  98. package/src/api/mutations/hubs.ts +385 -0
  99. package/src/api/mutations/index.ts +23 -0
  100. package/src/api/mutations/jack.ts +130 -0
  101. package/src/api/mutations/library.ts +212 -0
  102. package/src/api/mutations/map.ts +230 -0
  103. package/src/api/mutations/matching.ts +271 -0
  104. package/src/api/mutations/notifications.ts +114 -0
  105. package/src/api/mutations/offers.ts +73 -0
  106. package/src/api/mutations/subscriptions.ts +162 -0
  107. package/src/api/mutations/support.ts +390 -0
  108. package/src/api/mutations/users.ts +271 -0
  109. package/src/api/queries/admin.ts +480 -0
  110. package/src/api/queries/ambassadors.ts +139 -0
  111. package/src/api/queries/auth.ts +24 -0
  112. package/src/api/queries/bookings.ts +135 -0
  113. package/src/api/queries/businesses.ts +203 -0
  114. package/src/api/queries/event-chat.ts +78 -0
  115. package/src/api/queries/events.ts +272 -0
  116. package/src/api/queries/grow90.ts +98 -0
  117. package/src/api/queries/hubs.ts +211 -0
  118. package/src/api/queries/index.ts +24 -0
  119. package/src/api/queries/jack.ts +127 -0
  120. package/src/api/queries/library.ts +166 -0
  121. package/src/api/queries/map.ts +331 -0
  122. package/src/api/queries/matching.ts +238 -0
  123. package/src/api/queries/notifications.ts +103 -0
  124. package/src/api/queries/offers.ts +136 -0
  125. package/src/api/queries/subscriptions.ts +91 -0
  126. package/src/api/queries/support.ts +235 -0
  127. package/src/api/queries/users.ts +393 -0
  128. package/src/api/types.ts +596 -0
  129. package/src/index.ts +57 -0
@@ -0,0 +1,393 @@
1
+ /**
2
+ * Users Query Hooks
3
+ *
4
+ * TanStack Query hooks for user-related read operations.
5
+ * These hooks handle fetching user data, profiles, library items, and subscriptions.
6
+ *
7
+ * @module api/queries/users
8
+ */
9
+
10
+ import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
11
+ import { getApiClient } from '../client';
12
+ import type {
13
+ UserResponse,
14
+ UserPublicResponse,
15
+ LibraryContentResponse,
16
+ LibraryProgressResponse,
17
+ OfferResponse,
18
+ SubscriptionResponse,
19
+ } from '../types';
20
+
21
+ // ============================================================================
22
+ // QUERY KEYS
23
+ // ============================================================================
24
+
25
+ /**
26
+ * Query key factory for user-related queries
27
+ * @see https://tkdodo.eu/blog/effective-react-query-keys
28
+ */
29
+ export const userKeys = {
30
+ all: ['users'] as const,
31
+ me: () => [...userKeys.all, 'me'] as const,
32
+ detail: (id: string) => [...userKeys.all, 'detail', id] as const,
33
+ public: (id: string) => [...userKeys.all, 'public', id] as const,
34
+ library: {
35
+ all: () => [...userKeys.me(), 'library'] as const,
36
+ bookmarks: () => [...userKeys.library.all(), 'bookmarks'] as const,
37
+ progress: () => [...userKeys.library.all(), 'progress'] as const,
38
+ },
39
+ offers: {
40
+ all: () => [...userKeys.me(), 'offers'] as const,
41
+ redeemed: () => [...userKeys.offers.all(), 'redeemed'] as const,
42
+ },
43
+ subscription: () => [...userKeys.me(), 'subscription'] as const,
44
+ };
45
+
46
+ // ============================================================================
47
+ // QUERY HOOKS
48
+ // ============================================================================
49
+
50
+ /**
51
+ * Get current user's profile
52
+ *
53
+ * @description
54
+ * Retrieves the currently authenticated user's complete profile information.
55
+ * Requires a valid access token to be set via the SDK configuration.
56
+ *
57
+ * @endpoint GET /api/v1/users/me
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * import { useCurrentUser } from '@growsober/sdk';
62
+ *
63
+ * function ProfileScreen() {
64
+ * const { data: user, isLoading, error } = useCurrentUser();
65
+ *
66
+ * if (isLoading) return <Spinner />;
67
+ * if (error) return <Error message={error.message} />;
68
+ * if (!user) return <NotFound />;
69
+ *
70
+ * return (
71
+ * <div>
72
+ * <h1>{user.name}</h1>
73
+ * <p>{user.email}</p>
74
+ * <p>Sober Since: {user.soberDate}</p>
75
+ * </div>
76
+ * );
77
+ * }
78
+ * ```
79
+ *
80
+ * @example
81
+ * With custom options:
82
+ * ```tsx
83
+ * const { data: user } = useCurrentUser({
84
+ * refetchOnMount: false,
85
+ * staleTime: 5 * 60 * 1000, // 5 minutes
86
+ * });
87
+ * ```
88
+ *
89
+ * @param options - TanStack Query options for customizing the query behavior
90
+ * @returns TanStack Query result with user data
91
+ */
92
+ export function useCurrentUser(
93
+ options?: Omit<UseQueryOptions<UserResponse>, 'queryKey' | 'queryFn'>
94
+ ): UseQueryResult<UserResponse> {
95
+ return useQuery({
96
+ queryKey: userKeys.me(),
97
+ queryFn: async (): Promise<UserResponse> => {
98
+ const client = getApiClient();
99
+ const response = await client.get<UserResponse>('/api/v1/users/me');
100
+ return response.data;
101
+ },
102
+ ...options,
103
+ });
104
+ }
105
+
106
+ /**
107
+ * Get a specific user's full profile by ID
108
+ *
109
+ * @description
110
+ * Retrieves a user's complete profile information by their ID.
111
+ * This may include private information depending on the requesting user's permissions.
112
+ *
113
+ * @endpoint GET /api/v1/users/{id}
114
+ *
115
+ * @example
116
+ * ```tsx
117
+ * import { useUser } from '@growsober/sdk';
118
+ *
119
+ * function UserProfileScreen({ userId }: { userId: string }) {
120
+ * const { data: user, isLoading } = useUser(userId);
121
+ *
122
+ * if (isLoading) return <Spinner />;
123
+ *
124
+ * return (
125
+ * <div>
126
+ * <Avatar src={user.avatar} />
127
+ * <h1>{user.name}</h1>
128
+ * <p>{user.bio}</p>
129
+ * </div>
130
+ * );
131
+ * }
132
+ * ```
133
+ *
134
+ * @example
135
+ * With conditional fetching:
136
+ * ```tsx
137
+ * const { data: user } = useUser(userId, {
138
+ * enabled: !!userId, // Only fetch when userId is defined
139
+ * });
140
+ * ```
141
+ *
142
+ * @param id - The user ID to fetch
143
+ * @param options - TanStack Query options for customizing the query behavior
144
+ * @returns TanStack Query result with user data
145
+ */
146
+ export function useUser(
147
+ id: string,
148
+ options?: Omit<UseQueryOptions<UserResponse>, 'queryKey' | 'queryFn'>
149
+ ): UseQueryResult<UserResponse> {
150
+ return useQuery({
151
+ queryKey: userKeys.detail(id),
152
+ queryFn: async (): Promise<UserResponse> => {
153
+ const client = getApiClient();
154
+ const response = await client.get<UserResponse>(`/api/v1/users/${id}`);
155
+ return response.data;
156
+ },
157
+ ...options,
158
+ });
159
+ }
160
+
161
+ /**
162
+ * Get a user's public profile by ID
163
+ *
164
+ * @description
165
+ * Retrieves a user's public profile information.
166
+ * This endpoint returns only publicly visible information and doesn't require authentication.
167
+ *
168
+ * @endpoint GET /api/v1/users/{id}/public
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * import { usePublicProfile } from '@growsober/sdk';
173
+ *
174
+ * function PublicProfileCard({ userId }: { userId: string }) {
175
+ * const { data: profile, isLoading } = usePublicProfile(userId);
176
+ *
177
+ * if (isLoading) return <Skeleton />;
178
+ *
179
+ * return (
180
+ * <div>
181
+ * <Avatar src={profile.avatar} />
182
+ * <h2>{profile.displayName}</h2>
183
+ * <p>{profile.city}</p>
184
+ * {profile.soberSince && (
185
+ * <p>Sober since: {new Date(profile.soberSince).toLocaleDateString()}</p>
186
+ * )}
187
+ * </div>
188
+ * );
189
+ * }
190
+ * ```
191
+ *
192
+ * @param id - The user ID to fetch
193
+ * @param options - TanStack Query options for customizing the query behavior
194
+ * @returns TanStack Query result with public profile data
195
+ */
196
+ export function usePublicProfile(
197
+ id: string,
198
+ options?: Omit<UseQueryOptions<UserPublicResponse>, 'queryKey' | 'queryFn'>
199
+ ): UseQueryResult<UserPublicResponse> {
200
+ return useQuery({
201
+ queryKey: userKeys.public(id),
202
+ queryFn: async (): Promise<UserPublicResponse> => {
203
+ const client = getApiClient();
204
+ const response = await client.get<UserPublicResponse>(`/api/v1/users/${id}/public`);
205
+ return response.data;
206
+ },
207
+ ...options,
208
+ });
209
+ }
210
+
211
+ /**
212
+ * Get current user's bookmarked library content
213
+ *
214
+ * @description
215
+ * Retrieves all library content (articles, videos, podcasts, etc.) that the user has bookmarked.
216
+ * This allows users to save content for later reading/viewing.
217
+ *
218
+ * @endpoint GET /api/v1/users/me/library/bookmarks
219
+ *
220
+ * @example
221
+ * ```tsx
222
+ * import { useMyBookmarks } from '@growsober/sdk';
223
+ *
224
+ * function BookmarksScreen() {
225
+ * const { data: bookmarks, isLoading } = useMyBookmarks();
226
+ *
227
+ * if (isLoading) return <Loading />;
228
+ *
229
+ * return (
230
+ * <div>
231
+ * <h1>My Saved Content</h1>
232
+ * {bookmarks?.map(content => (
233
+ * <ContentCard key={content.id} content={content} />
234
+ * ))}
235
+ * </div>
236
+ * );
237
+ * }
238
+ * ```
239
+ *
240
+ * @example
241
+ * With auto-refresh:
242
+ * ```tsx
243
+ * const { data: bookmarks } = useMyBookmarks({
244
+ * refetchInterval: 60000, // Refresh every minute
245
+ * });
246
+ * ```
247
+ *
248
+ * @param options - TanStack Query options for customizing the query behavior
249
+ * @returns TanStack Query result with array of bookmarked content
250
+ */
251
+ export function useMyBookmarks(
252
+ options?: Omit<UseQueryOptions<LibraryContentResponse[]>, 'queryKey' | 'queryFn'>
253
+ ): UseQueryResult<LibraryContentResponse[]> {
254
+ return useQuery({
255
+ queryKey: userKeys.library.bookmarks(),
256
+ queryFn: async (): Promise<LibraryContentResponse[]> => {
257
+ const client = getApiClient();
258
+ const response = await client.get<LibraryContentResponse[]>('/api/v1/users/me/library/bookmarks');
259
+ return response.data;
260
+ },
261
+ ...options,
262
+ });
263
+ }
264
+
265
+ /**
266
+ * Get current user's library content progress
267
+ *
268
+ * @description
269
+ * Retrieves the user's progress on library content items.
270
+ * Tracks which content has been started, completed, or partially viewed/read.
271
+ *
272
+ * @endpoint GET /api/v1/users/me/library/progress
273
+ *
274
+ * @example
275
+ * ```tsx
276
+ * import { useMyProgress } from '@growsober/sdk';
277
+ *
278
+ * function LibraryProgressScreen() {
279
+ * const { data: progress, isLoading } = useMyProgress();
280
+ *
281
+ * if (isLoading) return <Loading />;
282
+ *
283
+ * const completed = progress?.filter(p => p.completed) || [];
284
+ * const inProgress = progress?.filter(p => !p.completed && p.progress > 0) || [];
285
+ *
286
+ * return (
287
+ * <div>
288
+ * <h2>Completed: {completed.length}</h2>
289
+ * <h2>In Progress: {inProgress.length}</h2>
290
+ * </div>
291
+ * );
292
+ * }
293
+ * ```
294
+ *
295
+ * @example
296
+ * Check progress for specific content:
297
+ * ```tsx
298
+ * function ContentProgress({ contentId }: { contentId: string }) {
299
+ * const { data: progress } = useMyProgress();
300
+ * const contentProgress = progress?.find(p => p.contentId === contentId);
301
+ *
302
+ * return (
303
+ * <ProgressBar
304
+ * value={contentProgress?.progress || 0}
305
+ * max={100}
306
+ * />
307
+ * );
308
+ * }
309
+ * ```
310
+ *
311
+ * @param options - TanStack Query options for customizing the query behavior
312
+ * @returns TanStack Query result with array of progress records
313
+ */
314
+ export function useMyProgress(
315
+ options?: Omit<UseQueryOptions<LibraryProgressResponse[]>, 'queryKey' | 'queryFn'>
316
+ ): UseQueryResult<LibraryProgressResponse[]> {
317
+ return useQuery({
318
+ queryKey: userKeys.library.progress(),
319
+ queryFn: async (): Promise<LibraryProgressResponse[]> => {
320
+ const client = getApiClient();
321
+ const response = await client.get<LibraryProgressResponse[]>('/api/v1/users/me/library/progress');
322
+ return response.data;
323
+ },
324
+ ...options,
325
+ });
326
+ }
327
+
328
+ /**
329
+ * Get current user's redeemed offers
330
+ *
331
+ * @description
332
+ * Retrieves all offers/deals that the user has redeemed.
333
+ * Shows history of partner offers used by the user.
334
+ *
335
+ * @endpoint GET /api/v1/users/me/offers/redeemed
336
+ *
337
+ * @example
338
+ * ```tsx
339
+ * import { useMyRedeemedOffers } from '@growsober/sdk';
340
+ *
341
+ * function RedeemedOffersScreen() {
342
+ * const { data: offers, isLoading } = useMyRedeemedOffers();
343
+ *
344
+ * if (isLoading) return <Loading />;
345
+ *
346
+ * return (
347
+ * <div>
348
+ * <h1>My Redeemed Offers</h1>
349
+ * {offers?.map(offer => (
350
+ * <div key={offer.id}>
351
+ * <h3>{offer.title}</h3>
352
+ * <p>Redeemed: {new Date(offer.redeemedAt).toLocaleDateString()}</p>
353
+ * <p>Code: {offer.code}</p>
354
+ * </div>
355
+ * ))}
356
+ * </div>
357
+ * );
358
+ * }
359
+ * ```
360
+ *
361
+ * @example
362
+ * Check if specific offer was redeemed:
363
+ * ```tsx
364
+ * function OfferCard({ offerId }: { offerId: string }) {
365
+ * const { data: redeemedOffers } = useMyRedeemedOffers();
366
+ * const isRedeemed = redeemedOffers?.some(o => o.id === offerId);
367
+ *
368
+ * return (
369
+ * <button disabled={isRedeemed}>
370
+ * {isRedeemed ? 'Already Redeemed' : 'Redeem Offer'}
371
+ * </button>
372
+ * );
373
+ * }
374
+ * ```
375
+ *
376
+ * @param options - TanStack Query options for customizing the query behavior
377
+ * @returns TanStack Query result with array of redeemed offers
378
+ */
379
+ export function useMyRedeemedOffers(
380
+ options?: Omit<UseQueryOptions<OfferResponse[]>, 'queryKey' | 'queryFn'>
381
+ ): UseQueryResult<OfferResponse[]> {
382
+ return useQuery({
383
+ queryKey: userKeys.offers.redeemed(),
384
+ queryFn: async (): Promise<OfferResponse[]> => {
385
+ const client = getApiClient();
386
+ const response = await client.get<OfferResponse[]>('/api/v1/users/me/offers/redeemed');
387
+ return response.data;
388
+ },
389
+ ...options,
390
+ });
391
+ }
392
+
393
+ // Note: useMySubscription is available from '@growsober/sdk' via ./subscriptions