Backend and frontend updates: auth, email, payments, events, tickets; carrousel images; mobile event detail layout; i18n

This commit is contained in:
Michilis
2026-02-02 20:58:21 +00:00
parent bafd1425c4
commit 4a84ad22c7
44 changed files with 1323 additions and 472 deletions

View File

@@ -76,6 +76,7 @@ paymentsRouter.get('/', requireAuth(['admin']), async (c) => {
...payment,
ticket: ticket ? {
id: ticket.id,
bookingId: ticket.bookingId,
attendeeFirstName: ticket.attendeeFirstName,
attendeeLastName: ticket.attendeeLastName,
attendeeEmail: ticket.attendeeEmail,
@@ -128,6 +129,7 @@ paymentsRouter.get('/pending-approval', requireAuth(['admin', 'organizer']), asy
...payment,
ticket: ticket ? {
id: ticket.id,
bookingId: ticket.bookingId,
attendeeFirstName: ticket.attendeeFirstName,
attendeeLastName: ticket.attendeeLastName,
attendeeEmail: ticket.attendeeEmail,
@@ -199,17 +201,42 @@ paymentsRouter.put('/:id', requireAuth(['admin', 'organizer']), zValidator('json
updateData.paidByAdminId = user.id;
}
await (db as any)
.update(payments)
.set(updateData)
.where(eq((payments as any).id, id));
// If payment confirmed, update ticket status and send emails
// If payment confirmed, handle multi-ticket booking
if (data.status === 'paid') {
await (db as any)
.update(tickets)
.set({ status: 'confirmed' })
.where(eq((tickets as any).id, existing.ticketId));
// Get the ticket associated with this payment
const ticket = await dbGet<any>(
(db as any)
.select()
.from(tickets)
.where(eq((tickets as any).id, existing.ticketId))
);
// Check if this is part of a multi-ticket booking
let ticketsToConfirm: any[] = [ticket];
if (ticket?.bookingId) {
// Get all tickets in this booking
ticketsToConfirm = await dbAll(
(db as any)
.select()
.from(tickets)
.where(eq((tickets as any).bookingId, ticket.bookingId))
);
console.log(`[Payment] Confirming multi-ticket booking: ${ticket.bookingId}, ${ticketsToConfirm.length} tickets`);
}
// Update all payments and tickets in the booking
for (const t of ticketsToConfirm) {
await (db as any)
.update(payments)
.set(updateData)
.where(eq((payments as any).ticketId, (t as any).id));
await (db as any)
.update(tickets)
.set({ status: 'confirmed' })
.where(eq((tickets as any).id, (t as any).id));
}
// Send confirmation emails asynchronously (don't block the response)
Promise.all([
@@ -218,6 +245,12 @@ paymentsRouter.put('/:id', requireAuth(['admin', 'organizer']), zValidator('json
]).catch(err => {
console.error('[Email] Failed to send confirmation emails:', err);
});
} else {
// For non-paid status updates, just update this payment
await (db as any)
.update(payments)
.set(updateData)
.where(eq((payments as any).id, id));
}
const updated = await dbGet(
@@ -254,23 +287,47 @@ paymentsRouter.post('/:id/approve', requireAuth(['admin', 'organizer']), zValida
const now = getNow();
// Update payment status to paid
await (db as any)
.update(payments)
.set({
status: 'paid',
paidAt: now,
paidByAdminId: user.id,
adminNote: adminNote || payment.adminNote,
updatedAt: now,
})
.where(eq((payments as any).id, id));
// Get the ticket associated with this payment
const ticket = await dbGet<any>(
(db as any)
.select()
.from(tickets)
.where(eq((tickets as any).id, payment.ticketId))
);
// Update ticket status to confirmed
await (db as any)
.update(tickets)
.set({ status: 'confirmed' })
.where(eq((tickets as any).id, payment.ticketId));
// Check if this is part of a multi-ticket booking
let ticketsToConfirm: any[] = [ticket];
if (ticket?.bookingId) {
// Get all tickets in this booking
ticketsToConfirm = await dbAll(
(db as any)
.select()
.from(tickets)
.where(eq((tickets as any).bookingId, ticket.bookingId))
);
console.log(`[Payment] Approving multi-ticket booking: ${ticket.bookingId}, ${ticketsToConfirm.length} tickets`);
}
// Update all payments in the booking to paid
for (const t of ticketsToConfirm) {
await (db as any)
.update(payments)
.set({
status: 'paid',
paidAt: now,
paidByAdminId: user.id,
adminNote: adminNote || payment.adminNote,
updatedAt: now,
})
.where(eq((payments as any).ticketId, (t as any).id));
// Update ticket status to confirmed
await (db as any)
.update(tickets)
.set({ status: 'confirmed' })
.where(eq((tickets as any).id, (t as any).id));
}
// Send confirmation emails asynchronously
Promise.all([
@@ -453,7 +510,7 @@ paymentsRouter.get('/stats/overview', requireAuth(['admin']), async (c) => {
failed: allPayments.filter((p: any) => p.status === 'failed').length,
totalRevenue: allPayments
.filter((p: any) => p.status === 'paid')
.reduce((sum: number, p: any) => sum + (p.amount || 0), 0),
.reduce((sum: number, p: any) => sum + Number(p.amount || 0), 0),
};
return c.json({ stats });