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:
120
apps/frontend/src/features/expenses/ExpensesProvider.tsx
Normal file
120
apps/frontend/src/features/expenses/ExpensesProvider.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
import { createContext, useContext, useState, useCallback, type ReactNode } from "react";
|
||||
import {
|
||||
usePeriodicExpenses,
|
||||
useCreatePeriodicExpense,
|
||||
useUpdatePeriodicExpense,
|
||||
useDeletePeriodicExpense,
|
||||
useGenerateMonthlyExpense,
|
||||
useExpenses,
|
||||
useCreateNonPeriodicExpense,
|
||||
usePayExpense,
|
||||
} from "@/lib/queries";
|
||||
import type {
|
||||
PeriodicExpense,
|
||||
Expense,
|
||||
CreatePeriodicExpenseInput,
|
||||
CreateNonPeriodicExpenseInput,
|
||||
PayExpenseInput,
|
||||
} from "@/lib/api";
|
||||
|
||||
interface ExpensesContextValue {
|
||||
periodicExpenses: PeriodicExpense[];
|
||||
isLoadingPeriodic: boolean;
|
||||
|
||||
expenses: Expense[];
|
||||
isLoadingExpenses: boolean;
|
||||
statusFilter: string;
|
||||
setStatusFilter: (status: string) => void;
|
||||
|
||||
createPeriodicExpense: (data: CreatePeriodicExpenseInput) => Promise<PeriodicExpense>;
|
||||
updatePeriodicExpense: (id: number, data: CreatePeriodicExpenseInput) => Promise<void>;
|
||||
deletePeriodicExpense: (id: number) => Promise<void>;
|
||||
generateMonthlyExpense: (id: number) => Promise<Expense>;
|
||||
createNonPeriodicExpense: (data: CreateNonPeriodicExpenseInput) => Promise<void>;
|
||||
payExpense: (id: number, data: PayExpenseInput) => Promise<void>;
|
||||
}
|
||||
|
||||
const ExpensesContext = createContext<ExpensesContextValue | null>(null);
|
||||
|
||||
export function ExpensesProvider({ children }: { children: ReactNode }) {
|
||||
const [statusFilter, setStatusFilter] = useState("PENDING");
|
||||
|
||||
const { data: periodicExpenses = [], isLoading: isLoadingPeriodic } = usePeriodicExpenses();
|
||||
const { data: expenses = [], isLoading: isLoadingExpenses } = useExpenses(statusFilter);
|
||||
|
||||
const createPeriodicMutation = useCreatePeriodicExpense();
|
||||
const updatePeriodicMutation = useUpdatePeriodicExpense();
|
||||
const deletePeriodicMutation = useDeletePeriodicExpense();
|
||||
const generateMonthlyMutation = useGenerateMonthlyExpense();
|
||||
const createExpenseMutation = useCreateNonPeriodicExpense();
|
||||
const payExpenseMutation = usePayExpense();
|
||||
|
||||
const createPeriodicExpense = useCallback(
|
||||
async (data: CreatePeriodicExpenseInput): Promise<PeriodicExpense> => {
|
||||
return createPeriodicMutation.mutateAsync(data);
|
||||
},
|
||||
[createPeriodicMutation],
|
||||
);
|
||||
|
||||
const updatePeriodicExpenseFn = useCallback(
|
||||
async (id: number, data: CreatePeriodicExpenseInput) => {
|
||||
await updatePeriodicMutation.mutateAsync({ id, data });
|
||||
},
|
||||
[updatePeriodicMutation],
|
||||
);
|
||||
|
||||
const deletePeriodicExpenseFn = useCallback(
|
||||
async (id: number) => {
|
||||
await deletePeriodicMutation.mutateAsync(id);
|
||||
},
|
||||
[deletePeriodicMutation],
|
||||
);
|
||||
|
||||
const generateMonthlyExpenseFn = useCallback(
|
||||
async (id: number): Promise<Expense> => {
|
||||
return generateMonthlyMutation.mutateAsync(id);
|
||||
},
|
||||
[generateMonthlyMutation],
|
||||
);
|
||||
|
||||
const createNonPeriodicExpenseFn = useCallback(
|
||||
async (data: CreateNonPeriodicExpenseInput) => {
|
||||
await createExpenseMutation.mutateAsync(data);
|
||||
},
|
||||
[createExpenseMutation],
|
||||
);
|
||||
|
||||
const payExpenseFn = useCallback(
|
||||
async (id: number, data: PayExpenseInput) => {
|
||||
await payExpenseMutation.mutateAsync({ id, data });
|
||||
},
|
||||
[payExpenseMutation],
|
||||
);
|
||||
|
||||
return (
|
||||
<ExpensesContext
|
||||
value={{
|
||||
periodicExpenses,
|
||||
isLoadingPeriodic,
|
||||
expenses,
|
||||
isLoadingExpenses,
|
||||
statusFilter,
|
||||
setStatusFilter,
|
||||
createPeriodicExpense,
|
||||
updatePeriodicExpense: updatePeriodicExpenseFn,
|
||||
deletePeriodicExpense: deletePeriodicExpenseFn,
|
||||
generateMonthlyExpense: generateMonthlyExpenseFn,
|
||||
createNonPeriodicExpense: createNonPeriodicExpenseFn,
|
||||
payExpense: payExpenseFn,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</ExpensesContext>
|
||||
);
|
||||
}
|
||||
|
||||
export function useExpensesContext() {
|
||||
const ctx = useContext(ExpensesContext);
|
||||
if (!ctx) throw new Error("useExpensesContext must be used within ExpensesProvider");
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user