feat(expenses): implement responsive dialog for expense management and create expense provider

- Added ResponsiveDialog component for handling responsive dialogs in the UI.
- Created ExpensesProvider to manage state and API interactions for expenses.
- Developed ExpensesTabContent to display expenses with filtering options and dialogs for new and pay expense actions.
- Implemented ExpensesTable for rendering expense data in a tabular format with actions.
- Added dialogs for creating new expenses and paying existing ones with form validation.
- Introduced PeriodicExpenseForm for managing periodic expenses with month selection.
- Created PeriodicExpensesTabContent to manage and display periodic expenses with create/edit functionality.
- Added GenerateCurrentMonthDialog for confirming monthly expense generation.
- Implemented PeriodicExpensesTable for displaying periodic expenses with edit and delete actions.
This commit is contained in:
Jose Selesan
2026-05-29 10:29:20 -03:00
parent bd5e29236b
commit e1786f7384
39 changed files with 4338 additions and 6435 deletions

View File

@@ -1,5 +1,14 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { getQuotes, fetchQuotes, getQuoteHistory, getDailyMinMax, getDailyQuotes } from "./api";
import {
getQuotes, fetchQuotes, getQuoteHistory, getDailyMinMax, getDailyQuotes,
getPeriodicExpenses, createPeriodicExpense as createPeriodicExpenseApi,
updatePeriodicExpense as updatePeriodicExpenseApi,
deletePeriodicExpense as deletePeriodicExpenseApi,
generateMonthlyExpense as generateMonthlyExpenseApi,
getExpenses, createNonPeriodicExpense as createNonPeriodicExpenseApi,
payExpense as payExpenseApi,
type CreatePeriodicExpenseInput, type CreateNonPeriodicExpenseInput, type PayExpenseInput,
} from "./api";
export const quoteKeys = {
all: ["quotes"] as const,
@@ -57,3 +66,87 @@ export function useDailyQuotes(type: string, startDate: string, endDate: string)
refetchInterval: 60_000,
});
}
// Expenses
export const expenseKeys = {
periodic: ["periodic-expenses"] as const,
all: ["expenses"] as const,
byStatus: (status: string) => ["expenses", status] as const,
};
export function usePeriodicExpenses() {
return useQuery({
queryKey: expenseKeys.periodic,
queryFn: getPeriodicExpenses,
});
}
export function useCreatePeriodicExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreatePeriodicExpenseInput) => createPeriodicExpenseApi(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
},
});
}
export function useUpdatePeriodicExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: CreatePeriodicExpenseInput }) =>
updatePeriodicExpenseApi(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
},
});
}
export function useDeletePeriodicExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => deletePeriodicExpenseApi(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.periodic });
},
});
}
export function useGenerateMonthlyExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: number) => generateMonthlyExpenseApi(id),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.all });
},
});
}
export function useExpenses(status: string) {
return useQuery({
queryKey: expenseKeys.byStatus(status),
queryFn: () => getExpenses(status === "all" ? undefined : status),
});
}
export function useCreateNonPeriodicExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (data: CreateNonPeriodicExpenseInput) => createNonPeriodicExpenseApi(data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.all });
},
});
}
export function usePayExpense() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ id, data }: { id: number; data: PayExpenseInput }) =>
payExpenseApi(id, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: expenseKeys.all });
},
});
}