-
-
-
Rides by {manufacturer.name}
+
+
+
+
Rides by {manufacturer.name}
+
+
Explore all rides manufactured by {manufacturer.name}
@@ -232,7 +276,7 @@ export default function ManufacturerRides() {
{filteredRides.length > 0 ? (
-
+
{filteredRides.map((ride) => (
))}
@@ -247,6 +291,15 @@ export default function ManufacturerRides() {
)}
+
+
);
}
diff --git a/src/pages/RideModelDetail.tsx b/src/pages/RideModelDetail.tsx
new file mode 100644
index 00000000..417fe55d
--- /dev/null
+++ b/src/pages/RideModelDetail.tsx
@@ -0,0 +1,324 @@
+import { useState, useEffect, useCallback } 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 } from '@/components/ui/card';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import { ArrowLeft, FerrisWheel, Building2, Filter, SlidersHorizontal } from 'lucide-react';
+import { RideModel, Ride, Company } from '@/types/database';
+import { supabase } from '@/integrations/supabase/client';
+import { RideCard } from '@/components/rides/RideCard';
+import { AutocompleteSearch } from '@/components/search/AutocompleteSearch';
+import { getCloudflareImageUrl } from '@/lib/cloudflareImageUtils';
+
+export default function RideModelDetail() {
+ const { manufacturerSlug, modelSlug } = useParams<{ manufacturerSlug: string; modelSlug: string }>();
+ const navigate = useNavigate();
+ const [model, setModel] = useState
(null);
+ const [manufacturer, setManufacturer] = useState(null);
+ const [rides, setRides] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [searchQuery, setSearchQuery] = useState('');
+ const [sortBy, setSortBy] = useState('name');
+ const [filterStatus, setFilterStatus] = useState('all');
+
+ const fetchData = useCallback(async () => {
+ try {
+ // Fetch manufacturer
+ const { data: manufacturerData, error: manufacturerError } = await supabase
+ .from('companies')
+ .select('*')
+ .eq('slug', manufacturerSlug)
+ .eq('company_type', 'manufacturer')
+ .maybeSingle();
+
+ if (manufacturerError) throw manufacturerError;
+ setManufacturer(manufacturerData);
+
+ if (manufacturerData) {
+ // Fetch ride model
+ const { data: modelData, error: modelError } = await supabase
+ .from('ride_models')
+ .select('*')
+ .eq('slug', modelSlug)
+ .eq('manufacturer_id', manufacturerData.id)
+ .maybeSingle();
+
+ if (modelError) throw modelError;
+ setModel(modelData as RideModel);
+
+ if (modelData) {
+ // Fetch rides using this model
+ let query = supabase
+ .from('rides')
+ .select(`
+ *,
+ park:parks!inner(name, slug, location:locations(*)),
+ manufacturer:companies!rides_manufacturer_id_fkey(*)
+ `)
+ .eq('ride_model_id', modelData.id);
+
+ if (filterStatus !== 'all') {
+ query = query.eq('status', filterStatus);
+ }
+
+ switch (sortBy) {
+ case 'rating':
+ query = query.order('average_rating', { ascending: false });
+ break;
+ case 'speed':
+ query = query.order('max_speed_kmh', { ascending: false, nullsFirst: false });
+ break;
+ case 'height':
+ query = query.order('max_height_meters', { ascending: false, nullsFirst: false });
+ break;
+ case 'reviews':
+ query = query.order('review_count', { ascending: false });
+ break;
+ default:
+ query = query.order('name');
+ }
+
+ const { data: ridesData, error: ridesError } = await query;
+ if (ridesError) throw ridesError;
+ setRides(ridesData || []);
+ }
+ }
+ } catch (error) {
+ console.error('Error fetching data:', error);
+ } finally {
+ setLoading(false);
+ }
+ }, [manufacturerSlug, modelSlug, sortBy, filterStatus]);
+
+ useEffect(() => {
+ if (manufacturerSlug && modelSlug) {
+ fetchData();
+ }
+ }, [manufacturerSlug, modelSlug, fetchData]);
+
+ const filteredRides = rides.filter(ride =>
+ ride.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ ride.park?.name?.toLowerCase().includes(searchQuery.toLowerCase())
+ );
+
+ const formatCategory = (category: string | null | undefined) => {
+ if (!category) return 'Unknown';
+ return category.split('_').map(word =>
+ word.charAt(0).toUpperCase() + word.slice(1)
+ ).join(' ');
+ };
+
+ const formatRideType = (type: string | null | undefined) => {
+ if (!type) return 'Unknown';
+ return type.split('_').map(word =>
+ word.charAt(0).toUpperCase() + word.slice(1)
+ ).join(' ');
+ };
+
+ const statusOptions = [
+ { value: 'all', label: 'All Status' },
+ { value: 'operating', label: 'Operating' },
+ { value: 'seasonal', label: 'Seasonal' },
+ { value: 'under_construction', label: 'Under Construction' },
+ { value: 'closed', label: 'Closed' }
+ ];
+
+ if (loading) {
+ return (
+
+
+
+
+
+
+
+ {[...Array(6)].map((_, i) => (
+
+ ))}
+
+
+
+
+ );
+ }
+
+ if (!model || !manufacturer) {
+ return (
+
+
+
+
+
Ride Model Not Found
+
+
+
+
+ );
+ }
+
+ const extendedModel = model as RideModel & {
+ card_image_url?: string;
+ card_image_id?: string;
+ banner_image_url?: string;
+ banner_image_id?: string;
+ };
+
+ return (
+
+
+
+
+
+
+
+
+ {/* Hero Section */}
+
+ {(extendedModel.banner_image_url || extendedModel.banner_image_id) && (
+
+

+
+ )}
+
+
+
+
+
+
{model.name}
+
+
+
+
+
+
+
+
+
+
+
+ {formatCategory(model.category)}
+
+
+ {formatRideType(model.ride_type)}
+
+
+ {rides.length} {rides.length === 1 ? 'ride' : 'rides'}
+
+
+
+
+
+
+ Overview
+ Rides ({rides.length})
+
+
+
+ {model.description && (
+
+
+ About
+ {model.description}
+
+
+ )}
+
+ {(model as any).technical_specs && Object.keys((model as any).technical_specs).length > 0 && (
+
+
+ Technical Specifications
+
+ {Object.entries((model as any).technical_specs as Record
).map(([key, value]) => (
+
+ {key.replace(/_/g, ' ')}
+ {String(value)}
+
+ ))}
+
+
+
+ )}
+
+
+
+
+
+
setSearchQuery(query)}
+ showRecentSearches={false}
+ />
+
+
+
+
+
+
+
+
+ {filteredRides.length > 0 ? (
+
+ {filteredRides.map((ride) => (
+
+ ))}
+
+ ) : (
+
+
+
No rides found
+
+ No rides match your search criteria
+
+
+ )}
+
+
+
+
+ );
+}