mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 22:11:24 -05:00
Approve database migration
This commit is contained in:
234
src/hooks/useRideCreditFilters.ts
Normal file
234
src/hooks/useRideCreditFilters.ts
Normal file
@@ -0,0 +1,234 @@
|
||||
import { useState, useMemo, useCallback } from 'react';
|
||||
import { useDebounce } from '@/hooks/useDebounce';
|
||||
import { RideCreditFilters, FilterPreset } from '@/types/ride-credits';
|
||||
import { UserRideCredit } from '@/types/database';
|
||||
|
||||
export function useRideCreditFilters(credits: UserRideCredit[]) {
|
||||
const [filters, setFilters] = useState<RideCreditFilters>({});
|
||||
const debouncedSearchQuery = useDebounce(filters.searchQuery || '', 300);
|
||||
|
||||
const updateFilter = useCallback((key: keyof RideCreditFilters, value: any) => {
|
||||
setFilters(prev => ({ ...prev, [key]: value }));
|
||||
}, []);
|
||||
|
||||
const clearFilters = useCallback(() => {
|
||||
setFilters({});
|
||||
}, []);
|
||||
|
||||
const applyPreset = useCallback((preset: FilterPreset) => {
|
||||
switch (preset) {
|
||||
case 'mostRidden':
|
||||
setFilters({ minRideCount: 10 });
|
||||
break;
|
||||
case 'recentlyAdded':
|
||||
// Will be sorted by date
|
||||
setFilters({});
|
||||
break;
|
||||
case 'singleRides':
|
||||
setFilters({ minRideCount: 1, maxRideCount: 1 });
|
||||
break;
|
||||
case 'needRating':
|
||||
setFilters({ hasRating: false });
|
||||
break;
|
||||
case 'highlyRated':
|
||||
setFilters({ hasRating: true, minUserRating: 4 });
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
clearFilters();
|
||||
break;
|
||||
}
|
||||
}, [clearFilters]);
|
||||
|
||||
const filteredCredits = useMemo(() => {
|
||||
let result = [...credits];
|
||||
|
||||
// Search filter
|
||||
if (debouncedSearchQuery) {
|
||||
const search = debouncedSearchQuery.toLowerCase();
|
||||
result = result.filter(credit =>
|
||||
credit.rides?.name?.toLowerCase().includes(search) ||
|
||||
credit.rides?.parks?.name?.toLowerCase().includes(search)
|
||||
);
|
||||
}
|
||||
|
||||
// Categories
|
||||
if (filters.categories && filters.categories.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.categories!.includes(credit.rides?.category || '')
|
||||
);
|
||||
}
|
||||
|
||||
// Geographic filters
|
||||
if (filters.countries && filters.countries.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.countries!.includes(credit.rides?.parks?.locations?.country || '')
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.statesProvinces && filters.statesProvinces.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.statesProvinces!.includes(credit.rides?.parks?.locations?.state_province || '')
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.cities && filters.cities.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.cities!.includes(credit.rides?.parks?.locations?.city || '')
|
||||
);
|
||||
}
|
||||
|
||||
// Park filters
|
||||
if (filters.parks && filters.parks.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.parks!.includes(credit.rides?.parks?.id || '')
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.parkTypes && filters.parkTypes.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.parkTypes!.includes(credit.rides?.parks?.park_type || '')
|
||||
);
|
||||
}
|
||||
|
||||
// Manufacturers
|
||||
if (filters.manufacturers && filters.manufacturers.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
credit.rides?.manufacturer?.id &&
|
||||
filters.manufacturers!.includes(credit.rides.manufacturer.id)
|
||||
);
|
||||
}
|
||||
|
||||
// Ride count range
|
||||
if (filters.minRideCount !== undefined) {
|
||||
result = result.filter(credit => credit.ride_count >= filters.minRideCount!);
|
||||
}
|
||||
|
||||
if (filters.maxRideCount !== undefined) {
|
||||
result = result.filter(credit => credit.ride_count <= filters.maxRideCount!);
|
||||
}
|
||||
|
||||
// Speed range
|
||||
if (filters.minSpeed !== undefined || filters.maxSpeed !== undefined) {
|
||||
result = result.filter(credit => {
|
||||
const speed = credit.rides?.max_speed_kmh;
|
||||
if (!speed) return false;
|
||||
if (filters.minSpeed && speed < filters.minSpeed) return false;
|
||||
if (filters.maxSpeed && speed > filters.maxSpeed) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Height range
|
||||
if (filters.minHeight !== undefined || filters.maxHeight !== undefined) {
|
||||
result = result.filter(credit => {
|
||||
const height = credit.rides?.max_height_meters;
|
||||
if (!height) return false;
|
||||
if (filters.minHeight && height < filters.minHeight) return false;
|
||||
if (filters.maxHeight && height > filters.maxHeight) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Inversions
|
||||
if (filters.hasInversions !== undefined) {
|
||||
result = result.filter(credit => {
|
||||
const inversions = credit.rides?.inversions || 0;
|
||||
return filters.hasInversions ? inversions > 0 : inversions === 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (filters.minInversions !== undefined) {
|
||||
result = result.filter(credit => {
|
||||
const inversions = credit.rides?.inversions || 0;
|
||||
return inversions >= filters.minInversions!;
|
||||
});
|
||||
}
|
||||
|
||||
// User rating
|
||||
if (filters.hasRating === true) {
|
||||
result = result.filter(credit => credit.personal_rating !== null);
|
||||
} else if (filters.hasRating === false) {
|
||||
result = result.filter(credit => credit.personal_rating === null);
|
||||
}
|
||||
|
||||
if (filters.minUserRating !== undefined) {
|
||||
result = result.filter(credit =>
|
||||
(credit.personal_rating || 0) >= filters.minUserRating!
|
||||
);
|
||||
}
|
||||
|
||||
// Notes
|
||||
if (filters.hasNotes === true) {
|
||||
result = result.filter(credit =>
|
||||
credit.personal_notes && credit.personal_notes.trim().length > 0
|
||||
);
|
||||
} else if (filters.hasNotes === false) {
|
||||
result = result.filter(credit =>
|
||||
!credit.personal_notes || credit.personal_notes.trim().length === 0
|
||||
);
|
||||
}
|
||||
|
||||
// Photos
|
||||
if (filters.hasPhotos === true) {
|
||||
result = result.filter(credit => credit.personal_photo_id !== null);
|
||||
} else if (filters.hasPhotos === false) {
|
||||
result = result.filter(credit => credit.personal_photo_id === null);
|
||||
}
|
||||
|
||||
// Date ranges
|
||||
if (filters.firstRideDateFrom) {
|
||||
result = result.filter(credit =>
|
||||
credit.first_ride_date &&
|
||||
new Date(credit.first_ride_date) >= filters.firstRideDateFrom!
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.firstRideDateTo) {
|
||||
result = result.filter(credit =>
|
||||
credit.first_ride_date &&
|
||||
new Date(credit.first_ride_date) <= filters.firstRideDateTo!
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.lastRideDateFrom) {
|
||||
result = result.filter(credit =>
|
||||
credit.last_ride_date &&
|
||||
new Date(credit.last_ride_date) >= filters.lastRideDateFrom!
|
||||
);
|
||||
}
|
||||
|
||||
if (filters.lastRideDateTo) {
|
||||
result = result.filter(credit =>
|
||||
credit.last_ride_date &&
|
||||
new Date(credit.last_ride_date) <= filters.lastRideDateTo!
|
||||
);
|
||||
}
|
||||
|
||||
// Ride status
|
||||
if (filters.rideStatuses && filters.rideStatuses.length > 0) {
|
||||
result = result.filter(credit =>
|
||||
filters.rideStatuses!.includes(credit.rides?.status || '')
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}, [credits, filters, debouncedSearchQuery]);
|
||||
|
||||
const activeFilterCount = useMemo(() => {
|
||||
return Object.entries(filters).filter(([_, value]) => {
|
||||
if (Array.isArray(value)) return value.length > 0;
|
||||
if (typeof value === 'boolean') return true;
|
||||
return value !== undefined && value !== null && value !== '';
|
||||
}).length;
|
||||
}, [filters]);
|
||||
|
||||
return {
|
||||
filters,
|
||||
updateFilter,
|
||||
clearFilters,
|
||||
applyPreset,
|
||||
filteredCredits,
|
||||
activeFilterCount,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user