'use client' import Link from 'next/link' import { useTranslations } from 'next-intl' import { Card, CardContent } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { cn, formatCurrency } from '@/lib/utils' import { UpcomingDeadlinesWidget } from '@/components/deadlines/UpcomingDeadlinesWidget' import { TaxTodoWidget } from '@/components/deadlines/TaxTodoWidget' import { useCapability } from '@/contexts/CompanyContext' import { CAPABILITY } from '@/lib/entitlements/keys' import NewUserChecklist from '@/components/onboarding/NewUserChecklist' import AttGoraSection from '@/components/dashboard/AttGoraSection' import BackupHealthBanner from '@/components/dashboard/BackupHealthBanner' import { SkatteverketPromoCard } from '@/components/dashboard/SkatteverketPromoCard' import { ChevronRight, CheckCircle2, ArrowRight, MessageCircle, } from 'lucide-react' import type { Deadline, InitialSetupState, OnboardingProgress } from '@/types' import type { SuggestedMatch, WorklistCounts } from '@/lib/worklist/types' import { visibleWorklistTotalFrom } from '@/lib/worklist/visible-total' interface DashboardContentProps { companyId: string summary: { ytd: { income: number; expenses: number; net: number } mtd: { income: number; expenses: number; net: number } unpaidInvoicesCount: number unpaidInvoicesTotal: number unpaidVatTotal: number overdueInvoicesCount: number bankBalance: number | null expiringBankConnections?: { id: string; bank_name: string; days_left: number }[] deadlines: Deadline[] staleUncategorizedCount: number } /** Unified pending-work counts from lib/worklist: same source as the sidebar badges. */ worklist: WorklistCounts /** High-confidence transaction↔invoice matches for inline one-click confirm. */ suggestedMatches: SuggestedMatch[] onboardingProgress?: OnboardingProgress initialSetup: InitialSetupState /** * False until the company has a verified agent_profile. When false the hero * slot shows a build-assistant prompt instead of the next-best-action card, * so existing/migrated users are nudged to build the assistant without a * full-screen onboarding takeover. */ agentBuilt?: boolean } export default function DashboardContent({ companyId, summary, worklist, suggestedMatches, onboardingProgress, initialSetup, agentBuilt = true }: DashboardContentProps) { const t = useTranslations('dashboard') const hasAi = useCapability(CAPABILITY.ai) const formatLargeNumber = (amount: number) => { return new Intl.NumberFormat('sv-SE', { style: 'decimal', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(amount) } // One number, one source (visibleWorklistTotal): the worklist total plus // expiring bank connections (dashboard-only), minus the hidden paid inbox row // for non-payers. Must match AttGoraSection's header off the same helper. const todoCount = visibleWorklistTotalFrom( worklist, hasAi, summary.expiringBankConnections?.length ?? 0, ) return (
Bygg din bokföringsassistent
{hasAi ? 'Några frågor om din verksamhet kalibrerar en assistent som föreslår bokföring åt dig.' : 'Ingår i abonnemanget: en assistent som föreslår bokföring åt dig.'}
{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)}
{t('bank_balance')}
{formatLargeNumber(summary.bankBalance)} kr
{t('bank_balance')}
{t('connect_bank')}
{t('todo')}
{todoCount} {t('units') && {t('units')}}
) : ({t('all_done')}
{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)}