Magnus Smari Smarason 53481bc70e
All checks were successful
Build and Deploy Arctic Species Portal / build-and-deploy (push) Successful in 1m11s
Fix: Remove unused variables causing TS build errors
2025-05-17 19:55:12 +00:00

241 lines
10 KiB
TypeScript

import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { AlertCircle, Edit, Loader2, Plus, Save, Trash2 } from "lucide-react";
import { SpeciesDetails, TimelineEvent } from "@/lib/api";
import { formatDate } from "@/lib/utils";
import { useTimelineEventCrud } from "@/hooks/useTimelineEventCrud";
import { useQuery } from "@tanstack/react-query";
import { getTimelineEvents } from "@/lib/api";
type TimelineTabProps = {
species: SpeciesDetails;
};
export function TimelineTab({ species }: TimelineTabProps) {
const { data: timelineEvents, isLoading: timelineLoading } = useQuery({
queryKey: ["timelineEvents", species.id],
queryFn: () => getTimelineEvents(species.id),
});
const {
isEditingTimelineEvent,
isAddingTimelineEvent,
timelineEventForm,
operationStatus,
handleTimelineEventFormChange,
handleEditTimelineEvent,
handleAddTimelineEvent,
handleSaveTimelineEvent,
handleDeleteTimelineEvent,
handleCancelTimelineEvent
} = useTimelineEventCrud(species.id);
return (
<Card>
<CardHeader>
<CardTitle>Conservation Timeline</CardTitle>
<CardDescription>Historical conservation and trade events</CardDescription>
</CardHeader>
<CardContent>
{/* Operation status messages */}
{operationStatus.error && (
<div className="rounded-md bg-red-50 p-4 flex items-start mb-4">
<AlertCircle className="h-5 w-5 text-red-500 mr-2 mt-0.5" />
<div>
<h4 className="text-sm font-medium text-red-800">Error</h4>
<p className="text-sm text-red-700 mt-1">{operationStatus.error}</p>
</div>
</div>
)}
{operationStatus.success && (
<div className="rounded-md bg-green-50 p-4 mb-4">
<p className="text-sm text-green-700">Operation completed successfully.</p>
</div>
)}
{/* Timeline event form */}
{(isAddingTimelineEvent || isEditingTimelineEvent) && (
<div className="rounded-md border p-4 mb-6">
<h3 className="text-lg font-semibold mb-4">
{isAddingTimelineEvent ? "Add New Timeline Event" : "Edit Timeline Event"}
</h3>
<div className="grid gap-4 md:grid-cols-2">
<div className="space-y-2">
<Label htmlFor="event-date">Event Date</Label>
<input
id="event-date"
type="date"
value={timelineEventForm.event_date}
onChange={(e) => {
handleTimelineEventFormChange("event_date", e.target.value);
// Also update the year based on the date
const year = new Date(e.target.value).getFullYear();
handleTimelineEventFormChange("year", year);
}}
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background"
/>
</div>
<div className="space-y-2">
<Label htmlFor="event-type">Event Type</Label>
<Select
value={timelineEventForm.event_type}
onValueChange={(value) => handleTimelineEventFormChange("event_type", value)}
>
<SelectTrigger id="event-type">
<SelectValue placeholder="Select Event Type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="cites_listing">CITES Listing</SelectItem>
<SelectItem value="iucn_assessment">IUCN Assessment</SelectItem>
<SelectItem value="conservation_action">Conservation Action</SelectItem>
<SelectItem value="population_trend">Population Trend</SelectItem>
<SelectItem value="legislation">Legislation</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2 md:col-span-2">
<Label htmlFor="title">Title</Label>
<input
id="title"
type="text"
value={timelineEventForm.title}
onChange={(e) => handleTimelineEventFormChange("title", e.target.value)}
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background"
placeholder="Event title"
/>
</div>
<div className="space-y-2 md:col-span-2">
<Label htmlFor="description">Description</Label>
<textarea
id="description"
value={timelineEventForm.description}
onChange={(e) => handleTimelineEventFormChange("description", e.target.value)}
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background min-h-[100px]"
placeholder="Optional description of this event"
/>
</div>
<div className="space-y-2">
<Label htmlFor="status">Status (Optional)</Label>
<input
id="status"
type="text"
value={timelineEventForm.status}
onChange={(e) => handleTimelineEventFormChange("status", e.target.value)}
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background"
placeholder="e.g., Completed, In Progress, etc."
/>
</div>
</div>
<div className="mt-6 flex justify-end space-x-2">
<Button
variant="outline"
onClick={handleCancelTimelineEvent}
>
Cancel
</Button>
<Button
onClick={handleSaveTimelineEvent}
disabled={operationStatus.loading || !timelineEventForm.title}
>
{operationStatus.loading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
<>
<Save className="mr-2 h-4 w-4" />
Save
</>
)}
</Button>
</div>
</div>
)}
{/* Timeline events list */}
{timelineLoading ? (
<div className="flex items-center justify-center py-8">
<Loader2 className="h-8 w-8 animate-spin text-primary" />
</div>
) : (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold">
Timeline Events ({timelineEvents?.length || 0})
</h3>
<Button
onClick={handleAddTimelineEvent}
disabled={isAddingTimelineEvent || isEditingTimelineEvent}
size="sm"
>
<Plus className="mr-2 h-4 w-4" />
Add Event
</Button>
</div>
{timelineEvents && timelineEvents.length > 0 ? (
<div className="relative ml-4 space-y-6 border-l border-muted pl-6 pt-2">
{timelineEvents.map((event: TimelineEvent) => (
<div key={event.id} className="relative">
<div className="absolute -left-10 top-1 h-4 w-4 rounded-full bg-primary"></div>
<div className="mb-1 flex items-center justify-between">
<div className="flex items-center text-sm">
<span className="font-medium">{formatDate(event.event_date)}</span>
{event.status && (
<Badge
className="ml-2"
variant={event.event_type === 'cites_listing' ? 'default' : 'secondary'}
>
{event.status}
</Badge>
)}
</div>
<div className="flex space-x-1">
<Button
variant="ghost"
size="icon"
onClick={() => handleEditTimelineEvent(event)}
disabled={isAddingTimelineEvent || isEditingTimelineEvent}
title="Edit event"
className="h-8 w-8"
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => handleDeleteTimelineEvent(event)}
disabled={isAddingTimelineEvent || isEditingTimelineEvent || operationStatus.loading}
title="Delete event"
className="h-8 w-8 text-red-500 hover:text-red-700 hover:bg-red-50"
>
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
<h4 className="text-base font-medium">{event.title}</h4>
{event.description && <p className="text-sm text-muted-foreground">{event.description}</p>}
</div>
))}
</div>
) : (
<p className="text-muted-foreground">No timeline events available for this species.</p>
)}
</div>
)}
</CardContent>
</Card>
);
}