First consumer migration onto lib/reference-data. FyPicker and
FiscalYearSelector (14 consumer surfaces, 47 fiscal-period fetch sites
before this series) now read useFiscalPeriods(); with the layout seed the
restore of the persisted scope runs in the first effect tick and onReady
fires on mount instead of after a round trip. Their restore rules are
extracted into a pure resolveInitialFiscalScope() (lib/reference-data/
fiscal-scope.ts) so the two pickers cannot drift apart again, and the
restore runs once per company load, not on every background revalidation.
- /reports: the static catalog renders immediately; only the "no fiscal
year" empty state waits for the picker (previously six skeleton bars
until /api/bookkeeping/fiscal-periods resolved).
- JournalEntryList (/bookkeeping): resolves its initial scope from the
cached list instead of its own fetch; the saved-scope shortcut still
unblocks the entries fetch first when nothing is cached, and resolution
is guarded to once per company so a revalidation can never snap a
deep-link "all years" visit back to the stored year.
- /transactions: the account chooser reads useCashAccounts({ enabledOnly })
(seeded) instead of fetching /api/cash-accounts on every visit; the bank
sync button invalidates that entry after a sync.
- STORAGE_KEY_PREFIX / ALL_YEARS_VALUE move to a dependency-free
fiscal-year-storage.ts (re-exported from FiscalYearSelector) so lib/ code
can import them without a React component.
raw-reference-fetch ratchet: 55 -> 51 files.
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
95 lines
3.2 KiB
TypeScript
95 lines
3.2 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
import { useRouter } from 'next/navigation'
|
|
import { useTranslations } from 'next-intl'
|
|
import { PageHeader } from '@/components/ui/page-header'
|
|
import { HelpPopover } from '@/components/ui/help-popover'
|
|
import { EmptyState } from '@/components/ui/empty-state'
|
|
import { useCompany } from '@/contexts/CompanyContext'
|
|
import { useCompanySettings } from '@/components/settings/useSettings'
|
|
import { FyPicker } from '@/components/common/FyPicker'
|
|
import { ReportLibrary } from '@/components/reports/ReportLibrary'
|
|
import { useRecentReports } from '@/components/reports/useRecentReports'
|
|
import { getReport } from '@/lib/reports/catalog'
|
|
|
|
/**
|
|
* Reports catalog landing (concept "Tabellen"): one dry table grouped by
|
|
* accounting taxonomy, with a "Senast öppnad" column instead of a separate
|
|
* recents shelf. Selecting a report opens the focused /reports/[slug] route.
|
|
* The fiscal year picked here persists (FyPicker localStorage) and is
|
|
* restored on the focused page, so the choice carries across without URL
|
|
* plumbing.
|
|
*/
|
|
export default function ReportsPage() {
|
|
const router = useRouter()
|
|
const [selectedPeriod, setSelectedPeriod] = useState('')
|
|
// The catalog itself is static; only the "no fiscal year" empty state has
|
|
// to wait for the picker to finish restoring its scope (one effect tick
|
|
// when the periods are seeded, see FyPicker).
|
|
const [fyReady, setFyReady] = useState(false)
|
|
const { company } = useCompany()
|
|
const { settings } = useCompanySettings()
|
|
const t = useTranslations('reports')
|
|
const { openedAt, pushRecent } = useRecentReports(company?.id)
|
|
|
|
// Open a report. Route-owning reports (cash flow, annual report, KPI, SIE)
|
|
// navigate to their own page; the rest open the focused /reports/[slug] route.
|
|
const openReport = (slug: string) => {
|
|
const report = getReport(slug)
|
|
if (report?.route) {
|
|
const href =
|
|
slug === 'arsredovisning' && selectedPeriod
|
|
? `${report.route}?period=${selectedPeriod}`
|
|
: report.route
|
|
router.push(href)
|
|
return
|
|
}
|
|
pushRecent(slug)
|
|
router.push(`/reports/${slug}`)
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-8">
|
|
<PageHeader
|
|
title={t('title')}
|
|
help={
|
|
<HelpPopover>
|
|
<p>{t('help_text')}</p>
|
|
</HelpPopover>
|
|
}
|
|
action={
|
|
<FyPicker
|
|
value={selectedPeriod || null}
|
|
onChange={(id) => setSelectedPeriod(id || '')}
|
|
includeAllOption={false}
|
|
hideFuturePeriods
|
|
onReady={() => setFyReady(true)}
|
|
/>
|
|
}
|
|
/>
|
|
|
|
{fyReady && !selectedPeriod ? (
|
|
<EmptyState
|
|
title="Inget räkenskapsår valt"
|
|
description="Skapa ett räkenskapsår för att kunna se rapporter."
|
|
actionLabel="Gå till inställningar"
|
|
actionHref="/settings"
|
|
/>
|
|
) : (
|
|
<>
|
|
<ReportLibrary
|
|
entityType={company?.entity_type}
|
|
dimensionsEnabled={settings?.dimensions_enabled === true}
|
|
openedAt={openedAt}
|
|
onOpen={openReport}
|
|
/>
|
|
<p className="px-1 text-xs leading-5 text-muted-foreground">
|
|
{t('catalog_footnote')}
|
|
</p>
|
|
</>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|