feat: Implement phases 5, 6, and 7

This commit is contained in:
gpt-engineer-app[bot]
2025-10-09 18:52:38 +00:00
parent f8232e4555
commit 8c5cf40ccb
5 changed files with 13 additions and 139 deletions

View File

@@ -1,6 +1,7 @@
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { entitySchemas } from '@/lib/entityValidationSchemas';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
@@ -14,37 +15,7 @@ import { useCompanyHeadquarters } from '@/hooks/useAutocompleteData';
import { useUserRole } from '@/hooks/useUserRole';
import { EntityMultiImageUploader, ImageAssignments } from '@/components/upload/EntityMultiImageUploader';
const designerSchema = z.object({
name: z.string().min(1, 'Name is required'),
slug: z.string().min(1, 'Slug is required'),
description: z.string().optional(),
person_type: z.enum(['company', 'individual', 'firm', 'organization']),
website_url: z.string().url().optional().or(z.literal('')),
founded_year: z.string()
.optional()
.transform(val => {
if (!val || val.trim() === '') return undefined;
const num = Number(val);
return isNaN(num) ? undefined : num;
})
.refine(val => val === undefined || (typeof val === 'number' && val >= 1800 && val <= new Date().getFullYear()), {
message: "Founded year must be between 1800 and current year"
}),
headquarters_location: z.string().optional(),
images: z.object({
uploaded: z.array(z.object({
url: z.string(),
cloudflare_id: z.string().optional(),
file: z.any().optional(),
isLocal: z.boolean().optional(),
caption: z.string().optional()
})),
banner_assignment: z.number().nullable().optional(),
card_assignment: z.number().nullable().optional()
}).optional()
});
type DesignerFormData = z.infer<typeof designerSchema>;
type DesignerFormData = z.infer<typeof entitySchemas.designer>;
// Input type for the form (before transformation)
type DesignerFormInput = {
@@ -89,7 +60,7 @@ export function DesignerForm({ onSubmit, onCancel, initialData }: DesignerFormPr
watch,
formState: { errors }
} = useForm<DesignerFormInput>({
resolver: zodResolver(designerSchema),
resolver: zodResolver(entitySchemas.designer),
defaultValues: {
name: initialData?.name || '',
slug: initialData?.slug || '',

View File

@@ -1,6 +1,7 @@
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { entitySchemas } from '@/lib/entityValidationSchemas';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
@@ -14,37 +15,7 @@ import { useCompanyHeadquarters } from '@/hooks/useAutocompleteData';
import { useUserRole } from '@/hooks/useUserRole';
import { EntityMultiImageUploader, ImageAssignments } from '@/components/upload/EntityMultiImageUploader';
const manufacturerSchema = z.object({
name: z.string().min(1, 'Name is required'),
slug: z.string().min(1, 'Slug is required'),
description: z.string().optional(),
person_type: z.enum(['company', 'individual', 'firm', 'organization']),
website_url: z.string().url().optional().or(z.literal('')),
founded_year: z.string()
.optional()
.transform(val => {
if (!val || val.trim() === '') return undefined;
const num = Number(val);
return isNaN(num) ? undefined : num;
})
.refine(val => val === undefined || (typeof val === 'number' && val >= 1800 && val <= new Date().getFullYear()), {
message: "Founded year must be between 1800 and current year"
}),
headquarters_location: z.string().optional(),
images: z.object({
uploaded: z.array(z.object({
url: z.string(),
cloudflare_id: z.string().optional(),
file: z.any().optional(),
isLocal: z.boolean().optional(),
caption: z.string().optional()
})),
banner_assignment: z.number().nullable().optional(),
card_assignment: z.number().nullable().optional()
}).optional()
});
type ManufacturerFormData = z.infer<typeof manufacturerSchema>;
type ManufacturerFormData = z.infer<typeof entitySchemas.manufacturer>;
// Input type for the form (before transformation)
type ManufacturerFormInput = {
@@ -89,7 +60,7 @@ export function ManufacturerForm({ onSubmit, onCancel, initialData }: Manufactur
watch,
formState: { errors }
} = useForm<ManufacturerFormInput>({
resolver: zodResolver(manufacturerSchema),
resolver: zodResolver(entitySchemas.manufacturer),
defaultValues: {
name: initialData?.name || '',
slug: initialData?.slug || '',

View File

@@ -1,6 +1,7 @@
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { entitySchemas } from '@/lib/entityValidationSchemas';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
@@ -14,37 +15,7 @@ import { useCompanyHeadquarters } from '@/hooks/useAutocompleteData';
import { useUserRole } from '@/hooks/useUserRole';
import { EntityMultiImageUploader, ImageAssignments } from '@/components/upload/EntityMultiImageUploader';
const operatorSchema = z.object({
name: z.string().min(1, 'Name is required'),
slug: z.string().min(1, 'Slug is required'),
description: z.string().optional(),
person_type: z.enum(['company', 'individual', 'firm', 'organization']),
website_url: z.string().url().optional().or(z.literal('')),
founded_year: z.string()
.optional()
.transform(val => {
if (!val || val.trim() === '') return undefined;
const num = Number(val);
return isNaN(num) ? undefined : num;
})
.refine(val => val === undefined || (typeof val === 'number' && val >= 1800 && val <= new Date().getFullYear()), {
message: "Founded year must be between 1800 and current year"
}),
headquarters_location: z.string().optional(),
images: z.object({
uploaded: z.array(z.object({
url: z.string(),
cloudflare_id: z.string().optional(),
file: z.any().optional(),
isLocal: z.boolean().optional(),
caption: z.string().optional()
})),
banner_assignment: z.number().nullable().optional(),
card_assignment: z.number().nullable().optional()
}).optional()
});
type OperatorFormData = z.infer<typeof operatorSchema>;
type OperatorFormData = z.infer<typeof entitySchemas.operator>;
// Input type for the form (before transformation)
type OperatorFormInput = {
@@ -89,7 +60,7 @@ export function OperatorForm({ onSubmit, onCancel, initialData }: OperatorFormPr
watch,
formState: { errors }
} = useForm<OperatorFormInput>({
resolver: zodResolver(operatorSchema),
resolver: zodResolver(entitySchemas.operator),
defaultValues: {
name: initialData?.name || '',
slug: initialData?.slug || '',

View File

@@ -128,7 +128,7 @@ export function ParkForm({ onSubmit, onCancel, initialData, isEditing = false }:
watch,
formState: { errors }
} = useForm<ParkFormData>({
resolver: zodResolver(parkSchema),
resolver: zodResolver(entitySchemas.park),
defaultValues: {
name: initialData?.name || '',
slug: initialData?.slug || '',

View File

@@ -3,6 +3,7 @@ import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import * as z from 'zod';
import { validateSubmissionHandler } from '@/lib/entityFormValidation';
import { entitySchemas } from '@/lib/entityValidationSchemas';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
@@ -34,47 +35,7 @@ import {
getHeightUnit
} from '@/lib/units';
const rideSchema = z.object({
name: z.string().min(1, 'Ride name is required'),
slug: z.string().min(1, 'Slug is required'),
description: z.string().optional(),
category: z.string().min(1, 'Category is required'),
ride_sub_type: z.string().optional(),
status: z.string().min(1, 'Status is required'),
opening_date: z.string().optional(),
closing_date: z.string().optional(),
height_requirement: z.number().optional(),
age_requirement: z.number().optional(),
capacity_per_hour: z.number().optional(),
duration_seconds: z.number().optional(),
max_speed_kmh: z.number().optional(),
max_height_meters: z.number().optional(),
length_meters: z.number().optional(),
inversions: z.number().optional(),
// New roller coaster specific fields
coaster_type: z.string().optional(),
seating_type: z.string().optional(),
intensity_level: z.string().optional(),
drop_height_meters: z.number().optional(),
max_g_force: z.number().optional(),
// Manufacturer and model
manufacturer_id: z.string().uuid().optional(),
ride_model_id: z.string().uuid().optional(),
// Images
images: z.object({
uploaded: z.array(z.object({
url: z.string(),
cloudflare_id: z.string().optional(),
file: z.any().optional(),
isLocal: z.boolean().optional(),
caption: z.string().optional(),
})),
banner_assignment: z.number().nullable().optional(),
card_assignment: z.number().nullable().optional(),
}).optional()
});
type RideFormData = z.infer<typeof rideSchema>;
type RideFormData = z.infer<typeof entitySchemas.ride>;
interface RideFormProps {
onSubmit: (data: RideFormData) => Promise<void>;
@@ -186,7 +147,7 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
watch,
formState: { errors }
} = useForm<RideFormData>({
resolver: zodResolver(rideSchema),
resolver: zodResolver(entitySchemas.ride),
defaultValues: {
name: initialData?.name || '',
slug: initialData?.slug || '',