import { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Header } from '@/components/layout/Header'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Separator } from '@/components/ui/separator'; import { MapPin, Star, Clock, Zap, ArrowLeft, Users, Ruler, Timer, TrendingUp, TrendingDown, Camera, Heart, RotateCcw, AlertTriangle, FerrisWheel, Waves, Theater, Train } from 'lucide-react'; import { ReviewsSection } from '@/components/reviews/ReviewsSection'; import { MeasurementDisplay } from '@/components/ui/measurement-display'; import { RidePhotoGallery } from '@/components/rides/RidePhotoGallery'; import { Ride } from '@/types/database'; import { supabase } from '@/integrations/supabase/client'; export default function RideDetail() { const { parkSlug, rideSlug } = useParams<{ parkSlug: string; rideSlug: string }>(); const navigate = useNavigate(); const [ride, setRide] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { if (parkSlug && rideSlug) { fetchRideData(); } }, [parkSlug, rideSlug]); const fetchRideData = async () => { try { // First get park to find park_id const { data: parkData } = await supabase .from('parks') .select('id') .eq('slug', parkSlug) .maybeSingle(); if (parkData) { // Then get ride details const { data: rideData } = await supabase .from('rides') .select(` *, park:parks!inner(id, name, slug, location:locations(*)), manufacturer:companies!rides_manufacturer_id_fkey(*), designer:companies!rides_designer_id_fkey(*) `) .eq('park_id', parkData.id) .eq('slug', rideSlug) .maybeSingle(); setRide(rideData); } } catch (error) { console.error('Error fetching ride data:', error); } finally { setLoading(false); } }; const getStatusColor = (status: string) => { switch (status) { case 'operating': return 'bg-green-500/20 text-green-400 border-green-500/30'; case 'seasonal': return 'bg-yellow-500/20 text-yellow-400 border-yellow-500/30'; case 'under_construction': return 'bg-blue-500/20 text-blue-400 border-blue-500/30'; default: return 'bg-red-500/20 text-red-400 border-red-500/30'; } }; const getRideIcon = (category: string) => { switch (category) { case 'roller_coaster': return ; case 'water_ride': return ; case 'dark_ride': return ; case 'flat_ride': return ; case 'kiddie_ride': return ; case 'transportation': return ; default: return ; } }; const formatCategory = (category: string) => { return category.split('_').map(word => word.charAt(0).toUpperCase() + word.slice(1) ).join(' '); }; if (loading) { return (
); } if (!ride || !ride.park) { return (

Ride Not Found

The ride you're looking for doesn't exist or has been removed.

); } return (
{/* Back Button */} {/* Hero Section */}
{ride.image_url ? ( {ride.name} ) : (
{getRideIcon(ride.category)}
)}
{/* Ride Title Overlay */}
{ride.status.replace('_', ' ').toUpperCase()} {formatCategory(ride.category)}

{ride.name}

{ride.park.name}
{ride.average_rating > 0 && (
{ride.average_rating.toFixed(1)}
{ride.review_count} reviews
)}
{/* Quick Stats */}
{ride.max_speed_kmh && (
)} {ride.max_height_meters && (
)} {ride.length_meters && (
long
)} {ride.duration_seconds && (
{Math.floor(ride.duration_seconds / 60)}:{(ride.duration_seconds % 60).toString().padStart(2, '0')}
duration
)} {ride.capacity_per_hour && (
{ride.capacity_per_hour}
riders/hour
)} {ride.inversions && ride.inversions > 0 && (
{ride.inversions}
inversions
)} {/* New roller coaster specific stats */} {ride.drop_height_meters && (
drop
)} {ride.max_g_force && (
{ride.max_g_force}g
max G-force
)}
{/* Requirements & Warnings */} {(ride.height_requirement || ride.age_requirement) && (

Ride Requirements

{ride.height_requirement && (
Minimum height:
)} {ride.age_requirement && (
Minimum age: {ride.age_requirement} years
)}
)} {/* Main Content */} Overview Specifications Reviews Photos
{/* Description */} {ride.description && ( About {ride.name}

{ride.description}

)}
{/* Ride Information */} Ride Information
{getRideIcon(ride.category)}
Category
{formatCategory(ride.category)}
{ride.opening_date && (
Opened
{new Date(ride.opening_date).getFullYear()}
)} {ride.manufacturer && (
Manufacturer
{ride.manufacturer.name}
)} {ride.designer && (
Designer
{ride.designer.name}
)} {/* 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)}
)}
)}
Located at
{/* Performance Stats */} Performance {ride.max_speed_kmh && (
Maximum Speed
)} {ride.max_height_meters && (
Maximum Height
)} {ride.length_meters && (
Track Length
)} {ride.duration_seconds && (
Ride Duration {Math.floor(ride.duration_seconds / 60)}:{(ride.duration_seconds % 60).toString().padStart(2, '0')}
)} {ride.inversions && ride.inversions > 0 && (
Inversions {ride.inversions}
)} {ride.drop_height_meters && (
Drop Height
)} {ride.max_g_force && (
Maximum G-Force {ride.max_g_force}g
)}
{/* Operational Info */} Operational Details {ride.capacity_per_hour && (
Capacity {ride.capacity_per_hour} riders/hour
)} {ride.height_requirement && (
Height Requirement minimum
)} {ride.age_requirement && (
Age Requirement {ride.age_requirement}+ years
)}
Status {ride.status.replace('_', ' ')}
); }