'use client' import { useState } from 'react' import Link from 'next/link' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Button } from '@/components/ui/button' import { useToast } from '@/components/ui/use-toast' import { Deadline, DeadlineStatus } from '@/types' import { getUpcomingDeadlines, PRIORITY_LABELS, STATUS_LABELS, STATUS_COLORS, } from '@/lib/calendar/utils' import { Calendar, ChevronRight, AlertTriangle, Clock, Check, Send, Loader2 } from 'lucide-react' interface UpcomingDeadlinesWidgetProps { deadlines: Deadline[] maxItems?: number onStatusChange?: (deadlineId: string, newStatus: DeadlineStatus) => void } export function UpcomingDeadlinesWidget({ deadlines, maxItems = 5, onStatusChange }: UpcomingDeadlinesWidgetProps) { const { toast } = useToast() const [updatingId, setUpdatingId] = useState(null) // Get upcoming deadlines (next 7 days) + any needing attention const upcomingDeadlines = getUpcomingDeadlines(deadlines, 7) const actionNeededDeadlines = deadlines.filter( (d) => !d.is_completed && d.status === 'action_needed' ) const overdueDeadlines = deadlines.filter( (d) => !d.is_completed && d.status === 'overdue' ) // Combine and sort (overdue first, then action_needed, then upcoming) const displayDeadlines = [...overdueDeadlines, ...actionNeededDeadlines, ...upcomingDeadlines] .filter((d, i, arr) => arr.findIndex((x) => x.id === d.id) === i) // Remove duplicates .slice(0, maxItems) const overdueCount = overdueDeadlines.length const actionNeededCount = actionNeededDeadlines.length if (displayDeadlines.length === 0) { return null } const formatDate = (dateStr: string) => { const date = new Date(dateStr) const today = new Date() const tomorrow = new Date(today) tomorrow.setDate(tomorrow.getDate() + 1) if (date.toDateString() === today.toDateString()) { return 'Idag' } if (date.toDateString() === tomorrow.toDateString()) { return 'Imorgon' } return date.toLocaleDateString('sv-SE', { day: 'numeric', month: 'short' }) } const handleStatusChange = async (deadlineId: string, newStatus: DeadlineStatus) => { setUpdatingId(deadlineId) try { const response = await fetch(`/api/deadlines/${deadlineId}/status`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: newStatus }), }) if (!response.ok) { const data = await response.json() throw new Error(data.error || 'Failed to update status') } toast({ title: 'Status uppdaterad', description: `Deadline markerad som ${STATUS_LABELS[newStatus].toLowerCase()}`, }) // Notify parent component onStatusChange?.(deadlineId, newStatus) } catch (error) { toast({ title: 'Fel', description: error instanceof Error ? error.message : 'Kunde inte uppdatera status', variant: 'destructive', }) } finally { setUpdatingId(null) } } const getStatusBadgeVariant = (status: DeadlineStatus): 'default' | 'secondary' | 'destructive' | 'warning' => { switch (status) { case 'overdue': return 'destructive' case 'action_needed': return 'warning' case 'submitted': case 'confirmed': return 'default' default: return 'secondary' } } return (
Kommande deadlines
{overdueCount > 0 && ( {overdueCount} försenad )} {actionNeededCount > 0 && ( {actionNeededCount} åtgärd )}
{displayDeadlines.map((deadline) => { const isUpdating = updatingId === deadline.id const statusColors = STATUS_COLORS[deadline.status] || STATUS_COLORS.upcoming return (
{deadline.status === 'overdue' ? ( ) : deadline.status === 'action_needed' ? ( ) : ( )}

{deadline.title}

{formatDate(deadline.due_date)} {deadline.due_time && ` kl. ${deadline.due_time.slice(0, 5)}`}

{deadline.tax_deadline_type && ( Skatt )}
{/* Status badge */} {STATUS_LABELS[deadline.status]} {/* Quick action buttons for tax deadlines */} {deadline.tax_deadline_type && !['submitted', 'confirmed'].includes(deadline.status) && ( )} {deadline.status === 'submitted' && ( )}
) })}
) }