feat: Implement composite submission system

This commit is contained in:
gpt-engineer-app[bot]
2025-11-02 19:51:20 +00:00
parent 0f742f36b6
commit 3c6d6a3bdf
5 changed files with 422 additions and 11 deletions

View File

@@ -46,8 +46,24 @@ export const parkValidationSchema = z.object({
if (!val || val === '') return true;
return z.string().email().safeParse(val).success;
}, 'Invalid email format'),
operator_id: z.string().uuid().optional().nullable().or(z.literal('')).transform(val => val || undefined),
property_owner_id: z.string().uuid().optional().nullable().or(z.literal('')).transform(val => val || undefined),
operator_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional()
.nullable()
.or(z.literal(''))
.transform(val => val || undefined),
property_owner_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional()
.nullable()
.or(z.literal(''))
.transform(val => val || undefined),
banner_image_id: z.string().optional(),
banner_image_url: z.string().optional(),
card_image_id: z.string().optional(),
@@ -83,7 +99,13 @@ export const rideValidationSchema = z.object({
ride_sub_type: z.string().trim().max(100, 'Sub type must be less than 100 characters').optional().or(z.literal('')),
status: z.enum(['operating', 'closed_permanently', 'closed_temporarily', 'under_construction', 'relocated', 'stored', 'demolished']),
park_id: z.string().uuid().optional().nullable(),
designer_id: z.string().uuid().optional().nullable(),
designer_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional()
.nullable(),
opening_date: z.string().optional().or(z.literal('')),
opening_date_precision: z.enum(['day', 'month', 'year']).optional(),
closing_date: z.string().optional().or(z.literal('')),
@@ -128,8 +150,20 @@ export const rideValidationSchema = z.object({
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(-10, 'G-force must be greater than -10').max(10, 'G-force must be less than 10').optional()
),
manufacturer_id: z.string().uuid().optional().nullable(),
ride_model_id: z.string().uuid().optional().nullable(),
manufacturer_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional()
.nullable(),
ride_model_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional()
.nullable(),
coaster_type: z.string().optional(),
seating_type: z.string().optional(),
intensity_level: z.string().optional(),
@@ -285,7 +319,12 @@ export const rideModelValidationSchema = z.object({
category: z.string().min(1, 'Category is required'),
ride_type: z.string().trim().min(1, 'Ride type is required').max(100, 'Ride type must be less than 100 characters'),
description: z.string().trim().max(2000, 'Description must be less than 2000 characters').optional().or(z.literal('')),
manufacturer_id: z.string().uuid('Invalid manufacturer ID').optional(),
manufacturer_id: z.string()
.refine(
val => !val || val === '' || val.startsWith('temp-') || /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(val),
'Must be a valid UUID or temporary placeholder'
)
.optional(),
source_url: z.string().trim().optional().or(z.literal('')).refine((val) => {
if (!val || val === '') return true;
return z.string().url().safeParse(val).success;