mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 00:11:14 -05:00
Fix entity filters
This commit is contained in:
@@ -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 (
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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() {
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex flex-wrap items-center gap-1.5 sm:gap-2">
|
||||
<Badge variant="secondary" className="flex items-center justify-center text-sm sm:text-base px-2 py-0.5 sm:px-3 sm:py-1 whitespace-nowrap">
|
||||
{filteredRides.length} rides
|
||||
{filteredAndSortedRides.length} rides
|
||||
</Badge>
|
||||
<Badge variant="outline" className="flex items-center justify-center text-xs sm:text-sm px-2 py-0.5 whitespace-nowrap">
|
||||
{rides.filter(r => r.category === 'roller_coaster').length} coasters
|
||||
@@ -276,15 +445,15 @@ export default function Rides() {
|
||||
|
||||
{/* Results Area */}
|
||||
<div className="flex-1 min-w-0">
|
||||
{filteredRides.length > 0 ? (
|
||||
{filteredAndSortedRides.length > 0 ? (
|
||||
viewMode === 'grid' ? (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 3xl:grid-cols-7 gap-4 lg:gap-5 xl:gap-4 2xl:gap-5">
|
||||
{filteredRides.map((ride) => (
|
||||
{filteredAndSortedRides.map((ride) => (
|
||||
<RideCard key={ride.id} ride={ride} showParkName={true} />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<RideListView rides={filteredRides} onRideClick={(ride) => navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`)} />
|
||||
<RideListView rides={filteredAndSortedRides} onRideClick={(ride) => navigate(`/parks/${ride.park?.slug}/rides/${ride.slug}`)} />
|
||||
)
|
||||
) : (
|
||||
<div className="text-center py-12">
|
||||
|
||||
Reference in New Issue
Block a user