import { useMutation, useQueryClient } from "@tanstack/react-query"; import { apiSend } from "../client"; import { keys } from "../keys"; import { BudgetSchema, SettingsSchema, LendingSchema, RevalueResultSchema, SubscriptionSchema, } from "../schemas"; // --- transactions --- export const useCategorize = () => { const qc = useQueryClient(); return useMutation({ mutationFn: (b: { matchKey: string; category: string; kind?: "income" | "expense" }) => apiSend("POST", "/transactions/categorize", b), onSuccess: () => { qc.invalidateQueries({ queryKey: ["transactions"] }); qc.invalidateQueries({ queryKey: ["analyze"] }); qc.invalidateQueries({ queryKey: keys.budget }); }, }); }; export const useRenameTxn = () => { const qc = useQueryClient(); return useMutation({ mutationFn: (b: { matchKey: string; name: string }) => apiSend("POST", "/transactions/rename", b), onSuccess: () => qc.invalidateQueries({ queryKey: ["transactions"] }), }); }; export const useSetNote = () => { const qc = useQueryClient(); return useMutation({ mutationFn: (b: { id: number; note: string }) => apiSend("PUT", `/transactions/${b.id}/note`, { note: b.note }), onSuccess: () => qc.invalidateQueries({ queryKey: ["transactions"] }), }); }; // --- budget --- export const usePutBudget = () => { const qc = useQueryClient(); return useMutation({ mutationFn: (b: { dayLimit: string; weekLimit: string; monthLimit: string; plannedIncomeManual: string; categories: { name: string; day: string; week: string; month: string }[]; }) => apiSend("PUT", "/budget", b, BudgetSchema), onSuccess: () => qc.invalidateQueries({ queryKey: keys.budget }), }); }; // --- settings --- export const useSaveSettings = () => { const qc = useQueryClient(); return useMutation({ mutationFn: (b: { holderName: string; employer: string; salaryKeywords: string[]; payDays: number[]; ownAccounts: string[]; peerAccounts: string[]; hideAmounts?: boolean; }) => apiSend("PUT", "/settings", b, SettingsSchema), onSuccess: () => qc.invalidateQueries({ queryKey: keys.settings }), }); }; // --- categories --- export const useCategoryMutations = () => { const qc = useQueryClient(); const invalidate = () => { qc.invalidateQueries({ queryKey: keys.categories }); qc.invalidateQueries({ queryKey: keys.budget }); qc.invalidateQueries({ queryKey: ["transactions"] }); }; const add = useMutation({ mutationFn: (b: { name: string; kind?: "income" | "expense"; parent?: string; icon?: string }) => apiSend("POST", "/categories", b), onSuccess: invalidate, }); const update = useMutation({ mutationFn: (b: { oldName: string; newName?: string; parent?: string | null; icon?: string | null }) => apiSend("PUT", "/categories", b), onSuccess: invalidate, }); const remove = useMutation({ mutationFn: (name: string) => apiSend("DELETE", `/categories?name=${encodeURIComponent(name)}`), onSuccess: invalidate, }); return { add, update, delete: remove }; }; // --- manual assets --- export const useManualAssetMutations = () => { const qc = useQueryClient(); const invalidate = () => { qc.invalidateQueries({ queryKey: keys.manualAssets }); qc.invalidateQueries({ queryKey: keys.networth }); }; const add = useMutation({ mutationFn: (b: { name: string; category?: string; value: string; acquiredValue?: string; currency?: string; condition?: string; isLiability?: boolean; }) => apiSend("POST", "/manual-assets", b), onSuccess: invalidate, }); const remove = useMutation({ mutationFn: (name: string) => apiSend("DELETE", `/manual-assets/${encodeURIComponent(name)}`), onSuccess: invalidate, }); const revalue = useMutation({ mutationFn: (name: string) => apiSend("POST", `/manual-assets/${encodeURIComponent(name)}/revalue`, undefined, RevalueResultSchema), onSuccess: invalidate, }); return { add, delete: remove, revalue }; }; // --- lending --- export const useLendingMutations = () => { const qc = useQueryClient(); const invalidate = () => qc.invalidateQueries({ queryKey: keys.lending }); const create = useMutation({ mutationFn: (b: { person: string; amount: string; lentOn: string; dueOn?: string; note?: string; txnId?: number }) => apiSend("POST", "/lending", b, LendingSchema), onSuccess: invalidate, }); const remove = useMutation({ mutationFn: (id: number) => apiSend("DELETE", `/lending/${id}`), onSuccess: invalidate, }); const addRepayment = useMutation({ mutationFn: (b: { id: number; amount: string; paidOn: string; note?: string; txnId?: number }) => apiSend("POST", `/lending/${b.id}/repayments`, { amount: b.amount, paidOn: b.paidOn, note: b.note, txnId: b.txnId }, LendingSchema), onSuccess: invalidate, }); const deleteRepayment = useMutation({ mutationFn: (b: { id: number; repaymentId: number }) => apiSend("DELETE", `/lending/${b.id}/repayments/${b.repaymentId}`), onSuccess: invalidate, }); return { create, delete: remove, addRepayment, deleteRepayment }; }; // --- subscriptions --- export const useSubscriptionMutations = () => { const qc = useQueryClient(); const invalidate = () => { qc.invalidateQueries({ queryKey: keys.subscriptions }); qc.invalidateQueries({ queryKey: keys.budget }); }; const setSubscription = useMutation({ mutationFn: (b: { matchKey: string; name?: string; active: boolean }) => apiSend("POST", "/subscriptions", b), onSuccess: invalidate, }); const createManualSub = useMutation({ mutationFn: (b: { name: string; amount: string; category?: string; nextDue?: string }) => apiSend("POST", "/manual-subscriptions", b, SubscriptionSchema), onSuccess: invalidate, }); const deleteManualSub = useMutation({ mutationFn: (id: number) => apiSend("DELETE", `/manual-subscriptions/${id}`), onSuccess: invalidate, }); return { setSubscription, createManualSub, deleteManualSub }; }; // --- savings goals --- export const useSavingsGoalMutations = () => { const qc = useQueryClient(); const invalidate = () => qc.invalidateQueries({ queryKey: keys.budget }); const post = useMutation({ mutationFn: (b: { originalName?: string; name: string; target: string; monthlyContribution?: string; accountId?: number; targetDate?: string; }) => apiSend("POST", "/savings-goals", b, BudgetSchema), onSuccess: invalidate, }); const remove = useMutation({ mutationFn: (name: string) => apiSend("DELETE", `/savings-goals/${encodeURIComponent(name)}`, undefined, BudgetSchema), onSuccess: invalidate, }); return { post, delete: remove }; };