Course and event creation Server Actions were failing with 'Something went
wrong' because empty form strings ('') were being inserted into date/uuid
columns which reject empty strings. Now converts '' to null for all
optional fields (dates, descriptions, IDs, contact info).
113 lines
4.7 KiB
TypeScript
113 lines
4.7 KiB
TypeScript
import type { Database } from '@kit/supabase/database';
|
|
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
|
|
import type { CreateEventInput } from '../schema/event.schema';
|
|
|
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
|
|
export function createEventManagementApi(client: SupabaseClient<Database>) {
|
|
const PAGE_SIZE = 25;
|
|
const db = client;
|
|
|
|
return {
|
|
async listEvents(accountId: string, opts?: { status?: string; page?: number }) {
|
|
let query = client.from('events').select('*', { count: 'exact' })
|
|
.eq('account_id', accountId).order('event_date', { ascending: false });
|
|
if (opts?.status) query = query.eq('status', opts.status);
|
|
const page = opts?.page ?? 1;
|
|
query = query.range((page - 1) * PAGE_SIZE, page * PAGE_SIZE - 1);
|
|
const { data, error, count } = await query;
|
|
if (error) throw error;
|
|
const total = count ?? 0;
|
|
return { data: data ?? [], total, page, pageSize: PAGE_SIZE, totalPages: Math.max(1, Math.ceil(total / PAGE_SIZE)) };
|
|
},
|
|
|
|
async getRegistrationCounts(eventIds: string[]) {
|
|
if (eventIds.length === 0) return {} as Record<string, number>;
|
|
const { data, error } = await client
|
|
.from('event_registrations')
|
|
.select('event_id', { count: 'exact', head: false })
|
|
.in('event_id', eventIds)
|
|
.in('status', ['pending', 'confirmed']);
|
|
if (error) throw error;
|
|
|
|
const counts: Record<string, number> = {};
|
|
for (const row of data ?? []) {
|
|
const eid = (row as Record<string, unknown>).event_id as string;
|
|
counts[eid] = (counts[eid] ?? 0) + 1;
|
|
}
|
|
return counts;
|
|
},
|
|
|
|
async getEvent(eventId: string) {
|
|
const { data, error } = await client.from('events').select('*').eq('id', eventId).single();
|
|
if (error) throw error;
|
|
return data;
|
|
},
|
|
|
|
async createEvent(input: CreateEventInput) {
|
|
const { data, error } = await client.from('events').insert({
|
|
account_id: input.accountId, name: input.name, description: input.description || null,
|
|
event_date: input.eventDate || null, event_time: input.eventTime || null, end_date: input.endDate || null,
|
|
location: input.location || null, capacity: input.capacity, min_age: input.minAge ?? null,
|
|
max_age: input.maxAge ?? null, fee: input.fee, status: input.status,
|
|
registration_deadline: input.registrationDeadline || null,
|
|
contact_name: input.contactName || null, contact_email: input.contactEmail || null, contact_phone: input.contactPhone || null,
|
|
}).select().single();
|
|
if (error) throw error;
|
|
return data;
|
|
},
|
|
|
|
async registerForEvent(input: { eventId: string; firstName: string; lastName: string; email?: string; parentName?: string }) {
|
|
// Check capacity
|
|
const event = await this.getEvent(input.eventId);
|
|
if (event.capacity) {
|
|
const { count } = await client.from('event_registrations').select('*', { count: 'exact', head: true })
|
|
.eq('event_id', input.eventId).in('status', ['pending', 'confirmed']);
|
|
if ((count ?? 0) >= event.capacity) {
|
|
throw new Error('Event is full');
|
|
}
|
|
}
|
|
|
|
const { data, error } = await client.from('event_registrations').insert({
|
|
event_id: input.eventId, first_name: input.firstName, last_name: input.lastName,
|
|
email: input.email, parent_name: input.parentName, status: 'confirmed',
|
|
}).select().single();
|
|
if (error) throw error;
|
|
return data;
|
|
},
|
|
|
|
async getRegistrations(eventId: string) {
|
|
const { data, error } = await client.from('event_registrations').select('*')
|
|
.eq('event_id', eventId).order('created_at');
|
|
if (error) throw error;
|
|
return data ?? [];
|
|
},
|
|
|
|
// Holiday passes
|
|
async listHolidayPasses(accountId: string) {
|
|
const { data, error } = await client.from('holiday_passes').select('*')
|
|
.eq('account_id', accountId).order('year', { ascending: false });
|
|
if (error) throw error;
|
|
return data ?? [];
|
|
},
|
|
|
|
async getPassActivities(passId: string) {
|
|
const { data, error } = await client.from('holiday_pass_activities').select('*')
|
|
.eq('pass_id', passId).order('activity_date');
|
|
if (error) throw error;
|
|
return data ?? [];
|
|
},
|
|
|
|
async createHolidayPass(input: { accountId: string; name: string; year: number; description?: string; price?: number; validFrom?: string; validUntil?: string }) {
|
|
const { data, error } = await client.from('holiday_passes').insert({
|
|
account_id: input.accountId, name: input.name, year: input.year,
|
|
description: input.description, price: input.price ?? 0,
|
|
valid_from: input.validFrom, valid_until: input.validUntil,
|
|
}).select().single();
|
|
if (error) throw error;
|
|
return data;
|
|
},
|
|
};
|
|
}
|