diff --git a/src/models/tickets/admin/events.admin.service.ts b/src/models/tickets/admin/events.admin.service.ts index f19a95a..62eaafa 100644 --- a/src/models/tickets/admin/events.admin.service.ts +++ b/src/models/tickets/admin/events.admin.service.ts @@ -14,6 +14,7 @@ export interface EventPickerEntry { startDateTime: Date; location: string; status: string | undefined; + redemptionDeadline: Date | null; } /** @@ -26,19 +27,26 @@ export interface EventPickerEntry { */ export const listEventsForPicker = async (): Promise => { let conn = await NachklangTicketsDB.getConnection(); - let enabledEventIds: number[]; + let deadlineByEventId: Map; try { - const rows = await conn.query('SELECT event_id FROM event_ticket_settings'); - enabledEventIds = rows.map((r: any) => r.event_id); + const rows = await conn.query('SELECT event_id, redemption_deadline FROM event_ticket_settings'); + deadlineByEventId = new Map(rows.map((r: any) => [r.event_id, r.redemption_deadline])); } finally { await conn.end(); } - if (enabledEventIds.length === 0) return []; + if (deadlineByEventId.size === 0) return []; - const events = await Promise.all(enabledEventIds.map(id => CalendarEventsService.getEventById(id))); + const events = await Promise.all([...deadlineByEventId.keys()].map(id => CalendarEventsService.getEventById(id))); return events .filter((e): e is NonNullable => e !== null && e.status !== 'DELETED') - .map(e => ({eventId: e.eventId, name: e.name, startDateTime: e.startDateTime, location: e.location, status: e.status})) + .map(e => ({ + eventId: e.eventId, + name: e.name, + startDateTime: e.startDateTime, + location: e.location, + status: e.status, + redemptionDeadline: deadlineByEventId.get(e.eventId) ?? null + })) .sort((a, b) => a.startDateTime.getTime() - b.startDateTime.getTime()); }; @@ -59,7 +67,9 @@ export const listAvailableEventsToAdd = async (): Promise => const events = await CalendarEventsService.getAllEventsAdmin(PUBLIC_CALENDAR_ID); return events .filter(e => e.status !== 'DELETED' && !enabledEventIds.has(e.eventId)) - .map(e => ({eventId: e.eventId, name: e.name, startDateTime: e.startDateTime, location: e.location, status: e.status})) + // Not yet added to the ticket shop, so there's no event_ticket_settings + // row and therefore no deadline to report. + .map(e => ({eventId: e.eventId, name: e.name, startDateTime: e.startDateTime, location: e.location, status: e.status, redemptionDeadline: null})) .sort((a, b) => a.startDateTime.getTime() - b.startDateTime.getTime()); }; diff --git a/src/models/tickets/public/voucher.public.service.ts b/src/models/tickets/public/voucher.public.service.ts index 4f8c4fc..586981a 100644 --- a/src/models/tickets/public/voucher.public.service.ts +++ b/src/models/tickets/public/voucher.public.service.ts @@ -39,6 +39,7 @@ export const validateVoucher = async (code: string): Promise new Date(ticketState.redemptionDeadline), isFull: ticketState.spotsRemaining !== null && ticketState.spotsRemaining <= 0, spotsRemaining: ticketState.spotsRemaining, diff --git a/src/models/tickets/tickets.interface.ts b/src/models/tickets/tickets.interface.ts index d74d331..eb07414 100644 --- a/src/models/tickets/tickets.interface.ts +++ b/src/models/tickets/tickets.interface.ts @@ -10,7 +10,7 @@ * enum: [ACTIVE, UNDONE] * EligibleEvent: * type: object - * required: [eventId, name, startDateTime, location, deadlinePassed, isFull, collectAddress, requireAddress] + * required: [eventId, name, startDateTime, location, redemptionDeadline, deadlinePassed, isFull, collectAddress, requireAddress] * properties: * eventId: * type: integer @@ -23,6 +23,11 @@ * format: date-time * location: * type: string + * redemptionDeadline: + * type: string + * format: date-time + * nullable: true + * description: null when the event has no redemption deadline set * deadlinePassed: * type: boolean * isFull: @@ -224,6 +229,7 @@ export interface EligibleEvent { name: string; startDateTime: Date; location: string; + redemptionDeadline: Date | null; deadlinePassed: boolean; isFull: boolean; spotsRemaining: number | null;