feat: Add category-specific ride fields

This commit is contained in:
gpt-engineer-app[bot]
2025-10-30 12:24:28 +00:00
parent 5bdab42211
commit 8795e756ce
5 changed files with 909 additions and 0 deletions

View File

@@ -694,6 +694,380 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
</div> </div>
)} )}
{/* Water Ride Specific Fields */}
{selectedCategory === 'water_ride' && (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Water Ride Details</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="space-y-2">
<Label htmlFor="water_depth_cm">Water Depth ({getHeightUnit(measurementSystem)})</Label>
<Input
id="water_depth_cm"
type="number"
min="0"
step="0.1"
{...register('water_depth_cm', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder={measurementSystem === 'imperial' ? 'e.g. 47' : 'e.g. 120'}
/>
</div>
<div className="space-y-2">
<Label htmlFor="splash_height_meters">Splash Height ({getDistanceUnit(measurementSystem)})</Label>
<Input
id="splash_height_meters"
type="number"
min="0"
step="0.1"
{...register('splash_height_meters', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder={measurementSystem === 'imperial' ? 'e.g. 16' : 'e.g. 5'}
/>
</div>
<div className="space-y-2">
<Label>Wetness Level</Label>
<Select onValueChange={(value) => setValue('wetness_level', value as 'dry' | 'light' | 'moderate' | 'soaked')} defaultValue={initialData?.wetness_level}>
<SelectTrigger>
<SelectValue placeholder="Select wetness level" />
</SelectTrigger>
<SelectContent>
<SelectItem value="dry">Dry</SelectItem>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="moderate">Moderate</SelectItem>
<SelectItem value="soaked">Soaked</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="flume_type">Flume Type</Label>
<Input
id="flume_type"
{...register('flume_type')}
placeholder="e.g. Log Flume, Shoot the Chute"
/>
</div>
<div className="space-y-2">
<Label htmlFor="boat_capacity">Boat Capacity</Label>
<Input
id="boat_capacity"
type="number"
min="1"
{...register('boat_capacity', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 8"
/>
</div>
</div>
</div>
)}
{/* Dark Ride Specific Fields */}
{selectedCategory === 'dark_ride' && (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Dark Ride Details</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label htmlFor="theme_name">Theme Name</Label>
<Input
id="theme_name"
{...register('theme_name')}
placeholder="e.g. Haunted Mansion, Pirates"
/>
</div>
<div className="space-y-2">
<Label htmlFor="show_duration_seconds">Show Duration (seconds)</Label>
<Input
id="show_duration_seconds"
type="number"
min="0"
{...register('show_duration_seconds', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 420"
/>
</div>
<div className="space-y-2">
<Label htmlFor="animatronics_count">Animatronics Count</Label>
<Input
id="animatronics_count"
type="number"
min="0"
{...register('animatronics_count', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 15"
/>
</div>
<div className="space-y-2">
<Label htmlFor="projection_type">Projection Type</Label>
<Input
id="projection_type"
{...register('projection_type')}
placeholder="e.g. 3D, 4D, LED, Projection Mapping"
/>
</div>
<div className="space-y-2">
<Label htmlFor="ride_system">Ride System</Label>
<Input
id="ride_system"
{...register('ride_system')}
placeholder="e.g. Omnimover, Dark Coaster, Trackless"
/>
</div>
<div className="space-y-2">
<Label htmlFor="scenes_count">Number of Scenes</Label>
<Input
id="scenes_count"
type="number"
min="0"
{...register('scenes_count', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 12"
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="story_description">Story Description</Label>
<Textarea
id="story_description"
{...register('story_description')}
placeholder="Describe the storyline and narrative..."
rows={3}
/>
</div>
</div>
)}
{/* Flat Ride Specific Fields */}
{selectedCategory === 'flat_ride' && (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Flat Ride Details</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="space-y-2">
<Label>Rotation Type</Label>
<Select onValueChange={(value) => setValue('rotation_type', value as 'horizontal' | 'vertical' | 'multi_axis' | 'pendulum' | 'none')} defaultValue={initialData?.rotation_type}>
<SelectTrigger>
<SelectValue placeholder="Select rotation type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="horizontal">Horizontal</SelectItem>
<SelectItem value="vertical">Vertical</SelectItem>
<SelectItem value="multi_axis">Multi-Axis</SelectItem>
<SelectItem value="pendulum">Pendulum</SelectItem>
<SelectItem value="none">None</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="platform_count">Platform/Gondola Count</Label>
<Input
id="platform_count"
type="number"
min="1"
{...register('platform_count', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 8"
/>
</div>
<div className="space-y-2">
<Label htmlFor="swing_angle_degrees">Swing Angle (degrees)</Label>
<Input
id="swing_angle_degrees"
type="number"
min="0"
max="360"
step="0.1"
{...register('swing_angle_degrees', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder="e.g. 120"
/>
</div>
<div className="space-y-2">
<Label htmlFor="rotation_speed_rpm">Rotation Speed (RPM)</Label>
<Input
id="rotation_speed_rpm"
type="number"
min="0"
step="0.1"
{...register('rotation_speed_rpm', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder="e.g. 12"
/>
</div>
<div className="space-y-2">
<Label htmlFor="arm_length_meters">Arm Length ({getDistanceUnit(measurementSystem)})</Label>
<Input
id="arm_length_meters"
type="number"
min="0"
step="0.1"
{...register('arm_length_meters', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder={measurementSystem === 'imperial' ? 'e.g. 33' : 'e.g. 10'}
/>
</div>
<div className="space-y-2">
<Label htmlFor="max_height_reached_meters">Max Height Reached ({getDistanceUnit(measurementSystem)})</Label>
<Input
id="max_height_reached_meters"
type="number"
min="0"
step="0.1"
{...register('max_height_reached_meters', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder={measurementSystem === 'imperial' ? 'e.g. 98' : 'e.g. 30'}
/>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="motion_pattern">Motion Pattern</Label>
<Input
id="motion_pattern"
{...register('motion_pattern')}
placeholder="e.g. Circular, Wave, Pendulum swing"
/>
</div>
</div>
)}
{/* Kiddie Ride Specific Fields */}
{selectedCategory === 'kiddie_ride' && (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Kiddie Ride Details</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label htmlFor="min_age">Minimum Age</Label>
<Input
id="min_age"
type="number"
min="0"
max="18"
{...register('min_age', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 2"
/>
</div>
<div className="space-y-2">
<Label htmlFor="max_age">Maximum Age</Label>
<Input
id="max_age"
type="number"
min="0"
max="18"
{...register('max_age', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 12"
/>
</div>
<div className="space-y-2">
<Label htmlFor="educational_theme">Educational Theme</Label>
<Input
id="educational_theme"
{...register('educational_theme')}
placeholder="e.g. Learning colors, Numbers"
/>
</div>
<div className="space-y-2">
<Label htmlFor="character_theme">Character Theme</Label>
<Input
id="character_theme"
{...register('character_theme')}
placeholder="e.g. Mickey Mouse, Dinosaurs"
/>
</div>
</div>
</div>
)}
{/* Transportation Ride Specific Fields */}
{selectedCategory === 'transportation' && (
<div className="space-y-4">
<h3 className="text-lg font-semibold">Transportation Ride Details</h3>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="space-y-2">
<Label>Transport Type</Label>
<Select onValueChange={(value) => setValue('transport_type', value as 'train' | 'monorail' | 'skylift' | 'ferry' | 'peoplemover' | 'cable_car')} defaultValue={initialData?.transport_type}>
<SelectTrigger>
<SelectValue placeholder="Select transport type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="train">Train</SelectItem>
<SelectItem value="monorail">Monorail</SelectItem>
<SelectItem value="skylift">Skylift / Chairlift</SelectItem>
<SelectItem value="ferry">Ferry / Boat</SelectItem>
<SelectItem value="peoplemover">PeopleMover</SelectItem>
<SelectItem value="cable_car">Cable Car</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="route_length_meters">Route Length ({getDistanceUnit(measurementSystem)})</Label>
<Input
id="route_length_meters"
type="number"
min="0"
step="0.1"
{...register('route_length_meters', { setValueAs: (v) => v === "" ? undefined : parseFloat(v) })}
placeholder={measurementSystem === 'imperial' ? 'e.g. 3280' : 'e.g. 1000'}
/>
</div>
<div className="space-y-2">
<Label htmlFor="stations_count">Number of Stations</Label>
<Input
id="stations_count"
type="number"
min="2"
{...register('stations_count', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 4"
/>
</div>
<div className="space-y-2">
<Label htmlFor="vehicle_capacity">Vehicle Capacity</Label>
<Input
id="vehicle_capacity"
type="number"
min="1"
{...register('vehicle_capacity', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 40"
/>
</div>
<div className="space-y-2">
<Label htmlFor="vehicles_count">Number of Vehicles</Label>
<Input
id="vehicles_count"
type="number"
min="1"
{...register('vehicles_count', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 6"
/>
</div>
<div className="space-y-2">
<Label htmlFor="round_trip_duration_seconds">Round Trip Duration (seconds)</Label>
<Input
id="round_trip_duration_seconds"
type="number"
min="0"
{...register('round_trip_duration_seconds', { setValueAs: (v) => v === "" ? undefined : parseInt(v) })}
placeholder="e.g. 600"
/>
</div>
</div>
</div>
)}
{/* Technical Specifications */} {/* Technical Specifications */}
<div className="space-y-4"> <div className="space-y-4">
<h3 className="text-lg font-semibold">Technical Specifications</h3> <h3 className="text-lg font-semibold">Technical Specifications</h3>

View File

@@ -2478,6 +2478,162 @@ export type Database = {
}, },
] ]
} }
ride_dark_details: {
Row: {
animatronics_count: number | null
created_at: string | null
effects_type: string[] | null
id: string
interactive: boolean | null
projection_type: string | null
ride_id: string
ride_system: string | null
scenes_count: number | null
show_duration_seconds: number | null
story_description: string | null
theme_name: string | null
updated_at: string | null
}
Insert: {
animatronics_count?: number | null
created_at?: string | null
effects_type?: string[] | null
id?: string
interactive?: boolean | null
projection_type?: string | null
ride_id: string
ride_system?: string | null
scenes_count?: number | null
show_duration_seconds?: number | null
story_description?: string | null
theme_name?: string | null
updated_at?: string | null
}
Update: {
animatronics_count?: number | null
created_at?: string | null
effects_type?: string[] | null
id?: string
interactive?: boolean | null
projection_type?: string | null
ride_id?: string
ride_system?: string | null
scenes_count?: number | null
show_duration_seconds?: number | null
story_description?: string | null
theme_name?: string | null
updated_at?: string | null
}
Relationships: [
{
foreignKeyName: "ride_dark_details_ride_id_fkey"
columns: ["ride_id"]
isOneToOne: true
referencedRelation: "rides"
referencedColumns: ["id"]
},
]
}
ride_flat_details: {
Row: {
arm_length_meters: number | null
created_at: string | null
id: string
max_height_reached_meters: number | null
motion_pattern: string | null
platform_count: number | null
ride_id: string
rotation_speed_rpm: number | null
rotation_type: string | null
spinning: boolean | null
swing_angle_degrees: number | null
updated_at: string | null
}
Insert: {
arm_length_meters?: number | null
created_at?: string | null
id?: string
max_height_reached_meters?: number | null
motion_pattern?: string | null
platform_count?: number | null
ride_id: string
rotation_speed_rpm?: number | null
rotation_type?: string | null
spinning?: boolean | null
swing_angle_degrees?: number | null
updated_at?: string | null
}
Update: {
arm_length_meters?: number | null
created_at?: string | null
id?: string
max_height_reached_meters?: number | null
motion_pattern?: string | null
platform_count?: number | null
ride_id?: string
rotation_speed_rpm?: number | null
rotation_type?: string | null
spinning?: boolean | null
swing_angle_degrees?: number | null
updated_at?: string | null
}
Relationships: [
{
foreignKeyName: "ride_flat_details_ride_id_fkey"
columns: ["ride_id"]
isOneToOne: true
referencedRelation: "rides"
referencedColumns: ["id"]
},
]
}
ride_kiddie_details: {
Row: {
character_theme: string | null
created_at: string | null
educational_theme: string | null
gentle_mode: boolean | null
id: string
max_age: number | null
min_age: number | null
parent_supervision_required: boolean | null
ride_id: string
updated_at: string | null
}
Insert: {
character_theme?: string | null
created_at?: string | null
educational_theme?: string | null
gentle_mode?: boolean | null
id?: string
max_age?: number | null
min_age?: number | null
parent_supervision_required?: boolean | null
ride_id: string
updated_at?: string | null
}
Update: {
character_theme?: string | null
created_at?: string | null
educational_theme?: string | null
gentle_mode?: boolean | null
id?: string
max_age?: number | null
min_age?: number | null
parent_supervision_required?: boolean | null
ride_id?: string
updated_at?: string | null
}
Relationships: [
{
foreignKeyName: "ride_kiddie_details_ride_id_fkey"
columns: ["ride_id"]
isOneToOne: true
referencedRelation: "rides"
referencedColumns: ["id"]
},
]
}
ride_model_submissions: { ride_model_submissions: {
Row: { Row: {
banner_image_id: string | null banner_image_id: string | null
@@ -3066,6 +3222,56 @@ export type Database = {
}, },
] ]
} }
ride_transportation_details: {
Row: {
accessibility_features: string[] | null
created_at: string | null
id: string
ride_id: string
round_trip_duration_seconds: number | null
route_length_meters: number | null
stations_count: number | null
transport_type: string | null
updated_at: string | null
vehicle_capacity: number | null
vehicles_count: number | null
}
Insert: {
accessibility_features?: string[] | null
created_at?: string | null
id?: string
ride_id: string
round_trip_duration_seconds?: number | null
route_length_meters?: number | null
stations_count?: number | null
transport_type?: string | null
updated_at?: string | null
vehicle_capacity?: number | null
vehicles_count?: number | null
}
Update: {
accessibility_features?: string[] | null
created_at?: string | null
id?: string
ride_id?: string
round_trip_duration_seconds?: number | null
route_length_meters?: number | null
stations_count?: number | null
transport_type?: string | null
updated_at?: string | null
vehicle_capacity?: number | null
vehicles_count?: number | null
}
Relationships: [
{
foreignKeyName: "ride_transportation_details_ride_id_fkey"
columns: ["ride_id"]
isOneToOne: true
referencedRelation: "rides"
referencedColumns: ["id"]
},
]
}
ride_versions: { ride_versions: {
Row: { Row: {
angle_degrees: number | null angle_degrees: number | null
@@ -3239,6 +3445,56 @@ export type Database = {
}, },
] ]
} }
ride_water_details: {
Row: {
boat_capacity: number | null
created_at: string | null
flume_type: string | null
id: string
pump_capacity_lph: number | null
ride_id: string
splash_height_meters: number | null
updated_at: string | null
water_depth_cm: number | null
water_volume_liters: number | null
wetness_level: string | null
}
Insert: {
boat_capacity?: number | null
created_at?: string | null
flume_type?: string | null
id?: string
pump_capacity_lph?: number | null
ride_id: string
splash_height_meters?: number | null
updated_at?: string | null
water_depth_cm?: number | null
water_volume_liters?: number | null
wetness_level?: string | null
}
Update: {
boat_capacity?: number | null
created_at?: string | null
flume_type?: string | null
id?: string
pump_capacity_lph?: number | null
ride_id?: string
splash_height_meters?: number | null
updated_at?: string | null
water_depth_cm?: number | null
water_volume_liters?: number | null
wetness_level?: string | null
}
Relationships: [
{
foreignKeyName: "ride_water_details_ride_id_fkey"
columns: ["ride_id"]
isOneToOne: true
referencedRelation: "rides"
referencedColumns: ["id"]
},
]
}
rides: { rides: {
Row: { Row: {
age_requirement: number | null age_requirement: number | null

View File

@@ -134,6 +134,94 @@ export const rideValidationSchema = z.object({
seating_type: z.string().optional(), seating_type: z.string().optional(),
intensity_level: z.string().optional(), intensity_level: z.string().optional(),
track_material: z.enum(['wood', 'steel', 'hybrid', 'aluminum', 'other']).optional(), track_material: z.enum(['wood', 'steel', 'hybrid', 'aluminum', 'other']).optional(),
// Water ride specific fields
water_depth_cm: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Water depth must be positive').max(1000, 'Water depth must be less than 1000cm').optional()
),
splash_height_meters: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Splash height must be positive').max(100, 'Splash height must be less than 100 meters').optional()
),
wetness_level: z.enum(['dry', 'light', 'moderate', 'soaked']).optional(),
flume_type: z.string().trim().max(100, 'Flume type must be less than 100 characters').optional().or(z.literal('')),
boat_capacity: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(1, 'Boat capacity must be positive').max(100, 'Boat capacity must be less than 100').optional()
),
// Dark ride specific fields
theme_name: z.string().trim().max(200, 'Theme name must be less than 200 characters').optional().or(z.literal('')),
story_description: z.string().trim().max(2000, 'Story description must be less than 2000 characters').optional().or(z.literal('')),
show_duration_seconds: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Show duration must be positive').max(7200, 'Show duration must be less than 2 hours').optional()
),
animatronics_count: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Animatronics count must be positive').max(1000, 'Animatronics count must be less than 1000').optional()
),
projection_type: z.string().trim().max(100, 'Projection type must be less than 100 characters').optional().or(z.literal('')),
ride_system: z.string().trim().max(100, 'Ride system must be less than 100 characters').optional().or(z.literal('')),
scenes_count: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Scenes count must be positive').max(100, 'Scenes count must be less than 100').optional()
),
// Flat ride specific fields
rotation_type: z.enum(['horizontal', 'vertical', 'multi_axis', 'pendulum', 'none']).optional(),
motion_pattern: z.string().trim().max(200, 'Motion pattern must be less than 200 characters').optional().or(z.literal('')),
platform_count: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(1, 'Platform count must be positive').max(100, 'Platform count must be less than 100').optional()
),
swing_angle_degrees: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Swing angle must be positive').max(360, 'Swing angle must be less than 360 degrees').optional()
),
rotation_speed_rpm: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Rotation speed must be positive').max(200, 'Rotation speed must be less than 200 RPM').optional()
),
arm_length_meters: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Arm length must be positive').max(100, 'Arm length must be less than 100 meters').optional()
),
max_height_reached_meters: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Max height reached must be positive').max(200, 'Max height reached must be less than 200 meters').optional()
),
// Kiddie ride specific fields
min_age: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Min age must be positive').max(18, 'Min age must be less than 18').optional()
),
max_age: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Max age must be positive').max(18, 'Max age must be less than 18').optional()
),
educational_theme: z.string().trim().max(200, 'Educational theme must be less than 200 characters').optional().or(z.literal('')),
character_theme: z.string().trim().max(200, 'Character theme must be less than 200 characters').optional().or(z.literal('')),
// Transportation ride specific fields
transport_type: z.enum(['train', 'monorail', 'skylift', 'ferry', 'peoplemover', 'cable_car']).optional(),
route_length_meters: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().min(0, 'Route length must be positive').max(50000, 'Route length must be less than 50km').optional()
),
stations_count: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(2, 'Stations count must be at least 2').max(50, 'Stations count must be less than 50').optional()
),
vehicle_capacity: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(1, 'Vehicle capacity must be positive').max(500, 'Vehicle capacity must be less than 500').optional()
),
vehicles_count: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(1, 'Vehicles count must be positive').max(100, 'Vehicles count must be less than 100').optional()
),
round_trip_duration_seconds: z.preprocess(
(val) => val === '' || val === null || val === undefined ? undefined : Number(val),
z.number().int().min(0, 'Round trip duration must be positive').max(7200, 'Round trip duration must be less than 2 hours').optional()
),
banner_image_id: z.string().optional(), banner_image_id: z.string().optional(),
banner_image_url: z.string().optional(), banner_image_url: z.string().optional(),
card_image_id: z.string().optional(), card_image_id: z.string().optional(),

View File

@@ -55,6 +55,42 @@ export interface RideSubmissionData {
coaster_type?: string | null; coaster_type?: string | null;
seating_type?: string | null; seating_type?: string | null;
intensity_level?: string | null; intensity_level?: string | null;
track_material?: string | null;
// Water ride specific
water_depth_cm?: number | null;
splash_height_meters?: number | null;
wetness_level?: string | null;
flume_type?: string | null;
boat_capacity?: number | null;
// Dark ride specific
theme_name?: string | null;
story_description?: string | null;
show_duration_seconds?: number | null;
animatronics_count?: number | null;
projection_type?: string | null;
ride_system?: string | null;
scenes_count?: number | null;
// Flat ride specific
rotation_type?: string | null;
motion_pattern?: string | null;
platform_count?: number | null;
swing_angle_degrees?: number | null;
rotation_speed_rpm?: number | null;
arm_length_meters?: number | null;
max_height_reached_meters?: number | null;
// Kiddie ride specific
min_age?: number | null;
max_age?: number | null;
educational_theme?: string | null;
character_theme?: string | null;
// Transportation ride specific
transport_type?: string | null;
route_length_meters?: number | null;
stations_count?: number | null;
vehicle_capacity?: number | null;
vehicles_count?: number | null;
round_trip_duration_seconds?: number | null;
// Images
banner_image_url?: string | null; banner_image_url?: string | null;
banner_image_id?: string | null; banner_image_id?: string | null;
card_image_url?: string | null; card_image_url?: string | null;

View File

@@ -0,0 +1,155 @@
-- Create category-specific detail tables for rides
-- Water Ride Details Table
CREATE TABLE IF NOT EXISTS public.ride_water_details (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE,
water_depth_cm DECIMAL(10,2),
splash_height_meters DECIMAL(10,2),
wetness_level TEXT CHECK (wetness_level IN ('dry', 'light', 'moderate', 'soaked')),
flume_type TEXT,
boat_capacity INTEGER,
water_volume_liters DECIMAL(15,2),
pump_capacity_lph DECIMAL(15,2),
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(ride_id)
);
-- Dark Ride Details Table
CREATE TABLE IF NOT EXISTS public.ride_dark_details (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE,
theme_name TEXT,
story_description TEXT,
show_duration_seconds INTEGER,
effects_type TEXT[],
animatronics_count INTEGER,
projection_type TEXT,
ride_system TEXT,
scenes_count INTEGER,
interactive BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(ride_id)
);
-- Flat Ride Details Table
CREATE TABLE IF NOT EXISTS public.ride_flat_details (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE,
rotation_type TEXT CHECK (rotation_type IN ('horizontal', 'vertical', 'multi_axis', 'pendulum', 'none')),
motion_pattern TEXT,
platform_count INTEGER,
swing_angle_degrees DECIMAL(10,2),
rotation_speed_rpm DECIMAL(10,2),
arm_length_meters DECIMAL(10,2),
max_height_reached_meters DECIMAL(10,2),
spinning BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(ride_id)
);
-- Kiddie Ride Details Table
CREATE TABLE IF NOT EXISTS public.ride_kiddie_details (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE,
min_age INTEGER,
max_age INTEGER,
parent_supervision_required BOOLEAN DEFAULT false,
educational_theme TEXT,
character_theme TEXT,
gentle_mode BOOLEAN DEFAULT true,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(ride_id)
);
-- Transportation Ride Details Table
CREATE TABLE IF NOT EXISTS public.ride_transportation_details (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
ride_id UUID NOT NULL REFERENCES public.rides(id) ON DELETE CASCADE,
transport_type TEXT CHECK (transport_type IN ('train', 'monorail', 'skylift', 'ferry', 'peoplemover', 'cable_car')),
route_length_meters DECIMAL(10,2),
stations_count INTEGER,
vehicle_capacity INTEGER,
vehicles_count INTEGER,
round_trip_duration_seconds INTEGER,
accessibility_features TEXT[],
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
UNIQUE(ride_id)
);
-- Create indexes for performance
CREATE INDEX IF NOT EXISTS idx_ride_water_details_ride_id ON public.ride_water_details(ride_id);
CREATE INDEX IF NOT EXISTS idx_ride_dark_details_ride_id ON public.ride_dark_details(ride_id);
CREATE INDEX IF NOT EXISTS idx_ride_flat_details_ride_id ON public.ride_flat_details(ride_id);
CREATE INDEX IF NOT EXISTS idx_ride_kiddie_details_ride_id ON public.ride_kiddie_details(ride_id);
CREATE INDEX IF NOT EXISTS idx_ride_transportation_details_ride_id ON public.ride_transportation_details(ride_id);
-- Enable RLS
ALTER TABLE public.ride_water_details ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ride_dark_details ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ride_flat_details ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ride_kiddie_details ENABLE ROW LEVEL SECURITY;
ALTER TABLE public.ride_transportation_details ENABLE ROW LEVEL SECURITY;
-- RLS Policies (read-only for all, write for authenticated)
CREATE POLICY "Water ride details are viewable by everyone"
ON public.ride_water_details FOR SELECT USING (true);
CREATE POLICY "Dark ride details are viewable by everyone"
ON public.ride_dark_details FOR SELECT USING (true);
CREATE POLICY "Flat ride details are viewable by everyone"
ON public.ride_flat_details FOR SELECT USING (true);
CREATE POLICY "Kiddie ride details are viewable by everyone"
ON public.ride_kiddie_details FOR SELECT USING (true);
CREATE POLICY "Transportation ride details are viewable by everyone"
ON public.ride_transportation_details FOR SELECT USING (true);
-- Write policies (moderators only)
CREATE POLICY "Moderators can manage water ride details"
ON public.ride_water_details FOR ALL
USING (public.is_moderator(auth.uid()));
CREATE POLICY "Moderators can manage dark ride details"
ON public.ride_dark_details FOR ALL
USING (public.is_moderator(auth.uid()));
CREATE POLICY "Moderators can manage flat ride details"
ON public.ride_flat_details FOR ALL
USING (public.is_moderator(auth.uid()));
CREATE POLICY "Moderators can manage kiddie ride details"
ON public.ride_kiddie_details FOR ALL
USING (public.is_moderator(auth.uid()));
CREATE POLICY "Moderators can manage transportation ride details"
ON public.ride_transportation_details FOR ALL
USING (public.is_moderator(auth.uid()));
-- Add update triggers
CREATE TRIGGER update_ride_water_details_updated_at
BEFORE UPDATE ON public.ride_water_details
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
CREATE TRIGGER update_ride_dark_details_updated_at
BEFORE UPDATE ON public.ride_dark_details
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
CREATE TRIGGER update_ride_flat_details_updated_at
BEFORE UPDATE ON public.ride_flat_details
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
CREATE TRIGGER update_ride_kiddie_details_updated_at
BEFORE UPDATE ON public.ride_kiddie_details
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
CREATE TRIGGER update_ride_transportation_details_updated_at
BEFORE UPDATE ON public.ride_transportation_details
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();