feat: Reorganize tabs and add "Recently Closed"

This commit is contained in:
gpt-engineer-app[bot]
2025-10-28 13:47:50 +00:00
parent 8406d66096
commit 55f1b8ea99

View File

@@ -35,6 +35,7 @@ export function ContentTabs() {
const [highestRatedRides, setHighestRatedRides] = useState<Ride[]>([]); const [highestRatedRides, setHighestRatedRides] = useState<Ride[]>([]);
const [openingSoon, setOpeningSoon] = useState<Array<(Park | Ride) & { entityType: 'park' | 'ride' }>>([]); const [openingSoon, setOpeningSoon] = useState<Array<(Park | Ride) & { entityType: 'park' | 'ride' }>>([]);
const [closingSoon, setClosingSoon] = useState<Array<(Park | Ride) & { entityType: 'park' | 'ride' }>>([]); const [closingSoon, setClosingSoon] = useState<Array<(Park | Ride) & { entityType: 'park' | 'ride' }>>([]);
const [recentlyClosed, setRecentlyClosed] = useState<Array<(Park | Ride) & { entityType: 'park' | 'ride' }>>([]);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
useEffect(() => { useEffect(() => {
@@ -295,6 +296,34 @@ export function ContentTabs() {
.sort((a, b) => new Date(a.closing_date).getTime() - new Date(b.closing_date).getTime()) .sort((a, b) => new Date(a.closing_date).getTime() - new Date(b.closing_date).getTime())
.slice(0, 24); .slice(0, 24);
// Recently Closed (closed in last year)
const { data: parksClosed } = await supabase
.from('parks')
.select(`*, location:locations(*), operator:companies!parks_operator_id_fkey(*)`)
.not('closing_date', 'is', null)
.lt('closing_date', new Date().toISOString().split('T')[0])
.gte('closing_date', dateThreshold)
.in('status', ['closed', 'permanently_closed'])
.order('closing_date', { ascending: false })
.limit(20);
const { data: ridesClosed } = await supabase
.from('rides')
.select(`*, park:parks!inner(name, slug, location:locations(*))`)
.not('closing_date', 'is', null)
.lt('closing_date', new Date().toISOString().split('T')[0])
.gte('closing_date', dateThreshold)
.in('status', ['closed', 'removed', 'permanently_closed'])
.order('closing_date', { ascending: false })
.limit(20);
const combinedClosed = [
...(parksClosed || []).map(p => ({ ...p, entityType: 'park' as const })),
...(ridesClosed || []).map(r => ({ ...r, entityType: 'ride' as const }))
]
.sort((a, b) => new Date(b.closing_date).getTime() - new Date(a.closing_date).getTime())
.slice(0, 24);
setTrendingParks(trending || []); setTrendingParks(trending || []);
setRecentParks(recent || []); setRecentParks(recent || []);
setTrendingRides(trendingRidesData || []); setTrendingRides(trendingRidesData || []);
@@ -305,6 +334,7 @@ export function ContentTabs() {
setHighestRatedRides(topRatedRides || []); setHighestRatedRides(topRatedRides || []);
setOpeningSoon(combinedOpening); setOpeningSoon(combinedOpening);
setClosingSoon(combinedClosing); setClosingSoon(combinedClosing);
setRecentlyClosed(combinedClosed);
} catch (error: unknown) { } catch (error: unknown) {
logger.error('Failed to fetch content', { error: getErrorMessage(error) }); logger.error('Failed to fetch content', { error: getErrorMessage(error) });
} finally { } finally {
@@ -346,7 +376,7 @@ export function ContentTabs() {
<div className="container mx-auto px-4"> <div className="container mx-auto px-4">
<Tabs defaultValue="trending-parks" className="w-full"> <Tabs defaultValue="trending-parks" className="w-full">
<div className="text-center mb-8"> <div className="text-center mb-8">
<TabsList className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-2 p-3 bg-muted/30 rounded-lg max-w-6xl mx-auto"> <TabsList className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-2 p-3 bg-muted/30 rounded-lg max-w-7xl mx-auto">
<TabsTrigger value="trending-parks" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center"> <TabsTrigger value="trending-parks" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Trending Parks Trending Parks
</TabsTrigger> </TabsTrigger>
@@ -362,9 +392,6 @@ export function ContentTabs() {
<TabsTrigger value="recent-changes" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center"> <TabsTrigger value="recent-changes" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Recent Changes Recent Changes
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="recently-opened" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Recently Opened
</TabsTrigger>
<TabsTrigger value="highest-rated-parks" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center"> <TabsTrigger value="highest-rated-parks" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Top Parks Top Parks
</TabsTrigger> </TabsTrigger>
@@ -374,9 +401,15 @@ export function ContentTabs() {
<TabsTrigger value="opening-soon" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center"> <TabsTrigger value="opening-soon" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Opening Soon Opening Soon
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="recently-opened" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Recently Opened
</TabsTrigger>
<TabsTrigger value="closing-soon" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center"> <TabsTrigger value="closing-soon" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Closing Soon Closing Soon
</TabsTrigger> </TabsTrigger>
<TabsTrigger value="recently-closed" className="px-4 py-2.5 text-sm font-medium rounded-full data-[state=active]:bg-primary data-[state=active]:text-primary-foreground hover:bg-muted/50 transition-colors text-center">
Recently Closed
</TabsTrigger>
</TabsList> </TabsList>
</div> </div>
@@ -604,6 +637,39 @@ export function ContentTabs() {
</div> </div>
)} )}
</TabsContent> </TabsContent>
<TabsContent value="recently-closed" className="mt-8">
<div className="text-center mb-6">
<h2 className="text-2xl md:text-3xl font-bold mb-2 bg-gradient-to-r from-primary via-secondary to-accent bg-clip-text text-transparent drop-shadow-[0_0_12px_rgba(139,92,246,0.3)]">Recently Closed</h2>
<p className="text-muted-foreground text-sm md:text-base animate-fade-in">Parks and rides that closed in the last year</p>
<div className="mt-4 mx-auto w-24 h-1 bg-gradient-to-r from-transparent via-primary to-transparent rounded-full opacity-60"></div>
</div>
{recentlyClosed.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 xl:grid-cols-6 2xl:grid-cols-7 3xl:grid-cols-8 gap-4 lg:gap-5 xl:gap-4 2xl:gap-5">
{recentlyClosed.map((entity: any) => (
entity.entityType === 'park' ? (
<div key={entity.id} className="relative">
<ParkCard park={entity} />
<Badge className="absolute top-2 right-2 bg-gray-500/90 text-white backdrop-blur-sm">
Closed {new Date(entity.closing_date).getFullYear()}
</Badge>
</div>
) : (
<div key={entity.id} className="relative">
<RideCard ride={entity} />
<Badge className="absolute top-2 right-2 bg-gray-500/90 text-white backdrop-blur-sm">
Closed {new Date(entity.closing_date).getFullYear()}
</Badge>
</div>
)
))}
</div>
) : (
<div className="text-center py-12 text-muted-foreground">
No parks or rides closed in the last year.
</div>
)}
</TabsContent>
</Tabs> </Tabs>
</div> </div>
</section> </section>