update advance trsnaction table

This commit is contained in:
pramod.mahajan 2025-11-06 13:17:31 +05:30
parent e4585d6c43
commit 28f15f649f
7 changed files with 147 additions and 70 deletions

View File

@ -1,14 +1,24 @@
import React from "react"; import React, { useEffect, useMemo } from "react";
import { useExpenseTransactions } from "../../hooks/useExpense"; import {
useExpenseTransactions,
} from "../../hooks/useExpense";
import Error from "../common/Error"; import Error from "../common/Error";
import { formatUTCToLocalTime } from "../../utils/dateUtils"; import { formatUTCToLocalTime } from "../../utils/dateUtils";
import Loader, { SpinnerLoader } from "../common/Loader"; import Loader, { SpinnerLoader } from "../common/Loader";
import { useForm, useFormContext } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { employee } from "../../data/masters";
import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage";
import { formatFigure } from "../../utils/appUtils";
const AdvancePaymentList = ({ employeeId }) => { const AdvancePaymentList = ({ employeeId }) => {
const { setBalance} = useAdvancePaymentContext()
const { data, isError, isLoading, error, isFetching } = const { data, isError, isLoading, error, isFetching } =
useExpenseTransactions(employeeId, { enabled: !!employeeId }); useExpenseTransactions(employeeId, { enabled: !!employeeId });
console.log(data)
// Handle no employee selected
if (!employeeId) { if (!employeeId) {
return ( return (
<div <div
@ -45,6 +55,7 @@ const AdvancePaymentList = ({ employeeId }) => {
); );
} }
const records = Array.isArray(data) ? data : []; const records = Array.isArray(data) ? data : [];
let currentBalance = 0; let currentBalance = 0;
@ -53,7 +64,7 @@ const AdvancePaymentList = ({ employeeId }) => {
const credit = isCredit ? r.amount : 0; const credit = isCredit ? r.amount : 0;
const debit = !isCredit ? Math.abs(r.amount) : 0; const debit = !isCredit ? Math.abs(r.amount) : 0;
currentBalance += credit - debit; currentBalance += credit - debit;
setBalance(currentBalance);
return { return {
id: r.id, id: r.id,
description: r.title || "-", description: r.title || "-",
@ -61,12 +72,23 @@ const AdvancePaymentList = ({ employeeId }) => {
createdAt: r.createdAt, createdAt: r.createdAt,
credit, credit,
debit, debit,
financeUId:r.financeUId,
balance: currentBalance, balance: currentBalance,
}; };
}); });
const columns = [ const columns = [
{
key: "date",
label: (
<>
Date <i className="bx bx-rupee text-danger"></i>
</>
),
align: "text-start",
},
{ key: "description", label: "Description", align: "text-start" }, { key: "description", label: "Description", align: "text-start" },
{ {
key: "credit", key: "credit",
label: ( label: (
@ -85,6 +107,7 @@ const AdvancePaymentList = ({ employeeId }) => {
), ),
align: "text-end", align: "text-end",
}, },
{ {
key: "balance", key: "balance",
label: ( label: (
@ -104,7 +127,18 @@ const AdvancePaymentList = ({ employeeId }) => {
</div> </div>
); );
} }
console.log("Kartik", rowsWithBalance) const DecideCreditOrDebit = ({ financeUId }) => {
if (!financeUId) return null;
const prefix = financeUId?.substring(0, 2).toUpperCase();
if (prefix === "PR") return <span className="text-success">+</span>;
if (prefix === "EX") return <span className="text-danger">-</span>;
return null;
};
return ( return (
<div className="table-responsive"> <div className="table-responsive">
<table className="table align-middle"> <table className="table align-middle">
@ -131,17 +165,22 @@ const AdvancePaymentList = ({ employeeId }) => {
) )
) : col.key === "debit" ? ( ) : col.key === "debit" ? (
row.amount < 0 ? ( row.amount < 0 ? (
<span>{Math.abs(row.amount).toLocaleString("en-IN")}</span> <span>
{Math.abs(row.amount).toLocaleString("en-IN")}
</span>
) : ( ) : (
"-" "-"
) )
) : col.key === "balance" ? ( ) : col.key === "balance" ? (
<span>{row.currentBalance?.toLocaleString("en-IN")}</span> <div className="d-flex align-items-center justify-content-end">
<DecideCreditOrDebit financeUId={row?.financeUId}/><span className="mx-2">{formatFigure(row.currentBalance)}</span>
</div>
) : col.key === "date" ? (
<small className="text-muted px-1">
{formatUTCToLocalTime(row.paidAt)}
</small>
) : ( ) : (
<div className="d-flex flex-column text-start"> <div className="d-flex flex-column text-start gap-1 py-1">
<small className="text-muted">
{formatUTCToLocalTime(row.paidAt)}
</small>
<small className="fw-semibold text-dark"> <small className="fw-semibold text-dark">
{row.project?.name || "-"} {row.project?.name || "-"}
</small> </small>
@ -154,21 +193,31 @@ const AdvancePaymentList = ({ employeeId }) => {
)) ))
) : ( ) : (
<tr> <tr>
<td colSpan={columns.length} className="text-center text-muted py-3"> <td
colSpan={columns.length}
className="text-center text-muted py-3"
>
No advance payment records found. No advance payment records found.
</td> </td>
</tr> </tr>
)} )}
</tbody> </tbody>
<tfoot className="table-secondary fw-bold"> <tfoot className=" fw-bold">
<tr> <tr className="tr-group text-dark py-2">
<td className="text-start p-3">Final Balance</td> <td className="text-start">
<td className="text-end" colSpan="3"> {" "}
{currentBalance.toLocaleString("en-IN", { <div className="d-flex align-items-center px-1 py-2">
style: "currency", Final Balance
currency: "INR", </div>
})} </td>
<td className="text-end" colSpan="4">
<div className="d-flex align-items-center justify-content-end px-1 py-2">
{currentBalance.toLocaleString("en-IN", {
style: "currency",
currency: "INR",
})}
</div>
</td> </td>
</tr> </tr>
</tfoot> </tfoot>

