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:
Michilis
2026-02-02 00:45:12 +00:00
parent b0cbaa60f0
commit 9410e83b89
28 changed files with 1930 additions and 85 deletions

View File

@@ -74,6 +74,8 @@ async function migrate() {
title_es TEXT,
description TEXT NOT NULL,
description_es TEXT,
short_description TEXT,
short_description_es TEXT,
start_datetime TEXT NOT NULL,
end_datetime TEXT,
location TEXT NOT NULL,
@@ -98,6 +100,14 @@ async function migrate() {
await (db as any).run(sql`ALTER TABLE events ADD COLUMN external_booking_url TEXT`);
} catch (e) { /* column may already exist */ }
// Add short description columns to events
try {
await (db as any).run(sql`ALTER TABLE events ADD COLUMN short_description TEXT`);
} catch (e) { /* column may already exist */ }
try {
await (db as any).run(sql`ALTER TABLE events ADD COLUMN short_description_es TEXT`);
} catch (e) { /* column may already exist */ }
await (db as any).run(sql`
CREATE TABLE IF NOT EXISTS tickets (
id TEXT PRIMARY KEY,
@@ -151,6 +161,11 @@ async function migrate() {
`);
} catch (e) { /* migration may have already run */ }
// Migration: Add checked_in_by_admin_id column to tickets
try {
await (db as any).run(sql`ALTER TABLE tickets ADD COLUMN checked_in_by_admin_id TEXT REFERENCES users(id)`);
} catch (e) { /* column may already exist */ }
// Make attendee_email and attendee_phone nullable (recreate table if needed or just allow nulls for new entries)
// SQLite doesn't support altering column constraints, so we'll just ensure new entries work
@@ -347,6 +362,28 @@ async function migrate() {
updated_at TEXT NOT NULL
)
`);
// Site settings table
await (db as any).run(sql`
CREATE TABLE IF NOT EXISTS site_settings (
id TEXT PRIMARY KEY,
timezone TEXT NOT NULL DEFAULT 'America/Asuncion',
site_name TEXT NOT NULL DEFAULT 'Spanglish',
site_description TEXT,
site_description_es TEXT,
contact_email TEXT,
contact_phone TEXT,
facebook_url TEXT,
instagram_url TEXT,
twitter_url TEXT,
linkedin_url TEXT,
maintenance_mode INTEGER NOT NULL DEFAULT 0,
maintenance_message TEXT,
maintenance_message_es TEXT,
updated_at TEXT NOT NULL,
updated_by TEXT REFERENCES users(id)
)
`);
} else {
// PostgreSQL migrations
await (db as any).execute(sql`
@@ -415,6 +452,8 @@ async function migrate() {
title_es VARCHAR(255),
description TEXT NOT NULL,
description_es TEXT,
short_description VARCHAR(300),
short_description_es VARCHAR(300),
start_datetime TIMESTAMP NOT NULL,
end_datetime TIMESTAMP,
location VARCHAR(500) NOT NULL,
@@ -439,6 +478,14 @@ async function migrate() {
await (db as any).execute(sql`ALTER TABLE events ADD COLUMN external_booking_url VARCHAR(500)`);
} catch (e) { /* column may already exist */ }
// Add short description columns to events
try {
await (db as any).execute(sql`ALTER TABLE events ADD COLUMN short_description VARCHAR(300)`);
} catch (e) { /* column may already exist */ }
try {
await (db as any).execute(sql`ALTER TABLE events ADD COLUMN short_description_es VARCHAR(300)`);
} catch (e) { /* column may already exist */ }
await (db as any).execute(sql`
CREATE TABLE IF NOT EXISTS tickets (
id UUID PRIMARY KEY,
@@ -462,6 +509,11 @@ async function migrate() {
try {
await (db as any).execute(sql`ALTER TABLE tickets ADD COLUMN attendee_ruc VARCHAR(15)`);
} catch (e) { /* column may already exist */ }
// Add checked_in_by_admin_id column to tickets
try {
await (db as any).execute(sql`ALTER TABLE tickets ADD COLUMN checked_in_by_admin_id UUID REFERENCES users(id)`);
} catch (e) { /* column may already exist */ }
await (db as any).execute(sql`
CREATE TABLE IF NOT EXISTS payments (
@@ -642,6 +694,28 @@ async function migrate() {
updated_at TIMESTAMP NOT NULL
)
`);
// Site settings table
await (db as any).execute(sql`
CREATE TABLE IF NOT EXISTS site_settings (
id UUID PRIMARY KEY,
timezone VARCHAR(100) NOT NULL DEFAULT 'America/Asuncion',
site_name VARCHAR(255) NOT NULL DEFAULT 'Spanglish',
site_description TEXT,
site_description_es TEXT,
contact_email VARCHAR(255),
contact_phone VARCHAR(50),
facebook_url VARCHAR(500),
instagram_url VARCHAR(500),
twitter_url VARCHAR(500),
linkedin_url VARCHAR(500),
maintenance_mode INTEGER NOT NULL DEFAULT 0,
maintenance_message TEXT,
maintenance_message_es TEXT,
updated_at TIMESTAMP NOT NULL,
updated_by UUID REFERENCES users(id)
)
`);
}
console.log('Migrations completed successfully!');