- Ticketed events: full CRUD, ticket tiers (free/paid/donation), Stripe checkout, QR-based check-in scanner, public event pages, ticket confirmation emails - Event formats: IN_PERSON/ONLINE/HYBRID with auto Jitsi meeting room lifecycle, ticket-gated meeting access, moderator JWT tokens, feature-flag guarded - Social engagement: challenges with scoring/leaderboards, referral tracking, volunteer spotlight, impact stories, campaign celebrations, wall of fame - Social calendar: personal calendar layers, shared calendar items with recurrence, scheduling polls, mobile day view - MCP server: events tool pack with full admin CRUD + meeting token generation - Unified calendar: eventFormat-aware tags, online event indicators - Updated docs site, pangolin configs, and various admin UI improvements Bunker Admin
81 lines
3.5 KiB
TypeScript
81 lines
3.5 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
// --- Layer schemas ---
|
|
|
|
export const createLayerSchema = z.object({
|
|
name: z.string().min(1).max(100),
|
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/, 'Color must be a hex color (#RRGGBB)'),
|
|
visibility: z.enum(['PRIVATE', 'FRIENDS', 'PUBLIC']),
|
|
});
|
|
|
|
export const updateLayerSchema = z.object({
|
|
name: z.string().min(1).max(100).optional(),
|
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/, 'Color must be a hex color (#RRGGBB)').optional(),
|
|
visibility: z.enum(['PRIVATE', 'FRIENDS', 'PUBLIC']).optional(),
|
|
isEnabled: z.boolean().optional(),
|
|
sortOrder: z.number().int().min(0).optional(),
|
|
});
|
|
|
|
// --- Item schemas ---
|
|
|
|
const recurrenceRuleSchema = z.object({
|
|
frequency: z.enum(['DAILY', 'WEEKLY', 'BIWEEKLY', 'MONTHLY']),
|
|
daysOfWeek: z.array(z.number().int().min(1).max(7)).optional(), // 1=Mon...7=Sun
|
|
dayOfMonth: z.number().int().min(1).max(31).optional(),
|
|
interval: z.number().int().min(1).max(12).optional(),
|
|
});
|
|
|
|
export const createItemSchema = z.object({
|
|
layerId: z.string().min(1),
|
|
title: z.string().min(1).max(200),
|
|
description: z.string().optional(),
|
|
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be YYYY-MM-DD'),
|
|
startTime: z.string().regex(/^\d{2}:\d{2}$/, 'Start time must be HH:MM'),
|
|
endTime: z.string().regex(/^\d{2}:\d{2}$/, 'End time must be HH:MM'),
|
|
isAllDay: z.boolean().optional(),
|
|
itemType: z.enum(['EVENT', 'TIME_BLOCK', 'REMINDER']),
|
|
location: z.string().optional(),
|
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
visibility: z.enum(['PRIVATE', 'FRIENDS', 'PUBLIC']).optional(),
|
|
busyStatus: z.enum(['BUSY', 'TENTATIVE', 'FREE']).optional(),
|
|
showDetailsTo: z.enum(['NOBODY', 'FRIENDS', 'EVERYONE']).optional(),
|
|
recurrenceRule: recurrenceRuleSchema.optional(),
|
|
recurrenceEnd: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Recurrence end must be YYYY-MM-DD').optional(),
|
|
});
|
|
|
|
export const updateItemSchema = z.object({
|
|
title: z.string().min(1).max(200).optional(),
|
|
description: z.string().nullable().optional(),
|
|
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Date must be YYYY-MM-DD').optional(),
|
|
startTime: z.string().regex(/^\d{2}:\d{2}$/, 'Start time must be HH:MM').optional(),
|
|
endTime: z.string().regex(/^\d{2}:\d{2}$/, 'End time must be HH:MM').optional(),
|
|
isAllDay: z.boolean().optional(),
|
|
itemType: z.enum(['EVENT', 'TIME_BLOCK', 'REMINDER']).optional(),
|
|
location: z.string().nullable().optional(),
|
|
color: z.string().regex(/^#[0-9a-fA-F]{6}$/).nullable().optional(),
|
|
visibility: z.enum(['PRIVATE', 'FRIENDS', 'PUBLIC']).nullable().optional(),
|
|
busyStatus: z.enum(['BUSY', 'TENTATIVE', 'FREE']).optional(),
|
|
showDetailsTo: z.enum(['NOBODY', 'FRIENDS', 'EVERYONE']).optional(),
|
|
recurrenceRule: recurrenceRuleSchema.nullable().optional(),
|
|
recurrenceEnd: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).nullable().optional(),
|
|
});
|
|
|
|
// --- Scope for recurring item edits ---
|
|
|
|
export const seriesEditScopeSchema = z.enum(['THIS_ONLY', 'THIS_AND_FUTURE', 'ALL']);
|
|
|
|
// --- Date range query ---
|
|
|
|
export const dateRangeSchema = z.object({
|
|
startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'startDate must be YYYY-MM-DD'),
|
|
endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'endDate must be YYYY-MM-DD'),
|
|
});
|
|
|
|
// --- Exported types ---
|
|
|
|
export type CreateLayerInput = z.infer<typeof createLayerSchema>;
|
|
export type UpdateLayerInput = z.infer<typeof updateLayerSchema>;
|
|
export type CreateItemInput = z.infer<typeof createItemSchema>;
|
|
export type UpdateItemInput = z.infer<typeof updateItemSchema>;
|
|
export type SeriesEditScope = z.infer<typeof seriesEditScopeSchema>;
|