From ce66c137aaa5add94749ac5c52d7dd34c2c574c7 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 21 Jul 2025 19:45:54 +0530 Subject: [PATCH] created and display expenses list --- src/components/Expenses/CreateExpense.jsx | 424 +++++++++++++++------- src/components/Expenses/ExpenseList.jsx | 334 ++++++++++++----- src/components/Expenses/ExpenseSchema.js | 119 +++--- src/components/Expenses/ViewExpense.jsx | 14 + src/hooks/masterHook/useMaster.js | 70 ++++ src/hooks/useExpense.js | 48 ++- src/pages/Expense/ExpensePage.jsx | 111 ++++-- src/repositories/ExpsenseRepository.jsx | 13 +- src/utils/dateUtils.jsx | 2 +- 9 files changed, 812 insertions(+), 323 deletions(-) create mode 100644 src/components/Expenses/ViewExpense.jsx diff --git a/src/components/Expenses/CreateExpense.jsx b/src/components/Expenses/CreateExpense.jsx index 2cd2d7c1..0ed1b119 100644 --- a/src/components/Expenses/CreateExpense.jsx +++ b/src/components/Expenses/CreateExpense.jsx @@ -1,18 +1,41 @@ import { zodResolver } from "@hookform/resolvers/zod"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { ExpenseSchema } from "./ExpenseSchema"; import { formatFileSize } from "../../utils/appUtils"; +import { useProjectName } from "../../hooks/useProjects"; +import { useDispatch, useSelector } from "react-redux"; +import { changeMaster } from "../../slices/localVariablesSlice"; +import useMaster, { + useExpenseStatus, + useExpenseType, + usePaymentMode, +} from "../../hooks/masterHook/useMaster"; +import { + useEmployeesAllOrByProjectId, + useEmployeesByProject, +} from "../../hooks/useEmployees"; +import Avatar from "../common/Avatar"; +import { useCreateExpnse } from "../../hooks/useExpense"; -const CreateExpense = () => { +const CreateExpense = ({closeModal}) => { + const [ExpenseType, setExpenseType] = useState(); + const dispatch = useDispatch(); + const { + ExpenseTypes, + loading: ExpenseLoading, + error: ExpenseError, + } = useExpenseType(); + const schema = ExpenseSchema(ExpenseTypes); const { register, handleSubmit, watch, setValue, + reset, formState: { errors }, } = useForm({ - resolver: zodResolver(ExpenseSchema), + resolver: zodResolver(schema), defaultValues: { projectId: "", expensesTypeId: "", @@ -25,45 +48,68 @@ const CreateExpense = () => { supplerName: "", amount: "", noOfPersons: "", - statusId: "", billAttachments: [], }, }); - const files = watch("billAttachments"); -const onFileChange = async (e) => { - const newFiles = Array.from(e.target.files); - if (newFiles.length === 0) return; - - const existingFiles = watch("billAttachments") || []; - - const parsedFiles = await Promise.all( - newFiles.map(async (file) => { - const base64Data = await toBase64(file); - return { - fileName: file.name, - base64Data, - contentType: file.type, - fileSize: file.size, - description: "", - }; - }) + const selectedproject = watch("projectId"); + const selectedProject = useSelector( + (store) => store.localVariables.projectId ); + const { projectNames, loading: projectLoading, error } = useProjectName(); - // Avoid duplicates based on file name + size - const combinedFiles = [ - ...existingFiles, - ...parsedFiles.filter( - (newFile) => - !existingFiles.some( - (f) => f.fileName === newFile.fileName && f.fileSize === newFile.fileSize - ) - ), - ]; + const { + PaymentModes, + loading: PaymentModeLoading, + error: PaymentModeError, + } = usePaymentMode(); + const { + ExpenseStatus, + loading: StatusLoadding, + error: stausError, + } = useExpenseStatus(); + const { + employees, + loading: EmpLoading, + error: EmpError, + } = useEmployeesByProject(selectedproject); - setValue("billAttachments", combinedFiles, { shouldDirty: true, shouldValidate: true }); -}; + const files = watch("billAttachments"); + const onFileChange = async (e) => { + const newFiles = Array.from(e.target.files); + if (newFiles.length === 0) return; + const existingFiles = watch("billAttachments") || []; + + const parsedFiles = await Promise.all( + newFiles.map(async (file) => { + const base64Data = await toBase64(file); + return { + fileName: file.name, + base64Data, + contentType: file.type, + fileSize: file.size, + description: "", + }; + }) + ); + + const combinedFiles = [ + ...existingFiles, + ...parsedFiles.filter( + (newFile) => + !existingFiles.some( + (f) => + f.fileName === newFile.fileName && f.fileSize === newFile.fileSize + ) + ), + ]; + + setValue("billAttachments", combinedFiles, { + shouldDirty: true, + shouldValidate: true, + }); + }; const toBase64 = (file) => new Promise((resolve, reject) => { @@ -72,86 +118,162 @@ const onFileChange = async (e) => { reader.onload = () => resolve(reader.result.split(",")[1]); // base64 only, no prefix reader.onerror = (error) => reject(error); }); -const removeFile = (index) => { - const newFiles = files.filter((_, i) => i !== index); - setValue("billAttachments", newFiles, { shouldValidate: true }); -}; - const onSubmit = (data) => { - console.log("Form Data:", data); + const removeFile = (index) => { + const newFiles = files.filter((_, i) => i !== index); + setValue("billAttachments", newFiles, { shouldValidate: true }); }; + + const {mutate:CreateExpense,isPending} = useCreateExpnse(()=>{ + handleClose() + }) + const onSubmit = (payload) => { + console.log("Form Data:", payload); + + CreateExpense(payload) + }; + const ExpenseTypeId = watch("expensesTypeId"); + + useEffect(() => { + setExpenseType(ExpenseTypes?.find((type) => type.id === ExpenseTypeId)); + }, [ExpenseTypeId]); + + const handleClose =()=>{ + reset() + closeModal() + } return ( -
-

Create New Expense

+
+
Create New Expense
-
-
-