refactor(reports/trends): rename chart type from 'line' to 'bar' to match actual rendering
The legacy chart was a stacked BarChart, not a LineChart — the initial 'line' naming was misleading. Rename internal type, i18n key (chartLine -> chartBar, Lignes -> Barres, Lines -> Bars) and icon. Legacy 'line' in localStorage is migrated to 'bar' on read.
This commit is contained in:
parent
02efc75542
commit
94104c4223
5 changed files with 23 additions and 16 deletions
|
|
@ -27,7 +27,7 @@ function formatMonth(month: string): string {
|
||||||
return date.toLocaleDateString("default", { month: "short", year: "2-digit" });
|
return date.toLocaleDateString("default", { month: "short", year: "2-digit" });
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CategoryOverTimeChartType = "line" | "area";
|
export type CategoryOverTimeChartType = "bar" | "area";
|
||||||
|
|
||||||
interface CategoryOverTimeChartProps {
|
interface CategoryOverTimeChartProps {
|
||||||
data: CategoryOverTimeData;
|
data: CategoryOverTimeData;
|
||||||
|
|
@ -37,10 +37,10 @@ interface CategoryOverTimeChartProps {
|
||||||
onViewDetails: (item: CategoryBreakdownItem) => void;
|
onViewDetails: (item: CategoryBreakdownItem) => void;
|
||||||
showAmounts?: boolean;
|
showAmounts?: boolean;
|
||||||
/**
|
/**
|
||||||
* Visual rendering mode. `line` (default) keeps the legacy stacked bars —
|
* Visual rendering mode. `bar` (default) keeps the legacy stacked-bar
|
||||||
* preserved for backward compatibility. `area` stacks Recharts <Area> layers
|
* composition. `area` stacks Recharts <Area> layers (stackId="1") for a
|
||||||
* (stackId="1") showing total composition over time. Both modes share the
|
* smoother flow view. Both modes share the same palette and SVG grayscale
|
||||||
* same palette and SVG grayscale patterns (existing signature visual).
|
* patterns (existing signature visual).
|
||||||
*/
|
*/
|
||||||
chartType?: CategoryOverTimeChartType;
|
chartType?: CategoryOverTimeChartType;
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ export default function CategoryOverTimeChart({
|
||||||
onShowAll,
|
onShowAll,
|
||||||
onViewDetails,
|
onViewDetails,
|
||||||
showAmounts,
|
showAmounts,
|
||||||
chartType = "line",
|
chartType = "bar",
|
||||||
}: CategoryOverTimeChartProps) {
|
}: CategoryOverTimeChartProps) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const hoveredRef = useRef<string | null>(null);
|
const hoveredRef = useRef<string | null>(null);
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,18 @@ describe("readTrendsChartType", () => {
|
||||||
vi.stubGlobal("localStorage", mockLocalStorage);
|
vi.stubGlobal("localStorage", mockLocalStorage);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 'line' fallback when key is missing", () => {
|
it("returns 'bar' fallback when key is missing", () => {
|
||||||
expect(readTrendsChartType()).toBe("line");
|
expect(readTrendsChartType()).toBe("bar");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 'line' when stored value is 'line'", () => {
|
it("returns 'bar' when stored value is 'bar'", () => {
|
||||||
|
store.set(TRENDS_CHART_TYPE_STORAGE_KEY, "bar");
|
||||||
|
expect(readTrendsChartType()).toBe("bar");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("migrates legacy 'line' stored value to 'bar'", () => {
|
||||||
store.set(TRENDS_CHART_TYPE_STORAGE_KEY, "line");
|
store.set(TRENDS_CHART_TYPE_STORAGE_KEY, "line");
|
||||||
expect(readTrendsChartType()).toBe("line");
|
expect(readTrendsChartType()).toBe("bar");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns 'area' when stored value is 'area'", () => {
|
it("returns 'area' when stored value is 'area'", () => {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { LineChart as LineIcon, AreaChart as AreaIcon } from "lucide-react";
|
import { BarChart3 as BarIcon, AreaChart as AreaIcon } from "lucide-react";
|
||||||
import type { CategoryOverTimeChartType } from "./CategoryOverTimeChart";
|
import type { CategoryOverTimeChartType } from "./CategoryOverTimeChart";
|
||||||
|
|
||||||
export const TRENDS_CHART_TYPE_STORAGE_KEY = "reports-trends-category-charttype";
|
export const TRENDS_CHART_TYPE_STORAGE_KEY = "reports-trends-category-charttype";
|
||||||
|
|
@ -14,11 +14,13 @@ export interface TrendsChartTypeToggleProps {
|
||||||
|
|
||||||
export function readTrendsChartType(
|
export function readTrendsChartType(
|
||||||
storageKey: string = TRENDS_CHART_TYPE_STORAGE_KEY,
|
storageKey: string = TRENDS_CHART_TYPE_STORAGE_KEY,
|
||||||
fallback: CategoryOverTimeChartType = "line",
|
fallback: CategoryOverTimeChartType = "bar",
|
||||||
): CategoryOverTimeChartType {
|
): CategoryOverTimeChartType {
|
||||||
if (typeof localStorage === "undefined") return fallback;
|
if (typeof localStorage === "undefined") return fallback;
|
||||||
const saved = localStorage.getItem(storageKey);
|
const saved = localStorage.getItem(storageKey);
|
||||||
return saved === "line" || saved === "area" ? saved : fallback;
|
// Back-compat: "line" was the historical key for the bar chart.
|
||||||
|
if (saved === "line") return "bar";
|
||||||
|
return saved === "bar" || saved === "area" ? saved : fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function TrendsChartTypeToggle({
|
export default function TrendsChartTypeToggle({
|
||||||
|
|
@ -33,7 +35,7 @@ export default function TrendsChartTypeToggle({
|
||||||
}, [value, storageKey]);
|
}, [value, storageKey]);
|
||||||
|
|
||||||
const options: { type: CategoryOverTimeChartType; icon: React.ReactNode; label: string }[] = [
|
const options: { type: CategoryOverTimeChartType; icon: React.ReactNode; label: string }[] = [
|
||||||
{ type: "line", icon: <LineIcon size={14} />, label: t("reports.trends.chartLine") },
|
{ type: "bar", icon: <BarIcon size={14} />, label: t("reports.trends.chartBar") },
|
||||||
{ type: "area", icon: <AreaIcon size={14} />, label: t("reports.trends.chartArea") },
|
{ type: "area", icon: <AreaIcon size={14} />, label: t("reports.trends.chartArea") },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,7 @@
|
||||||
"trends": {
|
"trends": {
|
||||||
"subviewGlobal": "Global flow",
|
"subviewGlobal": "Global flow",
|
||||||
"subviewByCategory": "By category",
|
"subviewByCategory": "By category",
|
||||||
"chartLine": "Lines",
|
"chartBar": "Bars",
|
||||||
"chartArea": "Stacked area",
|
"chartArea": "Stacked area",
|
||||||
"chartTypeAria": "Chart type"
|
"chartTypeAria": "Chart type"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -361,7 +361,7 @@
|
||||||
"trends": {
|
"trends": {
|
||||||
"subviewGlobal": "Flux global",
|
"subviewGlobal": "Flux global",
|
||||||
"subviewByCategory": "Par catégorie",
|
"subviewByCategory": "Par catégorie",
|
||||||
"chartLine": "Lignes",
|
"chartBar": "Barres",
|
||||||
"chartArea": "Surface empilée",
|
"chartArea": "Surface empilée",
|
||||||
"chartTypeAria": "Type de graphique"
|
"chartTypeAria": "Type de graphique"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue