mirror of
https://github.com/Zproger/Aurum.git
synced 2026-10-13 19:16:40 +07:00
feat: add year switcher to Dashboard, Transactions and Budget
Year was previously hardcoded to the current year on all three pages (useState with no setter) — only the month could be changed via MonthSelector, making it impossible to look at or compare older years even though transaction history goes back further than the current year. Adds GET /transactions/years (contiguous range from the earliest transaction through the current year) and a YearSelector component matching MonthSelector's style, wired into all three pages alongside a real year useState.
This commit is contained in:
@@ -3,10 +3,12 @@ import { Plus } from "lucide-react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { MonthSelector } from "@/components/layout/MonthSelector";
|
||||
import { YearSelector } from "@/components/layout/YearSelector";
|
||||
import { AlertBanner } from "@/components/insights/AlertBanner";
|
||||
import { BudgetList } from "@/components/budget/BudgetList";
|
||||
import { BudgetFormModal } from "@/components/budget/BudgetFormModal";
|
||||
import { useBudgets, useBudgetStatus, useDeleteBudget } from "@/hooks/useBudgets";
|
||||
import { useTransactionYears } from "@/hooks/useTransactions";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
import { translateCategoryName } from "@/lib/categoryLabels";
|
||||
import type { Budget, BudgetStatus } from "@/types";
|
||||
@@ -14,8 +16,9 @@ import type { Budget, BudgetStatus } from "@/types";
|
||||
export function BudgetPage() {
|
||||
const { t } = useTranslation();
|
||||
const now = new Date();
|
||||
const [year] = useState(now.getFullYear());
|
||||
const [year, setYear] = useState(now.getFullYear());
|
||||
const [month, setMonth] = useState(now.getMonth() + 1);
|
||||
const { data: years } = useTransactionYears();
|
||||
|
||||
const { data: budgets } = useBudgets();
|
||||
const { data: status, isLoading } = useBudgetStatus(year, month);
|
||||
@@ -51,7 +54,10 @@ export function BudgetPage() {
|
||||
<div className="space-y-5">
|
||||
<AlertBanner />
|
||||
|
||||
<MonthSelector month={month} onChange={setMonth} />
|
||||
<div className="space-y-2">
|
||||
<YearSelector years={years ?? [now.getFullYear()]} year={year} onChange={setYear} />
|
||||
<MonthSelector month={month} onChange={setMonth} />
|
||||
</div>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { MonthSelector } from "@/components/layout/MonthSelector";
|
||||
import { YearSelector } from "@/components/layout/YearSelector";
|
||||
import { StatCard } from "@/components/dashboard/StatCard";
|
||||
import { SpendingByCategoryCard } from "@/components/dashboard/SpendingByCategoryCard";
|
||||
import { RecentTransactionsCard } from "@/components/dashboard/RecentTransactionsCard";
|
||||
import { AlertBanner } from "@/components/insights/AlertBanner";
|
||||
import { useDashboardSummary } from "@/hooks/useDashboard";
|
||||
import { useTransactionYears } from "@/hooks/useTransactions";
|
||||
import { formatCurrency, formatSignedCurrency } from "@/lib/format";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
|
||||
@@ -22,8 +24,9 @@ function formatPercent(value: number): string {
|
||||
export function DashboardPage() {
|
||||
const { t } = useTranslation();
|
||||
const now = new Date();
|
||||
const [year] = useState(now.getFullYear());
|
||||
const [year, setYear] = useState(now.getFullYear());
|
||||
const [month, setMonth] = useState(now.getMonth() + 1);
|
||||
const { data: years } = useTransactionYears();
|
||||
|
||||
const { data, isLoading, isError } = useDashboardSummary(year, month);
|
||||
const rate = data ? savingsRate(Number(data.real_income), Number(data.net)) : null;
|
||||
@@ -32,7 +35,10 @@ export function DashboardPage() {
|
||||
<div className="space-y-5">
|
||||
<AlertBanner excludeKeys={["risky_allocation_exceeded"]} />
|
||||
|
||||
<MonthSelector month={month} onChange={setMonth} />
|
||||
<div className="space-y-2">
|
||||
<YearSelector years={years ?? [now.getFullYear()]} year={year} onChange={setYear} />
|
||||
<MonthSelector month={month} onChange={setMonth} />
|
||||
</div>
|
||||
|
||||
{isError && (
|
||||
<p className="rounded-lg border border-danger/30 bg-danger/10 px-4 py-3 text-sm text-danger">
|
||||
|
||||
@@ -4,9 +4,10 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/Card";
|
||||
import { Button } from "@/components/ui/Button";
|
||||
import { Select } from "@/components/ui/Input";
|
||||
import { MonthSelector } from "@/components/layout/MonthSelector";
|
||||
import { YearSelector } from "@/components/layout/YearSelector";
|
||||
import { TransactionsTable } from "@/components/transactions/TransactionsTable";
|
||||
import { TransactionFormModal } from "@/components/transactions/TransactionFormModal";
|
||||
import { useTransactions, useDeleteTransaction } from "@/hooks/useTransactions";
|
||||
import { useTransactions, useDeleteTransaction, useTransactionYears } from "@/hooks/useTransactions";
|
||||
import { useCategories } from "@/hooks/useCategories";
|
||||
import type { TransactionSort } from "@/api/transactions";
|
||||
import { useTranslation } from "@/lib/i18n";
|
||||
@@ -18,7 +19,7 @@ const PAGE_SIZE = 20;
|
||||
export function TransactionsPage() {
|
||||
const { t } = useTranslation();
|
||||
const now = new Date();
|
||||
const [year] = useState(now.getFullYear());
|
||||
const [year, setYear] = useState(now.getFullYear());
|
||||
const [month, setMonth] = useState(now.getMonth() + 1);
|
||||
const [type, setType] = useState<TransactionType | "">("");
|
||||
const [categoryId, setCategoryId] = useState<string>("");
|
||||
@@ -29,6 +30,7 @@ export function TransactionsPage() {
|
||||
const [editingTransaction, setEditingTransaction] = useState<Transaction | null>(null);
|
||||
|
||||
const { data: categories } = useCategories();
|
||||
const { data: years } = useTransactionYears();
|
||||
const { data, isLoading, isError } = useTransactions({
|
||||
year,
|
||||
month,
|
||||
@@ -61,13 +63,23 @@ export function TransactionsPage() {
|
||||
return (
|
||||
<div className="space-y-5">
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
||||
<MonthSelector
|
||||
month={month}
|
||||
onChange={(value) => {
|
||||
setMonth(value);
|
||||
setPage(1);
|
||||
}}
|
||||
/>
|
||||
<div className="space-y-2">
|
||||
<YearSelector
|
||||
years={years ?? [now.getFullYear()]}
|
||||
year={year}
|
||||
onChange={(value) => {
|
||||
setYear(value);
|
||||
setPage(1);
|
||||
}}
|
||||
/>
|
||||
<MonthSelector
|
||||
month={month}
|
||||
onChange={(value) => {
|
||||
setMonth(value);
|
||||
setPage(1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={openCreateModal} className="w-full sm:w-auto">
|
||||
<Plus size={16} />
|
||||
{t("transactions.addButton")}
|
||||
|
||||
Reference in New Issue
Block a user