Initial state for GitNexus analysis
This commit is contained in:
34
packages/features/event-management/package.json
Normal file
34
packages/features/event-management/package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "@kit/event-management",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"*": [
|
||||
"src/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
"./api": "./src/server/api.ts",
|
||||
"./schema/*": "./src/schema/*.ts",
|
||||
"./components": "./src/components/index.ts"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "git clean -xdf .turbo node_modules",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kit/next": "workspace:*",
|
||||
"@kit/shared": "workspace:*",
|
||||
"@kit/supabase": "workspace:*",
|
||||
"@kit/tsconfig": "workspace:*",
|
||||
"@kit/ui": "workspace:*",
|
||||
"@supabase/supabase-js": "catalog:",
|
||||
"@types/react": "catalog:",
|
||||
"next": "catalog:",
|
||||
"next-safe-action": "catalog:",
|
||||
"react": "catalog:",
|
||||
"zod": "catalog:"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1,44 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const EventStatusEnum = z.enum(['planned', 'open', 'full', 'running', 'completed', 'cancelled']);
|
||||
|
||||
export const CreateEventSchema = z.object({
|
||||
accountId: z.string().uuid(),
|
||||
name: z.string().min(1).max(256),
|
||||
description: z.string().optional(),
|
||||
eventDate: z.string(),
|
||||
eventTime: z.string().optional(),
|
||||
endDate: z.string().optional(),
|
||||
location: z.string().optional(),
|
||||
capacity: z.number().int().optional(),
|
||||
minAge: z.number().int().optional(),
|
||||
maxAge: z.number().int().optional(),
|
||||
fee: z.number().min(0).default(0),
|
||||
status: EventStatusEnum.default('planned'),
|
||||
registrationDeadline: z.string().optional(),
|
||||
contactName: z.string().optional(),
|
||||
contactEmail: z.string().email().optional().or(z.literal('')),
|
||||
contactPhone: z.string().optional(),
|
||||
});
|
||||
export type CreateEventInput = z.infer<typeof CreateEventSchema>;
|
||||
|
||||
export const EventRegistrationSchema = z.object({
|
||||
eventId: z.string().uuid(),
|
||||
firstName: z.string().min(1),
|
||||
lastName: z.string().min(1),
|
||||
email: z.string().email().optional().or(z.literal('')),
|
||||
phone: z.string().optional(),
|
||||
dateOfBirth: z.string().optional(),
|
||||
parentName: z.string().optional(),
|
||||
parentPhone: z.string().optional(),
|
||||
});
|
||||
|
||||
export const CreateHolidayPassSchema = z.object({
|
||||
accountId: z.string().uuid(),
|
||||
name: z.string().min(1),
|
||||
year: z.number().int(),
|
||||
description: z.string().optional(),
|
||||
price: z.number().min(0).default(0),
|
||||
validFrom: z.string().optional(),
|
||||
validUntil: z.string().optional(),
|
||||
});
|
||||
83
packages/features/event-management/src/server/api.ts
Normal file
83
packages/features/event-management/src/server/api.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
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 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) * 25, page * 25 - 1);
|
||||
const { data, error, count } = await query;
|
||||
if (error) throw error;
|
||||
return { data: data ?? [], total: count ?? 0 };
|
||||
},
|
||||
|
||||
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,
|
||||
event_date: input.eventDate, event_time: input.eventTime, end_date: input.endDate,
|
||||
location: input.location, capacity: input.capacity, min_age: input.minAge,
|
||||
max_age: input.maxAge, fee: input.fee, status: input.status,
|
||||
registration_deadline: input.registrationDeadline,
|
||||
contact_name: input.contactName, contact_email: input.contactEmail, contact_phone: input.contactPhone,
|
||||
}).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 ?? [];
|
||||
},
|
||||
};
|
||||
}
|
||||
6
packages/features/event-management/tsconfig.json
Normal file
6
packages/features/event-management/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "@kit/tsconfig/base.json",
|
||||
"compilerOptions": { "tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json" },
|
||||
"include": ["*.ts", "*.tsx", "src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user