diff --git a/src/components/homepage/ContentTabs.tsx b/src/components/homepage/ContentTabs.tsx index cce5d12b..f620438b 100644 --- a/src/components/homepage/ContentTabs.tsx +++ b/src/components/homepage/ContentTabs.tsx @@ -1,17 +1,11 @@ import { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { ParkCard } from '@/components/parks/ParkCard'; -import { Card, CardContent } from '@/components/ui/card'; -import { Badge } from '@/components/ui/badge'; -import { Button } from '@/components/ui/button'; -import { Star, TrendingUp, Plus, MapPin, Clock, Zap, FerrisWheel, Waves, Theater, Train } from 'lucide-react'; -import { MeasurementDisplay } from '@/components/ui/measurement-display'; +import { RideCard } from '@/components/rides/RideCard'; import { Park, Ride } from '@/types/database'; import { supabase } from '@/integrations/supabase/client'; export function ContentTabs() { - const navigate = useNavigate(); const [popularParks, setPopularParks] = useState([]); const [trendingParks, setTrendingParks] = useState([]); const [popularRides, setPopularRides] = useState([]); @@ -81,148 +75,6 @@ export function ContentTabs() { } }; - 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 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 formatCategory = (category: string) => { - return category.split('_').map(word => - word.charAt(0).toUpperCase() + word.slice(1) - ).join(' '); - }; - - const RideCard = ({ ride }: { ride: Ride }) => { - const handleRideClick = () => { - navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`); - }; - - return ( - -
- {/* Image/Icon Section */} -
- {ride.image_url ? ( - {ride.name} - ) : ( -
- {getRideIcon(ride.category)} -
- )} - - {/* Gradient Overlay */} -
- - {/* Status Badge */} - - {ride.status.replace('_', ' ').toUpperCase()} - -
- - - {/* Header */} -
-
-

- {ride.name} -

- {getRideIcon(ride.category)} -
- - {ride.park?.name && ( -
- - {ride.park.name} - {ride.park.location?.city && `, ${ride.park.location.city}`} -
- )} -
- - {/* Description */} - {ride.description && ( -

- {ride.description} -

- )} - - {/* Category Badge */} - - {formatCategory(ride.category)} - - - {/* Stats */} -
-
- {ride.max_speed_kmh && ride.max_speed_kmh > 0 && ( -
- - - - -
- )} - {ride.max_height_meters && ride.max_height_meters > 0 && ( -
- - - -
- )} - {ride.duration_seconds && ride.duration_seconds > 0 && ( -
- - {Math.floor(ride.duration_seconds / 60)} - min -
- )} -
- - {ride.average_rating > 0 && ( -
- - {ride.average_rating.toFixed(1)} - ({ride.review_count}) -
- )} -
- - {/* Action Button */} - -
-
- - ); - }; if (loading) { return ( diff --git a/src/components/rides/RideCard.tsx b/src/components/rides/RideCard.tsx new file mode 100644 index 00000000..a602e343 --- /dev/null +++ b/src/components/rides/RideCard.tsx @@ -0,0 +1,158 @@ +import { useNavigate } from 'react-router-dom'; +import { Card, CardContent } from '@/components/ui/card'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Star, MapPin, Clock, Zap, FerrisWheel, Waves, Theater, Train } from 'lucide-react'; +import { MeasurementDisplay } from '@/components/ui/measurement-display'; +import { Ride } from '@/types/database'; + +interface RideCardProps { + ride: Ride; + showParkName?: boolean; + className?: string; +} + +export function RideCard({ ride, showParkName = true, className }: RideCardProps) { + const navigate = useNavigate(); + + const handleRideClick = () => { + navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`); + }; + + 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 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 formatCategory = (category: string) => { + return category.split('_').map(word => + word.charAt(0).toUpperCase() + word.slice(1) + ).join(' '); + }; + + return ( + +
+ {/* Image/Icon Section */} +
+ {ride.image_url ? ( + {ride.name} + ) : ( +
+ {getRideIcon(ride.category)} +
+ )} + + {/* Gradient Overlay */} +
+ + {/* Status Badge */} + + {ride.status.replace('_', ' ').toUpperCase()} + +
+ + + {/* Header */} +
+
+

+ {ride.name} +

+ {getRideIcon(ride.category)} +
+ + {showParkName && ride.park?.name && ( +
+ + {ride.park.name} + {ride.park.location?.city && `, ${ride.park.location.city}`} +
+ )} +
+ + {/* Description */} + {ride.description && ( +

+ {ride.description} +

+ )} + + {/* Category Badge */} + + {formatCategory(ride.category)} + + + {/* Stats */} +
+
+ {ride.max_speed_kmh && ride.max_speed_kmh > 0 && ( +
+ + + + +
+ )} + {ride.max_height_meters && ride.max_height_meters > 0 && ( +
+ + + +
+ )} + {ride.duration_seconds && ride.duration_seconds > 0 && ( +
+ + {Math.floor(ride.duration_seconds / 60)} + min +
+ )} +
+ + {ride.average_rating > 0 && ( +
+ + {ride.average_rating.toFixed(1)} + ({ride.review_count}) +
+ )} +
+ + {/* Action Button */} + +
+
+ + ); +} \ No newline at end of file diff --git a/src/pages/Rides.tsx b/src/pages/Rides.tsx index 624598b6..55663a90 100644 --- a/src/pages/Rides.tsx +++ b/src/pages/Rides.tsx @@ -1,15 +1,12 @@ import { useState, useEffect } from 'react'; import { Header } from '@/components/layout/Header'; -import { Card, CardContent } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Badge } from '@/components/ui/badge'; -import { Filter, SlidersHorizontal, Zap, Clock, Star, FerrisWheel, Waves, Theater, Train } from 'lucide-react'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { Filter, SlidersHorizontal, FerrisWheel } from 'lucide-react'; import { AutocompleteSearch } from '@/components/search/AutocompleteSearch'; -import { MeasurementDisplay } from '@/components/ui/measurement-display'; +import { RideCard } from '@/components/rides/RideCard'; import { Ride } from '@/types/database'; import { supabase } from '@/integrations/supabase/client'; -import { useNavigate } from 'react-router-dom'; export default function Rides() { const [rides, setRides] = useState([]); @@ -18,7 +15,6 @@ export default function Rides() { const [sortBy, setSortBy] = useState('name'); const [filterCategory, setFilterCategory] = useState('all'); const [filterStatus, setFilterStatus] = useState('all'); - const navigate = useNavigate(); useEffect(() => { fetchRides(); @@ -75,32 +71,6 @@ export default function Rides() { ride.manufacturer?.name?.toLowerCase().includes(searchQuery.toLowerCase()) ); - 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 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 formatCategory = (category: string) => { - return category.split('_').map(word => - word.charAt(0).toUpperCase() + word.slice(1) - ).join(' '); - }; const categories = [ { value: 'all', label: 'All Categories' }, @@ -219,110 +189,7 @@ export default function Rides() { {filteredRides.length > 0 ? (
{filteredRides.map((ride) => ( - -
- {/* Image/Icon Section */} -
- {ride.image_url ? ( - {ride.name} - ) : ( -
- {getRideIcon(ride.category)} -
- )} - - {/* Gradient Overlay */} -
- - {/* Status Badge */} - - {ride.status.replace('_', ' ').toUpperCase()} - -
- - - {/* Header */} -
-
-

- {ride.name} -

- {getRideIcon(ride.category)} -
- - {ride.park?.name && ( -

- at {ride.park.name} -

- )} -
- - {/* Description */} - {ride.description && ( -

- {ride.description} -

- )} - - {/* Category Badge */} - - {formatCategory(ride.category)} - - - {/* Stats */} -
-
- {ride.max_speed_kmh && ( -
- - - - -
- )} - {ride.max_height_meters && ( -
- - - -
- )} - {ride.duration_seconds && ( -
- - {Math.floor(ride.duration_seconds / 60)}min -
- )} -
- - {ride.average_rating > 0 && ( -
- - {ride.average_rating.toFixed(1)} -
- )} -
- - {/* Action Button */} - -
-
- + ))}
) : (