mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-29 07:47:06 -05:00
Compare commits
2 Commits
5bdab42211
...
05217b00d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05217b00d4 | ||
|
|
8795e756ce |
@@ -20,6 +20,7 @@ import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible-
|
|||||||
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
|
||||||
import { Combobox } from '@/components/ui/combobox';
|
import { Combobox } from '@/components/ui/combobox';
|
||||||
import { SlugField } from '@/components/ui/slug-field';
|
import { SlugField } from '@/components/ui/slug-field';
|
||||||
|
import { Checkbox } from '@/components/ui/checkbox';
|
||||||
import { toast } from '@/hooks/use-toast';
|
import { toast } from '@/hooks/use-toast';
|
||||||
import { handleError } from '@/lib/errorHandler';
|
import { handleError } from '@/lib/errorHandler';
|
||||||
import { Plus, Zap, Save, X } from 'lucide-react';
|
import { Plus, Zap, Save, X } from 'lucide-react';
|
||||||
@@ -97,6 +98,39 @@ const intensityLevels = [
|
|||||||
'extreme'
|
'extreme'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const TRACK_MATERIALS = [
|
||||||
|
{ value: 'wood', label: 'Wood' },
|
||||||
|
{ value: 'steel', label: 'Steel' },
|
||||||
|
{ value: 'hybrid', label: 'Hybrid' },
|
||||||
|
{ value: 'aluminum', label: 'Aluminum' },
|
||||||
|
{ value: 'composite', label: 'Composite' },
|
||||||
|
{ value: 'other', label: 'Other' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const SUPPORT_MATERIALS = [
|
||||||
|
{ value: 'steel', label: 'Steel' },
|
||||||
|
{ value: 'wood', label: 'Wood' },
|
||||||
|
{ value: 'concrete', label: 'Concrete' },
|
||||||
|
{ value: 'aluminum', label: 'Aluminum' },
|
||||||
|
{ value: 'composite', label: 'Composite' },
|
||||||
|
{ value: 'other', label: 'Other' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const PROPULSION_METHODS = [
|
||||||
|
{ value: 'chain_lift', label: 'Chain Lift' },
|
||||||
|
{ value: 'cable_lift', label: 'Cable Lift' },
|
||||||
|
{ value: 'friction_wheel_lift', label: 'Friction Wheel Lift' },
|
||||||
|
{ value: 'lsm_launch', label: 'LSM Launch' },
|
||||||
|
{ value: 'lim_launch', label: 'LIM Launch' },
|
||||||
|
{ value: 'hydraulic_launch', label: 'Hydraulic Launch' },
|
||||||
|
{ value: 'compressed_air_launch', label: 'Compressed Air Launch' },
|
||||||
|
{ value: 'flywheel_launch', label: 'Flywheel Launch' },
|
||||||
|
{ value: 'gravity', label: 'Gravity' },
|
||||||
|
{ value: 'tire_drive', label: 'Tire Drive' },
|
||||||
|
{ value: 'water_propulsion', label: 'Water Propulsion' },
|
||||||
|
{ value: 'other', label: 'Other' },
|
||||||
|
];
|
||||||
|
|
||||||
// Status value mappings between display (form) and database values
|
// Status value mappings between display (form) and database values
|
||||||
const STATUS_DISPLAY_TO_DB: Record<string, string> = {
|
const STATUS_DISPLAY_TO_DB: Record<string, string> = {
|
||||||
'Operating': 'operating',
|
'Operating': 'operating',
|
||||||
@@ -645,24 +679,82 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-3">
|
||||||
<Label>Track Material</Label>
|
<Label>Track Material(s)</Label>
|
||||||
<Select
|
<p className="text-sm text-muted-foreground">Select all materials used in the track</p>
|
||||||
onValueChange={(value) => setValue('track_material', value === '' ? undefined : value as 'wood' | 'steel' | 'hybrid' | 'aluminum' | 'other')}
|
<div className="grid grid-cols-2 gap-3">
|
||||||
defaultValue={initialData?.track_material || ''}
|
{TRACK_MATERIALS.map((material) => (
|
||||||
>
|
<div key={material.value} className="flex items-center space-x-2">
|
||||||
<SelectTrigger>
|
<Checkbox
|
||||||
<SelectValue placeholder="Select track material" />
|
id={`track_${material.value}`}
|
||||||
</SelectTrigger>
|
checked={watch('track_material')?.includes(material.value) || false}
|
||||||
<SelectContent>
|
onCheckedChange={(checked) => {
|
||||||
<SelectItem value="">None</SelectItem>
|
const current = watch('track_material') || [];
|
||||||
<SelectItem value="wood">Wood</SelectItem>
|
if (checked) {
|
||||||
<SelectItem value="steel">Steel</SelectItem>
|
setValue('track_material', [...current, material.value]);
|
||||||
<SelectItem value="hybrid">Hybrid (Wood/Steel)</SelectItem>
|
} else {
|
||||||
<SelectItem value="aluminum">Aluminum</SelectItem>
|
setValue('track_material', current.filter((v) => v !== material.value));
|
||||||
<SelectItem value="other">Other</SelectItem>
|
}
|
||||||
</SelectContent>
|
}}
|
||||||
</Select>
|
/>
|
||||||
|
<Label htmlFor={`track_${material.value}`} className="font-normal cursor-pointer">
|
||||||
|
{material.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Label>Support Material(s)</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">Select all materials used in the supports</p>
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
{SUPPORT_MATERIALS.map((material) => (
|
||||||
|
<div key={material.value} className="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
id={`support_${material.value}`}
|
||||||
|
checked={watch('support_material')?.includes(material.value) || false}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
const current = watch('support_material') || [];
|
||||||
|
if (checked) {
|
||||||
|
setValue('support_material', [...current, material.value]);
|
||||||
|
} else {
|
||||||
|
setValue('support_material', current.filter((v) => v !== material.value));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Label htmlFor={`support_${material.value}`} className="font-normal cursor-pointer">
|
||||||
|
{material.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
<Label>Propulsion Method(s)</Label>
|
||||||
|
<p className="text-sm text-muted-foreground">Select all propulsion methods used</p>
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
{PROPULSION_METHODS.map((method) => (
|
||||||
|
<div key={method.value} className="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
id={`propulsion_${method.value}`}
|
||||||
|
checked={watch('propulsion_method')?.includes(method.value) || false}
|
||||||
|
onCheckedChange={(checked) => {
|
||||||
|
const current = watch('propulsion_method') || [];
|
||||||
|
if (checked) {
|
||||||
|
setValue('propulsion_method', [...current, method.value]);
|
||||||
|
} else {
|
||||||
|
setValue('propulsion_method', current.filter((v) => v !== method.value));
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Label htmlFor={`propulsion_${method.value}`} className="font-normal cursor-pointer">
|
||||||
|
{method.label}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -694,6 +786,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>
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -2925,13 +3081,15 @@ export type Database = {
|
|||||||
opening_date: string | null
|
opening_date: string | null
|
||||||
opening_date_precision: string | null
|
opening_date_precision: string | null
|
||||||
park_id: string | null
|
park_id: string | null
|
||||||
|
propulsion_method: string[] | null
|
||||||
ride_model_id: string | null
|
ride_model_id: string | null
|
||||||
ride_sub_type: string | null
|
ride_sub_type: string | null
|
||||||
seating_type: string | null
|
seating_type: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status: string
|
status: string
|
||||||
submission_id: string
|
submission_id: string
|
||||||
track_material: string | null
|
support_material: string[] | null
|
||||||
|
track_material: string[] | null
|
||||||
updated_at: string
|
updated_at: string
|
||||||
}
|
}
|
||||||
Insert: {
|
Insert: {
|
||||||
@@ -2964,13 +3122,15 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id?: string | null
|
park_id?: string | null
|
||||||
|
propulsion_method?: string[] | null
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
ride_sub_type?: string | null
|
ride_sub_type?: string | null
|
||||||
seating_type?: string | null
|
seating_type?: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status?: string
|
status?: string
|
||||||
submission_id: string
|
submission_id: string
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
}
|
}
|
||||||
Update: {
|
Update: {
|
||||||
@@ -3003,13 +3163,15 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id?: string | null
|
park_id?: string | null
|
||||||
|
propulsion_method?: string[] | null
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
ride_sub_type?: string | null
|
ride_sub_type?: string | null
|
||||||
seating_type?: string | null
|
seating_type?: string | null
|
||||||
slug?: string
|
slug?: string
|
||||||
status?: string
|
status?: string
|
||||||
submission_id?: string
|
submission_id?: string
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
}
|
}
|
||||||
Relationships: [
|
Relationships: [
|
||||||
@@ -3066,6 +3228,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
|
||||||
@@ -3098,12 +3310,14 @@ export type Database = {
|
|||||||
opening_date: string | null
|
opening_date: string | null
|
||||||
opening_date_precision: string | null
|
opening_date_precision: string | null
|
||||||
park_id: string | null
|
park_id: string | null
|
||||||
|
propulsion_method: string[] | null
|
||||||
ride_id: string
|
ride_id: string
|
||||||
ride_model_id: string | null
|
ride_model_id: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status: string
|
status: string
|
||||||
submission_id: string | null
|
submission_id: string | null
|
||||||
track_material: string | null
|
support_material: string[] | null
|
||||||
|
track_material: string[] | null
|
||||||
version_id: string
|
version_id: string
|
||||||
version_number: number
|
version_number: number
|
||||||
}
|
}
|
||||||
@@ -3138,12 +3352,14 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id?: string | null
|
park_id?: string | null
|
||||||
|
propulsion_method?: string[] | null
|
||||||
ride_id: string
|
ride_id: string
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status: string
|
status: string
|
||||||
submission_id?: string | null
|
submission_id?: string | null
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
version_id?: string
|
version_id?: string
|
||||||
version_number: number
|
version_number: number
|
||||||
}
|
}
|
||||||
@@ -3178,12 +3394,14 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id?: string | null
|
park_id?: string | null
|
||||||
|
propulsion_method?: string[] | null
|
||||||
ride_id?: string
|
ride_id?: string
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
slug?: string
|
slug?: string
|
||||||
status?: string
|
status?: string
|
||||||
submission_id?: string | null
|
submission_id?: string | null
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
version_id?: string
|
version_id?: string
|
||||||
version_number?: number
|
version_number?: number
|
||||||
}
|
}
|
||||||
@@ -3239,6 +3457,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
|
||||||
@@ -3271,13 +3539,15 @@ export type Database = {
|
|||||||
opening_date: string | null
|
opening_date: string | null
|
||||||
opening_date_precision: string | null
|
opening_date_precision: string | null
|
||||||
park_id: string
|
park_id: string
|
||||||
|
propulsion_method: string[] | null
|
||||||
review_count: number | null
|
review_count: number | null
|
||||||
ride_model_id: string | null
|
ride_model_id: string | null
|
||||||
ride_sub_type: string | null
|
ride_sub_type: string | null
|
||||||
seating_type: string | null
|
seating_type: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status: string
|
status: string
|
||||||
track_material: string | null
|
support_material: string[] | null
|
||||||
|
track_material: string[] | null
|
||||||
updated_at: string
|
updated_at: string
|
||||||
view_count_30d: number | null
|
view_count_30d: number | null
|
||||||
view_count_7d: number | null
|
view_count_7d: number | null
|
||||||
@@ -3314,13 +3584,15 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id: string
|
park_id: string
|
||||||
|
propulsion_method?: string[] | null
|
||||||
review_count?: number | null
|
review_count?: number | null
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
ride_sub_type?: string | null
|
ride_sub_type?: string | null
|
||||||
seating_type?: string | null
|
seating_type?: string | null
|
||||||
slug: string
|
slug: string
|
||||||
status?: string
|
status?: string
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
view_count_30d?: number | null
|
view_count_30d?: number | null
|
||||||
view_count_7d?: number | null
|
view_count_7d?: number | null
|
||||||
@@ -3357,13 +3629,15 @@ export type Database = {
|
|||||||
opening_date?: string | null
|
opening_date?: string | null
|
||||||
opening_date_precision?: string | null
|
opening_date_precision?: string | null
|
||||||
park_id?: string
|
park_id?: string
|
||||||
|
propulsion_method?: string[] | null
|
||||||
review_count?: number | null
|
review_count?: number | null
|
||||||
ride_model_id?: string | null
|
ride_model_id?: string | null
|
||||||
ride_sub_type?: string | null
|
ride_sub_type?: string | null
|
||||||
seating_type?: string | null
|
seating_type?: string | null
|
||||||
slug?: string
|
slug?: string
|
||||||
status?: string
|
status?: string
|
||||||
track_material?: string | null
|
support_material?: string[] | null
|
||||||
|
track_material?: string[] | null
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
view_count_30d?: number | null
|
view_count_30d?: number | null
|
||||||
view_count_7d?: number | null
|
view_count_7d?: number | null
|
||||||
|
|||||||
@@ -76,6 +76,9 @@ export function transformRideData(submissionData: RideSubmissionData): RideInser
|
|||||||
coaster_type: submissionData.coaster_type || null,
|
coaster_type: submissionData.coaster_type || null,
|
||||||
seating_type: submissionData.seating_type || null,
|
seating_type: submissionData.seating_type || null,
|
||||||
intensity_level: submissionData.intensity_level || null,
|
intensity_level: submissionData.intensity_level || null,
|
||||||
|
track_material: submissionData.track_material || null,
|
||||||
|
support_material: submissionData.support_material || null,
|
||||||
|
propulsion_method: submissionData.propulsion_method || null,
|
||||||
banner_image_url: submissionData.banner_image_url || null,
|
banner_image_url: submissionData.banner_image_url || null,
|
||||||
banner_image_id: submissionData.banner_image_id || null,
|
banner_image_id: submissionData.banner_image_id || null,
|
||||||
card_image_url: submissionData.card_image_url || null,
|
card_image_url: submissionData.card_image_url || null,
|
||||||
|
|||||||
@@ -133,7 +133,97 @@ export const rideValidationSchema = z.object({
|
|||||||
coaster_type: z.string().optional(),
|
coaster_type: z.string().optional(),
|
||||||
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.array(z.string()).optional().nullable(),
|
||||||
|
support_material: z.array(z.string()).optional().nullable(),
|
||||||
|
propulsion_method: z.array(z.string()).optional().nullable(),
|
||||||
|
// 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(),
|
||||||
|
|||||||
@@ -182,7 +182,8 @@ export default function Rides() {
|
|||||||
|
|
||||||
// Track material filter
|
// Track material filter
|
||||||
if (filters.trackMaterials.length > 0) {
|
if (filters.trackMaterials.length > 0) {
|
||||||
if (!ride.track_material || !filters.trackMaterials.includes(ride.track_material)) {
|
if (!ride.track_material || ride.track_material.length === 0 ||
|
||||||
|
!ride.track_material.some(material => filters.trackMaterials.includes(material))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,9 @@ export interface Ride {
|
|||||||
coaster_type?: string;
|
coaster_type?: string;
|
||||||
seating_type?: string;
|
seating_type?: string;
|
||||||
intensity_level?: string;
|
intensity_level?: string;
|
||||||
track_material?: string;
|
track_material?: string[];
|
||||||
|
support_material?: string[];
|
||||||
|
propulsion_method?: string[];
|
||||||
drop_height_meters?: number;
|
drop_height_meters?: number;
|
||||||
max_g_force?: number;
|
max_g_force?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,44 @@ 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;
|
||||||
|
support_material?: string[] | null;
|
||||||
|
propulsion_method?: 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;
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
-- Add coaster-specific multi-select fields for track material, support material, and propulsion method
|
||||||
|
|
||||||
|
-- Update rides table
|
||||||
|
ALTER TABLE rides
|
||||||
|
ALTER COLUMN track_material TYPE TEXT[] USING
|
||||||
|
CASE
|
||||||
|
WHEN track_material IS NULL THEN NULL
|
||||||
|
ELSE ARRAY[track_material]
|
||||||
|
END,
|
||||||
|
ADD COLUMN IF NOT EXISTS support_material TEXT[],
|
||||||
|
ADD COLUMN IF NOT EXISTS propulsion_method TEXT[];
|
||||||
|
|
||||||
|
-- Update ride_versions table
|
||||||
|
ALTER TABLE ride_versions
|
||||||
|
ALTER COLUMN track_material TYPE TEXT[] USING
|
||||||
|
CASE
|
||||||
|
WHEN track_material IS NULL THEN NULL
|
||||||
|
ELSE ARRAY[track_material]
|
||||||
|
END,
|
||||||
|
ADD COLUMN IF NOT EXISTS support_material TEXT[],
|
||||||
|
ADD COLUMN IF NOT EXISTS propulsion_method TEXT[];
|
||||||
|
|
||||||
|
-- Update ride_submissions table
|
||||||
|
ALTER TABLE ride_submissions
|
||||||
|
ALTER COLUMN track_material TYPE TEXT[] USING
|
||||||
|
CASE
|
||||||
|
WHEN track_material IS NULL THEN NULL
|
||||||
|
ELSE ARRAY[track_material]
|
||||||
|
END,
|
||||||
|
ADD COLUMN IF NOT EXISTS support_material TEXT[],
|
||||||
|
ADD COLUMN IF NOT EXISTS propulsion_method TEXT[];
|
||||||
|
|
||||||
|
-- Create indexes for efficient filtering
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rides_track_material ON rides USING GIN(track_material);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rides_support_material ON rides USING GIN(support_material);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_rides_propulsion_method ON rides USING GIN(propulsion_method);
|
||||||
|
|
||||||
|
-- Add comments for documentation
|
||||||
|
COMMENT ON COLUMN rides.track_material IS 'Array of track materials used in the ride (e.g., wood, steel, hybrid)';
|
||||||
|
COMMENT ON COLUMN rides.support_material IS 'Array of support materials used in the ride (e.g., steel, wood, concrete)';
|
||||||
|
COMMENT ON COLUMN rides.propulsion_method IS 'Array of propulsion methods used in the ride (e.g., chain_lift, lsm_launch, hydraulic_launch)';
|
||||||
Reference in New Issue
Block a user