@getmicdrop/venue-calendar 3.3.0 → 3.3.1

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 (39) hide show
  1. package/README.md +661 -661
  2. package/dist/{VenueCalendar-BMSfRl2d.js → VenueCalendar-Xppig0q_.js} +13 -10
  3. package/dist/VenueCalendar-Xppig0q_.js.map +1 -0
  4. package/dist/{index-CoJaem3n.js → index-BjErG0CG.js} +2 -2
  5. package/dist/{index-CoJaem3n.js.map → index-BjErG0CG.js.map} +1 -1
  6. package/dist/types/index.d.ts +395 -395
  7. package/dist/venue-calendar.css +1 -1
  8. package/dist/venue-calendar.es.js +1 -1
  9. package/dist/venue-calendar.iife.js +4 -4
  10. package/dist/venue-calendar.iife.js.map +1 -1
  11. package/dist/venue-calendar.umd.js +4 -4
  12. package/dist/venue-calendar.umd.js.map +1 -1
  13. package/package.json +2 -1
  14. package/src/lib/api/client.ts +210 -210
  15. package/src/lib/api/events.ts +358 -358
  16. package/src/lib/api/index.ts +182 -182
  17. package/src/lib/api/orders.ts +390 -390
  18. package/src/lib/api/promo.ts +164 -164
  19. package/src/lib/api/transformers/event.ts +248 -248
  20. package/src/lib/api/transformers/index.ts +29 -29
  21. package/src/lib/api/transformers/order.ts +207 -207
  22. package/src/lib/api/transformers/venue.ts +118 -118
  23. package/src/lib/api/types.ts +289 -289
  24. package/src/lib/api/venues.ts +100 -100
  25. package/src/lib/theme.js +209 -209
  26. package/src/lib/utils/api.js +790 -0
  27. package/src/lib/utils/api.test.js +1284 -0
  28. package/src/lib/utils/constants.js +8 -0
  29. package/src/lib/utils/constants.test.js +39 -0
  30. package/src/lib/utils/datetime.js +266 -0
  31. package/src/lib/utils/datetime.test.js +340 -0
  32. package/src/lib/utils/event-transform.js +464 -0
  33. package/src/lib/utils/event-transform.test.js +413 -0
  34. package/src/lib/utils/logger.js +105 -0
  35. package/src/lib/utils/timezone.js +109 -0
  36. package/src/lib/utils/timezone.test.js +222 -0
  37. package/src/lib/utils/utils.js +806 -0
  38. package/src/lib/utils/utils.test.js +959 -0
  39. package/dist/VenueCalendar-BMSfRl2d.js.map +0 -1
