Refactor monolithic modules and harden booking, email, and auth infrastructure.

Split oversized frontend API client, email service, and admin/booking pages into focused modules while preserving import surfaces, and add Redis-backed queues, stale booking cleanup, stronger auth, and scale deployment configs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-06-25 07:12:59 +00:00
co-authored by Cursor
parent f0e2de2834
commit 613bd7be1d
75 changed files with 7702 additions and 5580 deletions
@@ -0,0 +1,37 @@
import { useState, useEffect } from 'react';
import toast from 'react-hot-toast';
import { eventsApi, ticketsApi, emailsApi, Event, Ticket, EmailTemplate } from '@/lib/api';
/**
* Loads the core data for the admin event detail page (event, tickets, active
* email templates) and exposes a reload function used after mutations.
*/
export function useEventDetailData(eventId: string) {
const [loading, setLoading] = useState(true);
const [event, setEvent] = useState<Event | null>(null);
const [tickets, setTickets] = useState<Ticket[]>([]);
const [templates, setTemplates] = useState<EmailTemplate[]>([]);
const loadEventData = async () => {
try {
const [eventRes, ticketsRes, templatesRes] = await Promise.all([
eventsApi.getById(eventId),
ticketsApi.getAll({ eventId }),
emailsApi.getTemplates(),
]);
setEvent(eventRes.event);
setTickets(ticketsRes.tickets);
setTemplates(templatesRes.templates.filter(t => t.isActive));
} catch (error) {
toast.error('Failed to load event data');
} finally {
setLoading(false);
}
};
useEffect(() => {
loadEventData();
}, [eventId]);
return { loading, event, tickets, templates, loadEventData };
}
@@ -0,0 +1,96 @@
import { useState } from 'react';
import toast from 'react-hot-toast';
import { paymentOptionsApi, PaymentOptionsConfig } from '@/lib/api';
/**
* Manages the event-level payment override editor state: loading global +
* override config, computing effective values, editing, saving and resetting.
*/
export function usePaymentOverrides(eventId: string, locale: string) {
const [globalPaymentOptions, setGlobalPaymentOptions] = useState<PaymentOptionsConfig | null>(null);
const [paymentOverrides, setPaymentOverrides] = useState<Partial<PaymentOptionsConfig>>({});
const [hasPaymentOverrides, setHasPaymentOverrides] = useState(false);
const [savingPayments, setSavingPayments] = useState(false);
const [loadingPayments, setLoadingPayments] = useState(false);
const loadPaymentOptions = async () => {
if (globalPaymentOptions) return;
setLoadingPayments(true);
try {
const [globalRes, overridesRes] = await Promise.all([
paymentOptionsApi.getGlobal(),
paymentOptionsApi.getEventOverrides(eventId),
]);
setGlobalPaymentOptions(globalRes.paymentOptions);
if (overridesRes.overrides) {
setPaymentOverrides(overridesRes.overrides);
setHasPaymentOverrides(true);
}
} catch (error) {
toast.error('Failed to load payment options');
} finally {
setLoadingPayments(false);
}
};
const getEffectivePaymentOption = <K extends keyof PaymentOptionsConfig>(key: K): PaymentOptionsConfig[K] => {
if (paymentOverrides[key] !== undefined && paymentOverrides[key] !== null) {
return paymentOverrides[key] as PaymentOptionsConfig[K];
}
return globalPaymentOptions?.[key] as PaymentOptionsConfig[K];
};
const updatePaymentOverride = <K extends keyof PaymentOptionsConfig>(
key: K,
value: PaymentOptionsConfig[K] | null
) => {
setPaymentOverrides((prev) => ({ ...prev, [key]: value }));
setHasPaymentOverrides(true);
};
const handleSavePaymentOptions = async () => {
setSavingPayments(true);
try {
await paymentOptionsApi.updateEventOverrides(eventId, paymentOverrides);
toast.success(locale === 'es' ? 'Opciones de pago guardadas' : 'Payment options saved');
} catch (error: any) {
toast.error(error.message || 'Failed to save payment options');
} finally {
setSavingPayments(false);
}
};
const handleResetToGlobal = async () => {
if (!confirm(locale === 'es'
? '¿Resetear a la configuración global? Se eliminarán todas las personalizaciones de este evento.'
: 'Reset to global settings? This will remove all customizations for this event.')) {
return;
}
setSavingPayments(true);
try {
await paymentOptionsApi.deleteEventOverrides(eventId);
setPaymentOverrides({});
setHasPaymentOverrides(false);
toast.success(locale === 'es' ? 'Restablecido a configuración global' : 'Reset to global settings');
} catch (error: any) {
toast.error(error.message || 'Failed to reset payment options');
} finally {
setSavingPayments(false);
}
};
return {
globalPaymentOptions,
paymentOverrides,
hasPaymentOverrides,
savingPayments,
loadingPayments,
loadPaymentOptions,
getEffectivePaymentOption,
updatePaymentOverride,
handleSavePaymentOptions,
handleResetToGlobal,
};
}
export type PaymentOverridesController = ReturnType<typeof usePaymentOverrides>;