@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.
Files changed (70) hide show
  1. package/dist/__tests__/e2e.test.d.ts +30 -0
  2. package/dist/__tests__/e2e.test.js +959 -63
  3. package/dist/api/mutations/badges.d.ts +116 -0
  4. package/dist/api/mutations/badges.js +177 -0
  5. package/dist/api/mutations/brands.d.ts +251 -0
  6. package/dist/api/mutations/brands.js +242 -0
  7. package/dist/api/mutations/creators.d.ts +131 -0
  8. package/dist/api/mutations/creators.js +129 -0
  9. package/dist/api/mutations/event-chat.d.ts +2 -2
  10. package/dist/api/mutations/event-chat.js +9 -9
  11. package/dist/api/mutations/index.d.ts +4 -0
  12. package/dist/api/mutations/index.js +5 -1
  13. package/dist/api/mutations/jack.d.ts +29 -0
  14. package/dist/api/mutations/jack.js +41 -1
  15. package/dist/api/mutations/products.d.ts +175 -0
  16. package/dist/api/mutations/products.js +226 -0
  17. package/dist/api/mutations/support.d.ts +20 -1
  18. package/dist/api/mutations/support.js +36 -1
  19. package/dist/api/queries/badges.d.ts +221 -0
  20. package/dist/api/queries/badges.js +290 -0
  21. package/dist/api/queries/bookings.d.ts +1 -1
  22. package/dist/api/queries/brands.d.ts +248 -0
  23. package/dist/api/queries/brands.js +226 -0
  24. package/dist/api/queries/businesses.d.ts +61 -1
  25. package/dist/api/queries/businesses.js +27 -1
  26. package/dist/api/queries/creators.d.ts +332 -0
  27. package/dist/api/queries/creators.js +249 -0
  28. package/dist/api/queries/event-chat.d.ts +1 -1
  29. package/dist/api/queries/event-chat.js +4 -4
  30. package/dist/api/queries/events.d.ts +45 -0
  31. package/dist/api/queries/index.d.ts +5 -0
  32. package/dist/api/queries/index.js +6 -1
  33. package/dist/api/queries/jack.d.ts +80 -0
  34. package/dist/api/queries/jack.js +98 -1
  35. package/dist/api/queries/library.d.ts +8 -0
  36. package/dist/api/queries/products.d.ts +185 -0
  37. package/dist/api/queries/products.js +203 -0
  38. package/dist/api/queries/support.d.ts +46 -1
  39. package/dist/api/queries/support.js +48 -1
  40. package/dist/api/queries/venues.d.ts +304 -0
  41. package/dist/api/queries/venues.js +211 -0
  42. package/dist/api/types.d.ts +245 -0
  43. package/dist/api/types.js +6 -1
  44. package/dist/api/utils/eventGrouping.d.ts +104 -0
  45. package/dist/api/utils/eventGrouping.js +155 -0
  46. package/dist/index.d.ts +1 -0
  47. package/dist/index.js +5 -1
  48. package/package.json +5 -2
  49. package/src/__tests__/e2e.test.ts +996 -64
  50. package/src/api/mutations/badges.ts +228 -0
  51. package/src/api/mutations/brands.ts +376 -0
  52. package/src/api/mutations/creators.ts +171 -0
  53. package/src/api/mutations/event-chat.ts +8 -8
  54. package/src/api/mutations/index.ts +4 -0
  55. package/src/api/mutations/jack.ts +50 -1
  56. package/src/api/mutations/products.ts +336 -0
  57. package/src/api/mutations/support.ts +44 -0
  58. package/src/api/queries/badges.ts +385 -0
  59. package/src/api/queries/brands.ts +281 -0
  60. package/src/api/queries/businesses.ts +30 -1
  61. package/src/api/queries/creators.ts +308 -0
  62. package/src/api/queries/event-chat.ts +3 -3
  63. package/src/api/queries/index.ts +5 -0
  64. package/src/api/queries/jack.ts +139 -1
  65. package/src/api/queries/products.ts +312 -0
  66. package/src/api/queries/support.ts +54 -0
  67. package/src/api/queries/venues.ts +271 -0
  68. package/src/api/types.ts +317 -1
  69. package/src/api/utils/eventGrouping.ts +181 -0
  70. package/src/index.ts +6 -0
