@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.
- package/README.md +661 -661
- package/dist/{VenueCalendar-BMSfRl2d.js → VenueCalendar-Xppig0q_.js} +13 -10
- package/dist/VenueCalendar-Xppig0q_.js.map +1 -0
- package/dist/{index-CoJaem3n.js → index-BjErG0CG.js} +2 -2
- package/dist/{index-CoJaem3n.js.map → index-BjErG0CG.js.map} +1 -1
- package/dist/types/index.d.ts +395 -395
- package/dist/venue-calendar.css +1 -1
- package/dist/venue-calendar.es.js +1 -1
- package/dist/venue-calendar.iife.js +4 -4
- package/dist/venue-calendar.iife.js.map +1 -1
- package/dist/venue-calendar.umd.js +4 -4
- package/dist/venue-calendar.umd.js.map +1 -1
- package/package.json +2 -1
- package/src/lib/api/client.ts +210 -210
- package/src/lib/api/events.ts +358 -358
- package/src/lib/api/index.ts +182 -182
- package/src/lib/api/orders.ts +390 -390
- package/src/lib/api/promo.ts +164 -164
- package/src/lib/api/transformers/event.ts +248 -248
- package/src/lib/api/transformers/index.ts +29 -29
- package/src/lib/api/transformers/order.ts +207 -207
- package/src/lib/api/transformers/venue.ts +118 -118
- package/src/lib/api/types.ts +289 -289
- package/src/lib/api/venues.ts +100 -100
- package/src/lib/theme.js +209 -209
- package/src/lib/utils/api.js +790 -0
- package/src/lib/utils/api.test.js +1284 -0
- package/src/lib/utils/constants.js +8 -0
- package/src/lib/utils/constants.test.js +39 -0
- package/src/lib/utils/datetime.js +266 -0
- package/src/lib/utils/datetime.test.js +340 -0
- package/src/lib/utils/event-transform.js +464 -0
- package/src/lib/utils/event-transform.test.js +413 -0
- package/src/lib/utils/logger.js +105 -0
- package/src/lib/utils/timezone.js +109 -0
- package/src/lib/utils/timezone.test.js +222 -0
- package/src/lib/utils/utils.js +806 -0
- package/src/lib/utils/utils.test.js +959 -0
- package/dist/VenueCalendar-BMSfRl2d.js.map +0 -1
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Transformation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for transforming API event data into display-ready formats.
|
|
5
|
+
* Consolidates duplicate transformation logic from utils.js and api.js.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
getIANATimezone,
|
|
10
|
+
formatEventTime,
|
|
11
|
+
formatTimeRange,
|
|
12
|
+
getDateParts as getDatePartsNew,
|
|
13
|
+
} from './datetime.js';
|
|
14
|
+
|
|
15
|
+
/** CDN base URL for image assets */
|
|
16
|
+
const CDN_BASE_URL = 'https://moxy.sfo3.digitaloceanspaces.com';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Default placeholder image
|
|
20
|
+
* Using a data URI SVG to avoid third-party dependencies
|
|
21
|
+
*/
|
|
22
|
+
const PLACEHOLDER_IMAGE = 'data:image/svg+xml,' + encodeURIComponent(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 300" fill="none">
|
|
23
|
+
<rect width="200" height="300" fill="#E5E7EB"/>
|
|
24
|
+
<rect x="60" y="90" width="80" height="80" rx="10" fill="#D1D5DB"/>
|
|
25
|
+
<circle cx="85" cy="115" r="10" fill="#9CA3AF"/>
|
|
26
|
+
<path d="M70 155 L100 125 L130 155 L130 155" stroke="#9CA3AF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
27
|
+
<text x="100" y="210" text-anchor="middle" font-family="system-ui, sans-serif" font-size="14" fill="#6B7280">Event Image</text>
|
|
28
|
+
</svg>`);
|
|
29
|
+
|
|
30
|
+
// ============================================================================
|
|
31
|
+
// Shared Helpers
|
|
32
|
+
// ============================================================================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Prepend CDN URL to relative image paths.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} imagePath - Image path (relative or absolute)
|
|
38
|
+
* @returns {string} Full image URL
|
|
39
|
+
*/
|
|
40
|
+
export function getCDNImageUrl(imagePath) {
|
|
41
|
+
if (!imagePath) return '';
|
|
42
|
+
if (imagePath.startsWith('/')) {
|
|
43
|
+
return `${CDN_BASE_URL}${imagePath}`;
|
|
44
|
+
}
|
|
45
|
+
return imagePath;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Extract image URL from event data with fallbacks.
|
|
50
|
+
*
|
|
51
|
+
* @param {Object} event - Event object from API
|
|
52
|
+
* @returns {string} Resolved image URL
|
|
53
|
+
*/
|
|
54
|
+
export function getEventImageUrl(event) {
|
|
55
|
+
const rawImage = event.image || event.coverImage || event.imageUrl || event.image_url || '';
|
|
56
|
+
return getCDNImageUrl(rawImage) || PLACEHOLDER_IMAGE;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Calculate ticket status based on capacity and dates.
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} ticket - Ticket object
|
|
63
|
+
* @returns {string} Status: 'available', 'low', 'sold_out', 'not_started', 'ended'
|
|
64
|
+
*/
|
|
65
|
+
export function calculateTicketStatus(ticket) {
|
|
66
|
+
const now = new Date();
|
|
67
|
+
|
|
68
|
+
if (ticket.saleStartDate && new Date(ticket.saleStartDate) > now) {
|
|
69
|
+
return 'not_started';
|
|
70
|
+
}
|
|
71
|
+
if (ticket.saleEndDate && new Date(ticket.saleEndDate) < now) {
|
|
72
|
+
return 'ended';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const remaining = ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity ?? 0;
|
|
76
|
+
const total = ticket.totalCapacity ?? ticket.quantity ?? remaining;
|
|
77
|
+
|
|
78
|
+
if (remaining === 0) return 'sold_out';
|
|
79
|
+
if (total > 0 && remaining / total < 0.1) return 'low';
|
|
80
|
+
return 'available';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Filter tickets to only public/online sales.
|
|
85
|
+
*
|
|
86
|
+
* @param {Array} tickets - Array of ticket objects
|
|
87
|
+
* @param {Object} options - Filter options
|
|
88
|
+
* @param {boolean} options.excludeDoorOnly - Exclude "at the door only" tickets (salesChannel === 2)
|
|
89
|
+
* @param {boolean} options.publicOnly - Only include visibility === 0 tickets
|
|
90
|
+
* @returns {Array} Filtered tickets
|
|
91
|
+
*/
|
|
92
|
+
export function filterPublicTickets(tickets, options = {}) {
|
|
93
|
+
if (!Array.isArray(tickets)) return [];
|
|
94
|
+
|
|
95
|
+
let filtered = tickets;
|
|
96
|
+
|
|
97
|
+
if (options.excludeDoorOnly) {
|
|
98
|
+
filtered = filtered.filter(t => t.salesChannel !== 2);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (options.publicOnly) {
|
|
102
|
+
filtered = filtered.filter(t => t.visibility === 0);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return filtered;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Calculate scarcity data for an event's tickets.
|
|
110
|
+
*
|
|
111
|
+
* @param {Array} tickets - Array of ticket objects (should be pre-filtered)
|
|
112
|
+
* @returns {Object} { totalRemaining, totalCapacity, isSoldOut }
|
|
113
|
+
*/
|
|
114
|
+
export function calculateScarcity(tickets) {
|
|
115
|
+
if (!Array.isArray(tickets) || tickets.length === 0) {
|
|
116
|
+
return { totalRemaining: 0, totalCapacity: 0, isSoldOut: false };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let totalRemaining = 0;
|
|
120
|
+
let totalCapacity = 0;
|
|
121
|
+
|
|
122
|
+
for (const ticket of tickets) {
|
|
123
|
+
const remaining = ticket.remainingCapacity ?? ticket.quantityRemaining ?? ticket.quantity ?? 0;
|
|
124
|
+
const capacity = ticket.totalCapacity ?? ticket.quantity ?? remaining;
|
|
125
|
+
totalRemaining += remaining;
|
|
126
|
+
totalCapacity += capacity;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
totalRemaining,
|
|
131
|
+
totalCapacity,
|
|
132
|
+
isSoldOut: totalRemaining === 0,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Find the lowest price among tickets.
|
|
138
|
+
*
|
|
139
|
+
* @param {Array} tickets - Array of ticket objects
|
|
140
|
+
* @returns {number} Lowest price or 0
|
|
141
|
+
*/
|
|
142
|
+
export function findLowestPrice(tickets) {
|
|
143
|
+
if (!Array.isArray(tickets) || tickets.length === 0) return 0;
|
|
144
|
+
|
|
145
|
+
const prices = tickets
|
|
146
|
+
.map(t => t.price ?? t.ticketPrice ?? 0)
|
|
147
|
+
.filter(p => p > 0);
|
|
148
|
+
|
|
149
|
+
return prices.length > 0 ? Math.min(...prices) : 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Date/Time Formatting
|
|
154
|
+
// Now uses consolidated datetime module from @getmicdrop/svelte-components
|
|
155
|
+
// ============================================================================
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Format a datetime for display in a specific timezone.
|
|
159
|
+
* @deprecated Use formatEventTime or formatEventDateTime from datetime.js
|
|
160
|
+
*
|
|
161
|
+
* @param {string} isoString - ISO datetime string
|
|
162
|
+
* @param {string} timeZone - IANA timezone
|
|
163
|
+
* @param {Object} options - Intl.DateTimeFormat options
|
|
164
|
+
* @returns {string} Formatted string
|
|
165
|
+
*/
|
|
166
|
+
export function formatInTimezone(isoString, timeZone, options) {
|
|
167
|
+
if (!isoString) return '';
|
|
168
|
+
|
|
169
|
+
const date = new Date(isoString);
|
|
170
|
+
if (isNaN(date.getTime())) return '';
|
|
171
|
+
|
|
172
|
+
return new Intl.DateTimeFormat('en-US', { ...options, timeZone }).format(date);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Format event time range for display.
|
|
177
|
+
* Uses formatTimeRange from datetime module.
|
|
178
|
+
*
|
|
179
|
+
* @param {Object} event - Event object with startDateTime/endDateTime
|
|
180
|
+
* @param {string} timeZone - IANA timezone
|
|
181
|
+
* @returns {string} Formatted time range (e.g., "8:00 PM - 10:00 PM")
|
|
182
|
+
*/
|
|
183
|
+
export function formatEventTimeRange(event, timeZone) {
|
|
184
|
+
if (!event.startDateTime) return '';
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
if (!event.endDateTime) {
|
|
188
|
+
return formatEventTime(event.startDateTime, timeZone);
|
|
189
|
+
}
|
|
190
|
+
return formatTimeRange(event.startDateTime, event.endDateTime, timeZone);
|
|
191
|
+
} catch {
|
|
192
|
+
// Fallback to legacy implementation for invalid data
|
|
193
|
+
const formatOptions = {
|
|
194
|
+
hour: 'numeric',
|
|
195
|
+
minute: '2-digit',
|
|
196
|
+
hour12: true,
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const startTime = formatInTimezone(event.startDateTime, timeZone, formatOptions);
|
|
200
|
+
|
|
201
|
+
if (!event.endDateTime) return startTime;
|
|
202
|
+
|
|
203
|
+
const endTime = formatInTimezone(event.endDateTime, timeZone, formatOptions);
|
|
204
|
+
return startTime && endTime ? `${startTime} - ${endTime}` : startTime;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get date parts for display (day, month, dateOfMonth).
|
|
210
|
+
* Uses getDateParts from datetime module.
|
|
211
|
+
*
|
|
212
|
+
* @param {string} isoString - ISO datetime string
|
|
213
|
+
* @param {string} timeZone - IANA timezone
|
|
214
|
+
* @returns {Object} { day, month, dateOfMonth }
|
|
215
|
+
*/
|
|
216
|
+
export function getDateParts(isoString, timeZone) {
|
|
217
|
+
if (!isoString) return { day: '', month: '', dateOfMonth: '' };
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
const parts = getDatePartsNew(isoString, timeZone);
|
|
221
|
+
return {
|
|
222
|
+
day: parts.day,
|
|
223
|
+
month: parts.month,
|
|
224
|
+
dateOfMonth: String(parts.date),
|
|
225
|
+
};
|
|
226
|
+
} catch {
|
|
227
|
+
// Fallback to legacy implementation for invalid data
|
|
228
|
+
return {
|
|
229
|
+
day: formatInTimezone(isoString, timeZone, { weekday: 'short' }),
|
|
230
|
+
month: formatInTimezone(isoString, timeZone, { month: 'short' }),
|
|
231
|
+
dateOfMonth: formatInTimezone(isoString, timeZone, { day: 'numeric' }),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================================================
|
|
237
|
+
// Main Transform Functions
|
|
238
|
+
// ============================================================================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Transform modes for different use cases.
|
|
242
|
+
*/
|
|
243
|
+
export const TransformMode = {
|
|
244
|
+
/** Minimal data for list/card views */
|
|
245
|
+
BROWSE: 'browse',
|
|
246
|
+
/** Full data for detail pages */
|
|
247
|
+
DETAIL: 'detail',
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Transform an API event into display-ready format.
|
|
252
|
+
*
|
|
253
|
+
* @param {Object} apiEvent - Raw event from API
|
|
254
|
+
* @param {Object} options - Transform options
|
|
255
|
+
* @param {string} options.mode - Transform mode: 'browse' or 'detail'
|
|
256
|
+
* @returns {Object} Transformed event
|
|
257
|
+
*/
|
|
258
|
+
export function transformEvent(apiEvent, options = {}) {
|
|
259
|
+
const { mode = TransformMode.DETAIL } = options;
|
|
260
|
+
|
|
261
|
+
if (!apiEvent) {
|
|
262
|
+
return mode === TransformMode.BROWSE
|
|
263
|
+
? getEmptyBrowseEvent()
|
|
264
|
+
: getEmptyDetailEvent();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const timeZone = getIANATimezone(apiEvent.timeZone);
|
|
268
|
+
const imageUrl = getEventImageUrl(apiEvent);
|
|
269
|
+
|
|
270
|
+
// Base properties shared by both modes
|
|
271
|
+
const base = {
|
|
272
|
+
id: apiEvent.id || apiEvent.ID,
|
|
273
|
+
name: apiEvent.title || apiEvent.name || '',
|
|
274
|
+
image: imageUrl,
|
|
275
|
+
timeZone,
|
|
276
|
+
startDateTime: apiEvent.startDateTime || null,
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
if (mode === TransformMode.BROWSE) {
|
|
280
|
+
return transformBrowseEvent(apiEvent, base, timeZone);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return transformDetailEvent(apiEvent, base, timeZone, imageUrl);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Transform for browse/list views (minimal data).
|
|
288
|
+
*/
|
|
289
|
+
function transformBrowseEvent(apiEvent, base, timeZone) {
|
|
290
|
+
// Calculate date in venue timezone
|
|
291
|
+
let startDate = '';
|
|
292
|
+
if (apiEvent.startDateTime) {
|
|
293
|
+
const dt = new Date(apiEvent.startDateTime);
|
|
294
|
+
startDate = dt.toLocaleDateString('en-CA', {
|
|
295
|
+
timeZone,
|
|
296
|
+
year: 'numeric',
|
|
297
|
+
month: '2-digit',
|
|
298
|
+
day: '2-digit',
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Filter and calculate scarcity
|
|
303
|
+
const publicTickets = filterPublicTickets(apiEvent.availableTickets || [], { excludeDoorOnly: true });
|
|
304
|
+
const scarcity = calculateScarcity(publicTickets);
|
|
305
|
+
|
|
306
|
+
return {
|
|
307
|
+
...base,
|
|
308
|
+
date: startDate || apiEvent.date || '',
|
|
309
|
+
status: apiEvent.status || 'On Sale',
|
|
310
|
+
timeline: formatEventTimeRange(apiEvent, timeZone),
|
|
311
|
+
description: apiEvent.description || apiEvent.eventSummary || '',
|
|
312
|
+
venueId: apiEvent.venueId || apiEvent.venue_id,
|
|
313
|
+
eventSeriesId: apiEvent.eventSeriesId || null,
|
|
314
|
+
// Scarcity data
|
|
315
|
+
ticketsRemaining: scarcity.totalRemaining,
|
|
316
|
+
ticketsTotal: scarcity.totalCapacity,
|
|
317
|
+
isSoldOut: scarcity.isSoldOut,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Transform for detail views (full data).
|
|
323
|
+
*/
|
|
324
|
+
function transformDetailEvent(apiEvent, base, timeZone, imageUrl) {
|
|
325
|
+
const allTickets = (apiEvent.availableTickets || []).map(ticket => ({
|
|
326
|
+
...ticket,
|
|
327
|
+
status: calculateTicketStatus(ticket),
|
|
328
|
+
}));
|
|
329
|
+
const publicTickets = filterPublicTickets(allTickets, { publicOnly: true });
|
|
330
|
+
const dateParts = getDateParts(apiEvent.startDateTime, timeZone);
|
|
331
|
+
|
|
332
|
+
return {
|
|
333
|
+
...base,
|
|
334
|
+
date: apiEvent.startDateTime ? formatDateCustom(apiEvent.startDateTime) : null,
|
|
335
|
+
endDateTime: apiEvent.endDateTime,
|
|
336
|
+
description: apiEvent.description,
|
|
337
|
+
timeline: formatInTimezone(apiEvent.startDateTime, timeZone, {
|
|
338
|
+
hour: 'numeric',
|
|
339
|
+
minute: '2-digit',
|
|
340
|
+
hour12: true,
|
|
341
|
+
}),
|
|
342
|
+
location: apiEvent.venue?.googleLocationNameCache || apiEvent.venue?.address || '',
|
|
343
|
+
...dateParts,
|
|
344
|
+
coverImage: imageUrl,
|
|
345
|
+
price: findLowestPrice(apiEvent.availableTickets),
|
|
346
|
+
status: 'Only 2 left!', // TODO: Calculate from scarcity
|
|
347
|
+
eventSummary: apiEvent.eventSummary,
|
|
348
|
+
password: apiEvent.password,
|
|
349
|
+
availableTickets: allTickets,
|
|
350
|
+
publicTickets,
|
|
351
|
+
doorsOpenTime: apiEvent.doorsOpenTime,
|
|
352
|
+
venue: apiEvent.venue,
|
|
353
|
+
venueID: apiEvent.venueId,
|
|
354
|
+
eventID: apiEvent.ID,
|
|
355
|
+
stage: apiEvent.stage,
|
|
356
|
+
performers: apiEvent.performers,
|
|
357
|
+
ticketType: apiEvent.ticketType,
|
|
358
|
+
eventTicketingType: apiEvent.eventTicketingType,
|
|
359
|
+
purchasedTickets: apiEvent.purchasedTickets,
|
|
360
|
+
ShowImage: imageUrl,
|
|
361
|
+
displayStartTime: apiEvent.displayStartTime,
|
|
362
|
+
displayEndTime: apiEvent.displayEndTime,
|
|
363
|
+
displayDoorsTime: apiEvent.displayDoorsTime,
|
|
364
|
+
ageRestriction: apiEvent.ageRestriction || null,
|
|
365
|
+
minimumAge: apiEvent.ageRestriction || null,
|
|
366
|
+
ageRequirement: apiEvent.ageRestriction ? `${apiEvent.ageRestriction}` : null,
|
|
367
|
+
hasAgeRestriction: !!apiEvent.ageRestriction,
|
|
368
|
+
displayAgeRestriction: apiEvent.displayAgeRestriction ?? false,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Format date to custom format (for backwards compatibility).
|
|
374
|
+
*/
|
|
375
|
+
function formatDateCustom(isoString) {
|
|
376
|
+
if (!isoString) return null;
|
|
377
|
+
const date = new Date(isoString);
|
|
378
|
+
if (isNaN(date.getTime())) return null;
|
|
379
|
+
|
|
380
|
+
const options = {
|
|
381
|
+
weekday: 'short',
|
|
382
|
+
month: 'short',
|
|
383
|
+
day: 'numeric',
|
|
384
|
+
year: 'numeric',
|
|
385
|
+
};
|
|
386
|
+
return new Intl.DateTimeFormat('en-US', options).format(date);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Empty event for browse mode.
|
|
391
|
+
*/
|
|
392
|
+
function getEmptyBrowseEvent() {
|
|
393
|
+
return {
|
|
394
|
+
id: null,
|
|
395
|
+
name: '',
|
|
396
|
+
date: '',
|
|
397
|
+
image: '',
|
|
398
|
+
status: 'unavailable',
|
|
399
|
+
timeline: '',
|
|
400
|
+
description: '',
|
|
401
|
+
venueId: null,
|
|
402
|
+
timeZone: 'UTC',
|
|
403
|
+
eventSeriesId: null,
|
|
404
|
+
startDateTime: null,
|
|
405
|
+
ticketsRemaining: 0,
|
|
406
|
+
ticketsTotal: 0,
|
|
407
|
+
isSoldOut: false,
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Empty event for detail mode.
|
|
413
|
+
*/
|
|
414
|
+
function getEmptyDetailEvent() {
|
|
415
|
+
return {
|
|
416
|
+
id: null,
|
|
417
|
+
name: '',
|
|
418
|
+
date: null,
|
|
419
|
+
startDateTime: null,
|
|
420
|
+
endDateTime: null,
|
|
421
|
+
description: '',
|
|
422
|
+
timeline: '',
|
|
423
|
+
location: '',
|
|
424
|
+
day: '',
|
|
425
|
+
month: '',
|
|
426
|
+
dateOfMonth: null,
|
|
427
|
+
image: '',
|
|
428
|
+
coverImage: '',
|
|
429
|
+
price: 0,
|
|
430
|
+
status: 'unavailable',
|
|
431
|
+
eventSummary: '',
|
|
432
|
+
password: '',
|
|
433
|
+
availableTickets: [],
|
|
434
|
+
publicTickets: [],
|
|
435
|
+
doorsOpenTime: null,
|
|
436
|
+
venue: null,
|
|
437
|
+
venueID: null,
|
|
438
|
+
eventID: null,
|
|
439
|
+
stage: null,
|
|
440
|
+
performers: [],
|
|
441
|
+
ticketType: 0,
|
|
442
|
+
eventTicketingType: 0,
|
|
443
|
+
purchasedTickets: [],
|
|
444
|
+
ShowImage: '',
|
|
445
|
+
displayStartTime: null,
|
|
446
|
+
displayEndTime: null,
|
|
447
|
+
ageRestriction: null,
|
|
448
|
+
minimumAge: null,
|
|
449
|
+
ageRequirement: null,
|
|
450
|
+
hasAgeRestriction: false,
|
|
451
|
+
timeZone: 'UTC',
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// ============================================================================
|
|
456
|
+
// Backward Compatibility Exports
|
|
457
|
+
// ============================================================================
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* @deprecated Use transformEvent(event, { mode: TransformMode.BROWSE }) instead.
|
|
461
|
+
*/
|
|
462
|
+
export function transformEventData(apiEvent) {
|
|
463
|
+
return transformEvent(apiEvent, { mode: TransformMode.BROWSE });
|
|
464
|
+
}
|