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

@@ -145,7 +145,7 @@ export function FeaturedParks() {
</div>
<div className="grid md:grid-cols-3 gap-6">
{topRatedParks.map((park) => (
{topRated.data?.map((park) => (
<FeaturedParkCard
key={park.id}
park={park}
@@ -166,7 +166,7 @@ export function FeaturedParks() {
</div>
<div className="grid md:grid-cols-3 gap-6">
{mostRidesParks.map((park) => (
{mostRides.data?.map((park) => (
<FeaturedParkCard
key={park.id}
park={park}

View File

@@ -1,4 +1,5 @@
import { useState, useEffect } from 'react';
import { useState } from 'react';
import { useUserReviews } from '@/hooks/reviews/useUserReviews';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
import { Badge } from '@/components/ui/badge';
@@ -43,62 +44,11 @@ interface UserReviewsListProps {
}
export function UserReviewsList({ userId, reviewCount }: UserReviewsListProps) {
const [reviews, setReviews] = useState<ReviewWithEntity[]>([]);
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState<'all' | 'parks' | 'rides'>('all');
const [sortBy, setSortBy] = useState<'date' | 'rating'>('date');
useEffect(() => {
fetchReviews();
}, [userId, filter, sortBy]);
const fetchReviews = async () => {
try {
setLoading(true);
let query = supabase
.from('reviews')
.select(`
id,
rating,
title,
content,
visit_date,
wait_time_minutes,
helpful_votes,
moderation_status,
created_at,
parks:park_id (id, name, slug),
rides:ride_id (
id,
name,
slug,
parks:park_id (name, slug)
)
`)
.eq('user_id', userId);
if (filter === 'parks') {
query = query.not('park_id', 'is', null);
} else if (filter === 'rides') {
query = query.not('ride_id', 'is', null);
}
if (sortBy === 'date') {
query = query.order('created_at', { ascending: false });
} else {
query = query.order('rating', { ascending: false });
}
const { data, error } = await query;
if (error) throw error;
setReviews(data || []);
} catch (error: unknown) {
toast.error(getErrorMessage(error));
} finally {
setLoading(false);
}
};
// Use cached user reviews hook
const { data: reviews = [], isLoading: loading } = useUserReviews(userId, filter, sortBy);
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('en-US', {

View File

@@ -1,4 +1,6 @@
import { useState, useEffect } from 'react';
import { useDebouncedValue } from '@/hooks/useDebouncedValue';
import { useGlobalSearch } from '@/hooks/search/useGlobalSearch';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
@@ -20,57 +22,20 @@ type SearchResult = {
};
export function SearchResults({ query, onClose }: SearchResultsProps) {
const [results, setResults] = useState<SearchResult[]>([]);
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
useEffect(() => {
if (query.length >= 2) {
searchContent();
} else {
setResults([]);
}
}, [query]);
const searchContent = async () => {
setLoading(true);
try {
const searchTerm = `%${query.toLowerCase()}%`;
// Search parks
const { data: parks } = await supabase
.from('parks')
.select(`*, location:locations(*)`)
.or(`name.ilike.${searchTerm},description.ilike.${searchTerm}`)
.limit(5);
// Search rides
const { data: rides } = await supabase
.from('rides')
.select(`*, park:parks!inner(name, slug)`)
.or(`name.ilike.${searchTerm},description.ilike.${searchTerm}`)
.limit(5);
// Search companies
const { data: companies } = await supabase
.from('companies')
.select('id, name, slug, description, company_type, logo_url, average_rating, review_count')
.or(`name.ilike.${searchTerm},description.ilike.${searchTerm}`)
.limit(3);
const allResults: SearchResult[] = [
...(parks || []).map(park => ({ type: 'park' as const, data: park })),
...(rides || []).map(ride => ({ type: 'ride' as const, data: ride })),
...(companies || []).map(company => ({ type: 'company' as const, data: company }))
];
setResults(allResults);
} catch (error: unknown) {
logger.error('Search failed', { error: getErrorMessage(error), query });
} finally {
setLoading(false);
}
};
// Debounce search query
const debouncedQuery = useDebouncedValue(query, 300);
// Use global search hook with caching
const { data, isLoading: loading } = useGlobalSearch(debouncedQuery);
// Flatten results
const results: SearchResult[] = [
...(data?.parks || []).map(park => ({ type: 'park' as const, data: park })),
...(data?.rides || []).map(ride => ({ type: 'ride' as const, data: ride })),
...(data?.companies || []).map(company => ({ type: 'company' as const, data: company })),
];
const handleResultClick = (result: SearchResult) => {
onClose();