Neah/components/calendar.tsx
2025-05-02 18:19:46 +02:00

153 lines
6.1 KiB
TypeScript

"use client";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { RefreshCw, Calendar as CalendarIcon, ChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { format, isToday, isTomorrow } from "date-fns";
import { fr } from "date-fns/locale";
import { useCalendarEvents, CalendarEvent } from "@/hooks/use-calendar-events";
interface CalendarProps {
limit?: number;
showMore?: boolean;
showRefresh?: boolean;
cardClassName?: string;
}
export function Calendar({
limit = 5,
showMore = true,
showRefresh = true,
cardClassName = "transition-transform duration-500 ease-in-out transform hover:scale-105 bg-white/95 backdrop-blur-sm border-0 shadow-lg"
}: CalendarProps) {
const { events, loading, error, refresh } = useCalendarEvents({ limit });
const router = useRouter();
const formatEventDate = (date: Date | string, isAllDay: boolean) => {
const eventDate = date instanceof Date ? date : new Date(date);
let dateString = "";
if (isToday(eventDate)) {
dateString = "Today";
} else if (isTomorrow(eventDate)) {
dateString = "Tomorrow";
} else {
dateString = format(eventDate, "EEEE d MMMM", { locale: fr });
}
if (!isAllDay) {
dateString += ` · ${format(eventDate, "HH:mm", { locale: fr })}`;
}
return dateString;
};
return (
<Card className={cardClassName}>
<CardHeader className="flex flex-row items-center justify-between pb-2 border-b border-gray-100">
<CardTitle className="text-lg font-semibold text-gray-800 flex items-center gap-2">
<CalendarIcon className="h-5 w-5 text-gray-600" />
Calendar
</CardTitle>
<div className="flex items-center gap-1">
{showRefresh && (
<Button
variant="ghost"
size="icon"
onClick={refresh}
className="h-7 w-7 p-0 hover:bg-gray-100/50 rounded-full"
disabled={loading}
>
<RefreshCw className="h-3.5 w-3.5 text-gray-600" />
</Button>
)}
{showMore && (
<Link href='/agenda' passHref>
<Button variant='ghost' size='sm' className='h-8 w-8 p-0'>
<ChevronRight className='h-4 w-4' />
<span className='sr-only'>View calendar</span>
</Button>
</Link>
)}
</div>
</CardHeader>
<CardContent className="p-3">
{loading ? (
<div className="flex items-center justify-center py-6">
<div className="h-4 w-4 animate-spin rounded-full border-2 border-blue-500 border-t-transparent" />
</div>
) : error ? (
<div className="text-xs text-red-500 text-center py-3">{error}</div>
) : events.length === 0 ? (
<div className="text-xs text-gray-500 text-center py-6">No upcoming events</div>
) : (
<div className="space-y-2 max-h-[400px] overflow-y-auto pr-1 scrollbar-thin scrollbar-thumb-gray-200 scrollbar-track-transparent">
{events.map((event) => (
<div
key={event.id}
className="p-2 rounded-lg bg-white shadow-sm hover:shadow-md transition-all duration-200 border border-gray-100"
>
<div className="flex gap-2">
<div
className="flex-shrink-0 w-14 h-14 rounded-lg flex flex-col items-center justify-center border"
style={{
backgroundColor: `${event.calendarColor || '#4F46E5'}10`,
borderColor: event.calendarColor || '#4F46E5'
}}
>
<span
className="text-[10px] font-medium"
style={{ color: event.calendarColor || '#4F46E5' }}
>
{format(event.start instanceof Date ? event.start : new Date(event.start), 'MMM', { locale: fr })}
</span>
<span
className="text-[10px] font-bold mt-0.5"
style={{ color: event.calendarColor || '#4F46E5' }}
>
{format(event.start instanceof Date ? event.start : new Date(event.start), 'dd', { locale: fr })}
</span>
</div>
<div className="flex-1 min-w-0 space-y-1">
<div className="flex items-start justify-between gap-2">
<p className="text-sm font-medium text-gray-800 line-clamp-2 flex-1">
{event.title}
</p>
{!event.isAllDay && (
<span className="text-[10px] text-gray-500 whitespace-nowrap">
{format(event.start instanceof Date ? event.start : new Date(event.start), 'HH:mm', { locale: fr })} - {format(event.end instanceof Date ? event.end : new Date(event.end), 'HH:mm', { locale: fr })}
</span>
)}
</div>
<div
className="flex items-center text-[10px] px-1.5 py-0.5 rounded-md"
style={{
backgroundColor: `${event.calendarColor || '#4F46E5'}10`,
color: event.calendarColor || '#4F46E5'
}}
>
<span className="truncate">{event.calendarName || 'Calendar'}</span>
</div>
</div>
</div>
</div>
))}
{showMore && (
<Link href='/agenda' passHref>
<Button
size='sm'
className='w-full transition-all ease-in-out duration-500 bg-gray-100 text-gray-700 hover:bg-gray-200 mt-2'
>
View all events
</Button>
</Link>
)}
</div>
)}
</CardContent>
</Card>
);
}