package/src/api/types.ts CHANGED
@@ -3,6 +3,11 @@
3
3
  *
4
4
  * All types are derived from the @growsober/types package which is auto-generated
5
5
  * from the API OpenAPI specification. This ensures single source of truth from Prisma.
6
+ *
7
+ * To regenerate types:
8
+ * 1. Start the API: cd ../growsober-api && npm run start:dev
9
+ * 2. Generate types: cd ../growsober-types && npm run generate && npm run build
10
+ * 3. Rebuild SDK: npm run build
6
11
  */
7
12
 
8
13
  import type { paths, components } from '@growsober/types';
@@ -52,6 +57,40 @@ export type PathParams<
52
57
  ? P
53
58
  : Record<string, never>;
54
59
 
60
+ // ============================================================================
61
+ // ENUM TYPES (extracted from generated schemas - single source of truth)
62
+ // ============================================================================
63
+
64
+ // Business/Venue type (used for both Business and Venue models)
65
+ export type BusinessType = components['schemas']['BusinessResponseDto']['type'];
66
+
67
+ // Ownership roles
68
+ export type VenueOwnerRole = components['schemas']['VenueOwnerResponseDto']['role'];
69
+ export type BrandOwnerRole = components['schemas']['BrandOwnerResponseDto']['role'];
70
+
71
+ // Event types
72
+ export type GatheringType = NonNullable<components['schemas']['EventResponseDto']['gatheringType']>;
73
+ export type EventVisibility = components['schemas']['EventResponseDto']['visibility'];
74
+ export type EventStatus = components['schemas']['EventResponseDto']['status'];
75
+
76
+ // Chat roles
77
+ export type ChatMemberRole = components['schemas']['ChatMemberResponseDto']['role'];
78
+
79
+ // Content status
80
+ export type ContentStatus = components['schemas']['LibraryContentResponseDto']['contentStatus'];
81
+
82
+ // Badge types
83
+ export type BadgeType = components['schemas']['BadgeResponseDto']['type'];
84
+
85
+ // Notification types
86
+ export type NotificationType = components['schemas']['NotificationResponseDto']['type'];
87
+
88
+ // Streak types
89
+ export type StreakType = components['schemas']['StreakResponseDto']['type'];
90
+
91
+ // Craving triggers
92
+ export type CravingTrigger = NonNullable<components['schemas']['CravingLogResponseDto']['triggerType']>;
93
+
55
94
  // ============================================================================
56
95
  // AUTH TYPES
57
96
  // ============================================================================
@@ -105,15 +144,120 @@ export type CreateBookingRequest = components['schemas']['CreateBookingDto'];
105
144
  export type LibraryContentResponse = components['schemas']['LibraryContentResponseDto'];
106
145
  export type LibraryContentDetailResponse = components['schemas']['LibraryContentDetailResponseDto'];
107
146
  export type LibraryProgressResponse = components['schemas']['LibraryProgressResponseDto'];
147
+ export type ContentType = components['schemas']['LibraryContentResponseDto']['type'];
108
148
 
109
149
  // ============================================================================
110
- // BUSINESS & OFFER TYPES
150
+ // BUSINESS & OFFER TYPES (Legacy)
111
151
  // ============================================================================
112
152
 
113
153
  export type BusinessResponse = components['schemas']['BusinessResponseDto'];
114
154
  export type OfferResponse = components['schemas']['OfferResponseDto'];
115
155
  export type RedeemOfferRequest = components['schemas']['RedeemOfferDto'];
116
156
 
