refactor: remove obsolete member management API module
This commit is contained in:
@@ -6,6 +6,7 @@ import { authActionClient } from '@kit/next/safe-action';
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
import { getSupabaseServerClient } from '@kit/supabase/server-client';
|
||||
|
||||
import { isEventDomainError } from '../../lib/errors';
|
||||
import {
|
||||
CreateEventSchema,
|
||||
UpdateEventSchema,
|
||||
@@ -22,7 +23,7 @@ export const createEvent = authActionClient
|
||||
const api = createEventManagementApi(client);
|
||||
|
||||
logger.info({ name: 'event.create' }, 'Creating event...');
|
||||
const result = await api.createEvent(input);
|
||||
const result = await api.events.create(input, ctx.user.id);
|
||||
logger.info({ name: 'event.create' }, 'Event created');
|
||||
return { success: true, data: result };
|
||||
});
|
||||
@@ -34,41 +35,62 @@ export const updateEvent = authActionClient
|
||||
const logger = await getLogger();
|
||||
const api = createEventManagementApi(client);
|
||||
|
||||
logger.info({ name: 'event.update' }, 'Updating event...');
|
||||
const result = await api.updateEvent(input);
|
||||
logger.info({ name: 'event.update' }, 'Event updated');
|
||||
return { success: true, data: result };
|
||||
try {
|
||||
logger.info({ name: 'event.update' }, 'Updating event...');
|
||||
const result = await api.events.update(input, ctx.user.id);
|
||||
logger.info({ name: 'event.update' }, 'Event updated');
|
||||
return { success: true, data: result };
|
||||
} catch (e) {
|
||||
if (isEventDomainError(e)) {
|
||||
return { success: false, error: e.message, code: e.code };
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
export const deleteEvent = authActionClient
|
||||
.inputSchema(z.object({ eventId: z.string().uuid() }))
|
||||
.action(async ({ parsedInput: input, ctx }) => {
|
||||
.action(async ({ parsedInput: input }) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const logger = await getLogger();
|
||||
const api = createEventManagementApi(client);
|
||||
|
||||
logger.info({ name: 'event.delete' }, 'Cancelling event...');
|
||||
await api.deleteEvent(input.eventId);
|
||||
logger.info({ name: 'event.delete' }, 'Event cancelled');
|
||||
return { success: true };
|
||||
try {
|
||||
logger.info({ name: 'event.delete' }, 'Cancelling event...');
|
||||
await api.events.softDelete(input.eventId);
|
||||
logger.info({ name: 'event.delete' }, 'Event cancelled');
|
||||
return { success: true };
|
||||
} catch (e) {
|
||||
if (isEventDomainError(e)) {
|
||||
return { success: false, error: e.message, code: e.code };
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
export const registerForEvent = authActionClient
|
||||
.inputSchema(EventRegistrationSchema)
|
||||
.action(async ({ parsedInput: input, ctx }) => {
|
||||
.action(async ({ parsedInput: input }) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const logger = await getLogger();
|
||||
const api = createEventManagementApi(client);
|
||||
|
||||
logger.info({ name: 'event.register' }, 'Registering for event...');
|
||||
const result = await api.registerForEvent(input);
|
||||
logger.info({ name: 'event.register' }, 'Registered for event');
|
||||
return { success: true, data: result };
|
||||
try {
|
||||
logger.info({ name: 'event.register' }, 'Registering for event...');
|
||||
const result = await api.registrations.register(input);
|
||||
logger.info({ name: 'event.register' }, 'Registered for event');
|
||||
return { success: true, data: result };
|
||||
} catch (e) {
|
||||
if (isEventDomainError(e)) {
|
||||
return { success: false, error: e.message, code: e.code };
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
export const createHolidayPass = authActionClient
|
||||
.inputSchema(CreateHolidayPassSchema)
|
||||
.action(async ({ parsedInput: input, ctx }) => {
|
||||
.action(async ({ parsedInput: input }) => {
|
||||
const client = getSupabaseServerClient();
|
||||
const logger = await getLogger();
|
||||
const api = createEventManagementApi(client);
|
||||
@@ -77,7 +99,7 @@ export const createHolidayPass = authActionClient
|
||||
{ name: 'event.createHolidayPass' },
|
||||
'Creating holiday pass...',
|
||||
);
|
||||
const result = await api.createHolidayPass(input);
|
||||
const result = await api.holidayPasses.create(input);
|
||||
logger.info({ name: 'event.createHolidayPass' }, 'Holiday pass created');
|
||||
return { success: true, data: result };
|
||||
});
|
||||
|
||||
@@ -1,232 +1,16 @@
|
||||
import 'server-only';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import type { Database } from '@kit/supabase/database';
|
||||
|
||||
import type {
|
||||
CreateEventInput,
|
||||
UpdateEventInput,
|
||||
} from '../schema/event.schema';
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { createEventCrudService } from './services/event-crud.service';
|
||||
import { createEventRegistrationService } from './services/event-registration.service';
|
||||
import { createHolidayPassService } from './services/holiday-pass.service';
|
||||
|
||||
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,
|
||||
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 updateEvent(input: UpdateEventInput) {
|
||||
const update: Record<string, unknown> = {};
|
||||
if (input.name !== undefined) update.name = input.name;
|
||||
if (input.description !== undefined)
|
||||
update.description = input.description || null;
|
||||
if (input.eventDate !== undefined)
|
||||
update.event_date = input.eventDate || null;
|
||||
if (input.eventTime !== undefined)
|
||||
update.event_time = input.eventTime || null;
|
||||
if (input.endDate !== undefined) update.end_date = input.endDate || null;
|
||||
if (input.location !== undefined)
|
||||
update.location = input.location || null;
|
||||
if (input.capacity !== undefined) update.capacity = input.capacity;
|
||||
if (input.minAge !== undefined) update.min_age = input.minAge ?? null;
|
||||
if (input.maxAge !== undefined) update.max_age = input.maxAge ?? null;
|
||||
if (input.fee !== undefined) update.fee = input.fee;
|
||||
if (input.status !== undefined) update.status = input.status;
|
||||
if (input.registrationDeadline !== undefined)
|
||||
update.registration_deadline = input.registrationDeadline || null;
|
||||
if (input.contactName !== undefined)
|
||||
update.contact_name = input.contactName || null;
|
||||
if (input.contactEmail !== undefined)
|
||||
update.contact_email = input.contactEmail || null;
|
||||
if (input.contactPhone !== undefined)
|
||||
update.contact_phone = input.contactPhone || null;
|
||||
|
||||
const { data, error } = await client
|
||||
.from('events')
|
||||
.update(update)
|
||||
.eq('id', input.eventId)
|
||||
.select()
|
||||
.single();
|
||||
if (error) throw error;
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteEvent(eventId: string) {
|
||||
const { error } = await client
|
||||
.from('events')
|
||||
.update({ status: 'cancelled' })
|
||||
.eq('id', eventId);
|
||||
if (error) throw error;
|
||||
},
|
||||
|
||||
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;
|
||||
},
|
||||
events: createEventCrudService(client),
|
||||
registrations: createEventRegistrationService(client),
|
||||
holidayPasses: createHolidayPassService(client),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
import 'server-only';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import { getLogger } from '@kit/shared/logger';
|
||||
import type { Database } from '@kit/supabase/database';
|
||||
|
||||
import {
|
||||
EventConcurrencyConflictError,
|
||||
EventNotFoundError,
|
||||
InvalidEventStatusTransitionError,
|
||||
} from '../../lib/errors';
|
||||
import {
|
||||
canTransition,
|
||||
validateTransition,
|
||||
getValidTransitions,
|
||||
} from '../../lib/event-status-machine';
|
||||
import type {
|
||||
CreateEventInput,
|
||||
UpdateEventInput,
|
||||
} from '../../schema/event.schema';
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
const NAMESPACE = 'event-crud';
|
||||
|
||||
export function createEventCrudService(client: SupabaseClient<Database>) {
|
||||
return {
|
||||
async list(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 getById(eventId: string) {
|
||||
const { data, error } = await client
|
||||
.from('events')
|
||||
.select('*')
|
||||
.eq('id', eventId)
|
||||
.maybeSingle();
|
||||
if (error) throw error;
|
||||
if (!data) throw new EventNotFoundError(eventId);
|
||||
return data;
|
||||
},
|
||||
|
||||
async getRegistrationCounts(eventIds: string[]) {
|
||||
if (eventIds.length === 0) return {} as Record<string, number>;
|
||||
const { data, error } = await (client.rpc as CallableFunction)(
|
||||
'get_event_registration_counts',
|
||||
{ p_event_ids: eventIds },
|
||||
);
|
||||
if (error) throw error;
|
||||
const counts: Record<string, number> = {};
|
||||
for (const row of (data ?? []) as Array<{
|
||||
event_id: string;
|
||||
registration_count: number;
|
||||
}>) {
|
||||
counts[row.event_id] = Number(row.registration_count);
|
||||
}
|
||||
return counts;
|
||||
},
|
||||
|
||||
async create(input: CreateEventInput, userId?: string) {
|
||||
const logger = await getLogger();
|
||||
logger.info({ name: NAMESPACE }, 'Creating event...');
|
||||
|
||||
const { data, error } = await client
|
||||
.from('events')
|
||||
.insert({
|
||||
account_id: input.accountId,
|
||||
name: input.name,
|
||||
description: input.description || null,
|
||||
event_date: input.eventDate,
|
||||
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,
|
||||
...(userId ? { created_by: userId, updated_by: userId } : {}),
|
||||
} as any)
|
||||
.select()
|
||||
.single();
|
||||
if (error) throw error;
|
||||
return data;
|
||||
},
|
||||
|
||||
async update(input: UpdateEventInput, userId?: string) {
|
||||
const logger = await getLogger();
|
||||
logger.info(
|
||||
{ name: NAMESPACE, eventId: input.eventId },
|
||||
'Updating event...',
|
||||
);
|
||||
|
||||
const update: Record<string, unknown> = {};
|
||||
|
||||
if (input.name !== undefined) update.name = input.name;
|
||||
if (input.description !== undefined)
|
||||
update.description = input.description || null;
|
||||
if (input.eventDate !== undefined)
|
||||
update.event_date = input.eventDate || null;
|
||||
if (input.eventTime !== undefined)
|
||||
update.event_time = input.eventTime || null;
|
||||
if (input.endDate !== undefined) update.end_date = input.endDate || null;
|
||||
if (input.location !== undefined)
|
||||
update.location = input.location || null;
|
||||
if (input.capacity !== undefined) update.capacity = input.capacity;
|
||||
if (input.minAge !== undefined) update.min_age = input.minAge ?? null;
|
||||
if (input.maxAge !== undefined) update.max_age = input.maxAge ?? null;
|
||||
if (input.fee !== undefined) update.fee = input.fee;
|
||||
if (input.registrationDeadline !== undefined)
|
||||
update.registration_deadline = input.registrationDeadline || null;
|
||||
if (input.contactName !== undefined)
|
||||
update.contact_name = input.contactName || null;
|
||||
if (input.contactEmail !== undefined)
|
||||
update.contact_email = input.contactEmail || null;
|
||||
if (input.contactPhone !== undefined)
|
||||
update.contact_phone = input.contactPhone || null;
|
||||
|
||||
// Status machine validation
|
||||
if (input.status !== undefined) {
|
||||
// Fetch current event to validate transition
|
||||
const { data: current, error: fetchError } = await client
|
||||
.from('events')
|
||||
.select('status')
|
||||
.eq('id', input.eventId)
|
||||
.single();
|
||||
if (fetchError) throw fetchError;
|
||||
|
||||
const currentStatus = (current as Record<string, unknown>)
|
||||
.status as string;
|
||||
|
||||
if (currentStatus !== input.status) {
|
||||
try {
|
||||
const sideEffects = validateTransition(
|
||||
currentStatus as Parameters<typeof validateTransition>[0],
|
||||
input.status as Parameters<typeof validateTransition>[1],
|
||||
);
|
||||
Object.assign(update, sideEffects);
|
||||
} catch {
|
||||
throw new InvalidEventStatusTransitionError(
|
||||
currentStatus,
|
||||
input.status,
|
||||
getValidTransitions(
|
||||
currentStatus as Parameters<typeof getValidTransitions>[0],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
update.status = input.status;
|
||||
}
|
||||
|
||||
if (userId) {
|
||||
update.updated_by = userId;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- dynamic fields + future version column
|
||||
let query = client
|
||||
.from('events')
|
||||
.update(update as any)
|
||||
.eq('id', input.eventId);
|
||||
|
||||
// Optimistic locking — version column may be added via migration
|
||||
if (input.version !== undefined) {
|
||||
query = (query as any).eq('version', input.version);
|
||||
}
|
||||
|
||||
const { data, error } = await query.select().single();
|
||||
|
||||
// If version was provided and no rows matched, it's a concurrency conflict
|
||||
if (error && input.version !== undefined) {
|
||||
// PGRST116 = "JSON object requested, multiple (or no) rows returned"
|
||||
if (error.code === 'PGRST116') {
|
||||
throw new EventConcurrencyConflictError();
|
||||
}
|
||||
}
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
async softDelete(eventId: string) {
|
||||
const logger = await getLogger();
|
||||
logger.info({ name: NAMESPACE, eventId }, 'Cancelling event...');
|
||||
|
||||
const { data: current, error: fetchError } = await client
|
||||
.from('events')
|
||||
.select('status')
|
||||
.eq('id', eventId)
|
||||
.maybeSingle();
|
||||
if (fetchError) throw fetchError;
|
||||
if (!current) throw new EventNotFoundError(eventId);
|
||||
|
||||
type EventStatus = Parameters<typeof canTransition>[0];
|
||||
if (!canTransition(current.status as EventStatus, 'cancelled')) {
|
||||
throw new InvalidEventStatusTransitionError(
|
||||
current.status,
|
||||
'cancelled',
|
||||
getValidTransitions(current.status as EventStatus),
|
||||
);
|
||||
}
|
||||
|
||||
const { error } = await client
|
||||
.from('events')
|
||||
.update({ status: 'cancelled' })
|
||||
.eq('id', eventId);
|
||||
if (error) throw error;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import 'server-only';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import type { Database } from '@kit/supabase/database';
|
||||
|
||||
export function createEventRegistrationService(
|
||||
client: SupabaseClient<Database>,
|
||||
) {
|
||||
return {
|
||||
async register(input: {
|
||||
eventId: string;
|
||||
memberId?: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
dateOfBirth?: string;
|
||||
parentName?: string;
|
||||
parentPhone?: string;
|
||||
}) {
|
||||
// RPC function defined in migration; cast to bypass generated types
|
||||
// until `pnpm supabase:web:typegen` is re-run.
|
||||
const { data, error } = await (client.rpc as CallableFunction)(
|
||||
'register_for_event',
|
||||
{
|
||||
p_event_id: input.eventId,
|
||||
p_member_id: input.memberId ?? null,
|
||||
p_first_name: input.firstName,
|
||||
p_last_name: input.lastName,
|
||||
p_email: input.email || null,
|
||||
p_phone: input.phone || null,
|
||||
p_date_of_birth: input.dateOfBirth ?? null,
|
||||
p_parent_name: input.parentName ?? null,
|
||||
p_parent_phone: input.parentPhone ?? null,
|
||||
},
|
||||
);
|
||||
if (error) throw error;
|
||||
return data;
|
||||
},
|
||||
|
||||
async cancel(registrationId: string) {
|
||||
const { data, error } = await (client.rpc as CallableFunction)(
|
||||
'cancel_event_registration',
|
||||
{ p_registration_id: registrationId },
|
||||
);
|
||||
if (error) throw error;
|
||||
return data as {
|
||||
cancelled_id: string;
|
||||
promoted_id: string | null;
|
||||
promoted_name: string | null;
|
||||
};
|
||||
},
|
||||
|
||||
async list(eventId: string) {
|
||||
const { data, error } = await client
|
||||
.from('event_registrations')
|
||||
.select('*')
|
||||
.eq('event_id', eventId)
|
||||
.order('created_at');
|
||||
if (error) throw error;
|
||||
return data ?? [];
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import 'server-only';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import type { Database } from '@kit/supabase/database';
|
||||
|
||||
export function createHolidayPassService(client: SupabaseClient<Database>) {
|
||||
return {
|
||||
async list(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 getActivities(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 create(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;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'server-only';
|
||||
import type { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import type { Database } from '@kit/supabase/database';
|
||||
|
||||
import { createEventCrudService } from './event-crud.service';
|
||||
import { createEventRegistrationService } from './event-registration.service';
|
||||
import { createHolidayPassService } from './holiday-pass.service';
|
||||
|
||||
export {
|
||||
createEventCrudService,
|
||||
createEventRegistrationService,
|
||||
createHolidayPassService,
|
||||
};
|
||||
|
||||
export function createEventServices(client: SupabaseClient<Database>) {
|
||||
return {
|
||||
events: createEventCrudService(client),
|
||||
registrations: createEventRegistrationService(client),
|
||||
holidayPasses: createHolidayPassService(client),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user