@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,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
|