mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 10:31:12 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
120
src-old/components/timeline/TimelineEventCard.tsx
Normal file
120
src-old/components/timeline/TimelineEventCard.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Edit, Trash, Clock, CheckCircle } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { format } from 'date-fns';
|
||||
import { parseDateForDisplay } from '@/lib/dateUtils';
|
||||
import type { TimelineEvent } from '@/types/timeline';
|
||||
|
||||
interface TimelineEventCardProps {
|
||||
event: TimelineEvent;
|
||||
onEdit?: (event: TimelineEvent) => void;
|
||||
onDelete?: (eventId: string) => void;
|
||||
canEdit: boolean;
|
||||
canDelete: boolean;
|
||||
isPending?: boolean;
|
||||
}
|
||||
|
||||
// ⚠️ IMPORTANT: Use parseDateForDisplay to prevent timezone shifts
|
||||
// YYYY-MM-DD strings must be interpreted as local dates, not UTC
|
||||
const formatEventDate = (date: string, precision: string = 'day') => {
|
||||
const dateObj = parseDateForDisplay(date);
|
||||
|
||||
switch (precision) {
|
||||
case 'year':
|
||||
return format(dateObj, 'yyyy');
|
||||
case 'month':
|
||||
return format(dateObj, 'MMMM yyyy');
|
||||
case 'day':
|
||||
default:
|
||||
return format(dateObj, 'MMMM d, yyyy');
|
||||
}
|
||||
};
|
||||
|
||||
const getEventTypeLabel = (type: string): string => {
|
||||
return type.split('_').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join(' ');
|
||||
};
|
||||
|
||||
export function TimelineEventCard({
|
||||
event,
|
||||
onEdit,
|
||||
onDelete,
|
||||
canEdit,
|
||||
canDelete,
|
||||
isPending = false
|
||||
}: TimelineEventCardProps) {
|
||||
return (
|
||||
<Card className={isPending ? 'border-yellow-500/50 bg-yellow-500/5' : ''}>
|
||||
<CardContent className="p-4">
|
||||
<div className="flex justify-between items-start gap-4">
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<Badge variant={isPending ? 'secondary' : 'default'}>
|
||||
{getEventTypeLabel(event.event_type)}
|
||||
</Badge>
|
||||
{isPending && (
|
||||
<Badge variant="outline" className="gap-1">
|
||||
<Clock className="w-3 h-3" />
|
||||
Pending Approval
|
||||
</Badge>
|
||||
)}
|
||||
{!isPending && (
|
||||
<Badge variant="outline" className="gap-1">
|
||||
<CheckCircle className="w-3 h-3" />
|
||||
Approved
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="font-semibold text-lg">{event.title}</h4>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{formatEventDate(event.event_date, event.event_date_precision)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{event.description && (
|
||||
<p className="text-sm">{event.description}</p>
|
||||
)}
|
||||
|
||||
{(event.from_value || event.to_value) && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{event.from_value && <span>From: {event.from_value}</span>}
|
||||
{event.from_value && event.to_value && <span className="mx-2">→</span>}
|
||||
{event.to_value && <span>To: {event.to_value}</span>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{(canEdit || canDelete) && (
|
||||
<div className="flex gap-2">
|
||||
{canEdit && (
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={() => onEdit?.(event)}
|
||||
title="Edit event"
|
||||
>
|
||||
<Edit className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={() => onDelete?.(event.id)}
|
||||
title="Delete event"
|
||||
className="text-destructive hover:text-destructive"
|
||||
>
|
||||
<Trash className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user