@growsober/sdk 1.0.22 → 1.0.24

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.
@@ -1,40 +1,14 @@
1
1
  import { useMutation, useQueryClient } from '@tanstack/react-query';
2
2
  import { getApiClient } from '../client';
3
- import { productKeys, CreatorProductResponse, ProductBookingResponse, ProductType, DeliveryMethod } from '../queries/products';
3
+ import { productKeys, CreatorProductResponse, ProductBookingResponse, CreateProductDto, UpdateProductDto } from '../queries/products';
4
4
  import { creatorKeys } from '../queries/creators';
5
5
 
6
6
  // ============================================================================
7
- // TYPES
7
+ // TYPES — request types derived from auto-generated OpenAPI DTOs
8
8
  // ============================================================================
9
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
- }
10
+ export type CreateProductRequest = CreateProductDto;
11
+ export type UpdateProductRequest = UpdateProductDto;
38
12
 
39
13
  export interface BookProductRequest {
40
14
  scheduledAt: string;
@@ -57,25 +31,6 @@ export interface CancelBookingRequest {
57
31
  // MUTATION HOOKS - PRODUCTS
58
32
  // ============================================================================
59
33
 
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
34
  export function useCreateProduct() {
80
35
  const queryClient = useQueryClient();
81
36
 
@@ -98,23 +53,6 @@ export function useCreateProduct() {
98
53
  });
99
54
  }
100
55
 
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
56
  export function useUpdateProduct() {
119
57
  const queryClient = useQueryClient();
120
58
 
@@ -143,19 +81,6 @@ export function useUpdateProduct() {
143
81
  });
144
82
  }
145
83
 
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
84
  export function useDeleteProduct() {
160
85
  const queryClient = useQueryClient();
161
86
 
@@ -182,23 +107,6 @@ export function useDeleteProduct() {
182
107
  // MUTATION HOOKS - BOOKINGS
183
108
  // ============================================================================
184
109
 
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
110
  export function useBookProduct() {
203
111
  const queryClient = useQueryClient();
204
112
 
@@ -220,22 +128,6 @@ export function useBookProduct() {
220
128
  });
221
129
  }
222
130
 
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
131
  export function useUpdateProductBooking() {
240
132
  const queryClient = useQueryClient();
241
133
 
@@ -257,25 +149,11 @@ export function useUpdateProductBooking() {
257
149
  onSuccess: (_, { bookingId }) => {
258
150
  queryClient.invalidateQueries({ queryKey: productKeys.bookingDetail(bookingId) });
259
151
  queryClient.invalidateQueries({ queryKey: productKeys.myBookings() });
260
- // Also invalidate creator bookings as they see this
261
152
  queryClient.invalidateQueries({ queryKey: productKeys.bookings() });
262
153
  },
263
154
  });
264
155
  }
265
156
 
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
157
  export function useCancelProductBooking() {
280
158
  const queryClient = useQueryClient();
281
159
 
@@ -302,16 +180,6 @@ export function useCancelProductBooking() {
302
180
  });
303
181
  }
