Files
thrilltrack-explorer/src/components/moderation/TimelineEventPreview.tsx
gpt-engineer-app[bot] 4d7b00e4e7 feat: Implement rich timeline event display
Implement the plan to enhance the display of timeline event submissions in the moderation queue. This includes fixing the database function to fetch timeline event data, creating a new `RichTimelineEventDisplay` component, and updating the `SubmissionItemsList` and `TimelineEventPreview` components to leverage this new display. The goal is to provide moderators with complete and contextually rich information for timeline events.
2025-11-06 15:24:46 +00:00

130 lines
4.4 KiB
TypeScript

import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Calendar, Tag, Building2, MapPin } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { FlexibleDateDisplay } from '@/components/ui/flexible-date-display';
import type { TimelineSubmissionData } from '@/types/timeline';
import { useEffect, useState } from 'react';
import { supabase } from '@/lib/supabaseClient';
interface TimelineEventPreviewProps {
data: TimelineSubmissionData;
}
export function TimelineEventPreview({ data }: TimelineEventPreviewProps) {
const [entityName, setEntityName] = useState<string | null>(null);
useEffect(() => {
if (!data?.entity_id || !data?.entity_type) return;
const fetchEntityName = async () => {
const table = data.entity_type === 'park' ? 'parks' : 'rides';
const { data: entity } = await supabase
.from(table)
.select('name')
.eq('id', data.entity_id)
.single();
setEntityName(entity?.name || null);
};
fetchEntityName();
}, [data?.entity_id, data?.entity_type]);
const formatEventType = (type: string) => {
return type.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
};
const getEventTypeColor = (type: string) => {
const colors: Record<string, string> = {
opening: 'bg-green-600',
closure: 'bg-red-600',
reopening: 'bg-blue-600',
renovation: 'bg-purple-600',
expansion: 'bg-indigo-600',
acquisition: 'bg-amber-600',
name_change: 'bg-cyan-600',
operator_change: 'bg-orange-600',
owner_change: 'bg-orange-600',
location_change: 'bg-pink-600',
status_change: 'bg-yellow-600',
milestone: 'bg-emerald-600',
};
return colors[type] || 'bg-gray-600';
};
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calendar className="h-4 w-4" />
{data.title}
</CardTitle>
<div className="flex items-center gap-2 mt-2 flex-wrap">
<Badge className={`${getEventTypeColor(data.event_type)} text-white text-xs`}>
{formatEventType(data.event_type)}
</Badge>
<Badge variant="outline" className="text-xs">
{data.entity_type}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-4">
{entityName && (
<div className="flex items-center gap-2 text-sm">
<Building2 className="h-4 w-4 text-muted-foreground" />
<span className="font-medium">Entity:</span>
<span className="text-foreground">{entityName}</span>
</div>
)}
<div className="grid grid-cols-2 gap-4 text-sm">
<div>
<span className="font-medium">Event Date:</span>
<p className="text-muted-foreground flex items-center gap-1 mt-1">
<Calendar className="h-3 w-3" />
<FlexibleDateDisplay
date={data.event_date}
precision={data.event_date_precision}
/>
</p>
<p className="text-xs text-muted-foreground mt-0.5">
Precision: {data.event_date_precision}
</p>
</div>
</div>
{(data.from_value || data.to_value) && (
<div className="flex items-center gap-2 text-sm">
<span className="font-medium">Change:</span>
<span className="text-muted-foreground">
{data.from_value || '—'} {data.to_value || '—'}
</span>
</div>
)}
{(data.from_entity_id || data.to_entity_id) && (
<div className="text-xs text-muted-foreground">
<Tag className="h-3 w-3 inline mr-1" />
Related entities: {data.from_entity_id ? 'From entity' : ''} {data.to_entity_id ? 'To entity' : ''}
</div>
)}
{(data.from_location_id || data.to_location_id) && (
<div className="text-xs text-muted-foreground">
<MapPin className="h-3 w-3 inline mr-1" />
Location change involved
</div>
)}
{data.description && (
<div>
<span className="font-medium text-sm">Description:</span>
<p className="text-sm text-muted-foreground mt-1">
{data.description}
</p>
</div>
)}
</CardContent>
</Card>
);
}