feat: advanced features — dashboard, budgets, history, export
Backend: - GET /api/v1/dashboard?month=YYYY-MM: KPIs, by_category, 6-month trend, budget alerts - GET/POST/PUT/DELETE /api/v1/budgets: budget envelopes with spent_cents/remaining_cents - POST /api/v1/budgets/rollover: copy budgets from M-1 to target month - GET /api/v1/history?year=YYYY: monthly summary for the year - GET /api/v1/export/csv|pdf?month=YYYY-MM: StreamingResponse exports (WeasyPrint PDF) - New schemas: dashboard, budget, history - Services: dashboard_service, budget_service - Routers mounted in main.py Frontend: - DashboardPage: 4 KPI cards, PieChart (expenses by category), BarChart (6-month trend), month navigation, budget alert badges, CSV/PDF export buttons - BudgetsPage: progress bars (green/orange/red), create/edit form, delete, rollover M-1 - HistoryPage: annual table with month click → dashboard, LineChart revenues/expenses - CategoriesPage: list by type with create/edit/delete (was missing from Phase 2) - TransactionsPage: added CSV/PDF export buttons - App.tsx: full routing with ProtectedRoute + Layout for all authenticated pages - New hooks: useDashboard, useBudgets (with mutations), useHistory - API types + client updated for all new endpoints Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
createBudget,
|
||||
deleteBudget,
|
||||
getBudgets,
|
||||
rolloverBudgets,
|
||||
updateBudget,
|
||||
} from "../api/client";
|
||||
import type { CreateBudgetPayload, UpdateBudgetPayload } from "../api/types";
|
||||
|
||||
export function useBudgets(month?: string) {
|
||||
return useQuery({
|
||||
queryKey: ["budgets", month],
|
||||
queryFn: () => getBudgets(month),
|
||||
});
|
||||
}
|
||||
|
||||
export function useCreateBudget() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (payload: CreateBudgetPayload) => createBudget(payload),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["budgets"] }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateBudget() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, payload }: { id: string; payload: UpdateBudgetPayload }) =>
|
||||
updateBudget(id, payload),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["budgets"] }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteBudget() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => deleteBudget(id),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["budgets"] }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useRolloverBudgets() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (month: string) => rolloverBudgets(month),
|
||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["budgets"] }),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getDashboard } from "../api/client";
|
||||
|
||||
export function useDashboard(month?: string) {
|
||||
return useQuery({
|
||||
queryKey: ["dashboard", month],
|
||||
queryFn: () => getDashboard(month),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getHistory } from "../api/client";
|
||||
|
||||
export function useHistory(year?: number) {
|
||||
return useQuery({
|
||||
queryKey: ["history", year],
|
||||
queryFn: () => getHistory(year),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user