Add ticket system with QR scanner and PDF generation
- Add ticket validation and check-in API endpoints - Add PDF ticket generation with QR codes (pdfkit) - Add admin QR scanner page with camera support - Add admin site settings page - Update email templates with PDF ticket download link - Add checked_in_by_admin_id field for audit tracking - Update booking success page with ticket download - Various UI improvements to events and booking pages
This commit is contained in:
@@ -86,8 +86,15 @@ export const ticketsApi = {
|
||||
return fetchApi<{ tickets: Ticket[] }>(`/api/tickets?${query}`);
|
||||
},
|
||||
|
||||
// Validate ticket by QR code (for scanner)
|
||||
validate: (code: string, eventId?: string) =>
|
||||
fetchApi<TicketValidationResult>('/api/tickets/validate', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ code, eventId }),
|
||||
}),
|
||||
|
||||
checkin: (id: string) =>
|
||||
fetchApi<{ ticket: Ticket; message: string }>(`/api/tickets/${id}/checkin`, {
|
||||
fetchApi<{ ticket: Ticket & { attendeeName?: string }; event?: { id: string; title: string }; message: string }>(`/api/tickets/${id}/checkin`, {
|
||||
method: 'POST',
|
||||
}),
|
||||
|
||||
@@ -141,6 +148,9 @@ export const ticketsApi = {
|
||||
fetchApi<{ ticketStatus: string; paymentStatus: string; lnbitsStatus?: string; isPaid: boolean }>(
|
||||
`/api/lnbits/status/${ticketId}`
|
||||
),
|
||||
|
||||
// Get PDF download URL (returns the URL, not the PDF itself)
|
||||
getPdfUrl: (id: string) => `${API_BASE}/api/tickets/${id}/pdf`,
|
||||
};
|
||||
|
||||
// Contacts API
|
||||
@@ -413,6 +423,8 @@ export interface Event {
|
||||
titleEs?: string;
|
||||
description: string;
|
||||
descriptionEs?: string;
|
||||
shortDescription?: string;
|
||||
shortDescriptionEs?: string;
|
||||
startDatetime: string;
|
||||
endDatetime?: string;
|
||||
location: string;
|
||||
@@ -441,6 +453,7 @@ export interface Ticket {
|
||||
preferredLanguage?: string;
|
||||
status: 'pending' | 'confirmed' | 'cancelled' | 'checked_in';
|
||||
checkinAt?: string;
|
||||
checkedInByAdminId?: string;
|
||||
qrCode: string;
|
||||
adminNote?: string;
|
||||
createdAt: string;
|
||||
@@ -449,6 +462,29 @@ export interface Ticket {
|
||||
user?: User;
|
||||
}
|
||||
|
||||
export interface TicketValidationResult {
|
||||
valid: boolean;
|
||||
status: 'valid' | 'already_checked_in' | 'pending_payment' | 'cancelled' | 'invalid' | 'wrong_event';
|
||||
canCheckIn: boolean;
|
||||
ticket?: {
|
||||
id: string;
|
||||
qrCode: string;
|
||||
attendeeName: string;
|
||||
attendeeEmail?: string;
|
||||
attendeePhone?: string;
|
||||
status: string;
|
||||
checkinAt?: string;
|
||||
checkedInBy?: string;
|
||||
};
|
||||
event?: {
|
||||
id: string;
|
||||
title: string;
|
||||
startDatetime: string;
|
||||
location: string;
|
||||
};
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface Payment {
|
||||
id: string;
|
||||
ticketId: string;
|
||||
@@ -892,3 +928,42 @@ export const dashboardApi = {
|
||||
unlinkGoogle: () =>
|
||||
fetchApi<{ message: string }>('/api/dashboard/unlink-google', { method: 'POST' }),
|
||||
};
|
||||
|
||||
// ==================== Site Settings API ====================
|
||||
|
||||
export interface SiteSettings {
|
||||
id?: string;
|
||||
timezone: string;
|
||||
siteName: string;
|
||||
siteDescription?: string | null;
|
||||
siteDescriptionEs?: string | null;
|
||||
contactEmail?: string | null;
|
||||
contactPhone?: string | null;
|
||||
facebookUrl?: string | null;
|
||||
instagramUrl?: string | null;
|
||||
twitterUrl?: string | null;
|
||||
linkedinUrl?: string | null;
|
||||
maintenanceMode: boolean;
|
||||
maintenanceMessage?: string | null;
|
||||
maintenanceMessageEs?: string | null;
|
||||
updatedAt?: string;
|
||||
updatedBy?: string;
|
||||
}
|
||||
|
||||
export interface TimezoneOption {
|
||||
value: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export const siteSettingsApi = {
|
||||
get: () => fetchApi<{ settings: SiteSettings }>('/api/site-settings'),
|
||||
|
||||
update: (data: Partial<SiteSettings>) =>
|
||||
fetchApi<{ settings: SiteSettings; message: string }>('/api/site-settings', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
getTimezones: () =>
|
||||
fetchApi<{ timezones: TimezoneOption[] }>('/api/site-settings/timezones'),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user