View File

@ -267,7 +267,7 @@ const ExpenseList = ({ filters, groupBy = "transactionDate", searchText }) => {
Object.values(grouped).map(({ key, displayField, items }) => ( Object.values(grouped).map(({ key, displayField, items }) => (
<React.Fragment key={key}> <React.Fragment key={key}>
<tr className="tr-group text-dark"> <tr className="tr-group text-dark">
<td colSpan={8} className="text-start "> <td colSpan={8} className="text-start">
<div className="d-flex align-items-center px-2"> <div className="d-flex align-items-center px-2">
{" "} {" "}
<small className="fs-6 py-1"> <small className="fs-6 py-1">

View File

@ -403,26 +403,6 @@ function ManageRecurringExpense({ closeModal, requestToEdit = null }) {
</div> </div>
</div> </div>
{/* Notify */}
{/* <div className="row my-2 text-start">
<div className="col-md-6">
<Label htmlFor="notifyTo" className="form-label" required>
Notify Employees
</Label>
<input
type="text"
id="notifyTo"
className="form-control form-control-sm"
{...register("notifyTo")}
/>
{errors.notifyTo && (
<small className="danger-text">
{errors.notifyTo.message}
</small>
)}
</div>
</div> */}
<div className="row my-2 text-start"> <div className="row my-2 text-start">
<div className="col-md-6"> <div className="col-md-6">

View File

@ -32,6 +32,7 @@ const EmployeeSearchInput = ({
const found = employees.data.find((emp) => emp.id === value); const found = employees.data.find((emp) => emp.id === value);
if (found && forAll) { if (found && forAll) {
setSearch(`${found.firstName} ${found.lastName}`); setSearch(`${found.firstName} ${found.lastName}`);
sessionStorage.setItem("transaction-empId",found?.id)
} }
} }
}, [value, employees?.data, forAll]); }, [value, employees?.data, forAll]);

View File

@ -53,7 +53,7 @@ const MultiEmployeeSearchInput = ({
}, [value, employees?.data, forAll]); }, [value, employees?.data, forAll]);
const handleSelect = (employee) => { const handleSelect = (employee) => {
if (!selectedEmployees.find((emp) => emp.email === employee.email)) { if (!selectedEmployees.find((emp) => emp.id === employee.id)) {
const newSelected = [...selectedEmployees, employee]; const newSelected = [...selectedEmployees, employee];
setSelectedEmployees(newSelected); setSelectedEmployees(newSelected);
// Store emails instead of IDs // Store emails instead of IDs
@ -150,11 +150,11 @@ const MultiEmployeeSearchInput = ({
) : ( ) : (
employees?.data employees?.data
?.filter( ?.filter(
(emp) => !selectedEmployees.find((e) => e.email === emp.email) (emp) => !selectedEmployees.find((e) => e.id === emp.id)
) )
.map((emp) => ( .map((emp) => (
<li <li
key={emp.email} key={emp.id}
className="list-group-item list-group-item-action py-1 px-2" className="list-group-item list-group-item-action py-1 px-2"
style={{ cursor: "pointer" }} style={{ cursor: "pointer" }}
onClick={() => handleSelect(emp)} onClick={() => handleSelect(emp)}

View File

@ -434,7 +434,8 @@ export const useExpenseTransactions = (employeeId)=>{
const resp = await ExpenseRepository.GetTranctionList(employeeId); const resp = await ExpenseRepository.GetTranctionList(employeeId);
return resp.data return resp.data
}, },
enabled:!!employeeId enabled:!!employeeId,
keepPreviousData:true,
}) })
} }
//#endregion //#endregion

View File

@ -1,45 +1,91 @@
import React from "react"; import React, {
createContext,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import Breadcrumb from "../../components/common/Breadcrumb"; import Breadcrumb from "../../components/common/Breadcrumb";
import { useEmployee } from "../../hooks/useEmployees"; import { useEmployee } from "../../hooks/useEmployees";
import EmployeeSearchInput from "../../components/common/EmployeeSearchInput"; import EmployeeSearchInput from "../../components/common/EmployeeSearchInput";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import Label from "../../components/common/Label"; import Label from "../../components/common/Label";
import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList"; import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList";
import { employee } from "../../data/masters";
import { formatFigure } from "../../utils/appUtils";
export const AdvancePaymentContext = createContext();
export const useAdvancePaymentContext = () => {
const context = useContext(AdvancePaymentContext);
if (!context) {
throw new Error(
"useAdvancePaymentContext must be used within an AdvancePaymentProvider"
);
}
return context;
};
const AdvancePaymentPage = () => { const AdvancePaymentPage = () => {
const { control, watch } = useForm({ const [balance, setBalance] = useState(null);
const { control, reset, watch } = useForm({
defaultValues: { defaultValues: {
employeeId: "", employeeId: "",
}, },
}); });
const selectedEmployeeId = watch("employeeId"); const selectedEmployeeId = watch("employeeId");
useEffect(() => {
const selectedEmpoyee = sessionStorage.getItem("transaction-empId");
reset({
employeeId: selectedEmpoyee || "",
});
}, [reset]);
return ( return (
<div className="container-fluid"> <AdvancePaymentContext.Provider value={{ setBalance }}>
<Breadcrumb <div className="container-fluid">
data={[ <Breadcrumb
{ label: "Home", link: "/" }, data={[
{ label: "Finance", link: "/advance-payment" }, { label: "Home", link: "/" },
{ label: "Advance Payment" }, { label: "Finance", link: "/advance-payment" },
]} { label: "Advance Payment" },
/> ]}
<div className="card px-4 py-2 page-min-h "> />
<div className="row"> <div className="card px-4 py-2 page-min-h ">
<div className="col-12 col-md-4"> <div className="row py-1">
<div className="d-block text-start" > <div className="col-12 col-md-4">
<EmployeeSearchInput <div className="d-block text-start">
control={control} <EmployeeSearchInput
name="employeeId" control={control}
projectId={null} name="employeeId"
forAll={true} projectId={null}
placeholder={"Enter Employee Name"} forAll={true}
/> placeholder={"Enter Employee Name"}
</div> />
</div>
</div>
<div className="col-md-8 d-flex align-items-center justify-content-end">
{balance ? (
<>
<label className="fs-5 fw-semibold">Total Balance : </label>
<span
className={`${
balance > 0 ? "text-success" : "text-danger"
} fs-5 fw-bold ms-1`}
>
{formatFigure(balance, {
type: "currency",
currency: "INR",
})}
</span>
</>
) : (
<></>
)}
</div>
</div> </div>
<AdvancePaymentList employeeId={selectedEmployeeId} />
</div> </div>
<AdvancePaymentList employeeId={selectedEmployeeId}/>
</div> </div>
</div> </AdvancePaymentContext.Provider>
); );
}; };