fixed client side searching

This commit is contained in:
pramod.mahajan 2025-12-27 18:45:39 +05:30
parent 526929d298
commit 2ceb38b496
4 changed files with 138 additions and 174 deletions

View File

@ -1,4 +1,4 @@
import React, { useMemo,useEffect } from "react"; import React, { useMemo, useEffect } from "react";
import { PmsGrid, useGridCore } from "../../services/pmsGrid"; import { PmsGrid, useGridCore } from "../../services/pmsGrid";
import { formatUTCToLocalTime } from "../../utils/dateUtils"; import { formatUTCToLocalTime } from "../../utils/dateUtils";
import { formatFigure } from "../../utils/appUtils"; import { formatFigure } from "../../utils/appUtils";
@ -50,57 +50,6 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
{ key: "isActive", title: "Status", enableAdvancedFilter: false }, { key: "isActive", title: "Status", enableAdvancedFilter: false },
]; ];
// const fetcher = async ({ page, pageSize, search, filter }) => {
// const response = await CollectionRepository.getCollections(
// selectedProject,
// search || "",
// fromDate,
// toDate,
// pageSize,
// page,
// true, // isActive
// isPending,
// filter
// );
// const api = response.data;
// return {
// rows: api.data.map((item) => ({
// id: item.id,
// invoiceNumber: item.invoiceNumber,
// title: item.title,
// clientSubmitedDate: formatUTCToLocalTime(item.clientSubmitedDate),
// exceptedPaymentDate: formatUTCToLocalTime(item.exceptedPaymentDate),
// totalAmount: formatFigure(item.basicAmount + item.taxAmount, {
// type: "currency",
// currency: "INR",
// }),
// balanceAmount: formatFigure(item.balanceAmount, {
// type: "currency",
// currency: "INR",
// }),
// isActive: item.isActive ? (
// <span className="badge bg-label-primary">
// <span className="badge badge-dot bg-primary me-1"></span>
// Active
// </span>
// ) : (
// <span className="badge bg-label-danger">
// <span className="badge badge-dot bg-danger me-1"></span>
// In-Active
// </span>
// ),
// })),
// total: api.totalEntities,
// };
// };
function useGridCollectionQuery({ function useGridCollectionQuery({
projectId, projectId,
fromDate, fromDate,
@ -141,38 +90,38 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
const api = res.data; const api = res.data;
return { return {
rows: api.data.map((item) => ({ rows: api.data.map((item) => ({
id: item.id, id: item.id,
invoiceNumber: item.invoiceNumber, invoiceNumber: item.invoiceNumber,
title: item.title, title: item.title,
clientSubmitedDate: formatUTCToLocalTime(item.clientSubmitedDate), clientSubmitedDate: formatUTCToLocalTime(item.clientSubmitedDate),
exceptedPaymentDate: formatUTCToLocalTime(item.exceptedPaymentDate), exceptedPaymentDate: formatUTCToLocalTime(item.exceptedPaymentDate),
totalAmount: formatFigure(item.basicAmount + item.taxAmount, { totalAmount: formatFigure(item.basicAmount + item.taxAmount, {
type: "currency", type: "currency",
currency: "INR", currency: "INR",
}), }),
balanceAmount: formatFigure(item.balanceAmount, { balanceAmount: formatFigure(item.balanceAmount, {
type: "currency", type: "currency",
currency: "INR", currency: "INR",
}), }),
isActive: item.isActive ? ( isActive: item.isActive ? (
<span className="badge bg-label-primary"> <span className="badge bg-label-primary">
<span className="badge badge-dot bg-primary me-1"></span> <span className="badge badge-dot bg-primary me-1"></span>
Active Active
</span> </span>
) : ( ) : (
<span className="badge bg-label-danger"> <span className="badge bg-label-danger">
<span className="badge badge-dot bg-danger me-1"></span> <span className="badge badge-dot bg-danger me-1"></span>
In-Active In-Active
</span> </span>
), ),
})), })),
total: api.totalEntities, total: api.totalEntities,
}; };
}, },
keepPreviousData: true, keepPreviousData: true,
@ -181,7 +130,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
const grid = useGridCore({ const grid = useGridCore({
columns, columns,
serverMode: true, serverMode: true,
initialPageSize: 25, initialPageSize: 10,
}); });
const filterPayload = useMemo(() => { const filterPayload = useMemo(() => {
@ -210,6 +159,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
toDate, toDate,
isPending, isPending,
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
grid.setRows(data.rows); grid.setRows(data.rows);
@ -218,42 +168,6 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
}, [data]); }, [data]);
return ( return (
// <PmsGrid
// columns={columns}
// serverMode
// fetcher={fetcher}
// rowKey="id"
// features={{
// search: true,
// pagination: true,
// pinning: true,
// resizing: true,
// selection: false,
// reorder: true,
// columnVisibility: true,
// pageSizeSelector: true,
// grouping: true,
// groupByKey: "clientSubmitedDate",
// aggregation: true,
// IsNumbering: true,
// actions: [
// {
// label: "Edit",
// icon: "bx-edit ",
// onClick: (row) => console.log("Edit", row, col),
// },
// {
// label: "Delete",
// icon: "bx-trash text-danger",
// onClick: (row) => console.log("Delete", row),
// },
// ],
// }}
// />
<PmsGrid <PmsGrid
columns={columns} columns={columns}
grid={grid} grid={grid}
@ -268,6 +182,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
columnVisibility: true, columnVisibility: true,
pageSizeSelector: true, pageSizeSelector: true,
IsNumbering: true, IsNumbering: true,
expand: false,
actions: [ actions: [
{ {
label: "Edit", label: "Edit",
@ -281,6 +196,11 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
}, },
], ],
}} }}
renderExpanded={(row) => (
<div className="p-3 bg-white ">
<h6 className="fw-semibold mb-2">Item Details</h6>
</div>
)}
/> />
); );
}; };

