@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,171 @@
|
|
|
1
|
+
import { useMutation, useQueryClient, UseMutationOptions } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import { creatorKeys } from '../queries/creators';
|
|
4
|
+
import type {
|
|
5
|
+
CreatorResponse,
|
|
6
|
+
CreatorAvailabilityResponse,
|
|
7
|
+
CreateCreatorRequest,
|
|
8
|
+
UpdateCreatorRequest,
|
|
9
|
+
CreateAvailabilityRequest,
|
|
10
|
+
} from '../types';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// MUTATION HOOKS
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create a new creator profile for the current user
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```tsx
|
|
21
|
+
* const { mutateAsync: createCreator } = useCreateCreator();
|
|
22
|
+
*
|
|
23
|
+
* await createCreator({
|
|
24
|
+
* slug: 'john-doe',
|
|
25
|
+
* displayName: 'John Doe',
|
|
26
|
+
* bio: 'Wellness facilitator',
|
|
27
|
+
* canFacilitate: true,
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export function useCreateCreator(
|
|
32
|
+
options?: Omit<UseMutationOptions<CreatorResponse, Error, CreateCreatorRequest>, 'mutationFn'>
|
|
33
|
+
) {
|
|
34
|
+
const queryClient = useQueryClient();
|
|
35
|
+
|
|
36
|
+
return useMutation({
|
|
37
|
+
mutationFn: async (data: CreateCreatorRequest): Promise<CreatorResponse> => {
|
|
38
|
+
const client = getApiClient();
|
|
39
|
+
const response = await client.post('/api/v1/creators', data);
|
|
40
|
+
return response.data;
|
|
41
|
+
},
|
|
42
|
+
onSuccess: () => {
|
|
43
|
+
queryClient.invalidateQueries({ queryKey: creatorKeys.all });
|
|
44
|
+
},
|
|
45
|
+
...options,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Update a creator profile
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const { mutateAsync: updateCreator } = useUpdateCreator();
|
|
55
|
+
*
|
|
56
|
+
* await updateCreator({
|
|
57
|
+
* id: 'creator-123',
|
|
58
|
+
* data: { bio: 'Updated bio' },
|
|
59
|
+
* });
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export function useUpdateCreator(
|
|
63
|
+
options?: Omit<
|
|
64
|
+
UseMutationOptions<CreatorResponse, Error, { id: string; data: UpdateCreatorRequest }>,
|
|
65
|
+
'mutationFn'
|
|
66
|
+
>
|
|
67
|
+
) {
|
|
68
|
+
const queryClient = useQueryClient();
|
|
69
|
+
|
|
70
|
+
return useMutation({
|
|
71
|
+
mutationFn: async ({ id, data }: { id: string; data: UpdateCreatorRequest }): Promise<CreatorResponse> => {
|
|
72
|
+
const client = getApiClient();
|
|
73
|
+
const response = await client.patch(`/api/v1/creators/${id}`, data);
|
|
74
|
+
return response.data;
|
|
75
|
+
},
|
|
76
|
+
onSuccess: (_, variables) => {
|
|
77
|
+
queryClient.invalidateQueries({ queryKey: creatorKeys.detail(variables.id) });
|
|
78
|
+
queryClient.invalidateQueries({ queryKey: creatorKeys.me() });
|
|
79
|
+
},
|
|
80
|
+
...options,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Add an availability slot for a creator
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* const { mutateAsync: addAvailability } = useAddCreatorAvailability();
|
|
90
|
+
*
|
|
91
|
+
* await addAvailability({
|
|
92
|
+
* creatorId: 'creator-123',
|
|
93
|
+
* data: {
|
|
94
|
+
* dayOfWeek: 1, // Monday
|
|
95
|
+
* startTime: '09:00',
|
|
96
|
+
* endTime: '17:00',
|
|
97
|
+
* timezone: 'Europe/London',
|
|
98
|
+
* isRecurring: true,
|
|
99
|
+
* },
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export function useAddCreatorAvailability(
|
|
104
|
+
options?: Omit<
|
|
105
|
+
UseMutationOptions<
|
|
106
|
+
CreatorAvailabilityResponse,
|
|
107
|
+
Error,
|
|
108
|
+
{ creatorId: string; data: CreateAvailabilityRequest }
|
|
109
|
+
>,
|
|
110
|
+
'mutationFn'
|
|
111
|
+
>
|
|
112
|
+
) {
|
|
113
|
+
const queryClient = useQueryClient();
|
|
114
|
+
|
|
115
|
+
return useMutation({
|
|
116
|
+
mutationFn: async ({
|
|
117
|
+
creatorId,
|
|
118
|
+
data,
|
|
119
|
+
}: {
|
|
120
|
+
creatorId: string;
|
|
121
|
+
data: CreateAvailabilityRequest;
|
|
122
|
+
}): Promise<CreatorAvailabilityResponse> => {
|
|
123
|
+
const client = getApiClient();
|
|
124
|
+
const response = await client.post(`/api/v1/creators/${creatorId}/availability`, data);
|
|
125
|
+
return response.data;
|
|
126
|
+
},
|
|
127
|
+
onSuccess: (_, variables) => {
|
|
128
|
+
queryClient.invalidateQueries({ queryKey: creatorKeys.availability(variables.creatorId) });
|
|
129
|
+
},
|
|
130
|
+
...options,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Remove an availability slot for a creator
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```tsx
|
|
139
|
+
* const { mutateAsync: removeAvailability } = useRemoveCreatorAvailability();
|
|
140
|
+
*
|
|
141
|
+
* await removeAvailability({
|
|
142
|
+
* creatorId: 'creator-123',
|
|
143
|
+
* availabilityId: 'availability-456',
|
|
144
|
+
* });
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export function useRemoveCreatorAvailability(
|
|
148
|
+
options?: Omit<
|
|
149
|
+
UseMutationOptions<void, Error, { creatorId: string; availabilityId: string }>,
|
|
150
|
+
'mutationFn'
|
|
151
|
+
>
|
|
152
|
+
) {
|
|
153
|
+
const queryClient = useQueryClient();
|
|
154
|
+
|
|
155
|
+
return useMutation({
|
|
156
|
+
mutationFn: async ({
|
|
157
|
+
creatorId,
|
|
158
|
+
availabilityId,
|
|
159
|
+
}: {
|
|
160
|
+
creatorId: string;
|
|
161
|
+
availabilityId: string;
|
|
162
|
+
}): Promise<void> => {
|
|
163
|
+
const client = getApiClient();
|
|
164
|
+
await client.delete(`/api/v1/creators/${creatorId}/availability/${availabilityId}`);
|
|
165
|
+
},
|
|
166
|
+
onSuccess: (_, variables) => {
|
|
167
|
+
queryClient.invalidateQueries({ queryKey: creatorKeys.availability(variables.creatorId) });
|
|
168
|
+
},
|
|
169
|
+
...options,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
@@ -25,7 +25,7 @@ export function useUpdateChatSettings(eventId: string) {
|
|
|
25
25
|
mutationFn: async (data: UpdateChatSettingsRequest) => {
|
|
26
26
|
const client = getApiClient();
|
|
27
27
|
const response = await client.put<EventChatResponse>(
|
|
28
|
-
`/events/${eventId}/chat/settings`,
|
|
28
|
+
`/api/v1/events/${eventId}/chat/settings`,
|
|
29
29
|
data
|
|
30
30
|
);
|
|
31
31
|
return response.data;
|
|
@@ -50,7 +50,7 @@ export function useJoinEventChat(eventId: string) {
|
|
|
50
50
|
mutationFn: async () => {
|
|
51
51
|
const client = getApiClient();
|
|
52
52
|
const response = await client.post<ChatMemberResponse>(
|
|
53
|
-
`/events/${eventId}/chat/join`
|
|
53
|
+
`/api/v1/events/${eventId}/chat/join`
|
|
54
54
|
);
|
|
55
55
|
return response.data;
|
|
56
56
|
},
|
|
@@ -70,7 +70,7 @@ export function useLeaveEventChat(eventId: string) {
|
|
|
70
70
|
return useMutation({
|
|
71
71
|
mutationFn: async () => {
|
|
72
72
|
const client = getApiClient();
|
|
73
|
-
await client.post(`/events/${eventId}/chat/leave`);
|
|
73
|
+
await client.post(`/api/v1/events/${eventId}/chat/leave`);
|
|
74
74
|
},
|
|
75
75
|
onSuccess: () => {
|
|
76
76
|
queryClient.invalidateQueries({ queryKey: eventChatKeys.chat(eventId) });
|
|
@@ -89,7 +89,7 @@ export function useUpdateMemberSettings(eventId: string) {
|
|
|
89
89
|
mutationFn: async (data: UpdateMemberSettingsRequest) => {
|
|
90
90
|
const client = getApiClient();
|
|
91
91
|
const response = await client.put<ChatMemberResponse>(
|
|
92
|
-
`/events/${eventId}/chat/settings/me`,
|
|
92
|
+
`/api/v1/events/${eventId}/chat/settings/me`,
|
|
93
93
|
data
|
|
94
94
|
);
|
|
95
95
|
return response.data;
|
|
@@ -107,7 +107,7 @@ export function useMarkMessagesAsRead(eventId: string) {
|
|
|
107
107
|
return useMutation({
|
|
108
108
|
mutationFn: async () => {
|
|
109
109
|
const client = getApiClient();
|
|
110
|
-
await client.post(`/events/${eventId}/chat/read`);
|
|
110
|
+
await client.post(`/api/v1/events/${eventId}/chat/read`);
|
|
111
111
|
},
|
|
112
112
|
});
|
|
113
113
|
}
|
|
@@ -126,7 +126,7 @@ export function useSendEventChatMessage(eventId: string) {
|
|
|
126
126
|
mutationFn: async (data: SendChatMessageRequest) => {
|
|
127
127
|
const client = getApiClient();
|
|
128
128
|
const response = await client.post<ChatMessageResponse>(
|
|
129
|
-
`/events/${eventId}/chat/messages`,
|
|
129
|
+
`/api/v1/events/${eventId}/chat/messages`,
|
|
130
130
|
data
|
|
131
131
|
);
|
|
132
132
|
return response.data;
|
|
@@ -148,7 +148,7 @@ export function useUpdateEventChatMessage(eventId: string) {
|
|
|
148
148
|
mutationFn: async ({ messageId, content }: { messageId: string } & UpdateChatMessageRequest) => {
|
|
149
149
|
const client = getApiClient();
|
|
150
150
|
const response = await client.put<ChatMessageResponse>(
|
|
151
|
-
`/events/${eventId}/chat/messages/${messageId}`,
|
|
151
|
+
`/api/v1/events/${eventId}/chat/messages/${messageId}`,
|
|
152
152
|
{ content }
|
|
153
153
|
);
|
|
154
154
|
return response.data;
|
|
@@ -168,7 +168,7 @@ export function useDeleteEventChatMessage(eventId: string) {
|
|
|
168
168
|
return useMutation({
|
|
169
169
|
mutationFn: async (messageId: string) => {
|
|
170
170
|
const client = getApiClient();
|
|
171
|
-
await client.delete(`/events/${eventId}/chat/messages/${messageId}`);
|
|
171
|
+
await client.delete(`/api/v1/events/${eventId}/chat/messages/${messageId}`);
|
|
172
172
|
},
|
|
173
173
|
onSuccess: () => {
|
|
174
174
|
queryClient.invalidateQueries({ queryKey: eventChatKeys.messages(eventId) });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMutation, useQueryClient, UseMutationOptions } from '@tanstack/react-query';
|
|
2
2
|
import { getApiClient } from '../client';
|
|
3
|
-
import { jackKeys } from '../queries/jack';
|
|
3
|
+
import { jackKeys, JackEntryType, JackTimelineEntry } from '../queries/jack';
|
|
4
4
|
|
|
5
5
|
// ============================================================================
|
|
6
6
|
// TYPES
|
|
@@ -21,6 +21,12 @@ export interface NewConversationResponse {
|
|
|
21
21
|
conversationId: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
export interface AddEntryRequest {
|
|
25
|
+
entryType: JackEntryType;
|
|
26
|
+
content: string;
|
|
27
|
+
metadata?: Record<string, any>;
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
// ============================================================================
|
|
25
31
|
// MUTATION HOOKS
|
|
26
32
|
// ============================================================================
|
|
@@ -128,3 +134,46 @@ export function useArchiveJackConversation(
|
|
|
128
134
|
...options,
|
|
129
135
|
});
|
|
130
136
|
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Add an entry to the Jack timeline (check-in, reflection, mood log, win, journal)
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```tsx
|
|
143
|
+
* const addEntry = useAddJackEntry();
|
|
144
|
+
*
|
|
145
|
+
* // Add a check-in
|
|
146
|
+
* await addEntry.mutateAsync({
|
|
147
|
+
* entryType: 'CHECK_IN',
|
|
148
|
+
* content: 'Feeling great today! Day 30.',
|
|
149
|
+
* metadata: { moodScore: 4, stayedSober: true },
|
|
150
|
+
* });
|
|
151
|
+
*
|
|
152
|
+
* // Add a win
|
|
153
|
+
* await addEntry.mutateAsync({
|
|
154
|
+
* entryType: 'WIN',
|
|
155
|
+
* content: 'Said no to drinks at dinner!',
|
|
156
|
+
* metadata: { category: 'SOBRIETY' },
|
|
157
|
+
* });
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
export function useAddJackEntry(
|
|
161
|
+
options?: Omit<UseMutationOptions<JackTimelineEntry, Error, AddEntryRequest>, 'mutationFn'>
|
|
162
|
+
) {
|
|
163
|
+
const queryClient = useQueryClient();
|
|
164
|
+
|
|
165
|
+
return useMutation({
|
|
166
|
+
mutationFn: async (data: AddEntryRequest): Promise<JackTimelineEntry> => {
|
|
167
|
+
const client = getApiClient();
|
|
168
|
+
const response = await client.post('/api/v1/support/jack/entry', data);
|
|
169
|
+
return response.data?.data || response.data;
|
|
170
|
+
},
|
|
171
|
+
onSuccess: () => {
|
|
172
|
+
// Invalidate timeline and stats queries
|
|
173
|
+
queryClient.invalidateQueries({ queryKey: jackKeys.timeline() });
|
|
174
|
+
queryClient.invalidateQueries({ queryKey: jackKeys.stats() });
|
|
175
|
+
queryClient.invalidateQueries({ queryKey: jackKeys.history() });
|
|
176
|
+
},
|
|
177
|
+
...options,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|
2
|
+
import { getApiClient } from '../client';
|
|
3
|
+
import { productKeys, CreatorProductResponse, ProductBookingResponse, ProductType, DeliveryMethod } from '../queries/products';
|
|
4
|
+
import { creatorKeys } from '../queries/creators';
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// TYPES
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
export interface CreateProductRequest {
|
|
11
|
+
title: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
imageUrl?: string;
|
|
14
|
+
type?: ProductType;
|
|
15
|
+
price: number;
|
|
16
|
+
currency?: string;
|
|
17
|
+
durationMinutes?: number;
|
|
18
|
+
maxParticipants?: number;
|
|
19
|
+
deliveryMethod?: DeliveryMethod;
|
|
20
|
+
locationDetails?: string;
|
|
21
|
+
slug?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UpdateProductRequest {
|
|
25
|
+
title?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
imageUrl?: string;
|
|
28
|
+
type?: ProductType;
|
|
29
|
+
price?: number;
|
|
30
|
+
currency?: string;
|
|
31
|
+
durationMinutes?: number;
|
|
32
|
+
maxParticipants?: number;
|
|
33
|
+
deliveryMethod?: DeliveryMethod;
|
|
34
|
+
locationDetails?: string;
|
|
35
|
+
isActive?: boolean;
|
|
36
|
+
isFeatured?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface BookProductRequest {
|
|
40
|
+
scheduledAt: string;
|
|
41
|
+
timezone?: string;
|
|
42
|
+
clientNotes?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface UpdateBookingRequest {
|
|
46
|
+
scheduledAt?: string;
|
|
47
|
+
clientNotes?: string;
|
|
48
|
+
creatorNotes?: string;
|
|
49
|
+
meetingLink?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface CancelBookingRequest {
|
|
53
|
+
reason?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// MUTATION HOOKS - PRODUCTS
|
|
58
|
+
// ============================================================================
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Create a new product for a creator
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* const { mutate: createProduct, isLoading } = useCreateProduct();
|
|
66
|
+
*
|
|
67
|
+
* createProduct({
|
|
68
|
+
* creatorId: 'creator-123',
|
|
69
|
+
* data: {
|
|
70
|
+
* title: '1-on-1 Coaching Session',
|
|
71
|
+
* description: 'Personal coaching session',
|
|
72
|
+
* type: 'SESSION_1ON1',
|
|
73
|
+
* price: 5000,
|
|
74
|
+
* durationMinutes: 60,
|
|
75
|
+
* },
|
|
76
|
+
* });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function useCreateProduct() {
|
|
80
|
+
const queryClient = useQueryClient();
|
|
81
|
+
|
|
82
|
+
return useMutation({
|
|
83
|
+
mutationFn: async ({
|
|
84
|
+
creatorId,
|
|
85
|
+
data,
|
|
86
|
+
}: {
|
|
87
|
+
creatorId: string;
|
|
88
|
+
data: CreateProductRequest;
|
|
89
|
+
}): Promise<CreatorProductResponse> => {
|
|
90
|
+
const client = getApiClient();
|
|
91
|
+
const response = await client.post(`/api/v1/creators/${creatorId}/products`, data);
|
|
92
|
+
return response.data;
|
|
93
|
+
},
|
|
94
|
+
onSuccess: (_, { creatorId }) => {
|
|
95
|
+
queryClient.invalidateQueries({ queryKey: productKeys.byCreator(creatorId) });
|
|
96
|
+
queryClient.invalidateQueries({ queryKey: productKeys.lists() });
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Update an existing product
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```tsx
|
|
106
|
+
* const { mutate: updateProduct, isLoading } = useUpdateProduct();
|
|
107
|
+
*
|
|
108
|
+
* updateProduct({
|
|
109
|
+
* creatorId: 'creator-123',
|
|
110
|
+
* productId: 'product-456',
|
|
111
|
+
* data: {
|
|
112
|
+
* price: 6000,
|
|
113
|
+
* isActive: true,
|
|
114
|
+
* },
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export function useUpdateProduct() {
|
|
119
|
+
const queryClient = useQueryClient();
|
|
120
|
+
|
|
121
|
+
return useMutation({
|
|
122
|
+
mutationFn: async ({
|
|
123
|
+
creatorId,
|
|
124
|
+
productId,
|
|
125
|
+
data,
|
|
126
|
+
}: {
|
|
127
|
+
creatorId: string;
|
|
128
|
+
productId: string;
|
|
129
|
+
data: UpdateProductRequest;
|
|
130
|
+
}): Promise<CreatorProductResponse> => {
|
|
131
|
+
const client = getApiClient();
|
|
132
|
+
const response = await client.put(
|
|
133
|
+
`/api/v1/creators/${creatorId}/products/${productId}`,
|
|
134
|
+
data
|
|
135
|
+
);
|
|
136
|
+
return response.data;
|
|
137
|
+
},
|
|
138
|
+
onSuccess: (_, { creatorId, productId }) => {
|
|
139
|
+
queryClient.invalidateQueries({ queryKey: productKeys.detail(productId) });
|
|
140
|
+
queryClient.invalidateQueries({ queryKey: productKeys.byCreator(creatorId) });
|
|
141
|
+
queryClient.invalidateQueries({ queryKey: productKeys.lists() });
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Delete a product
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```tsx
|
|
151
|
+
* const { mutate: deleteProduct, isLoading } = useDeleteProduct();
|
|
152
|
+
*
|
|
153
|
+
* deleteProduct({
|
|
154
|
+
* creatorId: 'creator-123',
|
|
155
|
+
* productId: 'product-456',
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function useDeleteProduct() {
|
|
160
|
+
const queryClient = useQueryClient();
|
|
161
|
+
|
|
162
|
+
return useMutation({
|
|
163
|
+
mutationFn: async ({
|
|
164
|
+
creatorId,
|
|
165
|
+
productId,
|
|
166
|
+
}: {
|
|
167
|
+
creatorId: string;
|
|
168
|
+
productId: string;
|
|
169
|
+
}): Promise<void> => {
|
|
170
|
+
const client = getApiClient();
|
|
171
|
+
await client.delete(`/api/v1/creators/${creatorId}/products/${productId}`);
|
|
172
|
+
},
|
|
173
|
+
onSuccess: (_, { creatorId, productId }) => {
|
|
174
|
+
queryClient.removeQueries({ queryKey: productKeys.detail(productId) });
|
|
175
|
+
queryClient.invalidateQueries({ queryKey: productKeys.byCreator(creatorId) });
|
|
176
|
+
queryClient.invalidateQueries({ queryKey: productKeys.lists() });
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// MUTATION HOOKS - BOOKINGS
|
|
183
|
+
// ============================================================================
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Book a product/session
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```tsx
|
|
190
|
+
* const { mutate: bookProduct, isLoading } = useBookProduct();
|
|
191
|
+
*
|
|
192
|
+
* bookProduct({
|
|
193
|
+
* productId: 'product-123',
|
|
194
|
+
* data: {
|
|
195
|
+
* scheduledAt: '2024-03-15T10:00:00Z',
|
|
196
|
+
* timezone: 'Europe/London',
|
|
197
|
+
* clientNotes: 'Looking forward to the session!',
|
|
198
|
+
* },
|
|
199
|
+
* });
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
export function useBookProduct() {
|
|
203
|
+
const queryClient = useQueryClient();
|
|
204
|
+
|
|
205
|
+
return useMutation({
|
|
206
|
+
mutationFn: async ({
|
|
207
|
+
productId,
|
|
208
|
+
data,
|
|
209
|
+
}: {
|
|
210
|
+
productId: string;
|
|
211
|
+
data: BookProductRequest;
|
|
212
|
+
}): Promise<ProductBookingResponse> => {
|
|
213
|
+
const client = getApiClient();
|
|
214
|
+
const response = await client.post(`/api/v1/products/${productId}/book`, data);
|
|
215
|
+
return response.data;
|
|
216
|
+
},
|
|
217
|
+
onSuccess: () => {
|
|
218
|
+
queryClient.invalidateQueries({ queryKey: productKeys.myBookings() });
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Update a product booking
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```tsx
|
|
228
|
+
* const { mutate: updateBooking, isLoading } = useUpdateProductBooking();
|
|
229
|
+
*
|
|
230
|
+
* updateBooking({
|
|
231
|
+
* bookingId: 'booking-123',
|
|
232
|
+
* data: {
|
|
233
|
+
* scheduledAt: '2024-03-16T14:00:00Z',
|
|
234
|
+
* clientNotes: 'Rescheduled due to conflict',
|
|
235
|
+
* },
|
|
236
|
+
* });
|
|
237
|
+
* ```
|
|
238
|
+
*/
|
|
239
|
+
export function useUpdateProductBooking() {
|
|
240
|
+
const queryClient = useQueryClient();
|
|
241
|
+
|
|
242
|
+
return useMutation({
|
|
243
|
+
mutationFn: async ({
|
|
244
|
+
bookingId,
|
|
245
|
+
data,
|
|
246
|
+
}: {
|
|
247
|
+
bookingId: string;
|
|
248
|
+
data: UpdateBookingRequest;
|
|
249
|
+
}): Promise<ProductBookingResponse> => {
|
|
250
|
+
const client = getApiClient();
|
|
251
|
+
const response = await client.put(
|
|
252
|
+
`/api/v1/users/me/product-bookings/${bookingId}`,
|
|
253
|
+
data
|
|
254
|
+
);
|
|
255
|
+
return response.data;
|
|
256
|
+
},
|
|
257
|
+
onSuccess: (_, { bookingId }) => {
|
|
258
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookingDetail(bookingId) });
|
|
259
|
+
queryClient.invalidateQueries({ queryKey: productKeys.myBookings() });
|
|
260
|
+
// Also invalidate creator bookings as they see this
|
|
261
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookings() });
|
|
262
|
+
},
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Cancel a product booking
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* ```tsx
|
|
271
|
+
* const { mutate: cancelBooking, isLoading } = useCancelProductBooking();
|
|
272
|
+
*
|
|
273
|
+
* cancelBooking({
|
|
274
|
+
* bookingId: 'booking-123',
|
|
275
|
+
* data: { reason: 'Schedule conflict' },
|
|
276
|
+
* });
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
export function useCancelProductBooking() {
|
|
280
|
+
const queryClient = useQueryClient();
|
|
281
|
+
|
|
282
|
+
return useMutation({
|
|
283
|
+
mutationFn: async ({
|
|
284
|
+
bookingId,
|
|
285
|
+
data,
|
|
286
|
+
}: {
|
|
287
|
+
bookingId: string;
|
|
288
|
+
data?: CancelBookingRequest;
|
|
289
|
+
}): Promise<ProductBookingResponse> => {
|
|
290
|
+
const client = getApiClient();
|
|
291
|
+
const response = await client.delete(
|
|
292
|
+
`/api/v1/users/me/product-bookings/${bookingId}`,
|
|
293
|
+
{ data }
|
|
294
|
+
);
|
|
295
|
+
return response.data;
|
|
296
|
+
},
|
|
297
|
+
onSuccess: (_, { bookingId }) => {
|
|
298
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookingDetail(bookingId) });
|
|
299
|
+
queryClient.invalidateQueries({ queryKey: productKeys.myBookings() });
|
|
300
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookings() });
|
|
301
|
+
},
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Mark a booking as completed (creator only)
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```tsx
|
|
310
|
+
* const { mutate: completeBooking, isLoading } = useCompleteProductBooking();
|
|
311
|
+
*
|
|
312
|
+
* completeBooking({ bookingId: 'booking-123' });
|
|
313
|
+
* ```
|
|
314
|
+
*/
|
|
315
|
+
export function useCompleteProductBooking() {
|
|
316
|
+
const queryClient = useQueryClient();
|
|
317
|
+
|
|
318
|
+
return useMutation({
|
|
319
|
+
mutationFn: async ({
|
|
320
|
+
bookingId,
|
|
321
|
+
}: {
|
|
322
|
+
bookingId: string;
|
|
323
|
+
}): Promise<ProductBookingResponse> => {
|
|
324
|
+
const client = getApiClient();
|
|
325
|
+
const response = await client.post(
|
|
326
|
+
`/api/v1/users/me/product-bookings/${bookingId}/complete`
|
|
327
|
+
);
|
|
328
|
+
return response.data;
|
|
329
|
+
},
|
|
330
|
+
onSuccess: (_, { bookingId }) => {
|
|
331
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookingDetail(bookingId) });
|
|
332
|
+
queryClient.invalidateQueries({ queryKey: productKeys.myBookings() });
|
|
333
|
+
queryClient.invalidateQueries({ queryKey: productKeys.bookings() });
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
}
|
|
@@ -18,6 +18,8 @@ import type {
|
|
|
18
18
|
UpdateHabitRequest,
|
|
19
19
|
ReflectionResponse,
|
|
20
20
|
CreateReflectionRequest,
|
|
21
|
+
CravingLogResponse,
|
|
22
|
+
LogCravingRequest,
|
|
21
23
|
} from '../types';
|
|
22
24
|
import { supportKeys } from '../queries/support';
|
|
23
25
|
|
|
@@ -388,3 +390,45 @@ export function useCreateReflection(
|
|
|
388
390
|
...options,
|
|
389
391
|
});
|
|
390
392
|
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Log a craving
|
|
396
|
+
*
|
|
397
|
+
* @param options - TanStack Query mutation options
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* ```tsx
|
|
401
|
+
* const { mutate, isPending } = useLogCraving();
|
|
402
|
+
*
|
|
403
|
+
* mutate({
|
|
404
|
+
* intensity: 4,
|
|
405
|
+
* trigger: 'Saw a beer ad',
|
|
406
|
+
* triggerType: 'ENVIRONMENT',
|
|
407
|
+
* copingUsed: ['deep_breathing', 'called_friend'],
|
|
408
|
+
* didResist: true
|
|
409
|
+
* });
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
export function useLogCraving(
|
|
413
|
+
options?: Omit<
|
|
414
|
+
UseMutationOptions<CravingLogResponse, Error, LogCravingRequest>,
|
|
415
|
+
'mutationFn'
|
|
416
|
+
>
|
|
417
|
+
): UseMutationResult<CravingLogResponse, Error, LogCravingRequest> {
|
|
418
|
+
const queryClient = useQueryClient();
|
|
419
|
+
|
|
420
|
+
return useMutation({
|
|
421
|
+
mutationFn: async (data: LogCravingRequest): Promise<CravingLogResponse> => {
|
|
422
|
+
const client = getApiClient();
|
|
423
|
+
const response = await client.post('/api/v1/support/cravings', data);
|
|
424
|
+
return response.data;
|
|
425
|
+
},
|
|
426
|
+
onSuccess: (newCraving, variables, context) => {
|
|
427
|
+
// Invalidate cravings list and stats
|
|
428
|
+
queryClient.invalidateQueries({ queryKey: supportKeys.cravings() });
|
|
429
|
+
|
|
430
|
+
// Call user's onSuccess if provided
|
|
431
|
+
},
|
|
432
|
+
...options,
|
|
433
|
+
});
|
|
434
|
+
}
|