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",
|
||||
"categoryZoomDescription": "Zoom in on a single category"
|
||||
},
|
||||
"trends": {
|
||||
"subviewGlobal": "Global flow",
|
||||
"subviewByCategory": "By category"
|
||||
},
|
||||
"highlights": {
|
||||
"balances": "Balances",
|
||||
"netBalanceCurrent": "This month",
|
||||
|
|
|
|||
|
|
@ -399,10 +399,6 @@
|
|||
"categoryZoom": "Analyse par catégorie",
|
||||
"categoryZoomDescription": "Zoom sur une catégorie"
|
||||
},
|
||||
"trends": {
|
||||
"subviewGlobal": "Flux global",
|
||||
"subviewByCategory": "Par catégorie"
|
||||
},
|
||||
"highlights": {
|
||||
"balances": "Soldes",
|
||||
"netBalanceCurrent": "Ce mois-ci",
|
||||
|
|
|
|||
|
|
@ -1,116 +1,11 @@
|
|||
import { useState, useCallback } from "react";
|
||||
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() {
|
||||
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 (
|
||||
<div className={isLoading ? "opacity-60" : ""}>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<Link
|
||||
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 className="p-8 text-center text-[var(--muted-foreground)]">
|
||||
<h1 className="text-2xl font-bold mb-4">{t("reports.hub.trends")}</h1>
|
||||
<p>{t("common.underConstruction")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue