Compare commits
No commits in common. "fae76a6b82f7a6ab0f4e6fa7d7a1369a15e02731" and "5d206d5fafabf779ed81e70b231bc80bf5dca247" have entirely different histories.
fae76a6b82
...
5d206d5faf
3 changed files with 3 additions and 116 deletions
|
|
@ -399,10 +399,6 @@
|
||||||
"categoryZoom": "Category Analysis",
|
"categoryZoom": "Category Analysis",
|
||||||
"categoryZoomDescription": "Zoom in on a single category"
|
"categoryZoomDescription": "Zoom in on a single category"
|
||||||
},
|
},
|
||||||
"trends": {
|
|
||||||
"subviewGlobal": "Global flow",
|
|
||||||
"subviewByCategory": "By category"
|
|
||||||
},
|
|
||||||
"highlights": {
|
"highlights": {
|
||||||
"balances": "Balances",
|
"balances": "Balances",
|
||||||
"netBalanceCurrent": "This month",
|
"netBalanceCurrent": "This month",
|
||||||
|
|
|
||||||
|
|
@ -399,10 +399,6 @@
|
||||||
"categoryZoom": "Analyse par catégorie",
|
"categoryZoom": "Analyse par catégorie",
|
||||||
"categoryZoomDescription": "Zoom sur une catégorie"
|
"categoryZoomDescription": "Zoom sur une catégorie"
|
||||||
},
|
},
|
||||||
"trends": {
|
|
||||||
"subviewGlobal": "Flux global",
|
|
||||||
"subviewByCategory": "Par catégorie"
|
|
||||||
},
|
|
||||||
"highlights": {
|
"highlights": {
|
||||||
"balances": "Soldes",
|
"balances": "Soldes",
|
||||||
"netBalanceCurrent": "Ce mois-ci",
|
"netBalanceCurrent": "Ce mois-ci",
|
||||||
|
|
|
||||||
|
|
@ -1,116 +1,11 @@
|
||||||
import { useState, useCallback } from "react";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import { ArrowLeft } from "lucide-react";
|
|
||||||
import PeriodSelector from "../components/dashboard/PeriodSelector";
|
|
||||||
import MonthlyTrendsChart from "../components/reports/MonthlyTrendsChart";
|
|
||||||
import MonthlyTrendsTable from "../components/reports/MonthlyTrendsTable";
|
|
||||||
import CategoryOverTimeChart from "../components/reports/CategoryOverTimeChart";
|
|
||||||
import CategoryOverTimeTable from "../components/reports/CategoryOverTimeTable";
|
|
||||||
import ViewModeToggle, { readViewMode, type ViewMode } from "../components/reports/ViewModeToggle";
|
|
||||||
import { useTrends } from "../hooks/useTrends";
|
|
||||||
import { useReportsPeriod } from "../hooks/useReportsPeriod";
|
|
||||||
import type { CategoryBreakdownItem } from "../shared/types";
|
|
||||||
|
|
||||||
const STORAGE_KEY = "reports-viewmode-trends";
|
|
||||||
|
|
||||||
export default function ReportsTrendsPage() {
|
export default function ReportsTrendsPage() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { period, setPeriod, from, to, setCustomDates } = useReportsPeriod();
|
|
||||||
const { subView, setSubView, monthlyTrends, categoryOverTime, isLoading, error } = useTrends();
|
|
||||||
const [viewMode, setViewMode] = useState<ViewMode>(() => readViewMode(STORAGE_KEY));
|
|
||||||
const [hiddenCategories, setHiddenCategories] = useState<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const preserveSearch = typeof window !== "undefined" ? window.location.search : "";
|
|
||||||
|
|
||||||
const toggleHidden = useCallback((name: string) => {
|
|
||||||
setHiddenCategories((prev) => {
|
|
||||||
const next = new Set(prev);
|
|
||||||
if (next.has(name)) next.delete(name);
|
|
||||||
else next.add(name);
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const showAll = useCallback(() => setHiddenCategories(new Set()), []);
|
|
||||||
// viewDetails not used in trends view — transactions details are accessed from category zoom.
|
|
||||||
const noOpDetails = useCallback((_item: CategoryBreakdownItem) => {}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={isLoading ? "opacity-60" : ""}>
|
<div className="p-8 text-center text-[var(--muted-foreground)]">
|
||||||
<div className="flex items-center gap-3 mb-4">
|
<h1 className="text-2xl font-bold mb-4">{t("reports.hub.trends")}</h1>
|
||||||
<Link
|
<p>{t("common.underConstruction")}</p>
|
||||||
to={`/reports${preserveSearch}`}
|
|
||||||
className="text-[var(--muted-foreground)] hover:text-[var(--foreground)] p-1 rounded-md hover:bg-[var(--muted)]"
|
|
||||||
aria-label={t("reports.hub.title")}
|
|
||||||
>
|
|
||||||
<ArrowLeft size={18} />
|
|
||||||
</Link>
|
|
||||||
<h1 className="text-2xl font-bold">{t("reports.hub.trends")}</h1>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-6 flex-wrap">
|
|
||||||
<PeriodSelector
|
|
||||||
value={period}
|
|
||||||
onChange={setPeriod}
|
|
||||||
customDateFrom={from}
|
|
||||||
customDateTo={to}
|
|
||||||
onCustomDateChange={setCustomDates}
|
|
||||||
/>
|
|
||||||
<div className="flex gap-2 items-center flex-wrap">
|
|
||||||
<div className="inline-flex gap-1">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setSubView("global")}
|
|
||||||
aria-pressed={subView === "global"}
|
|
||||||
className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
||||||
subView === "global"
|
|
||||||
? "bg-[var(--primary)] text-white"
|
|
||||||
: "bg-[var(--card)] border border-[var(--border)] text-[var(--foreground)] hover:bg-[var(--muted)]"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{t("reports.trends.subviewGlobal")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => setSubView("byCategory")}
|
|
||||||
aria-pressed={subView === "byCategory"}
|
|
||||||
className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
|
||||||
subView === "byCategory"
|
|
||||||
? "bg-[var(--primary)] text-white"
|
|
||||||
: "bg-[var(--card)] border border-[var(--border)] text-[var(--foreground)] hover:bg-[var(--muted)]"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{t("reports.trends.subviewByCategory")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<ViewModeToggle value={viewMode} onChange={setViewMode} storageKey={STORAGE_KEY} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{error && (
|
|
||||||
<div className="bg-[var(--negative)]/10 text-[var(--negative)] rounded-xl p-4 mb-6">
|
|
||||||
{error}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{subView === "global" ? (
|
|
||||||
viewMode === "chart" ? (
|
|
||||||
<MonthlyTrendsChart data={monthlyTrends} />
|
|
||||||
) : (
|
|
||||||
<MonthlyTrendsTable data={monthlyTrends} />
|
|
||||||
)
|
|
||||||
) : viewMode === "chart" ? (
|
|
||||||
<CategoryOverTimeChart
|
|
||||||
data={categoryOverTime}
|
|
||||||
hiddenCategories={hiddenCategories}
|
|
||||||
onToggleHidden={toggleHidden}
|
|
||||||
onShowAll={showAll}
|
|
||||||
onViewDetails={noOpDetails}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<CategoryOverTimeTable data={categoryOverTime} hiddenCategories={hiddenCategories} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue