feat: Implement Phase 4 cleanup and polish

This commit is contained in:
gpt-engineer-app[bot]
2025-10-30 23:20:23 +00:00
parent 9073b239ba
commit cecb27a302
17 changed files with 660 additions and 435 deletions

View File

@@ -0,0 +1,39 @@
/**
* Model Rides Hook
*
* Fetches rides using a specific ride model with caching.
*/
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
import { queryKeys } from '@/lib/queryKeys';
export function useModelRides(modelId: string | undefined, limit?: number) {
return useQuery({
queryKey: queryKeys.rideModels.rides(modelId || '', limit),
queryFn: async () => {
if (!modelId) return [];
let query = supabase
.from('rides')
.select(`
*,
park:parks!inner(name, slug, location:locations(*)),
manufacturer:companies!rides_manufacturer_id_fkey(*),
ride_model:ride_models(id, name, slug, manufacturer_id, category)
`)
.eq('ride_model_id', modelId)
.order('name');
if (limit) query = query.limit(limit);
const { data, error } = await query;
if (error) throw error;
return data || [];
},
enabled: !!modelId,
staleTime: 5 * 60 * 1000,
gcTime: 15 * 60 * 1000,
refetchOnWindowFocus: false,
});
}

View File

@@ -0,0 +1,32 @@
/**
* Model Statistics Hook
*
* Fetches ride model statistics (ride count, photo count) with parallel queries.
*/
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
import { queryKeys } from '@/lib/queryKeys';
export function useModelStatistics(modelId: string | undefined) {
return useQuery({
queryKey: queryKeys.rideModels.statistics(modelId || ''),
queryFn: async () => {
if (!modelId) return { rideCount: 0, photoCount: 0 };
const [ridesResult, photosResult] = await Promise.all([
supabase.from('rides').select('id', { count: 'exact', head: true }).eq('ride_model_id', modelId),
supabase.from('photos').select('id', { count: 'exact', head: true }).eq('entity_type', 'ride_model').eq('entity_id', modelId)
]);
return {
rideCount: ridesResult.count || 0,
photoCount: photosResult.count || 0
};
},
enabled: !!modelId,
staleTime: 10 * 60 * 1000,
gcTime: 20 * 60 * 1000,
refetchOnWindowFocus: false,
});
}

View File

@@ -0,0 +1,48 @@
/**
* Ride Model Detail Hook
*
* Fetches ride model and manufacturer data with caching.
*/
import { useQuery } from '@tanstack/react-query';
import { supabase } from '@/integrations/supabase/client';
import { queryKeys } from '@/lib/queryKeys';
export function useRideModelDetail(
manufacturerSlug: string | undefined,
modelSlug: string | undefined
) {
return useQuery({
queryKey: queryKeys.rideModels.detail(manufacturerSlug || '', modelSlug || ''),
queryFn: async () => {
if (!manufacturerSlug || !modelSlug) return null;
// Fetch manufacturer first
const { data: manufacturer, error: mfgError } = await supabase
.from('companies')
.select('*')
.eq('slug', manufacturerSlug)
.eq('company_type', 'manufacturer')
.maybeSingle();
if (mfgError) throw mfgError;
if (!manufacturer) return null;
// Fetch ride model
const { data: model, error: modelError } = await supabase
.from('ride_models')
.select('*')
.eq('slug', modelSlug)
.eq('manufacturer_id', manufacturer.id)
.maybeSingle();
if (modelError) throw modelError;
return model ? { model, manufacturer } : null;
},
enabled: !!manufacturerSlug && !!modelSlug,
staleTime: 5 * 60 * 1000,
gcTime: 15 * 60 * 1000,
refetchOnWindowFocus: false,
});
}