@growsober/sdk 1.0.18 → 1.0.20

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.
@@ -0,0 +1,230 @@
1
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+ import {
4
+ communityKeys,
5
+ CommunityMemberResponse,
6
+ CommunityMessageResponse,
7
+ CreatorCommunityResponse,
8
+ } from '../queries/creator-community';
9
+
10
+ // ============================================================================
11
+ // COMMUNITY MANAGEMENT
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Update community settings (owner only)
16
+ */
17
+ export function useUpdateCommunitySettings(creatorId: string) {
18
+ const queryClient = useQueryClient();
19
+
20
+ return useMutation({
21
+ mutationFn: async (data: {
22
+ name?: string;
23
+ description?: string;
24
+ isLocked?: boolean;
25
+ }): Promise<CreatorCommunityResponse> => {
26
+ const client = getApiClient();
27
+ const response = await client.put(
28
+ `/api/v1/creators/${creatorId}/community/settings`,
29
+ data
30
+ );
31
+ return response.data?.data || response.data;
32
+ },
33
+ onSuccess: () => {
34
+ queryClient.invalidateQueries({ queryKey: communityKeys.detail(creatorId) });
35
+ },
36
+ });
37
+ }
38
+
39
+ // ============================================================================
40
+ // MEMBER MANAGEMENT
41
+ // ============================================================================
42
+
43
+ /**
44
+ * Join a creator's community
45
+ */
46
+ export function useJoinCommunity(creatorId: string) {
47
+ const queryClient = useQueryClient();
48
+
49
+ return useMutation({
50
+ mutationFn: async (): Promise<CommunityMemberResponse> => {
51
+ const client = getApiClient();
52
+ const response = await client.post(`/api/v1/creators/${creatorId}/community/join`);
53
+ return response.data?.data || response.data;
54
+ },
55
+ onSuccess: () => {
56
+ queryClient.invalidateQueries({ queryKey: communityKeys.detail(creatorId) });
57
+ queryClient.invalidateQueries({ queryKey: communityKeys.members(creatorId) });
58
+ },
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Leave a creator's community
64
+ */
65
+ export function useLeaveCommunity(creatorId: string) {
66
+ const queryClient = useQueryClient();
67
+
68
+ return useMutation({
69
+ mutationFn: async (): Promise<void> => {
70
+ const client = getApiClient();
71
+ await client.post(`/api/v1/creators/${creatorId}/community/leave`);
72
+ },
73
+ onSuccess: () => {
74
+ queryClient.invalidateQueries({ queryKey: communityKeys.detail(creatorId) });
75
+ queryClient.invalidateQueries({ queryKey: communityKeys.members(creatorId) });
76
+ },
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Invite a user to the community (owner/moderator only)
82
+ */
83
+ export function useInviteToCommunity(creatorId: string) {
84
+ const queryClient = useQueryClient();
85
+
86
+ return useMutation({
87
+ mutationFn: async (userId: string): Promise<CommunityMemberResponse> => {
88
+ const client = getApiClient();
89
+ const response = await client.post(
90
+ `/api/v1/creators/${creatorId}/community/invite`,
91
+ { userId }
92
+ );
93
+ return response.data?.data || response.data;
94
+ },
95
+ onSuccess: () => {
96
+ queryClient.invalidateQueries({ queryKey: communityKeys.members(creatorId) });
97
+ },
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Remove a member from the community (owner/moderator only)
103
+ */
104
+ export function useRemoveCommunityMember(creatorId: string) {
105
+ const queryClient = useQueryClient();
106
+
107
+ return useMutation({
108
+ mutationFn: async (userId: string): Promise<void> => {
109
+ const client = getApiClient();
110
+ await client.delete(`/api/v1/creators/${creatorId}/community/members/${userId}`);
111
+ },
112
+ onSuccess: () => {
113
+ queryClient.invalidateQueries({ queryKey: communityKeys.members(creatorId) });
114
+ queryClient.invalidateQueries({ queryKey: communityKeys.detail(creatorId) });
115
+ },
116
+ });
117
+ }
118
+
119
+ /**
120
+ * Update member settings (nickname, mute)
121
+ */
122
+ export function useUpdateCommunityMemberSettings(creatorId: string) {
123
+ const queryClient = useQueryClient();
124
+
125
+ return useMutation({
126
+ mutationFn: async (data: {
127
+ nickname?: string;
128
+ isMuted?: boolean;
129
+ }): Promise<CommunityMemberResponse> => {
130
+ const client = getApiClient();
131
+ const response = await client.put(
132
+ `/api/v1/creators/${creatorId}/community/settings/me`,
133
+ data
134
+ );
135
+ return response.data?.data || response.data;
136
+ },
137
+ onSuccess: () => {
138
+ queryClient.invalidateQueries({ queryKey: communityKeys.members(creatorId) });
139
+ },
140
+ });
141
+ }
142
+
143
+ /**
144
+ * Mark messages as read
145
+ */
146
+ export function useMarkCommunityAsRead(creatorId: string) {
147
+ return useMutation({
148
+ mutationFn: async (): Promise<void> => {
149
+ const client = getApiClient();
150
+ await client.post(`/api/v1/creators/${creatorId}/community/read`);
151
+ },
152
+ });
153
+ }
154
+
155
+ // ============================================================================
156
+ // MESSAGES
157
+ // ============================================================================
158
+
159
+ /**
160
+ * Send a message to the community
161
+ */
162
+ export function useSendCommunityMessage(creatorId: string) {
163
+ const queryClient = useQueryClient();
164
+
165
+ return useMutation({
166
+ mutationFn: async (data: {
167
+ content: string;
168
+ messageType?: 'TEXT' | 'IMAGE' | 'SYSTEM' | 'ANNOUNCEMENT';
169
+ imageUrl?: string;
170
+ replyToId?: string;
171
+ }): Promise<CommunityMessageResponse> => {
172
+ const client = getApiClient();
173
+ const response = await client.post(
174
+ `/api/v1/creators/${creatorId}/community/messages`,
175
+ data
176
+ );
177
+ return response.data?.data || response.data;
178
+ },
179
+ onSuccess: () => {
180
+ queryClient.invalidateQueries({ queryKey: communityKeys.messages(creatorId) });
181
+ queryClient.invalidateQueries({ queryKey: communityKeys.detail(creatorId) });
182
+ },
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Update a community message
188
+ */
189
+ export function useUpdateCommunityMessage(creatorId: string) {
190
+ const queryClient = useQueryClient();
191
+
192
+ return useMutation({
193
+ mutationFn: async ({
194
+ messageId,
195
+ content,
196
+ }: {
197
+ messageId: string;
198
+ content: string;
199
+ }): Promise<CommunityMessageResponse> => {
200
+ const client = getApiClient();
201
+ const response = await client.put(
202
+ `/api/v1/creators/${creatorId}/community/messages/${messageId}`,
203
+ { content }
204
+ );
205
+ return response.data?.data || response.data;
206
+ },
207
+ onSuccess: () => {
208
+ queryClient.invalidateQueries({ queryKey: communityKeys.messages(creatorId) });
209
+ },
210
+ });
211
+ }
212
+
213
+ /**
214
+ * Delete a community message
215
+ */
216
+ export function useDeleteCommunityMessage(creatorId: string) {
217
+ const queryClient = useQueryClient();
218
+
219
+ return useMutation({
220
+ mutationFn: async (messageId: string): Promise<void> => {
221
+ const client = getApiClient();
222
+ await client.delete(
223
+ `/api/v1/creators/${creatorId}/community/messages/${messageId}`
224
+ );
225
+ },
226
+ onSuccess: () => {
227
+ queryClient.invalidateQueries({ queryKey: communityKeys.messages(creatorId) });
228
+ },
229
+ });
230
+ }
@@ -28,3 +28,4 @@ export * from './brands';
28
28
  export * from './products';
29
29
  export * from './venues';
30
30
  export * from './stripe-connect';
31
+ export * from './creator-community';
@@ -334,3 +334,45 @@ export function useCompleteProductBooking() {
334
334
  },
335
335
  });
336
336
  }
337
+
338
+ // ============================================================================
339
+ // MUTATION HOOKS - PAYMENTS
340
+ // ============================================================================
341
+
342
+ export interface PaymentIntentResponse {
343
+ clientSecret: string;
344
+ paymentIntentId: string;
345
+ }
346
+
347
+ /**
348
+ * Create a payment intent for a product booking
349
+ * Use this with Stripe Elements to process payment
350
+ *
351
+ * @example
352
+ * ```tsx
353
+ * const { mutate: createPaymentIntent, data, isLoading } = useCreateProductPaymentIntent();
354
+ *
355
+ * // Create payment intent
356
+ * createPaymentIntent({ bookingId: 'booking-123' });
357
+ *
358
+ * // Use clientSecret with Stripe Elements
359
+ * if (data?.clientSecret) {
360
+ * // Pass to Stripe PaymentElement
361
+ * }
362
+ * ```
363
+ */
364
+ export function useCreateProductPaymentIntent() {
365
+ return useMutation({
366
+ mutationFn: async ({
367
+ bookingId,
368
+ }: {
369
+ bookingId: string;
370
+ }): Promise<PaymentIntentResponse> => {
371
+ const client = getApiClient();
372
+ const response = await client.post(
373
+ `/api/v1/users/me/product-bookings/${bookingId}/payment-intent`
374
+ );
375
+ return response.data;
376
+ },
377
+ });
378
+ }
@@ -0,0 +1,13 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ ### Jan 25, 2026
7
+
8
+ | ID | Time | T | Title | Read |
9
+ |----|------|---|-------|------|
10
+ | #1598 | 9:42 AM | 🔵 | Jack AI comprehensive file inventory reveals 40+ files across web, API, SDK, and mobile | ~720 |
11
+ | #1264 | 4:15 AM | 🔵 | Library content query system supports filtering by type, category, and drinking identity | ~639 |
12
+ | #1223 | 3:53 AM | 🔵 | SDK user query hooks provide comprehensive profile, library, and offer access | ~644 |
13
+ </claude-mem-context>
@@ -0,0 +1,154 @@
1
+ import { useQuery, useInfiniteQuery, UseQueryOptions } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+
4
+ // ============================================================================
5
+ // QUERY KEYS
6
+ // ============================================================================
7
+
8
+ export const communityKeys = {
9
+ all: ['creator-community'] as const,
10
+ detail: (creatorId: string) => [...communityKeys.all, creatorId] as const,
11
+ members: (creatorId: string) => [...communityKeys.detail(creatorId), 'members'] as const,
12
+ messages: (creatorId: string) => [...communityKeys.detail(creatorId), 'messages'] as const,
13
+ };
14
+
15
+ // ============================================================================
16
+ // TYPES
17
+ // ============================================================================
18
+
19
+ export interface CommunityCreator {
20
+ id: string;
21
+ displayName: string;
22
+ slug: string;
23
+ avatarUrl: string | null;
24
+ }
25
+
26
+ export interface CreatorCommunityResponse {
27
+ id: string;
28
+ creatorId: string;
29
+ name: string;
30
+ description: string | null;
31
+ memberCount: number;
32
+ messageCount: number;
33
+ isActive: boolean;
34
+ isLocked: boolean;
35
+ lastMessageAt: string | null;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ creator?: CommunityCreator;
39
+ }
40
+
41
+ export interface CommunityMemberResponse {
42
+ id: string;
43
+ communityId: string;
44
+ userId: string;
45
+ role: 'OWNER' | 'MODERATOR' | 'MEMBER';
46
+ nickname: string | null;
47
+ isMuted: boolean;
48
+ lastReadAt: string | null;
49
+ joinedAt: string;
50
+ leftAt: string | null;
51
+ sourceEventId: string | null;
52
+ user?: {
53
+ id: string;
54
+ name: string | null;
55
+ profileImage: string | null;
56
+ };
57
+ }
58
+
59
+ export interface CommunityMessageResponse {
60
+ id: string;
61
+ communityId: string;
62
+ userId: string;
63
+ content: string;
64
+ messageType: 'TEXT' | 'IMAGE' | 'SYSTEM' | 'ANNOUNCEMENT';
65
+ imageUrl: string | null;
66
+ replyToId: string | null;
67
+ isEdited: boolean;
68
+ isDeleted: boolean;
69
+ isPinned: boolean;
70
+ createdAt: string;
71
+ updatedAt: string;
72
+ user?: {
73
+ id: string;
74
+ name: string | null;
75
+ profileImage: string | null;
76
+ };
77
+ replyToContent?: string;
78
+ replyToUserName?: string;
79
+ }
80
+
81
+ export interface PaginatedCommunityMessagesResponse {
82
+ messages: CommunityMessageResponse[];
83
+ nextCursor: string | null;
84
+ hasMore: boolean;
85
+ total: number;
86
+ }
87
+
88
+ // ============================================================================
89
+ // HOOKS
90
+ // ============================================================================
91
+
92
+ /**
93
+ * Get a creator's community
94
+ */
95
+ export function useCreatorCommunity(
96
+ creatorId: string | undefined,
97
+ options?: Omit<UseQueryOptions<CreatorCommunityResponse>, 'queryKey' | 'queryFn'>
98
+ ) {
99
+ return useQuery({
100
+ queryKey: communityKeys.detail(creatorId || ''),
101
+ queryFn: async (): Promise<CreatorCommunityResponse> => {
102
+ if (!creatorId) throw new Error('Creator ID is required');
103
+ const client = getApiClient();
104
+ const response = await client.get(`/api/v1/creators/${creatorId}/community`);
105
+ return response.data?.data || response.data;
106
+ },
107
+ enabled: !!creatorId,
108
+ ...options,
109
+ });
110
+ }
111
+
112
+ /**
113
+ * Get community members
114
+ */
115
+ export function useCommunityMembers(
116
+ creatorId: string | undefined,
117
+ options?: Omit<UseQueryOptions<CommunityMemberResponse[]>, 'queryKey' | 'queryFn'>
118
+ ) {
119
+ return useQuery({
120
+ queryKey: communityKeys.members(creatorId || ''),
121
+ queryFn: async (): Promise<CommunityMemberResponse[]> => {
122
+ if (!creatorId) throw new Error('Creator ID is required');
123
+ const client = getApiClient();
124
+ const response = await client.get(`/api/v1/creators/${creatorId}/community/members`);
125
+ return response.data?.data || response.data || [];
126
+ },
127
+ enabled: !!creatorId,
128
+ ...options,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Get community messages with infinite scroll pagination
134
+ */
135
+ export function useCommunityMessages(creatorId: string | undefined, limit = 50) {
136
+ return useInfiniteQuery({
137
+ queryKey: communityKeys.messages(creatorId || ''),
138
+ queryFn: async ({ pageParam }): Promise<PaginatedCommunityMessagesResponse> => {
139
+ if (!creatorId) throw new Error('Creator ID is required');
140
+ const client = getApiClient();
141
+ const params = new URLSearchParams({ limit: String(limit) });
142
+ if (pageParam) {
143
+ params.append('cursor', pageParam);
144
+ }
145
+ const response = await client.get(
146
+ `/api/v1/creators/${creatorId}/community/messages?${params.toString()}`
147
+ );
148
+ return response.data?.data || response.data;
149
+ },
150
+ initialPageParam: undefined as string | undefined,
151
+ getNextPageParam: (lastPage) => lastPage.nextCursor,
152
+ enabled: !!creatorId,
153
+ });
154
+ }
@@ -299,16 +299,18 @@ export function useCreatorAllContent(
299
299
  export function useCreatorEvents(
300
300
  creatorId: string,
301
301
  upcoming = true,
302
+ includeUnpublished = false,
302
303
  options?: Omit<UseQueryOptions<EventResponse[]>, 'queryKey' | 'queryFn'>
303
304
  ) {
304
305
  return useQuery({
305
- queryKey: creatorKeys.events(creatorId),
306
+ queryKey: [...creatorKeys.events(creatorId), { upcoming, includeUnpublished }],
306
307
  queryFn: async (): Promise<EventResponse[]> => {
307
308
  const client = getApiClient();
308
309
  const response = await client.get(`/api/v1/creators/${creatorId}/events`, {
309
- params: { upcoming },
310
+ params: { upcoming, includeUnpublished },
310
311
  });
311
- return response.data;
312
+ // Handle wrapped response {data: [...], meta: {...}} or direct array
313
+ return response.data?.data || response.data || [];
312
314
  },
313
315
  enabled: !!creatorId,
314
316
  ...options,
@@ -30,3 +30,4 @@ export * from './creators';
30
30
  export * from './brands';
31
31
  export * from './products';
32
32
  export * from './stripe-connect';
33
+ export * from './creator-community';