'use client' import { useState, useEffect } from 'react' import Link from 'next/link' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { cn, formatCurrency } from '@/lib/utils' import { calculateEFTax, calculateABTax, getEnhancedTaxWarningStatus } from '@/lib/tax/calculator' import FSkattWarningCard from '@/components/dashboard/FSkattWarningCard' import { UpcomingDeadlinesWidget } from '@/components/deadlines/UpcomingDeadlinesWidget' import { TaxTodoWidget } from '@/components/deadlines/TaxTodoWidget' import NewUserChecklist from '@/components/onboarding/NewUserChecklist' import { Receipt, ArrowLeftRight, ChevronDown, ChevronUp, Camera, Users, Landmark, CheckCircle2, FileWarning, } from 'lucide-react' import { getExtensionDefinition } from '@/lib/extensions/sectors' import { resolveIcon } from '@/lib/extensions/icon-resolver' import type { QuickActionDefinition } from '@/lib/extensions/types' import type { CompanySettings, EntityType, Deadline, ReceiptQueueSummary, OnboardingProgress } from '@/types' interface DashboardContentProps { firstName?: string | null settings: CompanySettings | null 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 } onboardingProgress?: OnboardingProgress enabledExtensions?: { sector_slug: string; extension_slug: string }[] } export default function DashboardContent({ firstName, settings, summary, onboardingProgress, enabledExtensions }: DashboardContentProps) { const [showAllAlerts, setShowAllAlerts] = useState(false) const [showMore, setShowMore] = useState(false) const [liveExtensions, setLiveExtensions] = useState(enabledExtensions ?? []) useEffect(() => { setLiveExtensions(enabledExtensions ?? []) }, [enabledExtensions]) useEffect(() => { const handler = ((e: CustomEvent<{ sector_slug: string; extension_slug: string; enabled: boolean }>) => { setLiveExtensions(prev => { if (e.detail.enabled) { if (prev.some(x => x.sector_slug === e.detail.sector_slug && x.extension_slug === e.detail.extension_slug)) return prev return [...prev, { sector_slug: e.detail.sector_slug, extension_slug: e.detail.extension_slug }] } return prev.filter(x => !(x.sector_slug === e.detail.sector_slug && x.extension_slug === e.detail.extension_slug)) }) }) as EventListener window.addEventListener('extension-toggle-changed', handler) return () => window.removeEventListener('extension-toggle-changed', handler) }, []) const entityType = (settings?.entity_type as EntityType) || 'enskild_firma' const preliminaryTaxMonthly = settings?.preliminary_tax_monthly || 0 const currentMonth = new Date().getMonth() + 1 const preliminaryTaxPaidYTD = preliminaryTaxMonthly * currentMonth const totalTaxableIncome = summary.ytd.net const taxEstimate = entityType === 'enskild_firma' ? calculateEFTax(totalTaxableIncome, preliminaryTaxPaidYTD, null, summary.unpaidVatTotal) : calculateABTax(totalTaxableIncome, 0, preliminaryTaxPaidYTD, summary.unpaidVatTotal) const taxWarning = getEnhancedTaxWarningStatus(taxEstimate, preliminaryTaxMonthly, currentMonth) const formatLargeNumber = (amount: number) => { return new Intl.NumberFormat('sv-SE', { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(amount) } const isNewUser = onboardingProgress && !onboardingProgress.hasInvoices && !onboardingProgress.hasCustomers // Build alert items for "Att hantera" section const alertItems: React.ReactNode[] = [] if (summary.overdueInvoicesCount > 0) { alertItems.push(

Förfallna fakturor

{summary.overdueInvoicesCount} st

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

Obetalda fakturor

{summary.unpaidInvoicesCount - summary.overdueInvoicesCount} st · {formatCurrency(summary.unpaidInvoicesTotal)}

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

Transaktioner

{summary.uncategorizedCount} obokförda

) } if (summary.receiptQueue && (summary.receiptQueue.pending_review_count > 0 || summary.receiptQueue.unmatched_receipts_count > 0)) { alertItems.push(

Kvitton

{summary.receiptQueue.pending_review_count > 0 ? `${summary.receiptQueue.pending_review_count} att granska` : `${summary.receiptQueue.unmatched_receipts_count} omatchade`}

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

Saknade underlag

{summary.missingUnderlagCount} verifikationer utan underlag

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

Banksamtycke löper ut

{conn.bank_name} — {conn.days_left} {conn.days_left === 1 ? 'dag' : 'dagar'} kvar

) } const MAX_VISIBLE_ALERTS = 3 const visibleAlerts = showAllAlerts ? alertItems : alertItems.slice(0, MAX_VISIBLE_ALERTS) const hasMoreAlerts = alertItems.length > MAX_VISIBLE_ALERTS // Build extension quick actions from enabled extensions const extensionQuickActions: (QuickActionDefinition & { key: string })[] = liveExtensions .map(toggle => { const def = getExtensionDefinition(toggle.sector_slug, toggle.extension_slug) if (!def?.quickAction) return null return { ...def.quickAction, key: `${toggle.sector_slug}/${toggle.extension_slug}` } }) .filter((a): a is QuickActionDefinition & { key: string } => a !== null) .sort((a, b) => (a.order ?? 0) - (b.order ?? 0)) // Quick action items const quickActions = [ { href: '/invoices/new', icon: Receipt, label: 'Ny faktura', desc: 'Skapa och skicka', accent: true }, { href: '/customers', icon: Users, label: 'Ny kund', desc: 'Lägg till kunduppgifter' }, { href: '/transactions', icon: ArrowLeftRight, label: 'Transaktioner', desc: 'Bokför' }, ] return (
{/* Header */}

{(() => { const hour = new Date().getHours() if (hour < 5) return 'God natt' if (hour < 10) return 'Godmorgon' if (hour < 14) return 'Hej' if (hour < 18) return 'God eftermiddag' return 'God kväll' })()}{firstName ? `, ${firstName}` : ''}

{/* New user checklist */} {onboardingProgress && (
)} {/* 4 Key Summary Cards */} {(() => { 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 (
{/* Card 1: Resultat */}

Resultat

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

{formatCurrency(summary.ytd.net)} i år

{/* Card 2: Att få betalt */}

Att få betalt

{summary.unpaidInvoicesCount} st

{formatCurrency(summary.unpaidInvoicesTotal)}

{/* Card 3: Banksaldo */} {summary.bankBalance !== null ? (

Banksaldo

{formatLargeNumber(summary.bankBalance)} kr

) : (

Banksaldo

Koppla bank

Importera transaktioner

)} {/* Card 4: Att göra */}

Att göra

{todoCount > 0 ? ( <>

{todoCount} st

Åtgärder att hantera

) : ( <>

Allt klart!

)}
) })()} {/* Quick actions */}

Snabbåtgärder

{quickActions.map((action) => { const Icon = action.icon return (

{action.label}

{action.desc}

) })} {/* Extension quick actions */} {extensionQuickActions.map((action) => { const Icon = resolveIcon(action.icon) if (action.href) { return (

{action.label}

{action.description}

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

Att hantera

{visibleAlerts}
{hasMoreAlerts && !showAllAlerts && ( )}
)} {/* Upcoming deadlines — always visible */} {summary.deadlines && summary.deadlines.length > 0 && (
)} {/* Tax todo widget — visible when there are incomplete tax deadlines */} {summary.deadlines?.some(d => d.deadline_type === 'tax' && !d.is_completed) && (
)} {/* Collapsible details section */} {showMore && (
{/* F-skatt warning */}
{ window.location.href = '/settings' }} />
{/* Uncategorized transactions warning */} {summary.uncategorizedCount > 0 && (summary.uncategorizedIncome > 0 || summary.uncategorizedExpenses > 0) && (

{summary.uncategorizedCount} obokförda transaktioner

{summary.uncategorizedIncome > 0 && ( {formatCurrency(summary.uncategorizedIncome)} intäkter )} {summary.uncategorizedIncome > 0 && summary.uncategorizedExpenses > 0 && ', '} {summary.uncategorizedExpenses > 0 && ( {formatCurrency(summary.uncategorizedExpenses)} kostnader )} {' '}saknas i resultatet

)} {/* Income/Expenses */}

Resultat

Intäkter

{formatLargeNumber(summary.mtd.income)} kr

denna månad

I år

{formatCurrency(summary.ytd.income)}

Kostnader

{formatLargeNumber(summary.mtd.expenses)} kr

denna månad

I år

{formatCurrency(summary.ytd.expenses)}

)}
) }