feat: Implement full Phase 3 API optimizations

This commit is contained in:
gpt-engineer-app[bot]
2025-10-30 23:02:26 +00:00
parent 46ca1c29bc
commit 0091584677
18 changed files with 654 additions and 243 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback, lazy, Suspense } from 'react';
import { useState, lazy, Suspense, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Header } from '@/components/layout/Header';
import { getBannerUrls } from '@/lib/cloudflareImageUtils';
@@ -15,10 +15,12 @@ import { RideCard } from '@/components/rides/RideCard';
import { Park, Ride } from '@/types/database';
import { ParkLocationMap } from '@/components/maps/ParkLocationMap';
import { EntityPhotoGallery } from '@/components/upload/EntityPhotoGallery';
import { supabase } from '@/integrations/supabase/client';
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { AdminFormSkeleton } from '@/components/loading/PageSkeletons';
import { toast } from '@/hooks/use-toast';
import { useParkDetail } from '@/hooks/parks/useParkDetail';
import { useParkRides } from '@/hooks/parks/useParkRides';
import { usePhotoCount } from '@/hooks/photos/usePhotoCount';
// Lazy load admin forms
const RideForm = lazy(() => import('@/components/admin/RideForm').then(m => ({ default: m.RideForm })));
@@ -33,23 +35,23 @@ import { useDocumentTitle } from '@/hooks/useDocumentTitle';
import { useOpenGraph } from '@/hooks/useOpenGraph';
export default function ParkDetail() {
const {
slug
} = useParams<{
slug: string;
}>();
const { slug } = useParams<{ slug: string }>();
const navigate = useNavigate();
const { user } = useAuth();
const { requireAuth } = useAuthModal();
const [park, setPark] = useState<Park | null>(null);
const [rides, setRides] = useState<Ride[]>([]);
const [loading, setLoading] = useState(true);
const [isAddRideModalOpen, setIsAddRideModalOpen] = useState(false);
const [isEditParkModalOpen, setIsEditParkModalOpen] = useState(false);
const [photoCount, setPhotoCount] = useState<number>(0);
const [statsLoading, setStatsLoading] = useState(true);
const { isModerator } = useUserRole();
// Fetch park data with caching
const { data: park, isLoading: loading, error } = useParkDetail(slug);
// Fetch rides with caching
const { data: rides = [] } = useParkRides(park?.id, !!park?.id);
// Fetch photo count with caching
const { data: photoCount = 0, isLoading: statsLoading } = usePhotoCount('park', park?.id, !!park?.id);
// Update document title when park changes
useDocumentTitle(park?.name || 'Park Details');
@@ -62,58 +64,6 @@ export default function ParkDetail() {
type: 'website',
enabled: !!park
});
const fetchPhotoCount = useCallback(async (parkId: string) => {
try {
const { count, error } = await supabase
.from('photos')
.select('id', { count: 'exact', head: true })
.eq('entity_type', 'park')
.eq('entity_id', parkId);
if (error) throw error;
setPhotoCount(count || 0);
} catch (error) {
console.error('Error fetching photo count:', error);
setPhotoCount(0);
} finally {
setStatsLoading(false);
}
}, []);
const fetchParkData = useCallback(async () => {
try {
// Fetch park details
const {
data: parkData
} = await supabase.from('parks').select(`
*,
location:locations(*),
operator:companies!parks_operator_id_fkey(*),
property_owner:companies!parks_property_owner_id_fkey(*)
`).eq('slug', slug).maybeSingle();
if (parkData) {
setPark(parkData);
fetchPhotoCount(parkData.id);
// Fetch park rides
const {
data: ridesData
} = await supabase.from('rides').select(`*`).eq('park_id', parkData.id).order('name');
setRides(ridesData || []);
}
} catch (error) {
console.error('Error fetching park data:', error);
} finally {
setLoading(false);
}
}, [slug, fetchPhotoCount]);
useEffect(() => {
if (slug) {
fetchParkData();
}
}, [slug, fetchParkData]);
// Track page view when park is loaded
useEffect(() => {