'use client' import { useState } from 'react' import Link from 'next/link' import { useTranslations } from 'next-intl' 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, TAX_DEADLINE_TYPE_LABELS, DEADLINE_STATUS_LABELS } from '@/types' import { getReportUrl } from '@/lib/tax/deadline-config' // Use the labels from types const STATUS_LABELS = DEADLINE_STATUS_LABELS import { FileText, ChevronRight, AlertTriangle, Clock, Send, Check, Loader2, ExternalLink, } from 'lucide-react' interface TaxTodoWidgetProps { deadlines: Deadline[] onStatusChange?: (deadlineId: string, newStatus: DeadlineStatus) => void } export function TaxTodoWidget({ deadlines, onStatusChange }: TaxTodoWidgetProps) { const { toast } = useToast() const t = useTranslations('tax_todo') const [updatingId, setUpdatingId] = useState(null) // Filter to only tax deadlines needing attention const taxDeadlines = deadlines.filter( (d) => d.deadline_type === 'tax' && !d.is_completed && ['action_needed', 'overdue', 'in_progress'].includes(d.status) ) // Sort by urgency: overdue first, then by date const sortedDeadlines = taxDeadlines.sort((a, b) => { if (a.status === 'overdue' && b.status !== 'overdue') return -1 if (b.status === 'overdue' && a.status !== 'overdue') return 1 return a.due_date.localeCompare(b.due_date) }) const overdueCount = taxDeadlines.filter((d) => d.status === 'overdue').length const actionNeededCount = taxDeadlines.filter((d) => d.status === 'action_needed').length if (sortedDeadlines.length === 0) { return null } const formatDate = (dateStr: string) => { const date = new Date(dateStr) const today = new Date() today.setHours(0, 0, 0, 0) const diffDays = Math.ceil( (date.getTime() - today.getTime()) / (1000 * 60 * 60 * 24) ) if (diffDays === 0) return t('today') if (diffDays === 1) return t('tomorrow') if (diffDays < 0) return t('days_ago', { count: Math.abs(diffDays) }) if (diffDays <= 7) return t('in_days', { count: diffDays }) 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: t('toast_status_updated'), description: t('toast_status_updated_description', { status: STATUS_LABELS[newStatus].toLowerCase() }), }) onStatusChange?.(deadlineId, newStatus) } catch (error) { toast({ title: error instanceof Error ? error.message : t('toast_status_update_failed'), variant: 'destructive', }) } finally { setUpdatingId(null) } } const getReportLink = (deadline: Deadline): string | null => { if (!deadline.linked_report_type || !deadline.linked_report_period) { return null } return getReportUrl(deadline.linked_report_type, deadline.linked_report_period) } return (
{t('title')}
{overdueCount > 0 && ( {t('overdue_badge', { count: overdueCount })} )} {actionNeededCount > 0 && ( {t('action_needed_badge', { count: actionNeededCount })} )}
{sortedDeadlines.slice(0, 5).map((deadline) => { const isUpdating = updatingId === deadline.id const reportLink = getReportLink(deadline) const isOverdue = deadline.status === 'overdue' return (
{isOverdue ? ( ) : ( )}

{deadline.title}

{formatDate(deadline.due_date)} {deadline.tax_deadline_type && ( {TAX_DEADLINE_TYPE_LABELS[deadline.tax_deadline_type]} )}
{/* Link to report if available */} {reportLink && ( )} {/* Mark as in progress */} {['action_needed', 'overdue'].includes(deadline.status) && ( )} {/* Mark as submitted */} {deadline.status === 'in_progress' && ( )}
) })} {sortedDeadlines.length > 5 && (

{t('more_tasks', { count: sortedDeadlines.length - 5 })}

)}
) }