304
182
 
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
183
  export function useCompleteProductBooking() {
316
184
  const queryClient = useQueryClient();
317
185
 
@@ -344,23 +212,6 @@ export interface PaymentIntentResponse {
344
212
  paymentIntentId: string;
345
213
  }
346
214
 
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
215
  export function useCreateProductPaymentIntent() {
365
216
  return useMutation({
366
217
  mutationFn: async ({
@@ -23,6 +23,8 @@ export const creatorKeys = {
23
23
  byUser: (userId: string) => [...creatorKeys.all, 'user', userId] as const,
24
24
  me: () => [...creatorKeys.all, 'me'] as const,
25
25
  availability: (creatorId: string) => [...creatorKeys.detail(creatorId), 'availability'] as const,
26
+ availableDates: (creatorId: string, from: string, to: string) => [...creatorKeys.detail(creatorId), 'available-dates', from, to] as const,
27
+ availableSlots: (creatorId: string, date: string, durationMinutes: number) => [...creatorKeys.detail(creatorId), 'available-slots', date, durationMinutes] as const,
26
28
  content: (creatorId: string) => [...creatorKeys.detail(creatorId), 'content'] as const,
27
29
  allContent: (creatorId: string) => [...creatorKeys.detail(creatorId), 'content', 'all'] as const,
28
30
  events: (creatorId: string) => [...creatorKeys.detail(creatorId), 'events'] as const,
@@ -229,6 +231,74 @@ export function useCreatorAvailability(
229
231
  });
230
232
  }
231
233
 
234
+ // ============================================================================
235
+ // AVAILABILITY-AWARE SCHEDULING
236
+ // ============================================================================
237
+
238
+ export interface AvailableDateEntry {
239
+ date: string;
240
+ hasAvailability: boolean;
241
+ }
242
+
243
+ export interface AvailableDatesResponse {
244
+ dates: AvailableDateEntry[];
245
+ }
246
+
247
+ export interface AvailableSlotEntry {
248
+ startTime: string;
249
+ endTime: string;
250
+ available: boolean;
251
+ }
252
+
253
+ export interface AvailableSlotsResponse {
254
+ date: string;
255
+ slots: AvailableSlotEntry[];
256
+ }
257
+
258
+ /**
259
+ * Get dates with availability for a creator in a date range
260
+ */
261
+ export function useCreatorAvailableDates(
262
+ creatorId: string,
263
+ params: { from: string; to: string },
264
+ options?: Omit<UseQueryOptions<AvailableDatesResponse>, 'queryKey' | 'queryFn'>
265
+ ) {
266
+ return useQuery({
267
+ queryKey: creatorKeys.availableDates(creatorId, params.from, params.to),
268
+ queryFn: async (): Promise<AvailableDatesResponse> => {
269
+ const client = getApiClient();
270
+ const response = await client.get(`/api/v1/creators/${creatorId}/available-dates`, {
271
+ params,
272
+ });
273
+ return response.data;
274
+ },
275
+ enabled: !!creatorId && !!params.from && !!params.to,
276
+ ...options,
277
+ });
278
+ }
279
+
280
+ /**
281
+ * Get available time slots for a creator on a specific date
282
+ */
283
+ export function useCreatorAvailableSlots(
284
+ creatorId: string,
285
+ params: { date: string; durationMinutes?: number },
286
+ options?: Omit<UseQueryOptions<AvailableSlotsResponse>, 'queryKey' | 'queryFn'>
287
+ ) {
288
+ return useQuery({
289
+ queryKey: creatorKeys.availableSlots(creatorId, params.date, params.durationMinutes || 60),
290
+ queryFn: async (): Promise<AvailableSlotsResponse> => {
291
+ const client = getApiClient();
292
+ const response = await client.get(`/api/v1/creators/${creatorId}/available-slots`, {
293
+ params,
294
+ });
295
+ return response.data;
296
+ },
297
+ enabled: !!creatorId && !!params.date,
298
+ ...options,
299
+ });
300
+ }
301
+
232
302
  /**
233
303
  * Get a creator's published library content
234
304
  *
@@ -1,12 +1,16 @@
1
1
  import { useQuery, UseQueryOptions } from '@tanstack/react-query';
2
2
  import { getApiClient } from '../client';
3
+ import type { components } from '@growsober/types';
3
4
 
4
5
  // ============================================================================
5
- // TYPES
6
+ // TYPES — derived from auto-generated OpenAPI types
6
7
  // ============================================================================
7
8
 
8
- export type ProductType = 'SESSION_1ON1' | 'SESSION_GROUP' | 'PACKAGE' | 'WORKSHOP' | 'CONSULTATION';
9
- export type DeliveryMethod = 'VIDEO_CALL' | 'PHONE_CALL' | 'IN_PERSON' | 'HYBRID';
9
+ export type CreateProductDto = components['schemas']['CreateProductDto'];
10
+ export type UpdateProductDto = components['schemas']['UpdateProductDto'];
11
+
12
+ export type ProductType = CreateProductDto['type'];
13
+ export type DeliveryMethod = CreateProductDto['deliveryMethod'];
10
14
  export type BookingStatus = 'PENDING' | 'CONFIRMED' | 'CANCELLED' | 'COMPLETED';
11
15
  export type PaymentStatus = 'PENDING' | 'PAID' | 'REFUNDED' | 'FAILED';
12
16
 
@@ -17,6 +21,8 @@ export interface CreatorProductResponse {
17
21
  slug: string;
18
22
  description: string | null;
19
23
  imageUrl: string | null;
24
+ category: string | null;
25
+ tags: string[];
20
26
  type: ProductType;
21
27
  price: number;
22
28
  currency: string;
@@ -26,6 +32,8 @@ export interface CreatorProductResponse {
26
32
  locationDetails: string | null;
27
33
  isActive: boolean;
28
34
  isFeatured: boolean;
35
+ stripeProductId?: string | null;
36
+ stripePriceId?: string | null;
29
37
  createdAt: string;
30
38
  updatedAt: string;
31
39
  creator?: {
@@ -112,21 +120,6 @@ export const productKeys = {
112
120
  // QUERY HOOKS
113
121
  // ============================================================================
114
122
 
115
- /**
116
- * Get paginated list of all active products
117
- *
118
- * @param filters - Query parameters for filtering and pagination
119
- * @param options - TanStack Query options
120
- *
121
- * @example
122
- * ```tsx
123
- * const { data, isLoading } = useProducts({
124
- * page: 1,
125
- * limit: 20,
126
- * type: 'SESSION_1ON1',
127
- * });
128
- * ```
129
- */
130
123
  export function useProducts(
131
124
  filters?: ProductFilters,
132
125
  options?: Omit<UseQueryOptions<PaginatedProductsResponse>, 'queryKey' | 'queryFn'>
@@ -144,17 +137,6 @@ export function useProducts(
144
137
  });
145
138
  }
146
139
 
147
- /**
148
- * Get a single product by ID
149
- *
150
- * @param id - Product ID
151
- * @param options - TanStack Query options
152
- *
153
- * @example
154
- * ```tsx
155
- * const { data, isLoading } = useProduct('product-123');
156
- * ```
157
- */
158
140
  export function useProduct(
159
141
  id: string,
160
142
  options?: Omit<UseQueryOptions<CreatorProductResponse>, 'queryKey' | 'queryFn'>
@@ -171,17 +153,6 @@ export function useProduct(
171
153
  });
172
154
  }
173
155
 
174
- /**
175
- * Get a product by its slug
176
- *
177
- * @param slug - Product slug
178
- * @param options - TanStack Query options
179
- *
180
- * @example
181
- * ```tsx
182
- * const { data, isLoading } = useProductBySlug('1-on-1-coaching-abc123');
183
- * ```
184
- */
185
156
  export function useProductBySlug(
186
157
  slug: string,
187
158
  options?: Omit<UseQueryOptions<CreatorProductResponse>, 'queryKey' | 'queryFn'>
@@ -198,21 +169,6 @@ export function useProductBySlug(
198
169
  });
199
170
  }
200
171
 
201
- /**
202
- * Get products for a specific creator
203
- *
204
- * @param creatorId - Creator ID
205
- * @param filters - Query parameters for filtering
206
- * @param options - TanStack Query options
207
- *
208
- * @example
209
- * ```tsx
210
- * const { data, isLoading } = useCreatorProducts('creator-123', {
211
- * type: 'SESSION_1ON1',
212
- * isActive: true,
213
- * });
214
- * ```
215
- */
216
172
  export function useCreatorProducts(
217
173
  creatorId: string,
218
174
  filters?: ProductFilters,
@@ -232,16 +188,6 @@ export function useCreatorProducts(
232
188
  });
233
189
  }
234
190
 
235
- /**
236
- * Get current user's product bookings
237
- *
238
- * @param options - TanStack Query options
239
- *
240
- * @example
241
- * ```tsx
242
- * const { data, isLoading } = useMyProductBookings();
243
- * ```
244
- */
245
191
  export function useMyProductBookings(
246
192
  options?: Omit<UseQueryOptions<ProductBookingResponse[]>, 'queryKey' | 'queryFn'>
247
193
  ) {
@@ -256,17 +202,6 @@ export function useMyProductBookings(
256
202
  });
257
203
  }
258
204
 
259
- /**
260
- * Get a single product booking by ID
261
- *
262
- * @param bookingId - Booking ID
263
- * @param options - TanStack Query options
264
- *
265
- * @example
266
- * ```tsx
267
- * const { data, isLoading } = useProductBooking('booking-123');
268
- * ```
269
- */
270
205
  export function useProductBooking(
271
206
  bookingId: string,
272
207
  options?: Omit<UseQueryOptions<ProductBookingResponse>, 'queryKey' | 'queryFn'>
@@ -283,18 +218,6 @@ export function useProductBooking(
283
218
  });
284
219
  }
285
220
 
286
- /**
287
- * Get bookings for a creator's products (creator dashboard)
288
- *
289
- * @param creatorId - Creator ID
290
- * @param options - TanStack Query options
291
- *
292
- * @example
293
- * ```tsx
294
- * // For creator dashboard - see all bookings for their products
295
- * const { data, isLoading } = useCreatorBookings('creator-123');
296
- * ```
297
- */
298
221
  export function useCreatorBookings(
299
222
  creatorId: string,
300
223
  options?: Omit<UseQueryOptions<ProductBookingResponse[]>, 'queryKey' | 'queryFn'>