Simpl-Resultat/src/components/reports/CompareModeTabs.tsx
le king fu 4116db4090
All checks were successful
PR Check / rust (push) Successful in 24m37s
PR Check / frontend (push) Successful in 2m21s
PR Check / rust (pull_request) Successful in 24m25s
PR Check / frontend (pull_request) Successful in 2m26s
refactor(reports/compare): unify MoM/YoY under one Actual-vs-actual mode with reference month picker (#96)
Collapse the three Compare tabs (MoM / YoY / Budget) into two modes. The
new "Actual vs actual" mode exposes an explicit reference-month dropdown
in the header (defaults to the previous month, wraps around January) and
a MoM/YoY sub-toggle. The chart is rewritten to a grouped side-by-side
BarChart with two bars per category (reference period vs comparison
period) so both values are visible at a glance instead of just the
delta. The URL PeriodSelector stays in sync with the reference month.

- useCompare: state splits into { mode: "actual"|"budget", subMode:
  "mom"|"yoy", year, month }. Pure helpers previousMonth(),
  defaultReferencePeriod(), comparisonMeta() extracted for tests
- CompareModeTabs: 2 modes instead of 3
- New CompareSubModeToggle and CompareReferenceMonthPicker components
- ComparePeriodChart: grouped bars via two <Bar dataKey="..."/> on a
  vertical BarChart
- i18n: modeActual / subModeMoM / subModeYoY / referenceMonth (FR+EN),
  retire modeMoM / modeYoY
- 9 new vitest cases covering the pure helpers (January wrap-around for
  both MoM and YoY, default reference period, month/year arithmetic)

Closes #96

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 14:24:11 -04:00

37 lines
1.1 KiB
TypeScript

import { useTranslation } from "react-i18next";
import type { CompareMode } from "../../hooks/useCompare";
export interface CompareModeTabsProps {
value: CompareMode;
onChange: (mode: CompareMode) => void;
}
export default function CompareModeTabs({ value, onChange }: CompareModeTabsProps) {
const { t } = useTranslation();
const modes: { id: CompareMode; labelKey: string }[] = [
{ id: "actual", labelKey: "reports.compare.modeActual" },
{ id: "budget", labelKey: "reports.compare.modeBudget" },
];
return (
<div className="inline-flex gap-1" role="tablist">
{modes.map(({ id, labelKey }) => (
<button
key={id}
type="button"
role="tab"
onClick={() => onChange(id)}
aria-selected={value === id}
className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
value === id
? "bg-[var(--primary)] text-white"
: "bg-[var(--card)] border border-[var(--border)] text-[var(--foreground)] hover:bg-[var(--muted)]"
}`}
>
{t(labelKey)}
</button>
))}
</div>
);
}