From e7bcba8fee46e5fe9fb96989a8883c7f4fdad50c Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 17:13:27 +0000 Subject: [PATCH] Fix entity filters --- src/pages/Designers.tsx | 77 +++++++++++++-- src/pages/Manufacturers.tsx | 77 +++++++++++++-- src/pages/Rides.tsx | 191 +++++++++++++++++++++++++++++++++--- 3 files changed, 322 insertions(+), 23 deletions(-) diff --git a/src/pages/Designers.tsx b/src/pages/Designers.tsx index b04e83fc..abc9768c 100644 --- a/src/pages/Designers.tsx +++ b/src/pages/Designers.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Header } from '@/components/layout/Header'; import { Input } from '@/components/ui/input'; @@ -91,11 +91,76 @@ export default function Designers() { } }; - const filteredCompanies = companies.filter(company => - company.name.toLowerCase().includes(searchQuery.toLowerCase()) || - company.headquarters_location?.toLowerCase().includes(searchQuery.toLowerCase()) || - company.description?.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const filteredCompanies = React.useMemo(() => { + return companies.filter(company => { + // Search filter + const matchesSearch = company.name.toLowerCase().includes(searchQuery.toLowerCase()) || + company.headquarters_location?.toLowerCase().includes(searchQuery.toLowerCase()) || + company.description?.toLowerCase().includes(searchQuery.toLowerCase()); + + if (!matchesSearch) return false; + + // Person type filter + if (filters.personType !== 'all') { + if (filters.personType === 'individual' && company.person_type !== 'individual') { + return false; + } + if (filters.personType === 'company' && company.person_type === 'individual') { + return false; + } + } + + // Country filter + if (filters.countries.length > 0) { + if (!company.headquarters_location || + !filters.countries.some(c => company.headquarters_location?.includes(c))) { + return false; + } + } + + // Rating filter + const rating = company.average_rating || 0; + if (rating < filters.minRating || rating > filters.maxRating) { + return false; + } + + // Review count filter + const reviewCount = company.review_count || 0; + if (reviewCount < filters.minReviewCount || reviewCount > filters.maxReviewCount) { + return false; + } + + // Founded date filter + if (filters.foundedDateFrom || filters.foundedDateTo) { + if (!company.founded_year) { + return false; + } + if (filters.foundedDateFrom && company.founded_year < filters.foundedDateFrom.getFullYear()) { + return false; + } + if (filters.foundedDateTo && company.founded_year > filters.foundedDateTo.getFullYear()) { + return false; + } + } + + // Has rating filter + if (filters.hasRating && !company.average_rating) { + return false; + } + + // Has founded date filter + if (filters.hasFoundedDate && !company.founded_year) { + return false; + } + + // Is individual filter + if (filters.isIndividual && company.person_type !== 'individual') { + return false; + } + + return true; + }); + }, [companies, searchQuery, filters]); if (loading) { return ( diff --git a/src/pages/Manufacturers.tsx b/src/pages/Manufacturers.tsx index 4455d5dd..45257e9c 100644 --- a/src/pages/Manufacturers.tsx +++ b/src/pages/Manufacturers.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Header } from '@/components/layout/Header'; import { Input } from '@/components/ui/input'; @@ -78,11 +78,76 @@ export default function Manufacturers() { } }; - const filteredCompanies = companies.filter(company => - company.name.toLowerCase().includes(searchQuery.toLowerCase()) || - company.headquarters_location?.toLowerCase().includes(searchQuery.toLowerCase()) || - company.description?.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const filteredCompanies = React.useMemo(() => { + return companies.filter(company => { + // Search filter + const matchesSearch = company.name.toLowerCase().includes(searchQuery.toLowerCase()) || + company.headquarters_location?.toLowerCase().includes(searchQuery.toLowerCase()) || + company.description?.toLowerCase().includes(searchQuery.toLowerCase()); + + if (!matchesSearch) return false; + + // Person type filter + if (filters.personType !== 'all') { + if (filters.personType === 'individual' && company.person_type !== 'individual') { + return false; + } + if (filters.personType === 'company' && company.person_type === 'individual') { + return false; + } + } + + // Country filter + if (filters.countries.length > 0) { + if (!company.headquarters_location || + !filters.countries.some(c => company.headquarters_location?.includes(c))) { + return false; + } + } + + // Rating filter + const rating = company.average_rating || 0; + if (rating < filters.minRating || rating > filters.maxRating) { + return false; + } + + // Review count filter + const reviewCount = company.review_count || 0; + if (reviewCount < filters.minReviewCount || reviewCount > filters.maxReviewCount) { + return false; + } + + // Founded date filter + if (filters.foundedDateFrom || filters.foundedDateTo) { + if (!company.founded_year) { + return false; + } + if (filters.foundedDateFrom && company.founded_year < filters.foundedDateFrom.getFullYear()) { + return false; + } + if (filters.foundedDateTo && company.founded_year > filters.foundedDateTo.getFullYear()) { + return false; + } + } + + // Has rating filter + if (filters.hasRating && !company.average_rating) { + return false; + } + + // Has founded date filter + if (filters.hasFoundedDate && !company.founded_year) { + return false; + } + + // Is individual filter + if (filters.isIndividual && company.person_type !== 'individual') { + return false; + } + + return true; + }); + }, [companies, searchQuery, filters]); const handleCreateSubmit = async (data: any) => { try { diff --git a/src/pages/Rides.tsx b/src/pages/Rides.tsx index 09ae9857..086f42a2 100644 --- a/src/pages/Rides.tsx +++ b/src/pages/Rides.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Header } from '@/components/layout/Header'; import { Button } from '@/components/ui/button'; @@ -15,7 +15,7 @@ import { RideCard } from '@/components/rides/RideCard'; import { RideListView } from '@/components/rides/RideListView'; import { RideForm } from '@/components/admin/RideForm'; import { RideFilters, RideFilterState, defaultRideFilters } from '@/components/rides/RideFilters'; -import { Ride } from '@/types/database'; +import { Ride, Park } from '@/types/database'; import { supabase } from '@/integrations/supabase/client'; import { useAuth } from '@/hooks/useAuth'; import { useUserRole } from '@/hooks/useUserRole'; @@ -89,11 +89,180 @@ export default function Rides() { } }; - const filteredRides = rides.filter(ride => - ride.name.toLowerCase().includes(searchQuery.toLowerCase()) || - ride.park?.name?.toLowerCase().includes(searchQuery.toLowerCase()) || - ride.manufacturer?.name?.toLowerCase().includes(searchQuery.toLowerCase()) - ); + const filteredAndSortedRides = React.useMemo(() => { + let filtered = rides.filter(ride => { + // Search filter + if (searchQuery) { + const searchTerm = searchQuery.toLowerCase(); + const matchesSearch = + ride.name.toLowerCase().includes(searchTerm) || + ride.park?.name?.toLowerCase().includes(searchTerm) || + ride.manufacturer?.name?.toLowerCase().includes(searchTerm) || + ride.designer?.name?.toLowerCase().includes(searchTerm); + if (!matchesSearch) return false; + } + + // Category filter + if (filters.categories.length > 0 && !filters.categories.includes(ride.category)) { + return false; + } + + // Status filter + if (filters.status !== 'all' && ride.status !== filters.status) { + return false; + } + + // Country filter + if (filters.countries.length > 0) { + if (!ride.park?.location?.country || !filters.countries.includes(ride.park.location.country)) { + return false; + } + } + + // States filter + if (filters.statesProvinces.length > 0) { + if (!ride.park?.location?.state_province || !filters.statesProvinces.includes(ride.park.location.state_province)) { + return false; + } + } + + // Cities filter + if (filters.cities.length > 0) { + if (!ride.park?.location?.city || !filters.cities.includes(ride.park.location.city)) { + return false; + } + } + + // Parks filter + if (filters.parks.length > 0) { + const parkId = (ride.park as Park)?.id; + if (!parkId || !filters.parks.includes(parkId)) { + return false; + } + } + + // Manufacturer filter + if (filters.manufacturers.length > 0) { + if (!ride.manufacturer?.id || !filters.manufacturers.includes(ride.manufacturer.id)) { + return false; + } + } + + // Designer filter + if (filters.designers.length > 0) { + if (!ride.designer?.id || !filters.designers.includes(ride.designer.id)) { + return false; + } + } + + // Coaster type filter + if (filters.coasterTypes.length > 0) { + // Assuming coaster_type is a field on the ride + if (!ride.coaster_type || !filters.coasterTypes.includes(ride.coaster_type)) { + return false; + } + } + + // Seating type filter + if (filters.seatingTypes.length > 0) { + if (!ride.seating_type || !filters.seatingTypes.includes(ride.seating_type)) { + return false; + } + } + + // Intensity level filter + if (filters.intensityLevels.length > 0) { + if (!ride.intensity_level || !filters.intensityLevels.includes(ride.intensity_level)) { + return false; + } + } + + // Track material filter + if (filters.trackMaterials.length > 0) { + if (!ride.track_material || !filters.trackMaterials.includes(ride.track_material)) { + return false; + } + } + + // Speed filter + if (filters.minSpeed > 0 || filters.maxSpeed < 200) { + const speed = ride.max_speed_kmh || 0; + if (speed < filters.minSpeed || speed > filters.maxSpeed) { + return false; + } + } + + // Height filter + if (filters.minHeight > 0 || filters.maxHeight < 150) { + const height = ride.max_height_meters || 0; + if (height < filters.minHeight || height > filters.maxHeight) { + return false; + } + } + + // Length filter + if (filters.minLength > 0 || filters.maxLength < 3000) { + const length = ride.length_meters || 0; + if (length < filters.minLength || length > filters.maxLength) { + return false; + } + } + + // Inversions filter + if (filters.minInversions > 0 || filters.maxInversions < 14) { + const inversions = ride.inversions || 0; + if (inversions < filters.minInversions || inversions > filters.maxInversions) { + return false; + } + } + + // Has inversions checkbox + if (filters.hasInversions && (!ride.inversions || ride.inversions === 0)) { + return false; + } + + // Opening date filter + if (filters.openingDateFrom || filters.openingDateTo) { + if (!ride.opening_date) { + return false; + } + const openingDate = new Date(ride.opening_date); + if (filters.openingDateFrom && openingDate < filters.openingDateFrom) { + return false; + } + if (filters.openingDateTo && openingDate > filters.openingDateTo) { + return false; + } + } + + // Operating only filter + if (filters.operatingOnly && ride.status !== 'operating') { + return false; + } + + return true; + }); + + // Apply sorting + filtered.sort((a, b) => { + switch (sortBy) { + case 'name': + return a.name.localeCompare(b.name); + case 'rating': + return (b.average_rating || 0) - (a.average_rating || 0); + case 'speed': + return (b.max_speed_kmh || 0) - (a.max_speed_kmh || 0); + case 'height': + return (b.max_height_meters || 0) - (a.max_height_meters || 0); + case 'reviews': + return (b.review_count || 0) - (a.review_count || 0); + default: + return 0; + } + }); + + return filtered; + }, [rides, searchQuery, sortBy, filters]); const categories = [ @@ -150,7 +319,7 @@ export default function Rides() {
- {filteredRides.length} rides + {filteredAndSortedRides.length} rides {rides.filter(r => r.category === 'roller_coaster').length} coasters @@ -276,15 +445,15 @@ export default function Rides() { {/* Results Area */}
- {filteredRides.length > 0 ? ( + {filteredAndSortedRides.length > 0 ? ( viewMode === 'grid' ? (
- {filteredRides.map((ride) => ( + {filteredAndSortedRides.map((ride) => ( ))}
) : ( - navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`)} /> + navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`)} /> ) ) : (