added view deatils of purchases

This commit is contained in:
pramod.mahajan 2025-11-27 12:42:40 +05:30
parent 909022b034
commit 528255c2bd
6 changed files with 449 additions and 16 deletions

View File

@ -2,22 +2,130 @@ import React, { useState } from "react";
import { usePurchasesList } from "../../hooks/usePurchase"; import { usePurchasesList } from "../../hooks/usePurchase";
import { ITEMS_PER_PAGE } from "../../utils/constants"; import { ITEMS_PER_PAGE } from "../../utils/constants";
import Pagination from "../common/Pagination"; import Pagination from "../common/Pagination";
import { PurchaseColumn } from "./Purchasetable";
import { SpinnerLoader } from "../common/Loader";
import { useDebounce } from "../../utils/appUtils";
import { usePurchaseContext } from "../../pages/purchase/PurchasePage";
const PurchaseList = () => { const PurchaseList = ({ searchString }) => {
const { setViewPurchase } = usePurchaseContext();
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const { data, isLoading, isError, error } = usePurchasesList( const debounceSearch = useDebounce(searchString, 300);
const { data, isLoading } = usePurchasesList(
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
currentPage, currentPage,
true, true,
{} {},
debounceSearch
); );
const paginate = (page) => { const paginate = (page) => {
if (page >= 1 && page <= (data?.totalPages ?? 1)) { if (page >= 1 && page <= (data?.totalPages ?? 1)) {
setCurrentPage(page); setCurrentPage(page);
} }
}; };
const visibleColumns = PurchaseColumn.filter((col) => !col.hidden);
return ( return (
<div className="row"> <div className="card mt-2">
<div className="table-responsive px-3">
<table className="datatables-users table border-top text-nowrap">
<thead>
<tr>
{visibleColumns.map((col) => (
<th key={col.key} colSpan={col.colSpan || 1}>
<div className={col.className || ""}>{col.label}</div>
</th>
))}
<th>Action</th>
</tr>
</thead>
<tbody>
{/* LOADING */}
{isLoading && (
<tr>
<td colSpan={3} colSpan={visibleColumns.length}>
<div className="py-6 py-12">
<SpinnerLoader />
</div>
</td>
</tr>
)}
{!isLoading && data?.data?.length === 0 && (
<tr>
<td
colSpan={visibleColumns.length}
className="text-center py-4"
colSpan={4}
>
No Data Found
</td>
</tr>
)}
{!isLoading &&
data?.data?.map((item, index) => (
<tr key={item?.id || index}>
{visibleColumns.map((col) => (
<td key={col.key} className={col.className || ""}>
{col.render ? col.render(item) : item[col.key] || "NA"}
</td>
))}
<td>
<div className="dropdown z-2">
<button
type="button"
className="btn btn-icon btn-text-secondary rounded-pill dropdown-toggle hide-arrow p-0"
data-bs-toggle="dropdown"
aria-expanded="false"
>
<i
className="bx bx-dots-vertical-rounded bx-sm text-muted"
data-bs-toggle="tooltip"
data-bs-offset="0,8"
data-bs-placement="top"
data-bs-custom-class="tooltip-dark"
title="More Action"
></i>
</button>
<ul className="dropdown-menu dropdown-menu-end">
<li>
<a
className="dropdown-item cursor-pointer"
onClick={() =>
setViewPurchase({
isOpen: true,
purchaseId: item.id,
})
}
>
<i className="bx bx-eye me-2"></i>
<span className="align-left">view</span>
</a>
</li>
<li>
<a className="dropdown-item cursor-pointer">
<i className="bx bx-trash me-2"></i>
<span className="align-left">Add</span>
</a>
</li>
<li>
<a className="dropdown-item cursor-pointer">
<i className="bx bx-trash me-2"></i>
<span className="align-left">Delete</span>
</a>
</li>
</ul>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
{data?.data?.length > 0 && ( {data?.data?.length > 0 && (
<Pagination <Pagination
currentPage={currentPage} currentPage={currentPage}
@ -30,4 +138,3 @@ const PurchaseList = () => {
}; };
export default PurchaseList; export default PurchaseList;
``;

View File

@ -0,0 +1,60 @@
import { formatFigure, getColorNameFromHex } from "../../utils/appUtils";
export const PurchaseColumn = [
{
key: "purchaseInvoiceUId",
label: "Invoice Id",
className: "text-start",
render: (item) => (
<div className="d-flex justify-content-start align-items-center p-1">
<span className="fw-normal">{item?.purchaseInvoiceUId || "NA"}</span>
</div>
),
},
{
key: "title",
label: "Title",
className: "text-start",
render: (item) => (
<div className="d-flex justify-content-start align-items-center">
<span className="fw-normal">{item?.title || "NA"}</span>
</div>
),
},
{
key: "project",
label: "Project",
className: "text-start d-none d-sm-table-cell",
render: (item) => <span>{item?.project?.name || "NA"}</span>,
},
{
key: "supplier",
label: "Supplier",
className: "text-start d-none d-sm-table-cell",
render: (item) => <span>{item?.supplier?.name || "NA"}</span>,
},
{
key: "status",
label: "Status",
className: "text-start",
render: (item) => {
let color = getColorNameFromHex(item.status?.color);
return (
<span className={`badge rounded-pill bg-label-${color}`}>
<span className={`badge badge-dot bg-${color} me-1`}></span>
{item?.status.displayName || "NA"}
</span>
);
},
},
{
key: "totalAmount",
label: "Total Amount",
className: " text-end w-min",
render: (item) => (
<span>{formatFigure(item?.totalAmount, { type: "currency" })}</span>
),
},
];

View File

@ -0,0 +1,227 @@
import React from "react";
import { usePurchase } from "../../hooks/usePurchase";
import { SpinnerLoader } from "../common/Loader";
import { formatUTCToLocalTime } from "../../utils/dateUtils";
import { getColorNameFromHex } from "../../utils/appUtils";
const ViewPurchase = ({ purchaseId }) => {
const { data, isLoading, isError, error } = usePurchase(purchaseId);
if (isLoading) return <SpinnerLoader />;
if (isError) return <Error error={error} />;
return (
<div className="row g-3">
<div className="col-12 text-start">
<div className=" ">
<p className="fs-6 mb-3">Purchase Details</p>
<div className="row">
<div className="col-md-4">
<small className="text-secondary">Purchase No:</small>
<p className="fw-light mb-1">{data?.purchaseInvoiceUId}</p>
</div>
<div className="col-md-4">
<small className="text-secondary">Title:</small>
<p className="fw-light mb-1">{data?.title}</p>
</div>
<div className="col-md-4">
<small className="fw-light me-3">Status:</small>
<span className={`badge rounded-pill bg-label-${getColorNameFromHex(data?.status?.color)}`}>
{data?.status.displayName || "NA"}
</span>
</div>
<div className="col-12 ">
<small className="text-secondary">Description:</small>
<p className="fw-light mb-1">{data?.description}</p>
</div>
</div>
</div>
</div>
<div className="col-md-6">
<div className="text-start h-auto">
<p className="text-muted mb-2">Project</p>
<div>
<small className="text-secondary">Name:</small>
<p className="fw-light mb-1">{data?.project?.name}</p>
</div>
<div>
<small className="text-secondary">Organization</small>{" "}
<p className="fw-light mb-1"> {data?.organization?.name}</p>
</div>
<div className="d-flex flex-column flex-md-row gap-3 my-1">
<div>
<small className="text-secondary">Email:</small>
<p className="fw-light mb-0">{data?.organization?.email}</p>
</div>
<div>
<small className="text-secondary">Contact:</small>{" "}
<p className="fw-light mb-0">
{data?.organization?.contactNumber}
</p>
</div>
</div>
<div>
<small className="text-secondary">Address:</small>{" "}
<p className="fw-light">{data?.organization?.address}</p>
</div>
</div>
</div>
<div className="col-md-6">
<div className="text-start h-auto">
<p className="text-muted mb-2">Supplier</p>
<div>
<small className="text-secondary">Name:</small>
<p className="fw-light mb-1">{data?.supplier?.name}</p>
</div>
<div>
<small className="text-secondary">Contact Person:</small>
<p className="fw-light mb-1">{data?.supplier?.contactPerson}</p>
</div>
<div className="d-flex flex-column flex-md-row gap-3 my-1">
<div>
<small className="text-secondary">Email:</small>
<p className="fw-light mb-0">{data?.supplier?.email}</p>
</div>
<div>
<small className="text-secondary">Contact:</small>
<p className="fw-light mb-0">{data?.supplier?.contactNumber}</p>
</div>
</div>
<div>
<small className="text-secondary">Address:</small>
<p className="fw-light">{data?.supplier?.address}</p>
</div>
</div>
</div>
<div className="col-md-6">
<div className="text-start h-auto">
<p className="text-muted mb-2">Invoice Details</p>
<div className="row g-3">
{/* Left column */}
<div className="col-12 col-sm-6">
<div>
<small className="text-secondary">Invoice No:</small>
<p className="fw-light mb-1">{data?.invoiceNumber}</p>
</div>
<div>
<small className="text-secondary">Proforma No:</small>
<p className="fw-light mb-1">{data?.proformaInvoiceNumber}</p>
</div>
<div>
<small className="text-secondary">E-Way Bill:</small>
<p className="fw-light mb-1">{data?.eWayBillNumber}</p>
</div>
<div>
<small className="text-secondary">PO No:</small>
<p className="fw-light mb-1">{data?.purchaseOrderNumber}</p>
</div>
</div>
{/* Right column */}
<div className="col-12 col-sm-6">
<div>
<small className="text-secondary">Invoice Date:</small>
<p className="fw-light mb-1">
{formatUTCToLocalTime(data?.invoiceDate)}
</p>
</div>
<div>
<small className="text-secondary">Proforma Date:</small>
<p className="fw-light mb-1">
{formatUTCToLocalTime(data?.proformaInvoiceDate)}
</p>
</div>
<div>
<small className="text-secondary">E-Way Date:</small>
<p className="fw-light mb-1">
{formatUTCToLocalTime(data?.eWayBillDate)}
</p>
</div>
<div>
<small className="text-secondary">PO Date:</small>
<p className="fw-light">
{formatUTCToLocalTime(data?.purchaseOrderDate)}
</p>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-6">
<div className="text-start h-auto">
<p className="text-muted mb-2">Amount Summary</p>
<div className="d-flex justify-content-between">
<small className="text-secondary">Base Amount</small>
<p className="fw-light mb-1"> {data?.baseAmount}</p>
</div>
<div className="d-flex justify-content-between">
<small className="text-secondary">Tax</small>
<p className="fw-light mb-1"> {data?.taxAmount}</p>
</div>
<div className="d-flex justify-content-between">
<small className="text-secondary">Transport</small>
<p className="fw-light mb-1"> {data?.transportCharges}</p>
</div>
<hr className="my-2" />
<div className="d-flex justify-content-between fs-6 fs-medium">
<span>Total</span>
<span> {data?.totalAmount}</span>
</div>
<div className="mt-2">
<small className="text-secondary">Due Date:</small>
<p className="fw-light mb-0">
{formatUTCToLocalTime(data?.paymentDueDate)}
</p>
</div>
</div>
</div>
<div className="row mt-3 text-start">
<div className="col-md-6 mb-3">
<div className=" h-100">
<p className="text-secondary mb-2">Billing Address</p>
<p className="mb-0 fw-light">{data?.billingAddress || "-"}</p>
</div>
</div>
<div className="col-md-6 mb-3 text-start">
<div className=" h-100">
<p className="text-secondary mb-2">Shipping Address</p>
<p className="mb-0 fw-light">{data?.shippingAddress || "-"}</p>
</div>
</div>
</div>
</div>
);
};
export default ViewPurchase;

View File

@ -38,6 +38,7 @@ export const usePurchase = (id) => {
const resp = await PurchaseRepository.GetPurchase(id); const resp = await PurchaseRepository.GetPurchase(id);
return resp.data; return resp.data;
}, },
enabled: !!id,
}); });
}; };

View File

@ -4,6 +4,7 @@ import showToast from "../../services/toastService";
import GlobalModel from "../../components/common/GlobalModel"; import GlobalModel from "../../components/common/GlobalModel";
import ManagePurchase from "../../components/purchase/ManagePurchase"; import ManagePurchase from "../../components/purchase/ManagePurchase";
import PurchaseList from "../../components/purchase/PurchaseList"; import PurchaseList from "../../components/purchase/PurchaseList";
import ViewPurchase from "../../components/purchase/ViewPurchase";
export const PurchaseContext = createContext(); export const PurchaseContext = createContext();
export const usePurchaseContext = () => { export const usePurchaseContext = () => {
@ -13,11 +14,20 @@ export const usePurchaseContext = () => {
showToast("Please use Innne cntext", "warning"); showToast("Please use Innne cntext", "warning");
window.location = "/dashboard"; window.location = "/dashboard";
} }
return context;
}; };
const PurchasePage = () => { const PurchasePage = () => {
const [searchText, setSearchText] = useState("");
const [addePurchase, setAddedPurchase] = useState(false); const [addePurchase, setAddedPurchase] = useState(false);
const [viewPurchaseState, setViewPurchase] = useState({
isOpen: false,
purchaseId: null,
});
const contextValue = {}; const contextValue = {
setViewPurchase,
};
console.log(ViewPurchase);
return ( return (
<PurchaseContext.Provider value={contextValue}> <PurchaseContext.Provider value={contextValue}>
<div className="container-fluid"> <div className="container-fluid">
@ -30,7 +40,20 @@ const PurchasePage = () => {
/> />
<div className="card"> <div className="card">
<div className="row p-2"> <div className="row p-2">
<di className="col-12 text-end"> <div className="col-12 col-md-6 text-start">
{" "}
<label className="mb-0">
<input
type="search"
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
className="form-control form-control-sm"
placeholder="Search Purchase"
aria-controls="DataTables_Table_0"
/>
</label>
</div>
<di className="col-6 text-end">
<button <button
className="btn btn-sm btn-primary" className="btn btn-sm btn-primary"
onClick={() => setAddedPurchase(true)} onClick={() => setAddedPurchase(true)}
@ -41,15 +64,28 @@ const PurchasePage = () => {
</div> </div>
</div> </div>
<PurchaseList /> <PurchaseList searchString={searchText} />
{addePurchase && (
<GlobalModel
isOpen={addePurchase}
size="lg"
closeModal={() => setAddedPurchase(false)}
>
<ManagePurchase onClose={() => setAddedPurchase(false)} />
</GlobalModel>
)}
<GlobalModel {viewPurchaseState.isOpen && (
isOpen={addePurchase} <GlobalModel
size="lg" isOpen={viewPurchaseState.isOpen}
closeModal={() => setAddedPurchase(false)} size="lg"
> closeModal={() =>
<ManagePurchase onClose={() => setAddedPurchase(false)} /> setViewPurchase({ isOpen: false, purchaseId: null })
</GlobalModel> }
>
<ViewPurchase purchaseId={viewPurchaseState.purchaseId} />
</GlobalModel>
)}
</div> </div>
</PurchaseContext.Provider> </PurchaseContext.Provider>
); );

View File

@ -7,7 +7,9 @@ export const PurchaseRepository = {
`/api/PurchaseInvoice/list?pageSize=${pageSize}&pageNumber=${pageNumber}&isActive=${isActive}&filter=${filter}&searchString=${searchString}` `/api/PurchaseInvoice/list?pageSize=${pageSize}&pageNumber=${pageNumber}&isActive=${isActive}&filter=${filter}&searchString=${searchString}`
), ),
GetPurchase:(id)=>api.get(`/api/PurchaseInvoice/details/${id}`) GetPurchase: (id) => api.get(`/api/PurchaseInvoice/details/${id}`),
UpdatePurchase: (id, data) =>
api.patch(`/api/PurchaseInvoice/edit/${id}`, data),
}; };
// const filterPayload = JSON.stringify({ // const filterPayload = JSON.stringify({