From 8795e756ce24fc08d70bb084175d1320758b9804 Mon Sep 17 00:00:00 2001
From: "gpt-engineer-app[bot]"
<159125892+gpt-engineer-app[bot]@users.noreply.github.com>
Date: Thu, 30 Oct 2025 12:24:28 +0000
Subject: [PATCH] feat: Add category-specific ride fields
---
src/components/admin/RideForm.tsx | 374 ++++++++++++++++++
src/integrations/supabase/types.ts | 256 ++++++++++++
src/lib/entityValidationSchemas.ts | 88 +++++
src/types/submission-data.ts | 36 ++
...6_2ce614d0-ab06-40ba-a4d5-46fef2b3f74d.sql | 155 ++++++++
5 files changed, 909 insertions(+)
create mode 100644 supabase/migrations/20251030122126_2ce614d0-ab06-40ba-a4d5-46fef2b3f74d.sql
diff --git a/src/components/admin/RideForm.tsx b/src/components/admin/RideForm.tsx
index 98350161..c10fb74c 100644
--- a/src/components/admin/RideForm.tsx
+++ b/src/components/admin/RideForm.tsx
@@ -694,6 +694,380 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }:
)}
+ {/* Water Ride Specific Fields */}
+ {selectedCategory === 'water_ride' && (
+
+
Water Ride Details
+
+
+
+ )}
+
+ {/* Dark Ride Specific Fields */}
+ {selectedCategory === 'dark_ride' && (
+
+
Dark Ride Details
+
+
+
+
+
+
+
+
+ )}
+
+ {/* Flat Ride Specific Fields */}
+ {selectedCategory === 'flat_ride' && (
+
+
Flat Ride Details
+
+
+
+
+
+
+
+
+ )}
+
+ {/* Kiddie Ride Specific Fields */}
+ {selectedCategory === 'kiddie_ride' && (
+
+
Kiddie Ride Details
+
+
+
+ )}
+
+ {/* Transportation Ride Specific Fields */}
+ {selectedCategory === 'transportation' && (
+
+
Transportation Ride Details
+
+
+
+ )}
+
{/* Technical Specifications */}
Technical Specifications
diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts
index e27922c0..da2e3eb2 100644
--- a/src/integrations/supabase/types.ts
+++ b/src/integrations/supabase/types.ts
@@ -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: {
Row: {
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: {
Row: {
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: {
Row: {
age_requirement: number | null
diff --git a/src/lib/entityValidationSchemas.ts b/src/lib/entityValidationSchemas.ts
index ce46304f..41f9c1b2 100644
--- a/src/lib/entityValidationSchemas.ts
+++ b/src/lib/entityValidationSchemas.ts
@@ -134,6 +134,94 @@ export const rideValidationSchema = z.object({
seating_type: z.string().optional(),
intensity_level: z.string().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_url: z.string().optional(),
card_image_id: z.string().optional(),
diff --git a/src/types/submission-data.ts b/src/types/submission-data.ts
index f05b6f7a..3b224c36 100644
--- a/src/types/submission-data.ts
+++ b/src/types/submission-data.ts
@@ -55,6 +55,42 @@ export interface RideSubmissionData {
coaster_type?: string | null;
seating_type?: 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_id?: string | null;
card_image_url?: string | null;
diff --git a/supabase/migrations/20251030122126_2ce614d0-ab06-40ba-a4d5-46fef2b3f74d.sql b/supabase/migrations/20251030122126_2ce614d0-ab06-40ba-a4d5-46fef2b3f74d.sql
new file mode 100644
index 00000000..2f0243d8
--- /dev/null
+++ b/supabase/migrations/20251030122126_2ce614d0-ab06-40ba-a4d5-46fef2b3f74d.sql
@@ -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();
\ No newline at end of file