diff --git a/src/components/admin/RideForm.tsx b/src/components/admin/RideForm.tsx index c10fb74c..e06268bc 100644 --- a/src/components/admin/RideForm.tsx +++ b/src/components/admin/RideForm.tsx @@ -20,6 +20,7 @@ import { FlexibleDateInput, type DatePrecision } from '@/components/ui/flexible- import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Combobox } from '@/components/ui/combobox'; import { SlugField } from '@/components/ui/slug-field'; +import { Checkbox } from '@/components/ui/checkbox'; import { toast } from '@/hooks/use-toast'; import { handleError } from '@/lib/errorHandler'; import { Plus, Zap, Save, X } from 'lucide-react'; @@ -97,6 +98,39 @@ const intensityLevels = [ '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 const STATUS_DISPLAY_TO_DB: Record = { 'Operating': 'operating', @@ -645,24 +679,82 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: -
- - +
+ +

Select all materials used in the track

+
+ {TRACK_MATERIALS.map((material) => ( +
+ { + const current = watch('track_material') || []; + if (checked) { + setValue('track_material', [...current, material.value]); + } else { + setValue('track_material', current.filter((v) => v !== material.value)); + } + }} + /> + +
+ ))} +
+
+ +
+ +

Select all materials used in the supports

+
+ {SUPPORT_MATERIALS.map((material) => ( +
+ { + const current = watch('support_material') || []; + if (checked) { + setValue('support_material', [...current, material.value]); + } else { + setValue('support_material', current.filter((v) => v !== material.value)); + } + }} + /> + +
+ ))} +
+
+ +
+ +

Select all propulsion methods used

+
+ {PROPULSION_METHODS.map((method) => ( +
+ { + const current = watch('propulsion_method') || []; + if (checked) { + setValue('propulsion_method', [...current, method.value]); + } else { + setValue('propulsion_method', current.filter((v) => v !== method.value)); + } + }} + /> + +
+ ))} +
diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index da2e3eb2..262456c5 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -3081,13 +3081,15 @@ export type Database = { opening_date: string | null opening_date_precision: string | null park_id: string | null + propulsion_method: string[] | null ride_model_id: string | null ride_sub_type: string | null seating_type: string | null slug: string status: string submission_id: string - track_material: string | null + support_material: string[] | null + track_material: string[] | null updated_at: string } Insert: { @@ -3120,13 +3122,15 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id?: string | null + propulsion_method?: string[] | null ride_model_id?: string | null ride_sub_type?: string | null seating_type?: string | null slug: string status?: string submission_id: string - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null updated_at?: string } Update: { @@ -3159,13 +3163,15 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id?: string | null + propulsion_method?: string[] | null ride_model_id?: string | null ride_sub_type?: string | null seating_type?: string | null slug?: string status?: string submission_id?: string - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null updated_at?: string } Relationships: [ @@ -3304,12 +3310,14 @@ export type Database = { opening_date: string | null opening_date_precision: string | null park_id: string | null + propulsion_method: string[] | null ride_id: string ride_model_id: string | null slug: string status: string submission_id: string | null - track_material: string | null + support_material: string[] | null + track_material: string[] | null version_id: string version_number: number } @@ -3344,12 +3352,14 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id?: string | null + propulsion_method?: string[] | null ride_id: string ride_model_id?: string | null slug: string status: string submission_id?: string | null - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null version_id?: string version_number: number } @@ -3384,12 +3394,14 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id?: string | null + propulsion_method?: string[] | null ride_id?: string ride_model_id?: string | null slug?: string status?: string submission_id?: string | null - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null version_id?: string version_number?: number } @@ -3527,13 +3539,15 @@ export type Database = { opening_date: string | null opening_date_precision: string | null park_id: string + propulsion_method: string[] | null review_count: number | null ride_model_id: string | null ride_sub_type: string | null seating_type: string | null slug: string status: string - track_material: string | null + support_material: string[] | null + track_material: string[] | null updated_at: string view_count_30d: number | null view_count_7d: number | null @@ -3570,13 +3584,15 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id: string + propulsion_method?: string[] | null review_count?: number | null ride_model_id?: string | null ride_sub_type?: string | null seating_type?: string | null slug: string status?: string - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null updated_at?: string view_count_30d?: number | null view_count_7d?: number | null @@ -3613,13 +3629,15 @@ export type Database = { opening_date?: string | null opening_date_precision?: string | null park_id?: string + propulsion_method?: string[] | null review_count?: number | null ride_model_id?: string | null ride_sub_type?: string | null seating_type?: string | null slug?: string status?: string - track_material?: string | null + support_material?: string[] | null + track_material?: string[] | null updated_at?: string view_count_30d?: number | null view_count_7d?: number | null diff --git a/src/lib/entityTransformers.ts b/src/lib/entityTransformers.ts index 70a09233..d87bcf06 100644 --- a/src/lib/entityTransformers.ts +++ b/src/lib/entityTransformers.ts @@ -76,6 +76,9 @@ export function transformRideData(submissionData: RideSubmissionData): RideInser coaster_type: submissionData.coaster_type || null, seating_type: submissionData.seating_type || 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_id: submissionData.banner_image_id || null, card_image_url: submissionData.card_image_url || null, diff --git a/src/lib/entityValidationSchemas.ts b/src/lib/entityValidationSchemas.ts index 41f9c1b2..37ff6a62 100644 --- a/src/lib/entityValidationSchemas.ts +++ b/src/lib/entityValidationSchemas.ts @@ -133,7 +133,9 @@ export const rideValidationSchema = z.object({ coaster_type: z.string().optional(), seating_type: 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), diff --git a/src/pages/Rides.tsx b/src/pages/Rides.tsx index 0c220cb5..f177356f 100644 --- a/src/pages/Rides.tsx +++ b/src/pages/Rides.tsx @@ -182,7 +182,8 @@ export default function Rides() { // Track material filter 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; } } diff --git a/src/types/database.ts b/src/types/database.ts index db245861..77495d9d 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -166,7 +166,9 @@ export interface Ride { coaster_type?: string; seating_type?: string; intensity_level?: string; - track_material?: string; + track_material?: string[]; + support_material?: string[]; + propulsion_method?: string[]; drop_height_meters?: number; max_g_force?: number; } diff --git a/src/types/submission-data.ts b/src/types/submission-data.ts index 3b224c36..c4d09a4f 100644 --- a/src/types/submission-data.ts +++ b/src/types/submission-data.ts @@ -55,7 +55,9 @@ export interface RideSubmissionData { coaster_type?: string | null; seating_type?: string | null; intensity_level?: string | null; - track_material?: 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; diff --git a/supabase/migrations/20251030123322_734f5091-256e-4104-8f8f-9d7a69fa8540.sql b/supabase/migrations/20251030123322_734f5091-256e-4104-8f8f-9d7a69fa8540.sql new file mode 100644 index 00000000..17b802de --- /dev/null +++ b/supabase/migrations/20251030123322_734f5091-256e-4104-8f8f-9d7a69fa8540.sql @@ -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)'; \ No newline at end of file