157
+ // ============================================================================
158
+ // VENUE TYPES (from generated OpenAPI types)
159
+ // ============================================================================
160
+
161
+ export type VenueResponse = components['schemas']['VenueResponseDto'];
162
+ export type VenueOwnerResponse = components['schemas']['VenueOwnerResponseDto'];
163
+
164
+ // Request types for venue operations
165
+ export interface CreateVenueRequest {
166
+ name: string;
167
+ slug: string;
168
+ description?: string;
169
+ type: BusinessType;
170
+ hasAfDrinks?: boolean;
171
+ isAfVenue?: boolean;
172
+ afHighlights?: string[];
173
+ address?: string;
174
+ cityId?: string;
175
+ locationLat?: number;
176
+ locationLong?: number;
177
+ phone?: string;
178
+ email?: string;
179
+ website?: string;
180
+ instagram?: string;
181
+ profileImage?: string;
182
+ bannerImage?: string;
183
+ photos?: string[];
184
+ openingHours?: Record<string, string>;
185
+ }
186
+
187
+ export interface UpdateVenueRequest extends Partial<CreateVenueRequest> {}
188
+
189
+ export interface AddVenueOwnerRequest {
190
+ userId: string;
191
+ role: VenueOwnerRole;
192
+ }
193
+
194
+ // ============================================================================
195
+ // CREATOR TYPES (from generated OpenAPI types)
196
+ // ============================================================================
197
+
198
+ export type CreatorResponse = components['schemas']['CreatorResponseDto'];
199
+ export type CreatorAvailabilityResponse = components['schemas']['CreatorAvailabilityResponseDto'];
200
+
201
+ export interface CreateCreatorRequest {
202
+ slug: string;
203
+ displayName: string;
204
+ bio?: string;
205
+ avatarUrl?: string;
206
+ cityIds?: string[];
207
+ canFacilitate?: boolean;
208
+ canCreateContent?: boolean;
209
+ isInfluencer?: boolean;
210
+ specialties?: string[];
211
+ certifications?: string[];
212
+ sessionRate?: number;
213
+ }
214
+
215
+ export interface UpdateCreatorRequest extends Partial<CreateCreatorRequest> {}
216
+
217
+ export interface CreateAvailabilityRequest {
218
+ dayOfWeek?: number;
219
+ startTime: string;
220
+ endTime: string;
221
+ timezone: string;
222
+ isRecurring?: boolean;
223
+ specificDate?: string;
224
+ }
225
+
226
+ // ============================================================================
227
+ // BRAND TYPES (from generated OpenAPI types)
228
+ // ============================================================================
229
+
230
+ export type BrandResponse = components['schemas']['BrandResponseDto'];
231
+ export type BrandOwnerResponse = components['schemas']['BrandOwnerResponseDto'];
232
+ export type BrandCreatorResponse = components['schemas']['BrandCreatorResponseDto'];
233
+
234
+ export interface CreateBrandRequest {
235
+ slug: string;
236
+ name: string;
237
+ description?: string;
238
+ logoUrl?: string;
239
+ bannerUrl?: string;
240
+ primaryColor?: string;
241
+ website?: string;
242
+ email?: string;
243
+ instagram?: string;
244
+ }
245
+
246
+ export interface UpdateBrandRequest extends Partial<CreateBrandRequest> {}
247
+
248
+ export interface AddBrandOwnerRequest {
249
+ userId: string;
250
+ role: BrandOwnerRole;
251
+ }
252
+
253
+ export interface AddBrandCreatorRequest {
254
+ creatorId: string;
255
+ commissionRate?: number;
256
+ isActive?: boolean;
257
+ startDate?: string;
258
+ endDate?: string;
259
+ }
260
+
117
261
  // ============================================================================
118
262
  // SUBSCRIPTION TYPES
119
263
  // ============================================================================
@@ -172,6 +316,11 @@ export type ReflectionResponse = components['schemas']['ReflectionResponseDto'];
172
316
  export type CreateReflectionRequest = components['schemas']['CreateReflectionDto'];
173
317
  export type UpdateReflectionRequest = components['schemas']['UpdateReflectionDto'];
174
318
 
319
+ // Cravings
320
+ export type CravingLogResponse = components['schemas']['CravingLogResponseDto'];
321
+ export type LogCravingRequest = components['schemas']['LogCravingDto'];
322
+ export type CravingStatsResponse = components['schemas']['CravingStatsDto'];
323
+
175
324
  // ============================================================================
176
325
  // MAP TYPES
177
326
  // ============================================================================
