mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-22 10:11:13 -05:00
feat: Implement phases 5, 6, and 7
This commit is contained in:
@@ -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 || '',
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
Reference in New Issue
Block a user