Merge pull request 'Advance_Payment_List :- Implementing advance Payment new API.' (#514) from Advance_Payment_List into Project_Branch_Management
Reviewed-on: #514 merged
This commit is contained in:
commit
bd43475d12
@ -1,6 +1,6 @@
|
||||
|
||||
import React, { useEffect, useMemo } from "react";
|
||||
import { useExpenseTransactions } from "../../hooks/useExpense";
|
||||
import { useExpenseAllTransactionsList, useExpenseTransactions } from "../../hooks/useExpense";
|
||||
import Error from "../common/Error";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import Loader, { SpinnerLoader } from "../common/Loader";
|
||||
@ -11,11 +11,10 @@ import { employee } from "../../data/masters";
|
||||
import { useAdvancePaymentContext } from "../../pages/AdvancePayment/AdvancePaymentPage";
|
||||
import { formatFigure } from "../../utils/appUtils";
|
||||
|
||||
const AdvancePaymentList = ({ employeeId }) => {
|
||||
const { setBalance } = useAdvancePaymentContext();
|
||||
const AdvancePaymentList = ({ employeeId, searchString }) => {
|
||||
const { setBalance } = useAdvancePaymentContext();
|
||||
const { data, isError, isLoading, error, isFetching } =
|
||||
useExpenseTransactions(employeeId, { enabled: !!employeeId });
|
||||
|
||||
const records = Array.isArray(data) ? data : [];
|
||||
|
||||
let currentBalance = 0;
|
||||
@ -85,7 +84,7 @@ const AdvancePaymentList = ({ employeeId }) => {
|
||||
key: "date",
|
||||
label: (
|
||||
<>
|
||||
Date
|
||||
Date
|
||||
</>
|
||||
),
|
||||
align: "text-start",
|
||||
|
||||
100
src/components/AdvancePayment/AdvancePaymentList1.jsx
Normal file
100
src/components/AdvancePayment/AdvancePaymentList1.jsx
Normal file
@ -0,0 +1,100 @@
|
||||
import React from 'react'
|
||||
import Avatar from "../../components/common/Avatar"; // <-- ADD THIS
|
||||
import { useExpenseAllTransactionsList } from '../../hooks/useExpense';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { formatFigure } from '../../utils/appUtils';
|
||||
|
||||
const AdvancePaymentList1 = ({ searchString }) => {
|
||||
|
||||
const { data, isError, isLoading, error } =
|
||||
useExpenseAllTransactionsList(searchString);
|
||||
|
||||
const rows = data || [];
|
||||
const navigate = useNavigate();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
key: "employee",
|
||||
label: "Employee Name",
|
||||
align: "text-start",
|
||||
customRender: (r) => (
|
||||
<div className="d-flex align-items-center gap-2" onClick={() => navigate(`/advance-payment/${r.id}`)}
|
||||
style={{ cursor: "pointer" }}>
|
||||
<Avatar firstName={r.firstName} lastName={r.lastName} />
|
||||
|
||||
<span className="fw-medium">
|
||||
{r.firstName} {r.lastName}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "jobRoleName",
|
||||
label: "Job Role",
|
||||
align: "text-start",
|
||||
customRender: (r) => (
|
||||
<span className="fw-semibold">
|
||||
{r.jobRoleName}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "balanceAmount",
|
||||
label: "Balance (₹)",
|
||||
align: "text-end",
|
||||
customRender: (r) => (
|
||||
<span className="fw-semibold fs-6">
|
||||
{formatFigure(r.balanceAmount, {
|
||||
// type: "currency",
|
||||
currency: "INR",
|
||||
})}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
if (isLoading) return <p className="text-center py-4">Loading...</p>;
|
||||
if (isError) return <p className="text-center py-4 text-danger">{error.message}</p>;
|
||||
|
||||
return (
|
||||
<div className="card-datatable" id="payment-request-table">
|
||||
<div className="mx-2">
|
||||
<table className="table border-top dataTable text-nowrap align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
{columns.map((col) => (
|
||||
<th key={col.key} className={`sorting ${col.align}`}>
|
||||
{col.label}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{rows.length > 0 ? (
|
||||
rows.map((row) => (
|
||||
<tr key={row.id} className="align-middle" style={{ height: "40px" }}>
|
||||
{columns.map((col) => (
|
||||
<td key={col.key} className={`d-table-cell ${col.align} py-3`}>
|
||||
{col.customRender
|
||||
? col.customRender(row)
|
||||
: col.getValue(row)}
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan={columns.length} className="text-center border-0 py-3">
|
||||
No Employees Found
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdvancePaymentList1;
|
||||
@ -50,8 +50,11 @@ const Header = () => {
|
||||
const isRecurringExpense = /^\/recurring-payment$/.test(pathname);
|
||||
const isAdvancePayment = /^\/advance-payment$/.test(pathname);
|
||||
const isServiceProjectPage = /^\/service-projects\/[0-9a-fA-F-]{36}$/.test(pathname);
|
||||
const isAdvancePayment1 =
|
||||
/^\/advance-payment(\/[0-9a-fA-F-]{36})?$/.test(pathname);
|
||||
|
||||
return !(isDirectoryPath || isProfilePage || isExpensePage || isPaymentRequest || isRecurringExpense || isAdvancePayment ||isServiceProjectPage);
|
||||
|
||||
return !(isDirectoryPath || isProfilePage || isExpensePage || isPaymentRequest || isRecurringExpense || isAdvancePayment ||isServiceProjectPage || isAdvancePayment1);
|
||||
};
|
||||
const allowedProjectStatusIds = [
|
||||
"603e994b-a27f-4e5d-a251-f3d69b0498ba",
|
||||
|
||||
@ -166,7 +166,7 @@ const RecurringExpenseList = ({ search, filterStatuses }) => {
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
console.log("Tanish",filteredData)
|
||||
return (
|
||||
<>
|
||||
{IsDeleteModalOpen && (
|
||||
|
||||
@ -27,7 +27,7 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
|
||||
const selectedProject = useSelectedProject();
|
||||
const searchDebounce = useDebounce(searchString, 500);
|
||||
|
||||
|
||||
const { data, isLoading, isError, error } = useCollections(
|
||||
selectedProject,
|
||||
searchDebounce,
|
||||
@ -40,7 +40,6 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
);
|
||||
const { setProcessedPayment, setAddPayment, setViewCollection } =
|
||||
useCollectionContext();
|
||||
|
||||
const paginate = (page) => {
|
||||
if (page >= 1 && page <= (data?.totalPages ?? 1)) {
|
||||
setCurrentPage(page);
|
||||
@ -113,6 +112,16 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
),
|
||||
align: "text-center",
|
||||
},
|
||||
{
|
||||
key: "status",
|
||||
label: "Status",
|
||||
getValue: (col) => (
|
||||
<span className={`badge bg-label-${col?.isActive ? "primary" : "danger"}`}>
|
||||
{col?.isActive ? "Active" : "Inactive"}
|
||||
</span>
|
||||
),
|
||||
align: "text-center",
|
||||
},
|
||||
{
|
||||
key: "amount",
|
||||
label: "Total Amount",
|
||||
@ -129,6 +138,7 @@ const CollectionList = ({ fromDate, toDate, isPending, searchString }) => {
|
||||
),
|
||||
align: "text-end",
|
||||
},
|
||||
|
||||
{
|
||||
key: "balance",
|
||||
label: "Balance",
|
||||
|
||||
@ -25,7 +25,6 @@ const ViewCollection = ({ onClose }) => {
|
||||
|
||||
if (isLoading) return <CollectionDetailsSkeleton />;
|
||||
if (isError) return <div>{error.message}</div>;
|
||||
|
||||
return (
|
||||
<div className="container p-3">
|
||||
<p className="fs-5 fw-semibold">Collection Details</p>
|
||||
@ -43,9 +42,8 @@ const ViewCollection = ({ onClose }) => {
|
||||
<div>
|
||||
{" "}
|
||||
<span
|
||||
className={`badge bg-label-${
|
||||
data?.isActive ? "primary" : "danger"
|
||||
}`}
|
||||
className={`badge bg-label-${data?.isActive ? "primary" : "danger"
|
||||
}`}
|
||||
>
|
||||
{data?.isActive ? "Active" : "Inactive"}
|
||||
</span>
|
||||
@ -214,9 +212,8 @@ const ViewCollection = ({ onClose }) => {
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
activeTab === "payments" ? "active" : ""
|
||||
}`}
|
||||
className={`nav-link ${activeTab === "payments" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setActiveTab("payments")}
|
||||
type="button"
|
||||
>
|
||||
@ -225,9 +222,8 @@ const ViewCollection = ({ onClose }) => {
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<button
|
||||
className={`nav-link ${
|
||||
activeTab === "details" ? "active" : ""
|
||||
}`}
|
||||
className={`nav-link ${activeTab === "details" ? "active" : ""
|
||||
}`}
|
||||
onClick={() => setActiveTab("details")}
|
||||
type="button"
|
||||
>
|
||||
|
||||
@ -438,6 +438,15 @@ export const useExpenseTransactions = (employeeId)=>{
|
||||
keepPreviousData:true,
|
||||
})
|
||||
}
|
||||
export const useExpenseAllTransactionsList = (searchString) => {
|
||||
return useQuery({
|
||||
queryKey: ["transaction", searchString],
|
||||
queryFn: async () => {
|
||||
const resp = await ExpenseRepository.getAllTranctionList(searchString);
|
||||
return resp.data;
|
||||
},
|
||||
});
|
||||
};
|
||||
//#endregion
|
||||
|
||||
// ---------------------------Put Post Recurring Expense---------------------------------------
|
||||
|
||||
@ -13,6 +13,8 @@ import Label from "../../components/common/Label";
|
||||
import AdvancePaymentList from "../../components/AdvancePayment/AdvancePaymentList";
|
||||
import { employee } from "../../data/masters";
|
||||
import { formatFigure } from "../../utils/appUtils";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { useExpenseTransactions } from "../../hooks/useExpense";
|
||||
|
||||
export const AdvancePaymentContext = createContext();
|
||||
export const useAdvancePaymentContext = () => {
|
||||
@ -25,14 +27,32 @@ export const useAdvancePaymentContext = () => {
|
||||
return context;
|
||||
};
|
||||
const AdvancePaymentPage = () => {
|
||||
const { employeeId } = useParams();
|
||||
|
||||
const { data: transactionData } = useExpenseTransactions(employeeId, {
|
||||
enabled: !!employeeId
|
||||
});
|
||||
|
||||
const employeeName = useMemo(() => {
|
||||
if (Array.isArray(transactionData) && transactionData.length > 0) {
|
||||
const emp = transactionData[0].employee;
|
||||
if (emp) return `${emp.firstName} ${emp.lastName}`;
|
||||
}
|
||||
return "";
|
||||
}, [transactionData]);
|
||||
|
||||
const [balance, setBalance] = useState(null);
|
||||
const { control, reset, watch } = useForm({
|
||||
defaultValues: {
|
||||
employeeId: "",
|
||||
employeeId: employeeId || "",
|
||||
searchString: "",
|
||||
},
|
||||
});
|
||||
|
||||
const selectedEmployeeId = watch("employeeId");
|
||||
const selectedEmployeeId = employeeId || watch("employeeId");
|
||||
|
||||
const searchString = watch("searchString");
|
||||
|
||||
useEffect(() => {
|
||||
const selectedEmpoyee = sessionStorage.getItem("transaction-empId");
|
||||
reset({
|
||||
@ -47,30 +67,20 @@ const AdvancePaymentPage = () => {
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Finance", link: "/advance-payment" },
|
||||
{ label: "Advance Payment" },
|
||||
]}
|
||||
{ label: "Advance Payment", link: "/advance-payment" },
|
||||
employeeName && { label: employeeName, link: "" },
|
||||
].filter(Boolean)}
|
||||
/>
|
||||
|
||||
<div className="card px-4 py-2 page-min-h ">
|
||||
<div className="row py-1">
|
||||
<div className="col-12 col-md-4">
|
||||
<div className="d-block text-start">
|
||||
<EmployeeSearchInput
|
||||
control={control}
|
||||
name="employeeId"
|
||||
projectId={null}
|
||||
forAll={true}
|
||||
placeholder={"Enter Employee Name"}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row py-1 justify-content-end">
|
||||
<div className="col-md-8 d-flex align-items-center justify-content-end">
|
||||
{balance ? (
|
||||
<>
|
||||
<label className="fs-5 fw-semibold">Current Balance : </label>
|
||||
<span
|
||||
className={`${
|
||||
balance > 0 ? "text-success" : "text-danger"
|
||||
} fs-5 fw-bold ms-1`}
|
||||
className={`${balance > 0 ? "text-success" : "text-danger"
|
||||
} fs-5 fw-bold ms-1`}
|
||||
>
|
||||
{balance > 0 ? (
|
||||
<i className="bx bx-plus b-sm"></i>
|
||||
@ -88,7 +98,7 @@ const AdvancePaymentPage = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<AdvancePaymentList employeeId={selectedEmployeeId} />
|
||||
<AdvancePaymentList employeeId={selectedEmployeeId} searchString={searchString} />
|
||||
</div>
|
||||
</div>
|
||||
</AdvancePaymentContext.Provider>
|
||||
|
||||
34
src/pages/AdvancePayment/AdvancePaymentPage1.jsx
Normal file
34
src/pages/AdvancePayment/AdvancePaymentPage1.jsx
Normal file
@ -0,0 +1,34 @@
|
||||
import React from 'react'
|
||||
import Breadcrumb from '../../components/common/Breadcrumb'
|
||||
import AdvancePaymentList1 from '../../components/AdvancePayment/AdvancePaymentList1'
|
||||
import { useForm } from 'react-hook-form';
|
||||
import EmployeeSearchInput from '../../components/common/EmployeeSearchInput';
|
||||
|
||||
const AdvancePaymentPage1 = () => {
|
||||
const { control, reset, watch } = useForm({
|
||||
defaultValues: {
|
||||
searchString: "",
|
||||
},
|
||||
});
|
||||
const searchString = watch("searchString");
|
||||
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<Breadcrumb
|
||||
data={[
|
||||
{ label: "Home", link: "/dashboard" },
|
||||
{ label: "Finance", link: "/advance-payment" },
|
||||
{ label: "Advance Payment" },
|
||||
]}
|
||||
/>
|
||||
<div className="card px-4 py-2 page-min-h">
|
||||
<div className="row py-1">
|
||||
<AdvancePaymentList1 searchString={searchString} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default AdvancePaymentPage1
|
||||
@ -118,32 +118,33 @@ const CollectionPage = () => {
|
||||
<div className="card my-3 py-2 px-sm-4 px-2">
|
||||
<div className="row align-items-center mx-0">
|
||||
{/* Left side: Date Picker + Show Pending (stacked on mobile) */}
|
||||
<div className="col-12 col-md-6 d-flex flex-column flex-md-row flex-wrap align-items-start align-md-items-center gap-2 gap-md-3 mb-3 mb-md-0">
|
||||
<FormProvider {...methods}>
|
||||
<DateRangePicker1 howManyDay={180} startField="fromDate"
|
||||
endField="toDate" />
|
||||
</FormProvider>
|
||||
|
||||
<div className="form-check form-switch d-flex align-items-center mt-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
role="switch"
|
||||
id="inactiveEmployeesCheckbox"
|
||||
checked={showPending}
|
||||
onChange={(e) => setShowPending(e.target.checked)}
|
||||
/>
|
||||
<label
|
||||
className="form-check-label ms-2"
|
||||
htmlFor="inactiveEmployeesCheckbox"
|
||||
<div className="col-12 col-md-6 d-flex flex-column flex-md-row flex-wrap align-items-start">
|
||||
<div className="d-inline-flex border rounded-pill overflow-hidden shadow-none">
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-2 py-1 rounded-0 text-tiny ${!showPending ? "btn-primary text-white" : ""
|
||||
}`}
|
||||
onClick={() => setShowPending(false)}
|
||||
>
|
||||
Show Completed Collections
|
||||
</label>
|
||||
Show All
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn px-2 py-1 rounded-0 text-tiny ${showPending ? "btn-primary text-white" : ""
|
||||
}`}
|
||||
onClick={() => setShowPending(true)}
|
||||
>
|
||||
Pending
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right side: Search + Add Button */}
|
||||
<div className="col-12 col-sm-6 d-flex justify-content-end align-items-center gap-2">
|
||||
<FormProvider {...methods}>
|
||||
<DateRangePicker1 howManyDay={180} startField="fromDate"
|
||||
endField="toDate" />
|
||||
</FormProvider>
|
||||
<input
|
||||
type="search"
|
||||
value={searchText}
|
||||
|
||||
@ -44,13 +44,13 @@ const ExpenseRepository = {
|
||||
DeletePaymentRequest: () => api.get("delete here come"),
|
||||
CreatePaymentRequestExpense: (data) =>
|
||||
api.post("/api/Expense/payment-request/expense/create", data),
|
||||
GetPayee:()=>api.get('/api/Expense/payment-request/payee'),
|
||||
GetPayee: () => api.get('/api/Expense/payment-request/payee'),
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
//#region Recurring Expense
|
||||
GetRecurringExpenseList:(pageSize, pageNumber, filter,isActive, searchString) => {
|
||||
GetRecurringExpenseList: (pageSize, pageNumber, filter, isActive, searchString) => {
|
||||
const payloadJsonString = JSON.stringify(filter);
|
||||
return api.get(
|
||||
`/api/expense/get/recurring-payment/list?pageSize=${pageSize}&pageNumber=${pageNumber}&filter=${payloadJsonString}&isActive=${isActive}&searchString=${searchString}`
|
||||
@ -70,9 +70,11 @@ const ExpenseRepository = {
|
||||
//#region Advance Payment
|
||||
GetTranctionList: (employeeId) =>
|
||||
api.get(`/api/Expense/get/transactions/${employeeId}`),
|
||||
getAllTranctionList: (searchString) =>
|
||||
api.get(`/api/Expense/get/advance-payment/employee/list?searchString=${searchString}`),
|
||||
//#endregion
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
export default ExpenseRepository;
|
||||
|
||||
@ -61,6 +61,7 @@ import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage
|
||||
import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage";
|
||||
import ServiceProjectDetail from "../pages/ServiceProject/ServiceProjectDetail";
|
||||
import ManageJob from "../components/ServiceProject/ServiceProjectJob/ManageJob";
|
||||
import AdvancePaymentPage1 from "../pages/AdvancePayment/AdvancePaymentPage1";
|
||||
const router = createBrowserRouter(
|
||||
[
|
||||
{
|
||||
@ -116,7 +117,8 @@ const router = createBrowserRouter(
|
||||
{ path: "/expenses", element: <ExpensePage /> },
|
||||
{ path: "/payment-request", element: <PaymentRequestPage /> },
|
||||
{ path: "/recurring-payment", element: <RecurringExpensePage /> },
|
||||
{ path: "/advance-payment", element: <AdvancePaymentPage /> },
|
||||
{ path: "/advance-payment", element: <AdvancePaymentPage1 /> },
|
||||
{ path: "/advance-payment/:employeeId", element: <AdvancePaymentPage /> },
|
||||
{ path: "/collection", element: <CollectionPage /> },
|
||||
{ path: "/masters", element: <MasterPage /> },
|
||||
{ path: "/tenants", element: <TenantPage /> },
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user