View File

@ -1,5 +1,5 @@
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { PmsGrid } from "./index"; import { PmsGrid, useGrid, useGridCore } from "./index";
import { initPopover } from "./GridService"; import { initPopover } from "./GridService";
import PmsHeaderOption from "./PmsHeaderOption"; import PmsHeaderOption from "./PmsHeaderOption";
@ -705,22 +705,27 @@ const boqColumns = [
* DEMO COMPONENT * DEMO COMPONENT
*/ */
export default function DemoBOQGrid() { export default function DemoBOQGrid() {
useEffect(() => { const grid = useGridCore({
initPopover(); columns: boqColumns,
}, []); serverMode: false,
const wrapperRef = useRef(); initialPageSize: 12,
useEffect(() => { data: boqData.map((r) => ({
if (!wrapperRef.current) return; ...r,
const ps = new PerfectScrollbar(wrapperRef.current, { amount: r.quantity * r.rate,
wheelPropagation: false, }))
suppressScrollX: false, });
});
return () => ps.destroy();
}, []);
const container = document.getElementById("mainContainer"); useEffect(() => {
const trigger = document.getElementById("dropdownBtn"); if (!boqData || boqData.length === 0) return;
const dropdown = document.getElementById("dropdownMenu"); grid.setRows(
boqData.map((r) => ({
...r,
amount: r.quantity * r.rate,
}))
);
grid.setTotalRows(boqData.length);
}, [boqData]);
return ( return (
<div className="container-fluid py-3"> <div className="container-fluid py-3">
@ -738,10 +743,7 @@ export default function DemoBOQGrid() {
</div> </div>
<PmsGrid <PmsGrid
data={boqData.map((r) => ({ grid={grid}
...r,
amount: r.quantity * r.rate,
}))}
columns={boqColumns} columns={boqColumns}
features={{ features={{
search: true, search: true,
@ -761,7 +763,8 @@ export default function DemoBOQGrid() {
{ {
label: "Edit", label: "Edit",
icon: "bx-edit ", icon: "bx-edit ",
onClick: (row,ind,column) => console.log("Edit", row,ind,column), onClick: (row, ind, column) =>
console.log("Edit", row, ind, column),
}, },
{ {
label: "Delete", label: "Delete",

View File

@ -147,7 +147,7 @@ export default function PmsGrid({
isFullScreen ? "card card-action card-fullscreen p-4" : "" isFullScreen ? "card card-action card-fullscreen p-4" : ""
}`} }`}
> >
<div className="row px-4"> <div className="row ">
<div className="col-8"> <div className="col-8">
<div className="d-flex flex-row gap-2 gap-2 "> <div className="d-flex flex-row gap-2 gap-2 ">
<div> <div>

View File

@ -43,6 +43,35 @@ export function useGridCore({
})) }))
); );
/* ---------------- SELECTION ---------------- */
const toggleSelect = useCallback((id) => {
setSelected((prev) => {
const s = new Set(prev);
s.has(id) ? s.delete(id) : s.add(id);
return s;
});
}, []);
const selectAllOnPage = useCallback(
(rows) => {
setSelected((prev) => {
const s = new Set(prev);
rows.forEach((r) => s.add(r[rowKey]));
return s;
});
},
[rowKey]
);
const deselectAllOnPage = useCallback(
(rows) => {
setSelected((prev) => {
const s = new Set(prev);
rows.forEach((r) => s.delete(r[rowKey]));
return s;
});
},
[rowKey]
);
/* ---------------- SEARCH (DEBOUNCE) ---------------- */ /* ---------------- SEARCH (DEBOUNCE) ---------------- */
useEffect(() => { useEffect(() => {
const t = setTimeout(() => { const t = setTimeout(() => {
@ -53,40 +82,46 @@ export function useGridCore({
}, [search]); }, [search]);
/* ---------------- CLIENT MODE ---------------- */ /* ---------------- CLIENT MODE ---------------- */
const clientRows = useMemo(() => { const filteredData = useMemo(() => {
if (serverMode) return []; if (serverMode) return [];
let filtered = data;
let filtered = data; if (search) {
const q = search.toLowerCase();
filtered = filtered.filter((r) =>
Object.values(r).some((v) =>
String(v ?? "").toLowerCase().includes(q)
)
);
}
if (search) { if (sortBy.key) {
const q = search.toLowerCase(); const dir = sortBy.dir === "asc" ? 1 : -1;
filtered = filtered.filter((r) => filtered = [...filtered].sort(
Object.values(r).some((v) => (a, b) =>
String(v ?? "") String(a[sortBy.key] ?? "").localeCompare(
.toLowerCase() String(b[sortBy.key] ?? "")
.includes(q) ) * dir
) );
); }
}
if (sortBy.key) { return filtered;
const dir = sortBy.dir === "asc" ? 1 : -1; }, [data, search, sortBy, serverMode]);
filtered = [...filtered].sort(
(a, b) =>
String(a[sortBy.key] ?? "").localeCompare(
String(b[sortBy.key] ?? "")
) * dir
);
}
setTotalRows(filtered.length);
const start = (page - 1) * pageSize;
return filtered.slice(start, start + pageSize);
}, [data, search, sortBy, page, pageSize, serverMode]);
useEffect(() => {
if (!serverMode) setRows(clientRows); const pagedRows = useMemo(() => {
}, [clientRows, serverMode]); const start = (page - 1) * pageSize;
return filteredData.slice(start, start + pageSize);
}, [filteredData, page, pageSize]);
useEffect(() => {
if (!serverMode) {
setRows(pagedRows);
setTotalRows(filteredData.length);
}
}, [serverMode, page, pageSize, filteredData.length]);
/* ---------------- ADVANCED FILTER ---------------- */ /* ---------------- ADVANCED FILTER ---------------- */
const setColumnAdvanceFilter = useCallback((column, filter) => { const setColumnAdvanceFilter = useCallback((column, filter) => {
@ -148,35 +183,41 @@ export function useGridCore({
setSearch, setSearch,
debouncedSearch, debouncedSearch,
/* sorting */ /* ----------sorting------ */
sortBy, sortBy,
changeSort, changeSort,
/* grouping */ /* --------------grouping---------------- */
groupBy, groupBy,
setGroupBy, setGroupBy,
/* advanced filter */ /* --------------advanced filter----------------- */
advanceFilters, advanceFilters,
setColumnAdvanceFilter, setColumnAdvanceFilter,
/* selection */ /*--------- selection ---------------------- */
selected, selected,
setSelected, setSelected,
toggleSelect,
selectAllOnPage,
deselectAllOnPage,
// *------------- Expanding Row --------------*/
expanded, expanded,
setExpanded, setExpanded,
/* columns */ /* --------------columns--------------------- */
colState, colState,
visibleColumns, visibleColumns,
updateColumn, updateColumn,
setColState, setColState,
toggleExpand, toggleExpand,
/* data */
/* ---------------data---------------------- */
rows, rows,
setRows, setRows,
setTotalRows, setTotalRows,
/*------------Key and grid-mode-------------*/
serverMode, serverMode,
rowKey, rowKey,
}; };