import { useState, lazy, Suspense, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Header } from '@/components/layout/Header';
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
import { trackPageView } from '@/lib/viewTracking';
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 { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { AdminFormSkeleton } from '@/components/loading/PageSkeletons';
import {
MapPin,
Star,
Clock,
Zap,
ArrowLeft,
Users,
Ruler,
Timer,
TrendingUp,
TrendingDown,
Camera,
Heart,
RotateCcw,
AlertTriangle,
FerrisWheel,
Waves,
Theater,
Train,
Edit,
Wrench,
Sparkles,
Repeat,
Baby
} from 'lucide-react';
import { ReviewsSection } from '@/components/reviews/ReviewsSection';
import { MeasurementDisplay } from '@/components/ui/measurement-display';
import { EntityPhotoGallery } from '@/components/upload/EntityPhotoGallery';
import { RatingDistribution } from '@/components/rides/RatingDistribution';
import { RideHighlights } from '@/components/rides/RideHighlights';
import { SimilarRides } from '@/components/rides/SimilarRides';
import { FormerNames } from '@/components/rides/FormerNames';
import { RecentPhotosPreview } from '@/components/rides/RecentPhotosPreview';
import { ParkLocationMap } from '@/components/maps/ParkLocationMap';
import { Ride } from '@/types/database';
import { useAuth } from '@/hooks/useAuth';
import { useRideDetail } from '@/hooks/rides/useRideDetail';
import { usePhotoCount } from '@/hooks/photos/usePhotoCount';
// Lazy load admin forms
const RideForm = lazy(() => import('@/components/admin/RideForm').then(m => ({ default: m.RideForm })));
import { useUserRole } from '@/hooks/useUserRole';
import { toast } from '@/hooks/use-toast';
import { getErrorMessage } from '@/lib/errorHandler';
import { VersionIndicator } from '@/components/versioning/VersionIndicator';
import { EntityHistoryTabs } from '@/components/history/EntityHistoryTabs';
import { useAuthModal } from '@/hooks/useAuthModal';
import { MetaTags } from '@/components/seo';
// Extended Ride type with additional properties for easier access
interface RideWithParkId extends Ride {
currentParkId?: string;
}
export default function RideDetail() {
const { parkSlug, rideSlug } = useParams<{ parkSlug: string; rideSlug: string }>();
const navigate = useNavigate();
const { user } = useAuth();
const { isModerator } = useUserRole();
const { requireAuth } = useAuthModal();
const [activeTab, setActiveTab] = useState("overview");
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
// Fetch ride data with caching
const { data: rideData, isLoading: loading } = useRideDetail(parkSlug, rideSlug);
// Cast to RideWithParkId to include currentParkId
const ride = rideData as RideWithParkId | null;
// Fetch photo count with caching
const { data: photoCount = 0, isLoading: statsLoading } = usePhotoCount('ride', ride?.id, !!ride?.id);
// Track page view when ride is loaded
useEffect(() => {
if (ride?.id) {
trackPageView('ride', ride.id);
}
}, [ride?.id]);
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(' ');
};
const handleEditSubmit = async (data: any) => {
if (!user || !ride) return;
try {
// Everyone goes through submission queue
const { submitRideUpdate } = await import('@/lib/entitySubmissionHelpers');
await submitRideUpdate(ride.id, data, user.id);
toast({
title: "Edit Submitted",
description: isModerator()
? "Your edit has been submitted. You can approve it in the moderation queue."
: "Your ride edit has been submitted for review."
});
setIsEditModalOpen(false);
} catch (error) {
const errorMsg = getErrorMessage(error);
toast({
title: "Error",
description: errorMsg || "Failed to submit edit.",
variant: "destructive"
});
}
};
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 and Edit Button */}
{/* Hero Section */}
{(ride.banner_image_url || ride.banner_image_id) ? (
) : (
{getRideIcon(ride.category)}
)}
{/* Ride Title Overlay */}
{ride.status.replace('_', ' ').toUpperCase()}
{formatCategory(ride.category)}
{ride.name}
{ride.park.name}
{(ride.average_rating ?? 0) > 0 && (
{(ride.average_rating ?? 0).toFixed(1)}
{ride.review_count} {ride.review_count === 1 ? "review" : "reviews"}
)}
{/* Quick Stats */}
{ride.max_speed_kmh !== null && ride.max_speed_kmh !== undefined && ride.max_speed_kmh > 0 && (
)}
{ride.max_height_meters !== null && ride.max_height_meters !== undefined && ride.max_height_meters > 0 && (
)}
{ride.length_meters !== null && ride.length_meters !== undefined && ride.length_meters > 0 && (
long
)}
{ride.duration_seconds !== null && ride.duration_seconds !== undefined && ride.duration_seconds > 0 && (
{Math.floor(ride.duration_seconds / 60)}:{(ride.duration_seconds % 60).toString().padStart(2, '0')}
duration
)}
{ride.capacity_per_hour !== null && ride.capacity_per_hour !== undefined && ride.capacity_per_hour > 0 && (
{ride.capacity_per_hour}
riders/hour
)}
{ride.inversions !== null && ride.inversions !== undefined &&
(ride.category === 'roller_coaster' || ride.category?.toLowerCase().includes('coaster')) && (
{ride.inversions}
inversions
)}
{/* New roller coaster specific stats */}
{ride.drop_height_meters !== null && ride.drop_height_meters !== undefined && ride.drop_height_meters > 0 && (
drop
)}
{ride.max_g_force !== null && ride.max_g_force !== undefined && ride.max_g_force > 0 && (
{ride.max_g_force}g
max G-force
)}
{/* Main Content */}
Overview
Specifications
Reviews {(ride.review_count ?? 0) > 0 && `(${ride.review_count})`}
Photos {!statsLoading && photoCount > 0 && `(${photoCount})`}
History
{/* Description */}
{ride.description && (
About {ride.name}
{ride.description}
)}
{ride.name_history && ride.name_history.length > 0 && (
)}
setActiveTab("photos")}
/>
{/* Ride Information */}
Ride Information
Category
{formatCategory(ride.category)}
{ride.opening_date && (
Opened
{ride.opening_date.split('-')[0]}
)}
{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('_', ' ')}
{/* Coaster Materials & Propulsion */}
{ride.category === 'roller_coaster' && (
(ride.track_material?.length ?? 0) > 0 ||
(ride.support_material?.length ?? 0) > 0 ||
(ride.propulsion_method?.length ?? 0) > 0
) && (
Coaster Construction
{ride.track_material && ride.track_material.length > 0 && (
Track Material
{ride.track_material.map(material => (
{material.replace('_', ' ').toUpperCase()}
))}
)}
{ride.support_material && ride.support_material.length > 0 && (
Support Material
{ride.support_material.map(material => (
{material.replace('_', ' ').toUpperCase()}
))}
)}
{ride.propulsion_method && ride.propulsion_method.length > 0 && (
Propulsion Method
{ride.propulsion_method.map(method => (
{method.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
))}
)}
)}
{/* Water Ride Details */}
{ride.category === 'water_ride' && (
ride.water_depth_cm || ride.splash_height_meters || ride.wetness_level ||
ride.flume_type || ride.boat_capacity
) && (
Water Ride Details
{ride.water_depth_cm && (
Water Depth
)}
{ride.splash_height_meters && (
Splash Height
)}
{ride.wetness_level && (
Wetness Level
{ride.wetness_level.charAt(0).toUpperCase() + ride.wetness_level.slice(1)}
)}
{ride.flume_type && (
Flume Type
{ride.flume_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
{ride.boat_capacity && (
Boat Capacity
{ride.boat_capacity} riders
)}
)}
{/* Dark Ride Details */}
{ride.category === 'dark_ride' && (
ride.theme_name || ride.story_description || ride.show_duration_seconds ||
ride.animatronics_count || ride.projection_type || ride.ride_system || ride.scenes_count
) && (
Dark Ride Details
{ride.theme_name && (
Theme
{ride.theme_name}
)}
{ride.story_description && (
Story
{ride.story_description}
)}
{ride.show_duration_seconds && (
Show Duration
{Math.floor(ride.show_duration_seconds / 60)}:{(ride.show_duration_seconds % 60).toString().padStart(2, '0')}
)}
{ride.animatronics_count && (
Animatronics
{ride.animatronics_count}
)}
{ride.scenes_count && (
Scenes
{ride.scenes_count}
)}
{ride.projection_type && (
Projection Type
{ride.projection_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
{ride.ride_system && (
Ride System
{ride.ride_system.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
)}
{/* Flat Ride Details */}
{ride.category === 'flat_ride' && (
ride.rotation_type || ride.motion_pattern || ride.platform_count ||
ride.swing_angle_degrees || ride.rotation_speed_rpm || ride.arm_length_meters ||
ride.max_height_reached_meters
) && (
Flat Ride Details
{ride.rotation_type && (
Rotation Type
{ride.rotation_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
{ride.motion_pattern && (
Motion Pattern
{ride.motion_pattern.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
{ride.platform_count && (
Platforms
{ride.platform_count}
)}
{ride.swing_angle_degrees && (
Swing Angle
{ride.swing_angle_degrees}°
)}
{ride.rotation_speed_rpm && (
Rotation Speed
{ride.rotation_speed_rpm} RPM
)}
{ride.arm_length_meters && (
Arm Length
)}
{ride.max_height_reached_meters && (
Max Height Reached
)}
)}
{/* Kiddie Ride Details */}
{ride.category === 'kiddie_ride' && (
ride.min_age || ride.max_age || ride.educational_theme || ride.character_theme
) && (
Kiddie Ride Details
{(ride.min_age || ride.max_age) && (
Age Range
{ride.min_age && ride.max_age ? `${ride.min_age}-${ride.max_age} years` :
ride.min_age ? `${ride.min_age}+ years` :
ride.max_age ? `Up to ${ride.max_age} years` : 'N/A'}
)}
{ride.educational_theme && (
Educational Theme
{ride.educational_theme}
)}
{ride.character_theme && (
Character Theme
{ride.character_theme}
)}
)}
{/* Transportation Details */}
{ride.category === 'transportation' && (
ride.transport_type || ride.route_length_meters || ride.stations_count ||
ride.vehicle_capacity || ride.vehicles_count || ride.round_trip_duration_seconds
) && (
Transportation Details
{ride.transport_type && (
Transport Type
{ride.transport_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
)}
{ride.route_length_meters && (
Route Length
)}
{ride.stations_count && (
Stations
{ride.stations_count}
)}
{ride.vehicle_capacity && (
Vehicle Capacity
{ride.vehicle_capacity} passengers
)}
{ride.vehicles_count && (
Number of Vehicles
{ride.vehicles_count}
)}
{ride.round_trip_duration_seconds && (
Round Trip Duration
{Math.floor(ride.round_trip_duration_seconds / 60)}:{(ride.round_trip_duration_seconds % 60).toString().padStart(2, '0')}
)}
)}
{/* Edit Ride Modal */}
);
}