'use client' import { useState, useEffect } from 'react' import Link from 'next/link' import { useTranslations } from 'next-intl' import { Card, CardContent } from '@/components/ui/card' import { cn, formatCurrency } from '@/lib/utils' import { UpcomingDeadlinesWidget } from '@/components/deadlines/UpcomingDeadlinesWidget' import { TaxTodoWidget } from '@/components/deadlines/TaxTodoWidget' import NewUserChecklist from '@/components/onboarding/NewUserChecklist' import { Receipt, ArrowLeftRight, ChevronDown, ChevronRight, Landmark, CheckCircle2, FileWarning, Clock, } from 'lucide-react' import type { Deadline, ReceiptQueueSummary, OnboardingProgress } from '@/types' const setupFreshStartKey = (companyId: string) => `erp_setup_fresh_start:${companyId}` interface DashboardContentProps { companyId: string summary: { ytd: { income: number; expenses: number; net: number } mtd: { income: number; expenses: number; net: number } uncategorizedCount: number uncategorizedIncome: number uncategorizedExpenses: number unpaidInvoicesCount: number unpaidInvoicesTotal: number unpaidVatTotal: number overdueInvoicesCount: number bankBalance: number | null expiringBankConnections?: { id: string; bank_name: string; days_left: number }[] deadlines: Deadline[] receiptQueue: ReceiptQueueSummary | null missingUnderlagCount: number staleUncategorizedCount: number } onboardingProgress?: OnboardingProgress } export default function DashboardContent({ companyId, summary, onboardingProgress }: DashboardContentProps) { const [showAllAlerts, setShowAllAlerts] = useState(false) const t = useTranslations('dashboard') const needsSetup = onboardingProgress && !onboardingProgress.hasBankConnected && !onboardingProgress.hasSIEImport const [setupGateActive, setSetupGateActive] = useState(!!needsSetup) useEffect(() => { if (!needsSetup) { setSetupGateActive(false) return } const scopedKey = setupFreshStartKey(companyId) const freshStart = localStorage.getItem(scopedKey) === 'true' const legacyFreshStart = localStorage.getItem('erp_setup_fresh_start') === 'true' const legacyDismissed = localStorage.getItem('erp_checklist_dismissed') === 'true' if (freshStart || legacyFreshStart || legacyDismissed) { if (!freshStart) { localStorage.setItem(scopedKey, 'true') } setSetupGateActive(false) } }, [needsSetup, companyId]) if (setupGateActive) { return ( { localStorage.setItem(setupFreshStartKey(companyId), 'true') setSetupGateActive(false) }} /> ) } const formatLargeNumber = (amount: number) => { return new Intl.NumberFormat('sv-SE', { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(amount) } const alertItems: React.ReactNode[] = [] if (summary.overdueInvoicesCount > 0) { alertItems.push(

{t('overdue_invoices')}

{t('overdue_invoices_count', { count: summary.overdueInvoicesCount })}

) } if (summary.unpaidInvoicesCount > 0 && summary.overdueInvoicesCount < summary.unpaidInvoicesCount) { alertItems.push(

{t('unpaid_invoices')}

{t('unpaid_invoices_detail', { count: summary.unpaidInvoicesCount - summary.overdueInvoicesCount, amount: formatCurrency(summary.unpaidInvoicesTotal), })}

) } if (summary.uncategorizedCount > 0) { alertItems.push(

{t('transactions')}

{t('uncategorized_count', { count: summary.uncategorizedCount })}

) } if (summary.missingUnderlagCount > 0) { alertItems.push(

{t('missing_underlag')}

{t('missing_underlag_detail', { count: summary.missingUnderlagCount })}

) } if (summary.staleUncategorizedCount > 0) { alertItems.push(

{t('stale_transactions')}

{t('stale_transactions_detail', { count: summary.staleUncategorizedCount })}

) } if (summary.expiringBankConnections && summary.expiringBankConnections.length > 0) { const conn = summary.expiringBankConnections[0] alertItems.push(

{t('bank_consent_expiring')}

{conn.days_left === 1 ? t('bank_consent_detail_one', { bank: conn.bank_name, days: conn.days_left }) : t('bank_consent_detail_other', { bank: conn.bank_name, days: conn.days_left })}

) } const MAX_VISIBLE_ALERTS = 3 const visibleAlerts = showAllAlerts ? alertItems : alertItems.slice(0, MAX_VISIBLE_ALERTS) const hasMoreAlerts = alertItems.length > MAX_VISIBLE_ALERTS const passedDeadlinesCount = summary.deadlines.filter(d => !d.is_completed && new Date(d.due_date) <= new Date()).length const pendingReceiptsCount = summary.receiptQueue ? summary.receiptQueue.pending_review_count + summary.receiptQueue.unmatched_receipts_count : 0 const todoCount = summary.uncategorizedCount + summary.overdueInvoicesCount + pendingReceiptsCount + passedDeadlinesCount return (
{/* Key metrics — 4 compact cards */}

{t('result')}

= 0 ? 'text-success' : 'text-destructive' )}> {formatLargeNumber(summary.mtd.net)} kr

{formatCurrency(summary.ytd.net)} {t('this_year_short')}

{t('to_be_paid')}

{summary.unpaidInvoicesCount} {t('units') && {t('units')}}

{formatCurrency(summary.unpaidInvoicesTotal)}

{summary.bankBalance !== null ? (

{t('bank_balance')}

{formatLargeNumber(summary.bankBalance)} kr

) : (

{t('bank_balance')}

{t('connect_bank')}

)}

{t('todo')}

{todoCount > 0 ? (

{todoCount} {t('units') && {t('units')}}

) : (

{t('all_done')}

)}
{/* Result — revenue / expenses (always visible) */}

{t('revenue')}

{formatLargeNumber(summary.mtd.income)} kr

{t('this_month')}

{t('this_year_block')}

{formatCurrency(summary.ytd.income)}

{t('expenses')}

{formatLargeNumber(summary.mtd.expenses)} kr

{t('this_month')}

{t('this_year_block')}

{formatCurrency(summary.ytd.expenses)}

{/* Alerts */} {alertItems.length > 0 && (

{t('alerts_title')}

{visibleAlerts}
{hasMoreAlerts && ( )}
)} {/* Upcoming deadlines */} {summary.deadlines && summary.deadlines.length > 0 && (
)} {/* Tax todo */} {summary.deadlines?.some(d => d.deadline_type === 'tax' && !d.is_completed) && (
)}
) }