@@ -1,248 +1,248 @@
1
- /**
2
- * Event Transformer
3
- *
4
- * Normalizes API event responses to a consistent format.
5
- * Handles image URL resolution and CTA state calculation.
6
- */
7
-
8
- import type { Event, AvailableTicket } from '../types.js';
9
-
10
- // CDN base URL for images
11
- const CDN_BASE_URL = 'https://micdrop-images.sfo3.digitaloceanspaces.com';
12
-
13
- /**
14
- * Raw API event response (may have varying field names)
15
- */
16
- interface ApiEvent {
17
- eventID?: number;
18
- id?: number;
19
- ID?: number;
20
- name?: string;
21
- title?: string;
22
- slug?: string;
23
- description?: string;
24
- date?: string;
25
- startDateTime?: string;
26
- start_date_time?: string;
27
- endDateTime?: string;
28
- end_date_time?: string;
29
- doorsOpenTime?: string;
30
- doors_open_time?: string;
31
- timezone?: string;
32
- time_zone?: string;
33
- venueId?: number;
34
- venue_id?: number;
35
- venueName?: string;
36
- venue_name?: string;
37
- venueAddress?: string;
38
- venue_address?: string;
39
- location?: string;
40
- imageUrl?: string;
41
- imageURL?: string;
42
- image_url?: string;
43
- image?: string;
44
- status?: string;
45
- isPublished?: boolean;
46
- is_published?: boolean;
47
- isCancelled?: boolean;
48
- is_cancelled?: boolean;
49
- availableTickets?: any[];
50
- available_tickets?: any[];
51
- tickets?: any[];
52
- ticketsAvailable?: number;
53
- tickets_available?: number;
54
- ticketsSold?: number;
55
- tickets_sold?: number;
56
- minPrice?: number;
57
- min_price?: number;
58
- maxPrice?: number;
59
- max_price?: number;
60
- ctaText?: string;
61
- cta_text?: string;
62
- ctaState?: string;
63
- cta_state?: string;
64
- showPerformers?: boolean;
65
- show_performers?: boolean;
66
- eventSeriesId?: number;
67
- event_series_id?: number;
68
- seriesInstanceNumber?: number;
69
- series_instance_number?: number;
70
- }
71
-
72
- /**
73
- * Get CDN image URL
74
- *
75
- * Prepends the CDN base URL if the path is relative.
76
- */
77
- export function getCDNImageUrl(path: string | undefined): string {
78
- if (!path) return '';
79
- if (path.startsWith('http')) return path;
80
- return `${CDN_BASE_URL}/${path.replace(/^\//, '')}`;
81
- }
82
-
83
- /**
84
- * Extract image URL from event with fallbacks
85
- */
86
- export function getEventImageUrl(apiEvent: ApiEvent): string {
87
- const rawUrl =
88
- apiEvent.imageUrl ||
89
- apiEvent.imageURL ||
90
- apiEvent.image_url ||
91
- apiEvent.image ||
92
- '';
93
-
94
- return getCDNImageUrl(rawUrl);
95
- }
96
-
97
- /**
98
- * Calculate CTA state based on ticket availability
99
- */
100
- export function calculateCtaState(
101
- apiEvent: ApiEvent
102
- ): 'available' | 'sold_out' | 'coming_soon' | 'ended' {
103
- // Check explicit CTA state first
104
- const explicitState = apiEvent.ctaState || apiEvent.cta_state;
105
- if (explicitState) {
106
- return explicitState as any;
107
- }
108
-
109
- // Check if event is cancelled or ended
110
- if (apiEvent.isCancelled || apiEvent.is_cancelled) {
111
- return 'ended';
112
- }
113
-
114
- // Check event date
115
- const eventDate = apiEvent.startDateTime || apiEvent.start_date_time || apiEvent.date;
116
- if (eventDate) {
117
- const eventTime = new Date(eventDate).getTime();
118
- const now = Date.now();
119
-
120
- if (eventTime < now) {
121
- return 'ended';
122
- }
123
- }
124
-
125
- // Check ticket availability
126
- const availableCount =
127
- apiEvent.ticketsAvailable ?? apiEvent.tickets_available;
128
-
129
- if (availableCount !== undefined) {
130
- if (availableCount <= 0) {
131
- return 'sold_out';
132
- }
133
- return 'available';
134
- }
135
-
136
- // Check tickets array
137
- const tickets =
138
- apiEvent.availableTickets ||
139
- apiEvent.available_tickets ||
140
- apiEvent.tickets ||
141
- [];
142
-
143
- if (tickets.length === 0) {
144
- return 'coming_soon';
145
- }
146
-
147
- const totalAvailable = tickets.reduce((sum: number, t: any) => {
148
- const qty =
149
- t.quantityAvailable ?? t.quantity_available ?? t.quantity ?? 0;
150
- const sold = t.quantitySold ?? t.quantity_sold ?? 0;
151
- return sum + Math.max(0, qty - sold);
152
- }, 0);
153
-
154
- if (totalAvailable <= 0) {
155
- return 'sold_out';
156
- }
157
-
158
- return 'available';
159
- }
160
-
161
- /**
162
- * Transform a raw API ticket to normalized AvailableTicket
163
- */
164
- export function transformTicket(apiTicket: any): AvailableTicket {
165
- return {
166
- id: apiTicket.id || apiTicket.ID,
167
- name: apiTicket.name || apiTicket.ticketName || '',
168
- description: apiTicket.description,
169
- price: apiTicket.price || 0,
170
- quantity: apiTicket.quantity || apiTicket.totalQuantity || 0,
171
- quantitySold: apiTicket.quantitySold || apiTicket.quantity_sold || 0,
172
- quantityAvailable:
173
- apiTicket.quantityAvailable ||
174
- apiTicket.quantity_available ||
175
- (apiTicket.quantity || 0) - (apiTicket.quantitySold || 0),
176
- minPerOrder: apiTicket.minPerOrder || apiTicket.min_per_order || 1,
177
- maxPerOrder: apiTicket.maxPerOrder || apiTicket.max_per_order || 10,
178
- saleStartDate: apiTicket.saleStartDate || apiTicket.sale_start_date,
179
- saleEndDate: apiTicket.saleEndDate || apiTicket.sale_end_date,
180
- isHidden: apiTicket.isHidden || apiTicket.is_hidden || false,
181
- revealWithPromoCode:
182
- apiTicket.revealWithPromoCode || apiTicket.reveal_with_promo_code,
183
- ticketType: apiTicket.ticketType || apiTicket.ticket_type || 0,
184
- sectionId: apiTicket.sectionId || apiTicket.section_id,
185
- sortOrder: apiTicket.sortOrder || apiTicket.sort_order || 0,
186
- };
187
- }
188
-
189
- /**
190
- * Transform a raw API event to normalized Event
191
- */
192
- export function transformEvent(apiEvent: ApiEvent): Event {
193
- // Extract tickets array from various possible field names
194
- const rawTickets =
195
- apiEvent.availableTickets ||
196
- apiEvent.available_tickets ||
197
- apiEvent.tickets ||
198
- [];
199
-
200
- const tickets = rawTickets.map(transformTicket);
201
-
202
- // Calculate min/max prices from tickets
203
- const prices = tickets.map((t) => t.price).filter((p) => p > 0);
204
- const minPrice = prices.length > 0 ? Math.min(...prices) : undefined;
205
- const maxPrice = prices.length > 0 ? Math.max(...prices) : undefined;
206
-
207
- return {
208
- eventID: apiEvent.eventID || apiEvent.id || apiEvent.ID || 0,
209
- id: apiEvent.id || apiEvent.ID,
210
- name: apiEvent.name || apiEvent.title || '',
211
- title: apiEvent.title || apiEvent.name,
212
- slug: apiEvent.slug,
213
- description: apiEvent.description,
214
- date: apiEvent.date || apiEvent.startDateTime || apiEvent.start_date_time || '',
215
- startDateTime: apiEvent.startDateTime || apiEvent.start_date_time,
216
- endDateTime: apiEvent.endDateTime || apiEvent.end_date_time,
217
- doorsOpenTime: apiEvent.doorsOpenTime || apiEvent.doors_open_time,
218
- timezone: apiEvent.timezone || apiEvent.time_zone,
219
- venueId: apiEvent.venueId || apiEvent.venue_id,
220
- venueName: apiEvent.venueName || apiEvent.venue_name,
221
- venueAddress: apiEvent.venueAddress || apiEvent.venue_address,
222
- location: apiEvent.location || apiEvent.venueAddress || apiEvent.venue_address,
223
- imageUrl: getEventImageUrl(apiEvent),
224
- imageURL: getEventImageUrl(apiEvent),
225
- status: apiEvent.status,
226
- isPublished: apiEvent.isPublished ?? apiEvent.is_published,
227
- isCancelled: apiEvent.isCancelled ?? apiEvent.is_cancelled,
228
- availableTickets: tickets,
229
- ticketsAvailable:
230
- apiEvent.ticketsAvailable ??
231
- apiEvent.tickets_available ??
232
- tickets.reduce((sum, t) => sum + (t.quantityAvailable || 0), 0),
233
- ticketsSold: apiEvent.ticketsSold ?? apiEvent.tickets_sold,
234
- minPrice: apiEvent.minPrice ?? apiEvent.min_price ?? minPrice,
235
- maxPrice: apiEvent.maxPrice ?? apiEvent.max_price ?? maxPrice,
236
- ctaText: apiEvent.ctaText || apiEvent.cta_text,
237
- ctaState: calculateCtaState(apiEvent),
238
- showPerformers: apiEvent.showPerformers ?? apiEvent.show_performers,
239
- eventSeriesId: apiEvent.eventSeriesId || apiEvent.event_series_id,
240
- seriesInstanceNumber:
241
- apiEvent.seriesInstanceNumber || apiEvent.series_instance_number,
242
- };
243
- }
244
-
245
- /**
246
- * Legacy transformer name for backwards compatibility
247
- */
248
- export const transformEventData = transformEvent;
1
+ /**
2
+ * Event Transformer
3
+ *
4
+ * Normalizes API event responses to a consistent format.
5
+ * Handles image URL resolution and CTA state calculation.
6
+ */
7
+
8
+ import type { Event, AvailableTicket } from '../types.js';
9
+
10
+ // CDN base URL for images
11
+ const CDN_BASE_URL = 'https://micdrop-images.sfo3.digitaloceanspaces.com';
12
+
13
+ /**
14
+ * Raw API event response (may have varying field names)
15
+ */
16
+ interface ApiEvent {
17
+ eventID?: number;
18
+ id?: number;
19
+ ID?: number;
20
+ name?: string;
21
+ title?: string;
22
+ slug?: string;
23
+ description?: string;
24
+ date?: string;
25
+ startDateTime?: string;
26
+ start_date_time?: string;
27
+ endDateTime?: string;
28
+ end_date_time?: string;
29
+ doorsOpenTime?: string;
30
+ doors_open_time?: string;
31
+ timezone?: string;
32
+ time_zone?: string;
33
+ venueId?: number;
34
+ venue_id?: number;
35
+ venueName?: string;
36
+ venue_name?: string;
37
+ venueAddress?: string;
38
+ venue_address?: string;
39
+ location?: string;
40
+ imageUrl?: string;
41
+ imageURL?: string;
42
+ image_url?: string;
43
+ image?: string;
44
+ status?: string;
45
+ isPublished?: boolean;
46
+ is_published?: boolean;
47
+ isCancelled?: boolean;
48
+ is_cancelled?: boolean;
49
+ availableTickets?: any[];
50
+ available_tickets?: any[];
51
+ tickets?: any[];
52
+ ticketsAvailable?: number;
53
+ tickets_available?: number;
54
+ ticketsSold?: number;
55
+ tickets_sold?: number;
56
+ minPrice?: number;
57
+ min_price?: number;
58
+ maxPrice?: number;
59
+ max_price?: number;
60
+ ctaText?: string;
61
+ cta_text?: string;
62
+ ctaState?: string;
63
+ cta_state?: string;
64
+ showPerformers?: boolean;
65
+ show_performers?: boolean;
66
+ eventSeriesId?: number;
67
+ event_series_id?: number;
68
+ seriesInstanceNumber?: number;
69
+ series_instance_number?: number;
70
+ }
71
+
72
+ /**
73
+ * Get CDN image URL
74
+ *
75
+ * Prepends the CDN base URL if the path is relative.
76
+ */
77
+ export function getCDNImageUrl(path: string | undefined): string {
78
+ if (!path) return '';
79
+ if (path.startsWith('http')) return path;
80
+ return `${CDN_BASE_URL}/${path.replace(/^\//, '')}`;
81
+ }
82
+
83
+ /**
84
+ * Extract image URL from event with fallbacks
85
+ */
86
+ export function getEventImageUrl(apiEvent: ApiEvent): string {
87
+ const rawUrl =
88
+ apiEvent.imageUrl ||
89
+ apiEvent.imageURL ||
90
+ apiEvent.image_url ||
91
+ apiEvent.image ||
92
+ '';
93
+
94
+ return getCDNImageUrl(rawUrl);
95
+ }
96
+
97
+ /**
98
+ * Calculate CTA state based on ticket availability
99
+ */
100
+ export function calculateCtaState(
101
+ apiEvent: ApiEvent
102
+ ): 'available' | 'sold_out' | 'coming_soon' | 'ended' {
103
+ // Check explicit CTA state first
104
+ const explicitState = apiEvent.ctaState || apiEvent.cta_state;
105
+ if (explicitState) {
106
+ return explicitState as any;
107
+ }
108
+
109
+ // Check if event is cancelled or ended
110
+ if (apiEvent.isCancelled || apiEvent.is_cancelled) {
111
+ return 'ended';
112
+ }
113
+
114
+ // Check event date
115
+ const eventDate = apiEvent.startDateTime || apiEvent.start_date_time || apiEvent.date;
116
+ if (eventDate) {
117
+ const eventTime = new Date(eventDate).getTime();
118
+ const now = Date.now();
119
+
120
+ if (eventTime < now) {
121
+ return 'ended';
122
+ }
123
+ }
124
+
125
+ // Check ticket availability
126
+ const availableCount =
127
+ apiEvent.ticketsAvailable ?? apiEvent.tickets_available;
128
+
129
+ if (availableCount !== undefined) {
130
+ if (availableCount <= 0) {
131
+ return 'sold_out';
132
+ }
133
+ return 'available';
134
+ }
135
+
136
+ // Check tickets array
137
+ const tickets =
138
+ apiEvent.availableTickets ||
139
+ apiEvent.available_tickets ||
140
+ apiEvent.tickets ||
141
+ [];
142
+
143
+ if (tickets.length === 0) {
144
+ return 'coming_soon';
145
+ }
146
+
147
+ const totalAvailable = tickets.reduce((sum: number, t: any) => {
148
+ const qty =
149
+ t.quantityAvailable ?? t.quantity_available ?? t.quantity ?? 0;
150
+ const sold = t.quantitySold ?? t.quantity_sold ?? 0;
151
+ return sum + Math.max(0, qty - sold);
152
+ }, 0);
153
+
154
+ if (totalAvailable <= 0) {
155
+ return 'sold_out';
156
+ }
157
+
158
+ return 'available';
159
+ }
160
+
161
+ /**
162
+ * Transform a raw API ticket to normalized AvailableTicket
163
+ */
164
+ export function transformTicket(apiTicket: any): AvailableTicket {
165
+ return {
166
+ id: apiTicket.id || apiTicket.ID,
167
+ name: apiTicket.name || apiTicket.ticketName || '',
168
+ description: apiTicket.description,
169
+ price: apiTicket.price || 0,
170
+ quantity: apiTicket.quantity || apiTicket.totalQuantity || 0,
171
+ quantitySold: apiTicket.quantitySold || apiTicket.quantity_sold || 0,
172
+ quantityAvailable:
173
+ apiTicket.quantityAvailable ||
174
+ apiTicket.quantity_available ||
175
+ (apiTicket.quantity || 0) - (apiTicket.quantitySold || 0),
176
+ minPerOrder: apiTicket.minPerOrder || apiTicket.min_per_order || 1,
177
+ maxPerOrder: apiTicket.maxPerOrder || apiTicket.max_per_order || 10,
178
+ saleStartDate: apiTicket.saleStartDate || apiTicket.sale_start_date,
179
+ saleEndDate: apiTicket.saleEndDate || apiTicket.sale_end_date,
180
+ isHidden: apiTicket.isHidden || apiTicket.is_hidden || false,
181
+ revealWithPromoCode:
182
+ apiTicket.revealWithPromoCode || apiTicket.reveal_with_promo_code,
183
+ ticketType: apiTicket.ticketType || apiTicket.ticket_type || 0,
184
+ sectionId: apiTicket.sectionId || apiTicket.section_id,
185
+ sortOrder: apiTicket.sortOrder || apiTicket.sort_order || 0,
186
+ };
187
+ }
188
+
189
+ /**
190
+ * Transform a raw API event to normalized Event
191
+ */
192
+ export function transformEvent(apiEvent: ApiEvent): Event {
193
+ // Extract tickets array from various possible field names
194
+ const rawTickets =
195
+ apiEvent.availableTickets ||
196
+ apiEvent.available_tickets ||
197
+ apiEvent.tickets ||
198
+ [];
199
+
200
+ const tickets = rawTickets.map(transformTicket);
201
+
202
+ // Calculate min/max prices from tickets
203
+ const prices = tickets.map((t) => t.price).filter((p) => p > 0);
204
+ const minPrice = prices.length > 0 ? Math.min(...prices) : undefined;
205
+ const maxPrice = prices.length > 0 ? Math.max(...prices) : undefined;
206
+
207
+ return {
208
+ eventID: apiEvent.eventID || apiEvent.id || apiEvent.ID || 0,
209
+ id: apiEvent.id || apiEvent.ID,
210
+ name: apiEvent.name || apiEvent.title || '',
211
+ title: apiEvent.title || apiEvent.name,
212
+ slug: apiEvent.slug,
213
+ description: apiEvent.description,
214
+ date: apiEvent.date || apiEvent.startDateTime || apiEvent.start_date_time || '',
215
+ startDateTime: apiEvent.startDateTime || apiEvent.start_date_time,
216
+ endDateTime: apiEvent.endDateTime || apiEvent.end_date_time,
217
+ doorsOpenTime: apiEvent.doorsOpenTime || apiEvent.doors_open_time,
218
+ timezone: apiEvent.timezone || apiEvent.time_zone,
219
+ venueId: apiEvent.venueId || apiEvent.venue_id,
220
+ venueName: apiEvent.venueName || apiEvent.venue_name,
221
+ venueAddress: apiEvent.venueAddress || apiEvent.venue_address,
222
+ location: apiEvent.location || apiEvent.venueAddress || apiEvent.venue_address,
223
+ imageUrl: getEventImageUrl(apiEvent),
224
+ imageURL: getEventImageUrl(apiEvent),
225
+ status: apiEvent.status,
226
+ isPublished: apiEvent.isPublished ?? apiEvent.is_published,
227
+ isCancelled: apiEvent.isCancelled ?? apiEvent.is_cancelled,
228
+ availableTickets: tickets,
229
+ ticketsAvailable:
230
+ apiEvent.ticketsAvailable ??
231
+ apiEvent.tickets_available ??
232
+ tickets.reduce((sum, t) => sum + (t.quantityAvailable || 0), 0),
233
+ ticketsSold: apiEvent.ticketsSold ?? apiEvent.tickets_sold,
234
+ minPrice: apiEvent.minPrice ?? apiEvent.min_price ?? minPrice,
235
+ maxPrice: apiEvent.maxPrice ?? apiEvent.max_price ?? maxPrice,
236
+ ctaText: apiEvent.ctaText || apiEvent.cta_text,
237
+ ctaState: calculateCtaState(apiEvent),
238
+ showPerformers: apiEvent.showPerformers ?? apiEvent.show_performers,
239
+ eventSeriesId: apiEvent.eventSeriesId || apiEvent.event_series_id,
240
+ seriesInstanceNumber:
241
+ apiEvent.seriesInstanceNumber || apiEvent.series_instance_number,
242
+ };
243
+ }
244
+
245
+ /**
246
+ * Legacy transformer name for backwards compatibility
247
+ */
248
+ export const transformEventData = transformEvent;
@@ -1,29 +1,29 @@
1
- /**
2
- * Transformers Index
3
- *
4
- * Re-exports all transformer functions for convenient importing.
5
- */
6
-
7
- // Order transformers
8
- export {
9
- transformOrder,
10
- transformTicket,
11
- transformOrderForDisplay,
12
- } from './order.js';
13
-
14
- // Event transformers
15
- export {
16
- transformEvent,
17
- transformEventData, // Legacy alias
18
- transformTicket as transformAvailableTicket,
19
- getCDNImageUrl,
20
- getEventImageUrl,
21
- calculateCtaState,
22
- } from './event.js';
23
-
24
- // Venue transformers
25
- export {
26
- transformVenue,
27
- extractVenueFees,
28
- formatVenueAddress,
29
- } from './venue.js';
1
+ /**
2
+ * Transformers Index
3
+ *
4
+ * Re-exports all transformer functions for convenient importing.
5
+ */
6
+
7
+ // Order transformers
8
+ export {
9
+ transformOrder,
10
+ transformTicket,
11
+ transformOrderForDisplay,
12
+ } from './order.js';
13
+
14
+ // Event transformers
15
+ export {
16
+ transformEvent,
17
+ transformEventData, // Legacy alias
18
+ transformTicket as transformAvailableTicket,
19
+ getCDNImageUrl,
20
+ getEventImageUrl,
21
+ calculateCtaState,
22
+ } from './event.js';
23
+
24
+ // Venue transformers
25
+ export {
26
+ transformVenue,
27
+ extractVenueFees,
28
+ formatVenueAddress,
29
+ } from './venue.js';