@@ -236,6 +385,173 @@ export type AdminCreateContentRequest = components['schemas']['AdminCreateConten
236
385
  export type AdminCreateBusinessRequest = components['schemas']['AdminCreateBusinessDto'];
237
386
  export type AdminOverviewStatsResponse = components['schemas']['AdminOverviewStatsDto'];
238
387
 
388
+ // ============================================================================
389
+ // BADGE TYPES (from generated OpenAPI types)
390
+ // ============================================================================
391
+
392
+ export type BadgeResponse = components['schemas']['BadgeResponseDto'];
393
+ export type UserBadgeResponse = components['schemas']['UserBadgeResponseDto'];
394
+ export type BadgeProgressResponse = components['schemas']['BadgeProgressDto'];
395
+
396
+ // Alias for SDK consistency
397
+ export interface BadgeWithProgress {
398
+ badge: BadgeResponse;
399
+ currentProgress: number;
400
+ requiredProgress: number;
401
+ percentComplete: number;
402
+ isEarned: boolean;
403
+ }
404
+
405
+ // ============================================================================
406
+ // UNIFIED REWARD TYPES
407
+ // ============================================================================
408
+
409
+ // RedeemType enum - extracted from Prisma via API
410
+ export type RedeemType = 'IN_PERSON' | 'ONLINE' | 'BOTH';
411
+
412
+ // Reward response with relations
413
+ export interface RewardResponse {
414
+ id: string;
415
+ venueId: string | null;
416
+ brandId: string | null;
417
+ badgeId: string;
418
+ title: string;
419
+ description: string | null;
420
+ code: string | null;
421
+ redeemType: RedeemType;
422
+ maxRedemptions: number | null;
423
+ redemptionsUsed: number;
424
+ perUserLimit: number;
425
+ validFrom: string | null;
426
+ validUntil: string | null;
427
+ isActive: boolean;
428
+ createdAt: string;
429
+ badge: {
430
+ id: string;
431
+ name: string;
432
+ slug: string;
433
+ icon: string | null;
434
+ };
435
+ venue?: {
436
+ id: string;
437
+ name: string;
438
+ slug: string;
439
+ profileImage: string | null;
440
+ address: string | null;
441
+ } | null;
442
+ brand?: {
443
+ id: string;
444
+ name: string;
445
+ slug: string;
446
+ logoUrl: string | null;
447
+ } | null;
448
+ }
449
+
450
+ export interface RewardRedemptionResponse {
451
+ id: string;
452
+ userId: string;
453
+ rewardId: string;
454
+ redeemedAt: string;
455
+ verifiedAt: string | null;
456
+ verifiedBy: string | null;
457
+ codeUsed: string | null;
458
+ reward: RewardResponse;
459
+ }
460
+
461
+ export interface CreateRewardRequest {
462
+ badgeId: string;
463
+ title: string;
464
+ description?: string;
465
+ code?: string;
466
+ redeemType?: RedeemType;
467
+ maxRedemptions?: number;
468
+ perUserLimit?: number;
469
+ validFrom?: string;
470
+ validUntil?: string;
471
+ }
472
+
473
+ export interface UpdateRewardRequest {
474
+ title?: string;
475
+ description?: string;
476
+ code?: string;
477
+ redeemType?: RedeemType;
478
+ maxRedemptions?: number;
479
+ perUserLimit?: number;
480
+ validFrom?: string;
481
+ validUntil?: string;
482
+ isActive?: boolean;
483
+ }
484
+
485
+ export interface UserWalletResponse {
486
+ badges: Array<{
487
+ id: string;
488
+ badgeId: string;
489
+ userId: string;
490
+ awardedAt: string;
491
+ badge: BadgeResponse;
492
+ availableRewards: RewardResponse[];
493
+ redeemedRewards: Array<RewardRedemptionResponse & { qrToken: string }>;
494
+ }>;
495
+ stats: {
496
+ totalBadges: number;
497
+ totalAvailableRewards: number;
498
+ totalRedeemedRewards: number;
499
+ };
500
+ }
501
+
502
+ // ============================================================================
503
+ // LEGACY TYPES (deprecated - use unified types)
504
+ // ============================================================================
505
+
506
+ /** @deprecated Use RewardResponse instead */
507
+ export interface PartnerRewardResponse {
508
+ id: string;
509
+ businessId: string;
510
+ badgeId: string;
511
+ title: string;
512
+ description: string | null;
513
+ code: string | null;
514
+ maxRedemptions: number | null;
515
+ redemptionsUsed: number;
516
+ perUserLimit: number;
517
+ validFrom: string;
518
+ validUntil: string | null;
519
+ isActive: boolean;
520
+ createdAt: string;
521
+ badge: {
522
+ id: string;
523
+ name: string;
524
+ slug: string;
525
+ icon: string | null;
526
+ };
527
+ business: {
528
+ id: string;
529
+ name: string;
530
+ profileImage: string | null;
531
+ };
532
+ }
533
+
534
+ /** @deprecated Use RewardRedemptionResponse instead */
535
+ export interface PartnerRewardRedemptionResponse {
536
+ id: string;
537
+ userId: string;
538
+ partnerRewardId: string;
539
+ redeemedAt: string;
540
+ verifiedAt: string | null;
541
+ partnerReward: PartnerRewardResponse;
542
+ }
543
+
544
+ /** @deprecated Use CreateRewardRequest instead */
545
+ export interface CreatePartnerRewardRequest {
546
+ badgeId: string;
547
+ title: string;
548
+ description?: string;
549
+ code?: string;
550
+ maxRedemptions?: number;
551
+ perUserLimit?: number;
552
+ validUntil?: string;
553
+ }
554
+
239
555
  // ============================================================================
240
556
  // RE-EXPORTS
241
557
  // ============================================================================
@@ -0,0 +1,181 @@
1
+ /**
2
+ * Event Grouping Utilities
3
+ *
4
+ * Utilities for organizing events by time of day.
5
+ * Used in the Gatherings screen to show events grouped by
6
+ * Morning, Afternoon, and Evening.
7
+ *
8
+ * @module api/utils/eventGrouping
9
+ */
10
+
11
+ import { EventResponse } from '../types';
12
+
13
+ // ============================================================================
14
+ // TYPES
15
+ // ============================================================================
16
+
17
+ export type TimeOfDay = 'MORNING' | 'AFTERNOON' | 'EVENING';
18
+
19
+ export interface GroupedEvents {
20
+ morning: EventResponse[];
21
+ afternoon: EventResponse[];
22
+ evening: EventResponse[];
23
+ }
24
+
25
+ export interface TimeOfDayInfo {
26
+ key: TimeOfDay;
27
+ label: string;
28
+ emoji: string;
29
+ hours: { start: number; end: number };
30
+ }
31
+
32
+ // ============================================================================
33
+ // CONSTANTS
34
+ // ============================================================================
35
+
36
+ export const TIME_OF_DAY_CONFIG: Record<TimeOfDay, TimeOfDayInfo> = {
37
+ MORNING: {
38
+ key: 'MORNING',
39
+ label: 'Morning',
40
+ emoji: '',
41
+ hours: { start: 5, end: 11 }, // 5:00 AM - 11:59 AM
42
+ },
43
+ AFTERNOON: {
44
+ key: 'AFTERNOON',
45
+ label: 'Afternoon',
46
+ emoji: '',
47
+ hours: { start: 12, end: 16 }, // 12:00 PM - 4:59 PM
48
+ },
49
+ EVENING: {
50
+ key: 'EVENING',
51
+ label: 'Evening',
52
+ emoji: '',
53
+ hours: { start: 17, end: 4 }, // 5:00 PM - 4:59 AM (next day)
54
+ },
55
+ };
56
+
57
+ // ============================================================================
58
+ // FUNCTIONS
59
+ // ============================================================================
60
+
61
+ /**
62
+ * Get time of day for a given date
63
+ *
64
+ * @param date - Date string or Date object
65
+ * @returns TimeOfDay - MORNING, AFTERNOON, or EVENING
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * const timeOfDay = getTimeOfDay('2024-03-15T10:00:00Z');
70
+ * console.log(timeOfDay); // 'MORNING'
71
+ * ```
72
+ */
73
+ export function getTimeOfDay(date: Date | string): TimeOfDay {
74
+ const d = typeof date === 'string' ? new Date(date) : date;
75
+ const hour = d.getHours();
76
+
77
+ if (hour >= 5 && hour < 12) return 'MORNING';
78
+ if (hour >= 12 && hour < 17) return 'AFTERNOON';
79
+ return 'EVENING';
80
+ }
81
+
82
+ /**
83
+ * Get label for time of day
84
+ *
85
+ * @param timeOfDay - TimeOfDay enum value
86
+ * @returns Human-readable label
87
+ *
88
+ * @example
89
+ * ```tsx
90
+ * const label = getTimeOfDayLabel('MORNING');
91
+ * console.log(label); // 'Morning'
92
+ * ```
93
+ */
94
+ export function getTimeOfDayLabel(timeOfDay: TimeOfDay): string {
95
+ return TIME_OF_DAY_CONFIG[timeOfDay].label;
96
+ }
97
+
98
+ /**
99
+ * Group events by time of day
100
+ *
101
+ * @param events - Array of events to group
102
+ * @returns GroupedEvents object with morning, afternoon, and evening arrays
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * import { useUpcomingEvents, groupEventsByTimeOfDay } from '@growsober/sdk';
107
+ *
108
+ * function GatheringsList() {
109
+ * const { data: events } = useUpcomingEvents(30);
110
+ * const grouped = useMemo(() => {
111
+ * if (!events) return null;
112
+ * return groupEventsByTimeOfDay(events);
113
+ * }, [events]);
114
+ *
115
+ * return (
116
+ * <SectionList
117
+ * sections={[
118
+ * { title: 'Morning', data: grouped?.morning || [] },
119
+ * { title: 'Afternoon', data: grouped?.afternoon || [] },
120
+ * { title: 'Evening', data: grouped?.evening || [] },
121
+ * ]}
122
+ * ...
123
+ * />
124
+ * );
125
+ * }
126
+ * ```
127
+ */
128
+ export function groupEventsByTimeOfDay(events: EventResponse[]): GroupedEvents {
129
+ const grouped: GroupedEvents = {
130
+ morning: [],
131
+ afternoon: [],
132
+ evening: [],
133
+ };
134
+
135
+ for (const event of events) {
136
+ const timeOfDay = getTimeOfDay(event.startDate);
137
+ switch (timeOfDay) {
138
+ case 'MORNING':
139
+ grouped.morning.push(event);
140
+ break;
141
+ case 'AFTERNOON':
142
+ grouped.afternoon.push(event);
143
+ break;
144
+ case 'EVENING':
145
+ grouped.evening.push(event);
146
+ break;
147
+ }
148
+ }
149
+
150
+ return grouped;
151
+ }
152
+
153
+ /**
154
+ * Convert grouped events to section list data format
155
+ *
156
+ * @param events - Array of events to group
157
+ * @returns Array of sections with title and data
158
+ *
159
+ * @example
160
+ * ```tsx
161
+ * const sections = getEventSections(events);
162
+ * // [
163
+ * // { title: 'Morning', data: [...] },
164
+ * // { title: 'Afternoon', data: [...] },
165
+ * // { title: 'Evening', data: [...] },
166
+ * // ]
167
+ * ```
168
+ */
169
+ export function getEventSections(events: EventResponse[]): Array<{
170
+ title: string;
171
+ timeOfDay: TimeOfDay;
172
+ data: EventResponse[];
173
+ }> {
174
+ const grouped = groupEventsByTimeOfDay(events);
175
+
176
+ return [
177
+ { title: 'Morning', timeOfDay: 'MORNING' as TimeOfDay, data: grouped.morning },
178
+ { title: 'Afternoon', timeOfDay: 'AFTERNOON' as TimeOfDay, data: grouped.afternoon },
179
+ { title: 'Evening', timeOfDay: 'EVENING' as TimeOfDay, data: grouped.evening },
180
+ ].filter(section => section.data.length > 0);
181
+ }
package/src/index.ts CHANGED
@@ -55,3 +55,9 @@ export * from './api/queries';
55
55
 
56
56
  export * from './api/mutations';
57
57
 
58
+ // ============================================================================
59
+ // UTILITIES
60
+ // ============================================================================
61
+
62
+ export * from './api/utils/eventGrouping';
63
+