mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-29 06:47:07 -05:00
Compare commits
4 Commits
05217b00d4
...
bf860de3c4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf860de3c4 | ||
|
|
dd420a1684 | ||
|
|
8540d227b2 | ||
|
|
8fd8d2e843 |
@@ -99,21 +99,13 @@ const intensityLevels = [
|
||||
];
|
||||
|
||||
const TRACK_MATERIALS = [
|
||||
{ value: 'wood', label: 'Wood' },
|
||||
{ value: 'steel', label: 'Steel' },
|
||||
{ value: 'hybrid', label: 'Hybrid' },
|
||||
{ value: 'aluminum', label: 'Aluminum' },
|
||||
{ value: 'composite', label: 'Composite' },
|
||||
{ value: 'other', label: 'Other' },
|
||||
{ value: 'wood', label: 'Wood' },
|
||||
];
|
||||
|
||||
const SUPPORT_MATERIALS = [
|
||||
{ value: 'steel', label: 'Steel' },
|
||||
{ value: 'wood', label: 'Wood' },
|
||||
{ value: 'concrete', label: 'Concrete' },
|
||||
{ value: 'aluminum', label: 'Aluminum' },
|
||||
{ value: 'composite', label: 'Composite' },
|
||||
{ value: 'other', label: 'Other' },
|
||||
];
|
||||
|
||||
const PROPULSION_METHODS = [
|
||||
|
||||
@@ -27,6 +27,8 @@ export interface RideFilterState {
|
||||
seatingTypes: string[];
|
||||
intensityLevels: string[];
|
||||
trackMaterials: string[];
|
||||
supportMaterials: string[];
|
||||
propulsionMethods: string[];
|
||||
minSpeed: number;
|
||||
maxSpeed: number;
|
||||
minHeight: number;
|
||||
@@ -54,6 +56,8 @@ export const defaultRideFilters: RideFilterState = {
|
||||
seatingTypes: [],
|
||||
intensityLevels: [],
|
||||
trackMaterials: [],
|
||||
supportMaterials: [],
|
||||
propulsionMethods: [],
|
||||
minSpeed: 0,
|
||||
maxSpeed: 200,
|
||||
minHeight: 0,
|
||||
@@ -199,7 +203,22 @@ export function RideFilters({ filters, onFiltersChange, rides }: RideFiltersProp
|
||||
const trackMaterialOptions: MultiSelectOption[] = [
|
||||
{ label: 'Steel', value: 'steel' },
|
||||
{ label: 'Wood', value: 'wood' },
|
||||
{ label: 'Hybrid', value: 'hybrid' },
|
||||
];
|
||||
|
||||
const supportMaterialOptions: MultiSelectOption[] = [
|
||||
{ label: 'Steel', value: 'steel' },
|
||||
{ label: 'Wood', value: 'wood' },
|
||||
];
|
||||
|
||||
const propulsionMethodOptions: MultiSelectOption[] = [
|
||||
{ label: 'Chain Lift', value: 'chain_lift' },
|
||||
{ label: 'Cable Lift', value: 'cable_lift' },
|
||||
{ label: 'Launched (LIM/LSM)', value: 'launched_lim_lsm' },
|
||||
{ label: 'Hydraulic Launch', value: 'hydraulic_launch' },
|
||||
{ label: 'Compressed Air', value: 'compressed_air' },
|
||||
{ label: 'Flywheel', value: 'flywheel' },
|
||||
{ label: 'Gravity', value: 'gravity' },
|
||||
{ label: 'Other', value: 'other' },
|
||||
];
|
||||
|
||||
const resetFilters = () => {
|
||||
@@ -339,6 +358,20 @@ export function RideFilters({ filters, onFiltersChange, rides }: RideFiltersProp
|
||||
onChange={(value) => onFiltersChange({ ...filters, trackMaterials: value })}
|
||||
placeholder="Select material"
|
||||
/>
|
||||
<FilterMultiSelectCombobox
|
||||
label="Support Material"
|
||||
options={supportMaterialOptions}
|
||||
value={filters.supportMaterials}
|
||||
onChange={(value) => onFiltersChange({ ...filters, supportMaterials: value })}
|
||||
placeholder="Select support material"
|
||||
/>
|
||||
<FilterMultiSelectCombobox
|
||||
label="Propulsion Method"
|
||||
options={propulsionMethodOptions}
|
||||
value={filters.propulsionMethods}
|
||||
onChange={(value) => onFiltersChange({ ...filters, propulsionMethods: value })}
|
||||
placeholder="Select propulsion"
|
||||
/>
|
||||
</div>
|
||||
</FilterSection>
|
||||
|
||||
|
||||
@@ -184,12 +184,15 @@ export function useRideCreditFilters(credits: UserRideCredit[]) {
|
||||
);
|
||||
}
|
||||
|
||||
// Track material filter
|
||||
// Track material filter (handles array)
|
||||
if (filters.trackMaterial && filters.trackMaterial.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
credit.rides?.track_material &&
|
||||
filters.trackMaterial!.includes(credit.rides.track_material)
|
||||
);
|
||||
result = result.filter(credit => {
|
||||
if (!credit.rides?.track_material) return false;
|
||||
const rideMaterials = Array.isArray(credit.rides.track_material)
|
||||
? credit.rides.track_material
|
||||
: [credit.rides.track_material];
|
||||
return rideMaterials.some(material => filters.trackMaterial!.includes(material));
|
||||
});
|
||||
}
|
||||
|
||||
// User rating
|
||||
|
||||
@@ -3510,13 +3510,17 @@ export type Database = {
|
||||
rides: {
|
||||
Row: {
|
||||
age_requirement: number | null
|
||||
animatronics_count: number | null
|
||||
arm_length_meters: number | null
|
||||
average_rating: number | null
|
||||
banner_image_id: string | null
|
||||
banner_image_url: string | null
|
||||
boat_capacity: number | null
|
||||
capacity_per_hour: number | null
|
||||
card_image_id: string | null
|
||||
card_image_url: string | null
|
||||
category: string
|
||||
character_theme: string | null
|
||||
closing_date: string | null
|
||||
closing_date_precision: string | null
|
||||
coaster_type: string | null
|
||||
@@ -3525,6 +3529,8 @@ export type Database = {
|
||||
designer_id: string | null
|
||||
drop_height_meters: number | null
|
||||
duration_seconds: number | null
|
||||
educational_theme: string | null
|
||||
flume_type: string | null
|
||||
height_requirement: number | null
|
||||
id: string
|
||||
image_url: string | null
|
||||
@@ -3532,36 +3538,63 @@ export type Database = {
|
||||
inversions: number | null
|
||||
length_meters: number | null
|
||||
manufacturer_id: string | null
|
||||
max_age: number | null
|
||||
max_g_force: number | null
|
||||
max_height_meters: number | null
|
||||
max_height_reached_meters: number | null
|
||||
max_speed_kmh: number | null
|
||||
min_age: number | null
|
||||
motion_pattern: string | null
|
||||
name: string
|
||||
opening_date: string | null
|
||||
opening_date_precision: string | null
|
||||
park_id: string
|
||||
platform_count: number | null
|
||||
projection_type: string | null
|
||||
propulsion_method: string[] | null
|
||||
review_count: number | null
|
||||
ride_model_id: string | null
|
||||
ride_sub_type: string | null
|
||||
ride_system: string | null
|
||||
rotation_speed_rpm: number | null
|
||||
rotation_type: string | null
|
||||
round_trip_duration_seconds: number | null
|
||||
route_length_meters: number | null
|
||||
scenes_count: number | null
|
||||
seating_type: string | null
|
||||
show_duration_seconds: number | null
|
||||
slug: string
|
||||
splash_height_meters: number | null
|
||||
stations_count: number | null
|
||||
status: string
|
||||
story_description: string | null
|
||||
support_material: string[] | null
|
||||
swing_angle_degrees: number | null
|
||||
theme_name: string | null
|
||||
track_material: string[] | null
|
||||
transport_type: string | null
|
||||
updated_at: string
|
||||
vehicle_capacity: number | null
|
||||
vehicles_count: number | null
|
||||
view_count_30d: number | null
|
||||
view_count_7d: number | null
|
||||
view_count_all: number | null
|
||||
water_depth_cm: number | null
|
||||
wetness_level: string | null
|
||||
}
|
||||
Insert: {
|
||||
age_requirement?: number | null
|
||||
animatronics_count?: number | null
|
||||
arm_length_meters?: number | null
|
||||
average_rating?: number | null
|
||||
banner_image_id?: string | null
|
||||
banner_image_url?: string | null
|
||||
boat_capacity?: number | null
|
||||
capacity_per_hour?: number | null
|
||||
card_image_id?: string | null
|
||||
card_image_url?: string | null
|
||||
category: string
|
||||
character_theme?: string | null
|
||||
closing_date?: string | null
|
||||
closing_date_precision?: string | null
|
||||
coaster_type?: string | null
|
||||
@@ -3570,6 +3603,8 @@ export type Database = {
|
||||
designer_id?: string | null
|
||||
drop_height_meters?: number | null
|
||||
duration_seconds?: number | null
|
||||
educational_theme?: string | null
|
||||
flume_type?: string | null
|
||||
height_requirement?: number | null
|
||||
id?: string
|
||||
image_url?: string | null
|
||||
@@ -3577,36 +3612,63 @@ export type Database = {
|
||||
inversions?: number | null
|
||||
length_meters?: number | null
|
||||
manufacturer_id?: string | null
|
||||
max_age?: number | null
|
||||
max_g_force?: number | null
|
||||
max_height_meters?: number | null
|
||||
max_height_reached_meters?: number | null
|
||||
max_speed_kmh?: number | null
|
||||
min_age?: number | null
|
||||
motion_pattern?: string | null
|
||||
name: string
|
||||
opening_date?: string | null
|
||||
opening_date_precision?: string | null
|
||||
park_id: string
|
||||
platform_count?: number | null
|
||||
projection_type?: string | null
|
||||
propulsion_method?: string[] | null
|
||||
review_count?: number | null
|
||||
ride_model_id?: string | null
|
||||
ride_sub_type?: string | null
|
||||
ride_system?: string | null
|
||||
rotation_speed_rpm?: number | null
|
||||
rotation_type?: string | null
|
||||
round_trip_duration_seconds?: number | null
|
||||
route_length_meters?: number | null
|
||||
scenes_count?: number | null
|
||||
seating_type?: string | null
|
||||
show_duration_seconds?: number | null
|
||||
slug: string
|
||||
splash_height_meters?: number | null
|
||||
stations_count?: number | null
|
||||
status?: string
|
||||
story_description?: string | null
|
||||
support_material?: string[] | null
|
||||
swing_angle_degrees?: number | null
|
||||
theme_name?: string | null
|
||||
track_material?: string[] | null
|
||||
transport_type?: string | null
|
||||
updated_at?: string
|
||||
vehicle_capacity?: number | null
|
||||
vehicles_count?: number | null
|
||||
view_count_30d?: number | null
|
||||
view_count_7d?: number | null
|
||||
view_count_all?: number | null
|
||||
water_depth_cm?: number | null
|
||||
wetness_level?: string | null
|
||||
}
|
||||
Update: {
|
||||
age_requirement?: number | null
|
||||
animatronics_count?: number | null
|
||||
arm_length_meters?: number | null
|
||||
average_rating?: number | null
|
||||
banner_image_id?: string | null
|
||||
banner_image_url?: string | null
|
||||
boat_capacity?: number | null
|
||||
capacity_per_hour?: number | null
|
||||
card_image_id?: string | null
|
||||
card_image_url?: string | null
|
||||
category?: string
|
||||
character_theme?: string | null
|
||||
closing_date?: string | null
|
||||
closing_date_precision?: string | null
|
||||
coaster_type?: string | null
|
||||
@@ -3615,6 +3677,8 @@ export type Database = {
|
||||
designer_id?: string | null
|
||||
drop_height_meters?: number | null
|
||||
duration_seconds?: number | null
|
||||
educational_theme?: string | null
|
||||
flume_type?: string | null
|
||||
height_requirement?: number | null
|
||||
id?: string
|
||||
image_url?: string | null
|
||||
@@ -3622,26 +3686,49 @@ export type Database = {
|
||||
inversions?: number | null
|
||||
length_meters?: number | null
|
||||
manufacturer_id?: string | null
|
||||
max_age?: number | null
|
||||
max_g_force?: number | null
|
||||
max_height_meters?: number | null
|
||||
max_height_reached_meters?: number | null
|
||||
max_speed_kmh?: number | null
|
||||
min_age?: number | null
|
||||
motion_pattern?: string | null
|
||||
name?: string
|
||||
opening_date?: string | null
|
||||
opening_date_precision?: string | null
|
||||
park_id?: string
|
||||
platform_count?: number | null
|
||||
projection_type?: string | null
|
||||
propulsion_method?: string[] | null
|
||||
review_count?: number | null
|
||||
ride_model_id?: string | null
|
||||
ride_sub_type?: string | null
|
||||
ride_system?: string | null
|
||||
rotation_speed_rpm?: number | null
|
||||
rotation_type?: string | null
|
||||
round_trip_duration_seconds?: number | null
|
||||
route_length_meters?: number | null
|
||||
scenes_count?: number | null
|
||||
seating_type?: string | null
|
||||
show_duration_seconds?: number | null
|
||||
slug?: string
|
||||
splash_height_meters?: number | null
|
||||
stations_count?: number | null
|
||||
status?: string
|
||||
story_description?: string | null
|
||||
support_material?: string[] | null
|
||||
swing_angle_degrees?: number | null
|
||||
theme_name?: string | null
|
||||
track_material?: string[] | null
|
||||
transport_type?: string | null
|
||||
updated_at?: string
|
||||
vehicle_capacity?: number | null
|
||||
vehicles_count?: number | null
|
||||
view_count_30d?: number | null
|
||||
view_count_7d?: number | null
|
||||
view_count_all?: number | null
|
||||
water_depth_cm?: number | null
|
||||
wetness_level?: string | null
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
|
||||
@@ -79,6 +79,40 @@ export function transformRideData(submissionData: RideSubmissionData): RideInser
|
||||
track_material: submissionData.track_material || null,
|
||||
support_material: submissionData.support_material || null,
|
||||
propulsion_method: submissionData.propulsion_method || null,
|
||||
// Water ride specific fields
|
||||
water_depth_cm: submissionData.water_depth_cm || null,
|
||||
splash_height_meters: submissionData.splash_height_meters || null,
|
||||
wetness_level: submissionData.wetness_level || null,
|
||||
flume_type: submissionData.flume_type || null,
|
||||
boat_capacity: submissionData.boat_capacity || null,
|
||||
// Dark ride specific fields
|
||||
theme_name: submissionData.theme_name || null,
|
||||
story_description: submissionData.story_description || null,
|
||||
show_duration_seconds: submissionData.show_duration_seconds || null,
|
||||
animatronics_count: submissionData.animatronics_count || null,
|
||||
projection_type: submissionData.projection_type || null,
|
||||
ride_system: submissionData.ride_system || null,
|
||||
scenes_count: submissionData.scenes_count || null,
|
||||
// Flat ride specific fields
|
||||
rotation_type: submissionData.rotation_type || null,
|
||||
motion_pattern: submissionData.motion_pattern || null,
|
||||
platform_count: submissionData.platform_count || null,
|
||||
swing_angle_degrees: submissionData.swing_angle_degrees || null,
|
||||
rotation_speed_rpm: submissionData.rotation_speed_rpm || null,
|
||||
arm_length_meters: submissionData.arm_length_meters || null,
|
||||
max_height_reached_meters: submissionData.max_height_reached_meters || null,
|
||||
// Kiddie ride specific fields
|
||||
min_age: submissionData.min_age || null,
|
||||
max_age: submissionData.max_age || null,
|
||||
educational_theme: submissionData.educational_theme || null,
|
||||
character_theme: submissionData.character_theme || null,
|
||||
// Transportation ride specific fields
|
||||
transport_type: submissionData.transport_type || null,
|
||||
route_length_meters: submissionData.route_length_meters || null,
|
||||
stations_count: submissionData.stations_count || null,
|
||||
vehicle_capacity: submissionData.vehicle_capacity || null,
|
||||
vehicles_count: submissionData.vehicles_count || null,
|
||||
round_trip_duration_seconds: submissionData.round_trip_duration_seconds || null,
|
||||
banner_image_url: submissionData.banner_image_url || null,
|
||||
banner_image_id: submissionData.banner_image_id || null,
|
||||
card_image_url: submissionData.card_image_url || null,
|
||||
|
||||
@@ -29,7 +29,11 @@ import {
|
||||
Waves,
|
||||
Theater,
|
||||
Train,
|
||||
Edit
|
||||
Edit,
|
||||
Wrench,
|
||||
Sparkles,
|
||||
Repeat,
|
||||
Baby
|
||||
} from 'lucide-react';
|
||||
import { ReviewsSection } from '@/components/reviews/ReviewsSection';
|
||||
import { MeasurementDisplay } from '@/components/ui/measurement-display';
|
||||
@@ -703,6 +707,345 @@ export default function RideDetail() {
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Coaster Materials & Propulsion */}
|
||||
{ride.category === 'roller_coaster' && (
|
||||
ride.track_material?.length > 0 ||
|
||||
ride.support_material?.length > 0 ||
|
||||
ride.propulsion_method?.length > 0
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Wrench className="w-5 h-5" />
|
||||
Coaster Construction
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{ride.track_material && ride.track_material.length > 0 && (
|
||||
<div>
|
||||
<div className="text-sm font-medium mb-2">Track Material</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{ride.track_material.map(material => (
|
||||
<Badge key={material} variant="outline">
|
||||
{material.replace('_', ' ').toUpperCase()}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ride.support_material && ride.support_material.length > 0 && (
|
||||
<div>
|
||||
<div className="text-sm font-medium mb-2">Support Material</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{ride.support_material.map(material => (
|
||||
<Badge key={material} variant="outline">
|
||||
{material.replace('_', ' ').toUpperCase()}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{ride.propulsion_method && ride.propulsion_method.length > 0 && (
|
||||
<div>
|
||||
<div className="text-sm font-medium mb-2">Propulsion Method</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{ride.propulsion_method.map(method => (
|
||||
<Badge key={method} variant="outline">
|
||||
{method.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Water Ride Details */}
|
||||
{ride.category === 'water_ride' && (
|
||||
ride.water_depth_cm || ride.splash_height_meters || ride.wetness_level ||
|
||||
ride.flume_type || ride.boat_capacity
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Waves className="w-5 h-5" />
|
||||
Water Ride Details
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{ride.water_depth_cm && (
|
||||
<div className="flex justify-between">
|
||||
<span>Water Depth</span>
|
||||
<span className="font-medium">
|
||||
<MeasurementDisplay value={ride.water_depth_cm} type="height" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.splash_height_meters && (
|
||||
<div className="flex justify-between">
|
||||
<span>Splash Height</span>
|
||||
<span className="font-medium">
|
||||
<MeasurementDisplay value={ride.splash_height_meters} type="distance" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.wetness_level && (
|
||||
<div className="flex justify-between">
|
||||
<span>Wetness Level</span>
|
||||
<Badge variant="outline">
|
||||
{ride.wetness_level.charAt(0).toUpperCase() + ride.wetness_level.slice(1)}
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
{ride.flume_type && (
|
||||
<div className="flex justify-between">
|
||||
<span>Flume Type</span>
|
||||
<span className="font-medium">
|
||||
{ride.flume_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.boat_capacity && (
|
||||
<div className="flex justify-between">
|
||||
<span>Boat Capacity</span>
|
||||
<span className="font-medium">{ride.boat_capacity} riders</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 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
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Sparkles className="w-5 h-5" />
|
||||
Dark Ride Details
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{ride.theme_name && (
|
||||
<div className="flex justify-between">
|
||||
<span>Theme</span>
|
||||
<span className="font-medium">{ride.theme_name}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.story_description && (
|
||||
<div>
|
||||
<div className="text-sm font-medium mb-1">Story</div>
|
||||
<p className="text-sm text-muted-foreground">{ride.story_description}</p>
|
||||
</div>
|
||||
)}
|
||||
{ride.show_duration_seconds && (
|
||||
<div className="flex justify-between">
|
||||
<span>Show Duration</span>
|
||||
<span className="font-medium">
|
||||
{Math.floor(ride.show_duration_seconds / 60)}:{(ride.show_duration_seconds % 60).toString().padStart(2, '0')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.animatronics_count && (
|
||||
<div className="flex justify-between">
|
||||
<span>Animatronics</span>
|
||||
<span className="font-medium">{ride.animatronics_count}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.scenes_count && (
|
||||
<div className="flex justify-between">
|
||||
<span>Scenes</span>
|
||||
<span className="font-medium">{ride.scenes_count}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.projection_type && (
|
||||
<div className="flex justify-between">
|
||||
<span>Projection Type</span>
|
||||
<span className="font-medium">
|
||||
{ride.projection_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.ride_system && (
|
||||
<div className="flex justify-between">
|
||||
<span>Ride System</span>
|
||||
<span className="font-medium">
|
||||
{ride.ride_system.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 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
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Repeat className="w-5 h-5" />
|
||||
Flat Ride Details
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{ride.rotation_type && (
|
||||
<div className="flex justify-between">
|
||||
<span>Rotation Type</span>
|
||||
<span className="font-medium">
|
||||
{ride.rotation_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.motion_pattern && (
|
||||
<div className="flex justify-between">
|
||||
<span>Motion Pattern</span>
|
||||
<span className="font-medium">
|
||||
{ride.motion_pattern.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.platform_count && (
|
||||
<div className="flex justify-between">
|
||||
<span>Platforms</span>
|
||||
<span className="font-medium">{ride.platform_count}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.swing_angle_degrees && (
|
||||
<div className="flex justify-between">
|
||||
<span>Swing Angle</span>
|
||||
<span className="font-medium">{ride.swing_angle_degrees}°</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.rotation_speed_rpm && (
|
||||
<div className="flex justify-between">
|
||||
<span>Rotation Speed</span>
|
||||
<span className="font-medium">{ride.rotation_speed_rpm} RPM</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.arm_length_meters && (
|
||||
<div className="flex justify-between">
|
||||
<span>Arm Length</span>
|
||||
<span className="font-medium">
|
||||
<MeasurementDisplay value={ride.arm_length_meters} type="distance" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.max_height_reached_meters && (
|
||||
<div className="flex justify-between">
|
||||
<span>Max Height Reached</span>
|
||||
<span className="font-medium">
|
||||
<MeasurementDisplay value={ride.max_height_reached_meters} type="distance" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Kiddie Ride Details */}
|
||||
{ride.category === 'kiddie_ride' && (
|
||||
ride.min_age || ride.max_age || ride.educational_theme || ride.character_theme
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Baby className="w-5 h-5" />
|
||||
Kiddie Ride Details
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{(ride.min_age || ride.max_age) && (
|
||||
<div className="flex justify-between">
|
||||
<span>Age Range</span>
|
||||
<span className="font-medium">
|
||||
{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'}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.educational_theme && (
|
||||
<div className="flex justify-between">
|
||||
<span>Educational Theme</span>
|
||||
<span className="font-medium">{ride.educational_theme}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.character_theme && (
|
||||
<div className="flex justify-between">
|
||||
<span>Character Theme</span>
|
||||
<span className="font-medium">{ride.character_theme}</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* 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
|
||||
) && (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Train className="w-5 h-5" />
|
||||
Transportation Details
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
{ride.transport_type && (
|
||||
<div className="flex justify-between">
|
||||
<span>Transport Type</span>
|
||||
<span className="font-medium">
|
||||
{ride.transport_type.replace('_', ' ').replace(/\b\w/g, l => l.toUpperCase())}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.route_length_meters && (
|
||||
<div className="flex justify-between">
|
||||
<span>Route Length</span>
|
||||
<span className="font-medium">
|
||||
<MeasurementDisplay value={ride.route_length_meters} type="distance" />
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.stations_count && (
|
||||
<div className="flex justify-between">
|
||||
<span>Stations</span>
|
||||
<span className="font-medium">{ride.stations_count}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.vehicle_capacity && (
|
||||
<div className="flex justify-between">
|
||||
<span>Vehicle Capacity</span>
|
||||
<span className="font-medium">{ride.vehicle_capacity} passengers</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.vehicles_count && (
|
||||
<div className="flex justify-between">
|
||||
<span>Number of Vehicles</span>
|
||||
<span className="font-medium">{ride.vehicles_count}</span>
|
||||
</div>
|
||||
)}
|
||||
{ride.round_trip_duration_seconds && (
|
||||
<div className="flex justify-between">
|
||||
<span>Round Trip Duration</span>
|
||||
<span className="font-medium">
|
||||
{Math.floor(ride.round_trip_duration_seconds / 60)}:{(ride.round_trip_duration_seconds % 60).toString().padStart(2, '0')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
@@ -768,11 +1111,50 @@ export default function RideDetail() {
|
||||
max_height_meters: ride.max_height_meters,
|
||||
length_meters: ride.length_meters,
|
||||
inversions: ride.inversions,
|
||||
// Coaster fields
|
||||
coaster_type: ride.coaster_type,
|
||||
seating_type: ride.seating_type,
|
||||
intensity_level: ride.intensity_level,
|
||||
track_material: ride.track_material,
|
||||
support_material: ride.support_material,
|
||||
propulsion_method: ride.propulsion_method,
|
||||
drop_height_meters: ride.drop_height_meters,
|
||||
max_g_force: ride.max_g_force,
|
||||
// Water ride fields
|
||||
water_depth_cm: ride.water_depth_cm,
|
||||
splash_height_meters: ride.splash_height_meters,
|
||||
wetness_level: ride.wetness_level as any,
|
||||
flume_type: ride.flume_type,
|
||||
boat_capacity: ride.boat_capacity,
|
||||
// Dark ride fields
|
||||
theme_name: ride.theme_name,
|
||||
story_description: ride.story_description,
|
||||
show_duration_seconds: ride.show_duration_seconds,
|
||||
animatronics_count: ride.animatronics_count,
|
||||
projection_type: ride.projection_type,
|
||||
ride_system: ride.ride_system,
|
||||
scenes_count: ride.scenes_count,
|
||||
// Flat ride fields
|
||||
rotation_type: ride.rotation_type as any,
|
||||
motion_pattern: ride.motion_pattern,
|
||||
platform_count: ride.platform_count,
|
||||
swing_angle_degrees: ride.swing_angle_degrees,
|
||||
rotation_speed_rpm: ride.rotation_speed_rpm,
|
||||
arm_length_meters: ride.arm_length_meters,
|
||||
max_height_reached_meters: ride.max_height_reached_meters,
|
||||
// Kiddie ride fields
|
||||
min_age: ride.min_age,
|
||||
max_age: ride.max_age,
|
||||
educational_theme: ride.educational_theme,
|
||||
character_theme: ride.character_theme,
|
||||
// Transportation fields
|
||||
transport_type: ride.transport_type as any,
|
||||
route_length_meters: ride.route_length_meters,
|
||||
stations_count: ride.stations_count,
|
||||
vehicle_capacity: ride.vehicle_capacity,
|
||||
vehicles_count: ride.vehicles_count,
|
||||
round_trip_duration_seconds: ride.round_trip_duration_seconds,
|
||||
// Common fields
|
||||
manufacturer_id: ride.manufacturer?.id,
|
||||
ride_model_id: ride.ride_model?.id,
|
||||
banner_image_url: ride.banner_image_url,
|
||||
|
||||
@@ -180,7 +180,7 @@ export default function Rides() {
|
||||
}
|
||||
}
|
||||
|
||||
// Track material filter
|
||||
// Track material filter (array field)
|
||||
if (filters.trackMaterials.length > 0) {
|
||||
if (!ride.track_material || ride.track_material.length === 0 ||
|
||||
!ride.track_material.some(material => filters.trackMaterials.includes(material))) {
|
||||
@@ -188,6 +188,22 @@ export default function Rides() {
|
||||
}
|
||||
}
|
||||
|
||||
// Support material filter (array field)
|
||||
if (filters.supportMaterials.length > 0) {
|
||||
if (!ride.support_material || ride.support_material.length === 0 ||
|
||||
!ride.support_material.some(material => filters.supportMaterials.includes(material))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Propulsion method filter (array field)
|
||||
if (filters.propulsionMethods.length > 0) {
|
||||
if (!ride.propulsion_method || ride.propulsion_method.length === 0 ||
|
||||
!ride.propulsion_method.some(method => filters.propulsionMethods.includes(method))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Speed filter
|
||||
if (filters.minSpeed > 0 || filters.maxSpeed < 200) {
|
||||
const speed = ride.max_speed_kmh || 0;
|
||||
|
||||
@@ -162,7 +162,7 @@ export interface Ride {
|
||||
banner_image_id?: string;
|
||||
card_image_url?: string;
|
||||
card_image_id?: string;
|
||||
// New roller coaster specific fields
|
||||
// Roller coaster specific fields
|
||||
coaster_type?: string;
|
||||
seating_type?: string;
|
||||
intensity_level?: string;
|
||||
@@ -171,6 +171,40 @@ export interface Ride {
|
||||
propulsion_method?: string[];
|
||||
drop_height_meters?: number;
|
||||
max_g_force?: number;
|
||||
// Water ride specific fields
|
||||
water_depth_cm?: number;
|
||||
splash_height_meters?: number;
|
||||
wetness_level?: string;
|
||||
flume_type?: string;
|
||||
boat_capacity?: number;
|
||||
// Dark ride specific fields
|
||||
theme_name?: string;
|
||||
story_description?: string;
|
||||
show_duration_seconds?: number;
|
||||
animatronics_count?: number;
|
||||
projection_type?: string;
|
||||
ride_system?: string;
|
||||
scenes_count?: number;
|
||||
// Flat ride specific fields
|
||||
rotation_type?: string;
|
||||
motion_pattern?: string;
|
||||
platform_count?: number;
|
||||
swing_angle_degrees?: number;
|
||||
rotation_speed_rpm?: number;
|
||||
arm_length_meters?: number;
|
||||
max_height_reached_meters?: number;
|
||||
// Kiddie ride specific fields
|
||||
min_age?: number;
|
||||
max_age?: number;
|
||||
educational_theme?: string;
|
||||
character_theme?: string;
|
||||
// Transportation specific fields
|
||||
transport_type?: string;
|
||||
route_length_meters?: number;
|
||||
stations_count?: number;
|
||||
vehicle_capacity?: number;
|
||||
vehicles_count?: number;
|
||||
round_trip_duration_seconds?: number;
|
||||
}
|
||||
|
||||
export interface Profile {
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
-- Add category-specific fields to rides table
|
||||
|
||||
-- Water ride specific columns
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS water_depth_cm INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS splash_height_meters DECIMAL(10,2);
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS wetness_level TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS flume_type TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS boat_capacity INTEGER;
|
||||
|
||||
-- Dark ride specific columns
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS theme_name TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS story_description TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS show_duration_seconds INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS animatronics_count INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS projection_type TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS ride_system TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS scenes_count INTEGER;
|
||||
|
||||
-- Flat ride specific columns
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS rotation_type TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS motion_pattern TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS platform_count INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS swing_angle_degrees INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS rotation_speed_rpm INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS arm_length_meters DECIMAL(10,2);
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS max_height_reached_meters DECIMAL(10,2);
|
||||
|
||||
-- Kiddie ride specific columns
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS min_age INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS max_age INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS educational_theme TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS character_theme TEXT;
|
||||
|
||||
-- Transportation ride specific columns
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS transport_type TEXT;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS route_length_meters DECIMAL(10,2);
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS stations_count INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS vehicle_capacity INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS vehicles_count INTEGER;
|
||||
ALTER TABLE public.rides ADD COLUMN IF NOT EXISTS round_trip_duration_seconds INTEGER;
|
||||
|
||||
-- Add check constraints for enum-like fields
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_wetness_level;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_wetness_level
|
||||
CHECK (wetness_level IS NULL OR wetness_level IN ('none', 'light', 'moderate', 'heavy', 'soaked'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_flume_type;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_flume_type
|
||||
CHECK (flume_type IS NULL OR flume_type IN ('log_flume', 'shoot_the_chute', 'river_rapids', 'water_coaster', 'flume_ride'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_projection_type;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_projection_type
|
||||
CHECK (projection_type IS NULL OR projection_type IN ('2d', '3d', '4d', 'holographic', 'projection_mapping', 'none'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_ride_system;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_ride_system
|
||||
CHECK (ride_system IS NULL OR ride_system IN ('omnimover', 'trackless', 'motion_simulator', 'boat', 'suspended', 'walk_through'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_rotation_type;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_rotation_type
|
||||
CHECK (rotation_type IS NULL OR rotation_type IN ('horizontal', 'vertical', 'diagonal', 'multi_axis', 'none'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_motion_pattern;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_motion_pattern
|
||||
CHECK (motion_pattern IS NULL OR motion_pattern IN ('circular', 'pendulum', 'spinning', 'tilting', 'rocking', 'wave', 'bouncing'));
|
||||
|
||||
ALTER TABLE public.rides DROP CONSTRAINT IF EXISTS check_transport_type;
|
||||
ALTER TABLE public.rides ADD CONSTRAINT check_transport_type
|
||||
CHECK (transport_type IS NULL OR transport_type IN ('monorail', 'train', 'chairlift', 'gondola', 'tram', 'peoplemover', 'cable_car'));
|
||||
|
||||
-- Add indexes for commonly queried fields
|
||||
CREATE INDEX IF NOT EXISTS idx_rides_wetness_level ON public.rides(wetness_level) WHERE wetness_level IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_rides_transport_type ON public.rides(transport_type) WHERE transport_type IS NOT NULL;
|
||||
CREATE INDEX IF NOT EXISTS idx_rides_rotation_type ON public.rides(rotation_type) WHERE rotation_type IS NOT NULL;
|
||||
|
||||
-- Add comments for documentation
|
||||
COMMENT ON COLUMN public.rides.water_depth_cm IS 'Water depth in centimeters for water rides';
|
||||
COMMENT ON COLUMN public.rides.splash_height_meters IS 'Maximum splash height in meters';
|
||||
COMMENT ON COLUMN public.rides.wetness_level IS 'How wet riders get: none, light, moderate, heavy, soaked';
|
||||
COMMENT ON COLUMN public.rides.theme_name IS 'Theme name for dark rides';
|
||||
COMMENT ON COLUMN public.rides.story_description IS 'Story/narrative description for dark rides';
|
||||
COMMENT ON COLUMN public.rides.rotation_type IS 'Type of rotation for flat rides';
|
||||
COMMENT ON COLUMN public.rides.transport_type IS 'Type of transportation system';
|
||||
Reference in New Issue
Block a user