From ec664a166972308dd5ec73a18c75517f900938dd Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Sun, 28 Sep 2025 21:15:23 +0000 Subject: [PATCH] Refactor profile stats calculation --- src/components/admin/RideForm.tsx | 130 +++++++++++++++++- src/integrations/supabase/types.ts | 18 +++ src/pages/RideDetail.tsx | 76 ++++++++++ src/types/database.ts | 7 + ...2_3c3b516b-2302-4610-8d3d-65aa161d969b.sql | 21 +++ 5 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 supabase/migrations/20250928211232_3c3b516b-2302-4610-8d3d-65aa161d969b.sql diff --git a/src/components/admin/RideForm.tsx b/src/components/admin/RideForm.tsx index 2c688144..79d728fd 100644 --- a/src/components/admin/RideForm.tsx +++ b/src/components/admin/RideForm.tsx @@ -28,7 +28,16 @@ const rideSchema = z.object({ max_speed_kmh: z.number().optional(), max_height_meters: z.number().optional(), length_meters: z.number().optional(), - inversions: z.number().optional() + inversions: z.number().optional(), + // New roller coaster specific fields + coaster_type: z.string().optional(), + seating_type: z.string().optional(), + intensity_level: z.string().optional(), + drop_height_meters: z.number().optional(), + max_g_force: z.number().optional(), + former_names: z.string().optional(), + coaster_stats: z.string().optional(), + technical_specs: z.string().optional() }); type RideFormData = z.infer; @@ -59,6 +68,30 @@ const statusOptions = [ 'SBNO' // Standing But Not Operating ]; +const coasterTypes = [ + 'steel', + 'wood', + 'hybrid' +]; + +const seatingTypes = [ + 'sit_down', + 'stand_up', + 'flying', + 'inverted', + 'floorless', + 'suspended', + 'wing', + 'dive', + 'spinning' +]; + +const intensityLevels = [ + 'family', + 'thrill', + 'extreme' +]; + export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: RideFormProps) { const [submitting, setSubmitting] = useState(false); const [rideImage, setRideImage] = useState(initialData?.image_url || ''); @@ -87,10 +120,20 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: max_speed_kmh: initialData?.max_speed_kmh || undefined, max_height_meters: initialData?.max_height_meters || undefined, length_meters: initialData?.length_meters || undefined, - inversions: initialData?.inversions || undefined + inversions: initialData?.inversions || undefined, + coaster_type: initialData?.coaster_type || undefined, + seating_type: initialData?.seating_type || undefined, + intensity_level: initialData?.intensity_level || undefined, + drop_height_meters: initialData?.drop_height_meters || undefined, + max_g_force: initialData?.max_g_force || undefined, + former_names: initialData?.former_names || '', + coaster_stats: initialData?.coaster_stats || '', + technical_specs: initialData?.technical_specs || '' } }); + const selectedCategory = watch('category'); + const generateSlug = (name: string) => { return name .toLowerCase() @@ -279,6 +322,89 @@ export function RideForm({ onSubmit, onCancel, initialData, isEditing = false }: + {/* Roller Coaster Specific Fields */} + {selectedCategory === 'roller_coaster' && ( +
+

Roller Coaster Details

+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ +
+
+ + +
+ +
+ + +
+
+
+ )} + {/* Technical Specifications */}

Technical Specifications

diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 217acaa8..9657dfff 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -618,16 +618,21 @@ export type Database = { category: string closing_date: string | null coaster_stats: Json | null + coaster_type: string | null created_at: string description: string | null designer_id: string | null + drop_height_meters: number | null duration_seconds: number | null + former_names: Json | null height_requirement: number | null id: string image_url: string | null + intensity_level: string | null inversions: number | null length_meters: number | null manufacturer_id: string | null + max_g_force: number | null max_height_meters: number | null max_speed_kmh: number | null name: string @@ -636,6 +641,7 @@ export type Database = { review_count: number | null ride_model_id: string | null ride_sub_type: string | null + seating_type: string | null slug: string status: string technical_specs: Json | null @@ -648,16 +654,21 @@ export type Database = { category: string closing_date?: string | null coaster_stats?: Json | null + coaster_type?: string | null created_at?: string description?: string | null designer_id?: string | null + drop_height_meters?: number | null duration_seconds?: number | null + former_names?: Json | null height_requirement?: number | null id?: string image_url?: string | null + intensity_level?: string | null inversions?: number | null length_meters?: number | null manufacturer_id?: string | null + max_g_force?: number | null max_height_meters?: number | null max_speed_kmh?: number | null name: string @@ -666,6 +677,7 @@ export type Database = { review_count?: number | null ride_model_id?: string | null ride_sub_type?: string | null + seating_type?: string | null slug: string status?: string technical_specs?: Json | null @@ -678,16 +690,21 @@ export type Database = { category?: string closing_date?: string | null coaster_stats?: Json | null + coaster_type?: string | null created_at?: string description?: string | null designer_id?: string | null + drop_height_meters?: number | null duration_seconds?: number | null + former_names?: Json | null height_requirement?: number | null id?: string image_url?: string | null + intensity_level?: string | null inversions?: number | null length_meters?: number | null manufacturer_id?: string | null + max_g_force?: number | null max_height_meters?: number | null max_speed_kmh?: number | null name?: string @@ -696,6 +713,7 @@ export type Database = { review_count?: number | null ride_model_id?: string | null ride_sub_type?: string | null + seating_type?: string | null slug?: string status?: string technical_specs?: Json | null diff --git a/src/pages/RideDetail.tsx b/src/pages/RideDetail.tsx index 506034f5..cd5a8c6c 100644 --- a/src/pages/RideDetail.tsx +++ b/src/pages/RideDetail.tsx @@ -261,6 +261,27 @@ export default function RideDetail() { )} + + {/* New roller coaster specific stats */} + {ride.drop_height_meters && ( + + +
⬇️
+
{ride.drop_height_meters}m
+
drop
+
+
+ )} + + {ride.max_g_force && ( + + +
+
{ride.max_g_force}g
+
max G-force
+
+
+ )}
{/* Requirements & Warnings */} @@ -367,6 +388,49 @@ export default function RideDetail() { )} + {/* Roller Coaster Specific Info */} + {ride.category === 'roller_coaster' && (ride.coaster_type || ride.seating_type || ride.intensity_level) && ( + <> + +
+
Coaster Details
+ {ride.coaster_type && ( +
+
🎢
+
+
Type
+
+ {ride.coaster_type.charAt(0).toUpperCase() + ride.coaster_type.slice(1)} +
+
+
+ )} + {ride.seating_type && ( +
+
💺
+
+
Seating
+
+ {ride.seating_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())} +
+
+
+ )} + {ride.intensity_level && ( +
+
🔥
+
+
Intensity
+
+ {ride.intensity_level.charAt(0).toUpperCase() + ride.intensity_level.slice(1)} +
+
+
+ )} +
+ + )} +
@@ -424,6 +488,18 @@ export default function RideDetail() { {ride.inversions}
)} + {ride.drop_height_meters && ( +
+ Drop Height + {ride.drop_height_meters}m +
+ )} + {ride.max_g_force && ( +
+ Maximum G-Force + {ride.max_g_force}g +
+ )} diff --git a/src/types/database.ts b/src/types/database.ts index 4c28c0c6..61fd4d92 100644 --- a/src/types/database.ts +++ b/src/types/database.ts @@ -88,6 +88,13 @@ export interface Ride { average_rating: number; review_count: number; image_url?: string; + // New roller coaster specific fields + coaster_type?: string; + seating_type?: string; + intensity_level?: string; + drop_height_meters?: number; + max_g_force?: number; + former_names?: any; } export interface Profile { diff --git a/supabase/migrations/20250928211232_3c3b516b-2302-4610-8d3d-65aa161d969b.sql b/supabase/migrations/20250928211232_3c3b516b-2302-4610-8d3d-65aa161d969b.sql new file mode 100644 index 00000000..b6c8a283 --- /dev/null +++ b/supabase/migrations/20250928211232_3c3b516b-2302-4610-8d3d-65aa161d969b.sql @@ -0,0 +1,21 @@ +-- Add roller coaster specific columns to the rides table +ALTER TABLE public.rides +ADD COLUMN coaster_type TEXT CHECK (coaster_type IN ('steel', 'wood', 'hybrid')), +ADD COLUMN seating_type TEXT, +ADD COLUMN intensity_level TEXT CHECK (intensity_level IN ('family', 'thrill', 'extreme')), +ADD COLUMN former_names JSONB DEFAULT '[]'::jsonb, +ADD COLUMN drop_height_meters NUMERIC(6,2), +ADD COLUMN max_g_force NUMERIC(4,2); + +-- Add indexes for better query performance on commonly filtered fields +CREATE INDEX idx_rides_coaster_type ON public.rides(coaster_type) WHERE coaster_type IS NOT NULL; +CREATE INDEX idx_rides_seating_type ON public.rides(seating_type) WHERE seating_type IS NOT NULL; +CREATE INDEX idx_rides_intensity_level ON public.rides(intensity_level) WHERE intensity_level IS NOT NULL; + +-- Add comments for documentation +COMMENT ON COLUMN public.rides.coaster_type IS 'Type of roller coaster construction: steel, wood, or hybrid'; +COMMENT ON COLUMN public.rides.seating_type IS 'How riders are seated: sit_down, stand_up, flying, inverted, etc.'; +COMMENT ON COLUMN public.rides.intensity_level IS 'Target audience intensity: family, thrill, or extreme'; +COMMENT ON COLUMN public.rides.former_names IS 'Array of previous names this ride has had'; +COMMENT ON COLUMN public.rides.drop_height_meters IS 'Maximum drop height in meters'; +COMMENT ON COLUMN public.rides.max_g_force IS 'Maximum G-force experienced on the ride'; \ No newline at end of file