refactor(transactions): drop the Q1-Q4 chips from the period filter (#1579)

The quarter chips (#1545) appeared only once a rakenskapsar was chosen,
pushed the filter row out of alignment, and on a brutet rakenskapsar
they were fiscal-year quarters rather than momsdeklaration quarters, so
they misled more than they scoped. The rakenskapsar filter itself (the
user-requested half) stays; lib/transactions/period-filter.ts keeps its
quarter helpers and tests since resolvePeriodBounds still serves the
full-year bounds.

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-08-13 15:17:03 +02:00
committed by GitHub
co-authored by Jakob Wennberg Claude Fable 5
parent d583a4e5bb
commit c420fd2aa1
3 changed files with 13 additions and 63 deletions
+13 -61
View File
@@ -65,13 +65,7 @@ import type { TransactionCategory, CreateTransactionInput, Invoice, Customer, Su
import type { SuggestedTemplate } from '@/lib/transactions/category-suggestions'
import { isImportedTransaction } from '@/lib/transactions/origin'
import { computeJeUnderlagStatus, type JeUnderlagStatus } from '@/lib/transactions/underlag-status'
import {
QUARTERS,
isWithinBounds,
quarterBounds,
resolvePeriodBounds,
type Quarter,
} from '@/lib/transactions/period-filter'
import { isWithinBounds, resolvePeriodBounds } from '@/lib/transactions/period-filter'
import type { FiscalPeriod } from '@/types'
function InlineDialogContentLoading() {
@@ -451,40 +445,28 @@ export default function TransactionsPage() {
}
}, [])
// Period filter (rakenskapsar + optional quarter within it). Quarters
// follow the fiscal year, so a brutet rakenskapsar (July-June) gets
// Q1 = Jul-Sep. FyPicker owns the persistence under the page-local key;
// the quarter is session-only.
// Period filter (rakenskapsar). FyPicker owns the persistence under the
// page-local key. Quarter chips existed briefly (#1545) but were dropped:
// they crowded the filter row, and on a brutet rakenskapsar they were not
// momsdeklaration quarters, which made them misleading rather than useful.
const [fyPeriodId, setFyPeriodId] = useState<string | null>(null)
const [fyPeriod, setFyPeriod] = useState<FiscalPeriod | null>(null)
const [fyQuarter, setFyQuarter] = useState<Quarter | null>(null)
const periodBounds = useMemo(
() => resolvePeriodBounds(fyPeriod, fyQuarter),
[fyPeriod, fyQuarter],
)
const periodBounds = useMemo(() => resolvePeriodBounds(fyPeriod, null), [fyPeriod])
const handlePeriodChange = useCallback((periodId: string | null, period?: FiscalPeriod | null) => {
setFyPeriodId(periodId)
setFyPeriod(period ?? null)
setFyQuarter(null)
// Batch selections may reference rows the new scope hides; every batch
// action operates on "what you see", so drop them.
setSelectedIds(new Set())
setSkvSelectedIds(new Set())
}, [])
const handleQuarterChange = useCallback((quarter: Quarter | null) => {
setFyQuarter(quarter)
setSelectedIds(new Set())
setSkvSelectedIds(new Set())
}, [])
// Footer "Visa alla" escape hatch: clears the period scope AND its
// persisted value (FyPicker only writes storage from its own dropdown).
const clearPeriodFilter = useCallback(() => {
setFyPeriodId(null)
setFyPeriod(null)
setFyQuarter(null)
setSelectedIds(new Set())
setSkvSelectedIds(new Set())
if (companyId) {
@@ -2926,49 +2908,19 @@ export default function TransactionsPage() {
/>
</div>
{/* Far-right context group, shared by both view modes: period scope
(rakenskapsar chip + quarter chips once a year is chosen) and the
account chooser (concept scene 10). Approved deviation from
convention 8's single chip: booking is period work, so the period
scope earns the second chip (user request 2026-08-12). */}
(rakenskapsar chip) and the account chooser (concept scene 10).
Approved deviation from convention 8's single chip: booking is
period work, so the period scope earns the second chip (user
request 2026-08-12). The Q1-Q4 chips that briefly rendered here
(#1545) were removed: they crowded the row into a second line,
and on a brutet rakenskapsar they were not momsdeklaration
quarters, so they misled more than they scoped. */}
<div className="ml-auto flex flex-wrap items-center justify-end gap-2">
<FyPicker
value={fyPeriodId}
onChange={handlePeriodChange}
storageKeyPrefix={PERIOD_FILTER_STORAGE_PREFIX}
/>
{fyPeriod && (
<div
className="inline-flex shrink-0 gap-0.5 rounded-lg bg-muted/70 p-[3px]"
role="group"
// Quarters follow the rakenskapsar, NOT the calendar: on a
// brutet rakenskapsar these are not momsdeklaration quarters.
// The label says so to keep VAT reconciliation off this chip.
aria-label={t('period_quarter_group')}
title={t('period_quarter_group')}
>
{QUARTERS.map((quarter) => {
const bounds = quarterBounds(fyPeriod, quarter)
const active = fyQuarter === quarter
return (
<button
key={quarter}
type="button"
disabled={!bounds}
aria-pressed={active}
// Clicking the active quarter widens back to the full year.
onClick={() => handleQuarterChange(active ? null : quarter)}
className={`rounded-md px-3 py-[5px] text-[12.5px] tabular-nums transition-colors duration-150 disabled:cursor-not-allowed disabled:opacity-40 ${
active
? 'border border-border bg-card font-medium text-foreground'
: 'text-muted-foreground hover:text-foreground'
}`}
>
{`Q${quarter}`}
</button>
)
})}
</div>
)}
{sourceItems.length > 1 && (
<ContextPicker
value={sourceFilter}
-1
View File
@@ -5274,7 +5274,6 @@
"no_search_results": "No transactions match your search.",
"source_empty": "The selected source has no transactions. Choose All to show the other sources.",
"period_empty": "The selected period has no transactions. Choose All fiscal years to show everything.",
"period_quarter_group": "Quarter of the fiscal year (not calendar quarter)",
"period_pending_outside": "{count, plural, one {# transaction to record outside the selected period.} other {# transactions to record outside the selected period.}}",
"period_show_all": "Show all",
"skv_reconnect_title": "The Skatteverket connection needs to be renewed",
-1
View File
@@ -5274,7 +5274,6 @@
"no_search_results": "Inga transaktioner matchar din sökning.",
"source_empty": "Den valda källan har inga transaktioner. Välj Alla för att visa övriga källor.",
"period_empty": "Den valda perioden har inga transaktioner. Välj Alla räkenskapsår för att visa allt.",
"period_quarter_group": "Räkenskapsårets kvartal (inte kalenderkvartal)",
"period_pending_outside": "{count, plural, one {# transaktion att bokföra utanför vald period.} other {# transaktioner att bokföra utanför vald period.}}",
"period_show_all": "Visa alla",
"skv_reconnect_title": "Anslutningen till Skatteverket behöver förnyas",