mirror of
https://github.com/Zproger/Aurum.git
synced 2026-10-14 19:46:40 +07:00
feat: add category management page (create/edit/delete)
The backend already had full category CRUD but nothing in the UI exposed it — categories could only be viewed inside charts. Adds a Categories nav item and page with icon/color pickers, grouped by expense/income, backed by new create/update/delete mutations. Also expands icons.tsx's ICON_MAP, which was missing 14 icon keys already in use by real category data and silently falling back to a wallet glyph everywhere they render. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,46 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { fetchCategories } from "@/api/categories";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { createCategory, deleteCategory, fetchCategories, updateCategory } from "@/api/categories";
|
||||
import type { CategoryInput, CategoryUpdateInput } from "@/types";
|
||||
|
||||
export function useCategories() {
|
||||
return useQuery({ queryKey: ["categories"], queryFn: fetchCategories });
|
||||
}
|
||||
|
||||
// Category name/color/icon are denormalized into several read models
|
||||
// (transactions, dashboard, reports, budgets, recurring templates) — any
|
||||
// create/update/delete has to refresh all of them, same set an account
|
||||
// mutation invalidates in useAccounts.ts.
|
||||
function invalidateCategoryConsumers(queryClient: ReturnType<typeof useQueryClient>) {
|
||||
queryClient.invalidateQueries({ queryKey: ["categories"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["transactions"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["dashboard-summary"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["category-spending-report"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["category-ranking"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["budgets"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["budget-status"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["recurring"] });
|
||||
}
|
||||
|
||||
export function useCreateCategory() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (input: CategoryInput) => createCategory(input),
|
||||
onSuccess: () => invalidateCategoryConsumers(queryClient),
|
||||
});
|
||||
}
|
||||
|
||||
export function useUpdateCategory() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, input }: { id: number; input: CategoryUpdateInput }) => updateCategory(id, input),
|
||||
onSuccess: () => invalidateCategoryConsumers(queryClient),
|
||||
});
|
||||
}
|
||||
|
||||
export function useDeleteCategory() {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: number) => deleteCategory(id),
|
||||
onSuccess: () => invalidateCategoryConsumers(queryClient),
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user