'use client' import { Suspense, useState } from 'react' import dynamic from 'next/dynamic' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useTranslations } from 'next-intl' import { ChevronLeft } from 'lucide-react' import { PageHeader } from '@/components/ui/page-header' import { HelpPopover } from '@/components/ui/help-popover' import { EmptyState } from '@/components/ui/empty-state' import { Card, CardContent } from '@/components/ui/card' import { Skeleton } from '@/components/ui/skeleton' import { useCompany } from '@/contexts/CompanyContext' import { FyPicker } from '@/components/common/FyPicker' import { ReportDateRange, type DateRangeValue } from '@/components/common/ReportDateRange' import { DimensionFilter, type DimensionFilterValue } from '@/components/reports/DimensionFilter' import { DATE_RANGE_SLUGS, DIMENSION_FILTER_SLUGS, getReport } from '@/lib/reports/catalog' import type { FiscalPeriod } from '@/types' function ReportViewLoading() { return ( ) } const TrialBalanceView = dynamic(() => import('./lazy-views/TrialBalanceView'), { loading: ReportViewLoading }) const IncomeStatementView = dynamic(() => import('./lazy-views/IncomeStatementView'), { loading: ReportViewLoading }) const BalanceSheetView = dynamic(() => import('./lazy-views/BalanceSheetView'), { loading: ReportViewLoading }) const ResultatrapportView = dynamic(() => import('./lazy-views/ResultatrapportView'), { loading: ReportViewLoading }) const BalansrapportView = dynamic(() => import('./lazy-views/BalansrapportView'), { loading: ReportViewLoading }) const VatDeclarationView = dynamic(() => import('./lazy-views/VatDeclarationView'), { loading: ReportViewLoading }) const SupplierLedgerView = dynamic(() => import('./lazy-views/SupplierLedgerView'), { loading: ReportViewLoading }) const GeneralLedgerView = dynamic(() => import('./lazy-views/GeneralLedgerView'), { loading: ReportViewLoading }) const JournalRegisterView = dynamic(() => import('./lazy-views/JournalRegisterView'), { loading: ReportViewLoading }) const ARLedgerView = dynamic(() => import('./lazy-views/ARLedgerView'), { loading: ReportViewLoading }) const DimensionPnlView = dynamic(() => import('./lazy-views/DimensionPnlView'), { loading: ReportViewLoading }) const NEDeclarationView = dynamic(() => import('./NEDeclarationView').then((module) => ({ default: module.NEDeclarationView })), { loading: ReportViewLoading }, ) const PeriodiskSammanstallningView = dynamic(() => import('./PeriodiskSammanstallningView').then((module) => ({ default: module.PeriodiskSammanstallningView })), { loading: ReportViewLoading }, ) const INK2DeclarationView = dynamic(() => import('./INK2DeclarationView').then((module) => ({ default: module.INK2DeclarationView })), { loading: ReportViewLoading }, ) const BankReconciliationView = dynamic(() => import('./BankReconciliationView').then((module) => ({ default: module.BankReconciliationView })), { loading: ReportViewLoading }, ) /** * The focused single-report experience at /reports/[slug]. Carries one report: * a back link to the library, the shared fiscal-year selector (restored from * localStorage so it matches the year picked on the landing), the report's * optional date-range control, and the report body. Drilling into an account * navigates to /reports/huvudbok?account=…: drill state lives in the URL. */ function FocusedReportInner({ slug, initialPeriods, initialCompanyId, }: { slug: string initialPeriods: FiscalPeriod[] initialCompanyId: string | null }) { const router = useRouter() const searchParams = useSearchParams() const { company } = useCompany() const t = useTranslations('reports') const [selectedPeriod, setSelectedPeriod] = useState('') const [selectedPeriodBounds, setSelectedPeriodBounds] = useState<{ start: string; end: string } | null>(null) const [dateRange, setDateRange] = useState({}) const [dimensionFilter, setDimensionFilter] = useState(null) const [isReady, setIsReady] = useState(false) const report = getReport(slug) // Calendar (VAT family) and param-less reports don't need a fiscal period. const isPeriodless = report?.params === 'calendar' || report?.params === 'none' // Nav-promoted pages (Momsdeklaration) drop the library chrome: no back // link, no shell fiscal-year selector — the view owns its period controls. const isStandalone = !!report?.standalone const reportName = report ? t(report.labelKey) : slug const accountFilter = searchParams.get('account') const isEnskildFirma = company?.entity_type === 'enskild_firma' const isAktiebolag = company?.entity_type === 'aktiebolag' // Drilling from a report into the general ledger is a route change, so the // account lands in the URL and the browser back button returns to the report. const navigateToAccount = (accountNumber: string) => { router.push(`/reports/huvudbok?account=${encodeURIComponent(accountNumber)}`) } return (
{!isStandalone && ( {t('back_to_library')} )} {/* Standalone pages (Momsdeklaration) render their own PageHeader so the primary action can live on the title row; the view receives the title via pageTitle instead. */} {!isStandalone && (

{t('help_bank_reconciliation_scope')}

{t('help_bank_reconciliation_preview')}

{t('help_bank_reconciliation_ib')}

{t('help_bank_reconciliation_ignored')}

) : undefined } action={ { setSelectedPeriod(id || '') setSelectedPeriodBounds( period ? { start: period.period_start, end: period.period_end } : null, ) setDateRange({}) }} includeAllOption={false} hideFuturePeriods onReady={() => setIsReady(true)} initialPeriods={initialPeriods} initialCompanyId={initialCompanyId} /> } /> )} {DATE_RANGE_SLUGS.has(slug) && selectedPeriodBounds && ( )} {DIMENSION_FILTER_SLUGS.has(slug) && selectedPeriod && ( )} {!isReady && !isPeriodless ? ( ) : isPeriodless || selectedPeriod ? ( ) : ( )}
) } function FocusedView({ slug, reportName, periodId, periodBounds, dateRange, dimensionFilter, accountFilter, isEnskildFirma, isAktiebolag, onNavigateToAccount, }: { slug: string reportName: string periodId: string periodBounds: { start: string; end: string } | null dateRange: DateRangeValue dimensionFilter: DimensionFilterValue | null accountFilter: string | null isEnskildFirma: boolean isAktiebolag: boolean onNavigateToAccount: (account: string) => void }) { switch (slug) { case 'resultatrapport': return case 'dimension-pnl': return case 'balansrapport': return case 'trial-balance': return case 'income-statement': return case 'balance-sheet': return case 'vat-declaration': return case 'periodisk-sammanstallning': return case 'ne-declaration': return isEnskildFirma ? : null case 'ink2-declaration': return isAktiebolag ? : null case 'huvudbok': return case 'grundbok': return case 'kundreskontra': return case 'supplier-ledger': return case 'bank-reconciliation': return default: return null } } export function FocusedReport({ slug, initialPeriods, initialCompanyId, }: { slug: string initialPeriods: FiscalPeriod[] initialCompanyId: string | null }) { return ( }> ) }