fixed static data sorting (client side)
This commit is contained in:
parent
2ceb38b496
commit
5a182c5027
@ -12,6 +12,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
title: "Invoice Number",
|
||||
className: "text-start",
|
||||
groupable: true,
|
||||
sortable: true,
|
||||
enableAdvancedFilter: false,
|
||||
onCellClick: (row, column) => {
|
||||
console.log("Clicked cell:", row, column);
|
||||
@ -35,6 +36,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
key: "exceptedPaymentDate",
|
||||
title: "Expected Payment Date",
|
||||
className: "text-start",
|
||||
sortable: true,
|
||||
enableAdvancedFilter: { type: "date" },
|
||||
},
|
||||
{
|
||||
@ -148,6 +150,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
});
|
||||
}, [grid.sortBy, grid.advanceFilters, grid.groupBy]);
|
||||
|
||||
|
||||
const { data, isLoading, error } = useGridCollectionQuery({
|
||||
projectId: selectedProject,
|
||||
page: grid.page,
|
||||
@ -161,9 +164,10 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if(!data) return
|
||||
if (data) {
|
||||
grid.setRows(data.rows);
|
||||
grid.setTotalRows(data.total);
|
||||
grid.setServerRows(data.rows);
|
||||
grid.setServerTotal(data.total);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
@ -174,6 +178,7 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
loading={isLoading}
|
||||
features={{
|
||||
search: true,
|
||||
selection:true,
|
||||
pagination: true,
|
||||
pinning: true,
|
||||
resizing: true,
|
||||
|
||||
@ -621,6 +621,9 @@ const boqColumns = [
|
||||
sortable: true,
|
||||
pinned: "left",
|
||||
className: "text-start",
|
||||
onCellClick: (row, column) => {
|
||||
console.log("Clicked cell:", row, column);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "description",
|
||||
@ -714,28 +717,15 @@ export default function DemoBOQGrid() {
|
||||
amount: r.quantity * r.rate,
|
||||
}))
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!boqData || boqData.length === 0) return;
|
||||
grid.setRows(
|
||||
boqData.map((r) => ({
|
||||
...r,
|
||||
amount: r.quantity * r.rate,
|
||||
}))
|
||||
);
|
||||
|
||||
grid.setTotalRows(boqData.length);
|
||||
}, [boqData]);
|
||||
|
||||
return (
|
||||
<div className="container-fluid py-3">
|
||||
<div className="card p-3">
|
||||
<div id="mainContainer" class="container-box">
|
||||
<button id="dropdownBtn" class="btn">
|
||||
<div id="mainContainer" className="container-box">
|
||||
<button id="dropdownBtn" className="btn">
|
||||
Open Dropdown
|
||||
</button>
|
||||
|
||||
<div id="dropdownMenu" class="dropdown-menu">
|
||||
<div id="dropdownMenu" className="dropdown-menu">
|
||||
<div>Option 1</div>
|
||||
<div>Option 2</div>
|
||||
<div>Option 3</div>
|
||||
|
||||
@ -357,7 +357,7 @@ export default function PmsGrid({
|
||||
<tbody>
|
||||
{loading || totalRows === 0
|
||||
? Array.from({ length: 1 }).map((_, index) => (
|
||||
<tr className="">
|
||||
<tr className="" key={`row-${index}`}>
|
||||
<td
|
||||
key={index}
|
||||
colSpan={
|
||||
@ -390,7 +390,7 @@ export default function PmsGrid({
|
||||
colSpan={
|
||||
visibleColumns.length +
|
||||
(features.selection ? 1 : 0) +
|
||||
(features.actions ? 1 : 0)
|
||||
(features.actions ? columns.length : 0)
|
||||
}
|
||||
className="text-start pinned pinned-left tr-group"
|
||||
>
|
||||
@ -464,7 +464,7 @@ export default function PmsGrid({
|
||||
|
||||
return (
|
||||
<React.Fragment key={row[rowKey]}>
|
||||
<tr>
|
||||
<tr >
|
||||
{features.IsNumbering && (
|
||||
<td className="text-center align-middle p-2">
|
||||
<small className="text-secondry">{ind + 1}</small>
|
||||
|
||||
@ -64,7 +64,7 @@ const PmsHeaderOption = ({
|
||||
<div ref={rootRef} style={{ position: "relative", zIndex: 9999 }}>
|
||||
<button
|
||||
ref={btnRef}
|
||||
class="btn btn-icon btn-text-secondary rounded-pill d-inline-block"
|
||||
className="btn btn-icon btn-text-secondary rounded-pill d-inline-block"
|
||||
onClick={() => setOpen((p) => !p)}
|
||||
>
|
||||
<span className="icon-base bx bx-dots-vertical-rounded bx-sm"></span>
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
- rowKey
|
||||
- initialPageSize
|
||||
*/
|
||||
|
||||
export function useGridCore({
|
||||
data = [],
|
||||
serverMode = false,
|
||||
@ -20,6 +21,7 @@ export function useGridCore({
|
||||
initialPageSize = 20,
|
||||
columns = [],
|
||||
}) {
|
||||
/* ---------------- BASIC STATE ---------------- */
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(initialPageSize);
|
||||
const [search, setSearch] = useState("");
|
||||
@ -32,9 +34,11 @@ export function useGridCore({
|
||||
const [selected, setSelected] = useState(new Set());
|
||||
const [expanded, setExpanded] = useState(new Set());
|
||||
|
||||
const [rows, setRows] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
/* ---------------- SERVER MODE STATE ---------------- */
|
||||
const [serverRows, setServerRows] = useState([]);
|
||||
const [serverTotal, setServerTotal] = useState(0);
|
||||
|
||||
/* ---------------- COLUMN STATE ---------------- */
|
||||
const [colState, setColState] = useState(() =>
|
||||
columns.map((c, i) => ({
|
||||
...c,
|
||||
@ -43,35 +47,6 @@ 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) ---------------- */
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => {
|
||||
@ -81,47 +56,93 @@ export function useGridCore({
|
||||
return () => clearTimeout(t);
|
||||
}, [search]);
|
||||
|
||||
/* ---------------- CLIENT MODE ---------------- */
|
||||
const filteredData = useMemo(() => {
|
||||
if (serverMode) return [];
|
||||
let filtered = data;
|
||||
/* ---------------- CLIENT MODE (PURE DERIVED DATA) ---------------- */
|
||||
const filteredData = useMemo(() => {
|
||||
if (serverMode) return [];
|
||||
|
||||
if (search) {
|
||||
const q = search.toLowerCase();
|
||||
filtered = filtered.filter((r) =>
|
||||
Object.values(r).some((v) =>
|
||||
String(v ?? "").toLowerCase().includes(q)
|
||||
)
|
||||
let filtered = [...data]; // IMPORTANT: clone
|
||||
|
||||
// SEARCH
|
||||
if (debouncedSearch) {
|
||||
const q = debouncedSearch.toLowerCase();
|
||||
filtered = filtered.filter((r) =>
|
||||
Object.values(r).some((v) =>
|
||||
String(v ?? "")
|
||||
.toLowerCase()
|
||||
.includes(q)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// SORT
|
||||
if (sortBy.key) {
|
||||
const dir = sortBy.dir === "asc" ? 1 : -1;
|
||||
filtered.sort(
|
||||
(a, b) =>
|
||||
String(a?.[sortBy.key] ?? "").localeCompare(
|
||||
String(b?.[sortBy.key] ?? ""),
|
||||
undefined,
|
||||
{ numeric: true, sensitivity: "base" }
|
||||
) * dir
|
||||
);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}, [data, debouncedSearch, sortBy, serverMode]);
|
||||
|
||||
const pagedClientRows = useMemo(() => {
|
||||
if (serverMode) return [];
|
||||
const start = (page - 1) * pageSize;
|
||||
return filteredData.slice(start, start + pageSize);
|
||||
}, [filteredData, page, pageSize, serverMode]);
|
||||
|
||||
/* ---------------- FINAL ROW SOURCE ---------------- */
|
||||
const rows = serverMode ? serverRows : pagedClientRows;
|
||||
const totalRows = serverMode ? serverTotal : filteredData.length;
|
||||
const totalPages = Math.max(1, Math.ceil(totalRows / pageSize));
|
||||
|
||||
/* ---------------- 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]
|
||||
);
|
||||
|
||||
/* ---------------- SORT ---------------- */
|
||||
const changeSort = useCallback((key) => {
|
||||
setSortBy((p) =>
|
||||
p.key !== key
|
||||
? { key, dir: "asc" }
|
||||
: p.dir === "asc"
|
||||
? { key, dir: "desc" }
|
||||
: { key: null, dir: "asc" }
|
||||
);
|
||||
}
|
||||
|
||||
if (sortBy.key) {
|
||||
const dir = sortBy.dir === "asc" ? 1 : -1;
|
||||
filtered = [...filtered].sort(
|
||||
(a, b) =>
|
||||
String(a[sortBy.key] ?? "").localeCompare(
|
||||
String(b[sortBy.key] ?? "")
|
||||
) * dir
|
||||
);
|
||||
}
|
||||
|
||||
return filtered;
|
||||
}, [data, search, sortBy, serverMode]);
|
||||
|
||||
|
||||
|
||||
const pagedRows = useMemo(() => {
|
||||
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]);
|
||||
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
/* ---------------- ADVANCED FILTER ---------------- */
|
||||
const setColumnAdvanceFilter = useCallback((column, filter) => {
|
||||
@ -136,18 +157,6 @@ useEffect(() => {
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
/* ---------------- SORT ---------------- */
|
||||
const changeSort = useCallback((key) => {
|
||||
setSortBy((p) =>
|
||||
p.key !== key
|
||||
? { key, dir: "asc" }
|
||||
: p.dir === "asc"
|
||||
? { key, dir: "desc" }
|
||||
: { key: null, dir: "asc" }
|
||||
);
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
/* ---------------- COLUMNS ---------------- */
|
||||
const visibleColumns = useMemo(
|
||||
() => colState.filter((c) => c.visible).sort((a, b) => a.order - b.order),
|
||||
@ -160,8 +169,7 @@ useEffect(() => {
|
||||
);
|
||||
}, []);
|
||||
|
||||
// *---------------- ROW EXPAND -----------------------*/
|
||||
|
||||
/* ---------------- EXPAND ---------------- */
|
||||
const toggleExpand = useCallback((id) => {
|
||||
setExpanded((prev) => {
|
||||
const s = new Set(prev);
|
||||
@ -169,55 +177,58 @@ useEffect(() => {
|
||||
return s;
|
||||
});
|
||||
}, []);
|
||||
|
||||
/* ---------------- RETURN API ---------------- */
|
||||
return {
|
||||
/* paging */
|
||||
// paging
|
||||
page,
|
||||
setPage,
|
||||
pageSize,
|
||||
setPageSize,
|
||||
totalRows,
|
||||
totalPages: Math.max(1, Math.ceil(totalRows / pageSize)),
|
||||
totalPages,
|
||||
|
||||
/* search */
|
||||
// search
|
||||
search,
|
||||
setSearch,
|
||||
debouncedSearch,
|
||||
|
||||
/* ----------sorting------ */
|
||||
// sorting
|
||||
sortBy,
|
||||
changeSort,
|
||||
|
||||
/* --------------grouping---------------- */
|
||||
// grouping
|
||||
groupBy,
|
||||
setGroupBy,
|
||||
|
||||
/* --------------advanced filter----------------- */
|
||||
// advanced filters
|
||||
advanceFilters,
|
||||
setColumnAdvanceFilter,
|
||||
|
||||
/*--------- selection ---------------------- */
|
||||
// selection
|
||||
selected,
|
||||
setSelected,
|
||||
toggleSelect,
|
||||
selectAllOnPage,
|
||||
deselectAllOnPage,
|
||||
|
||||
// *------------- Expanding Row --------------*/
|
||||
// expand
|
||||
expanded,
|
||||
setExpanded,
|
||||
toggleExpand,
|
||||
|
||||
/* --------------columns--------------------- */
|
||||
// columns
|
||||
colState,
|
||||
visibleColumns,
|
||||
updateColumn,
|
||||
setColState,
|
||||
toggleExpand,
|
||||
|
||||
/* ---------------data---------------------- */
|
||||
// data
|
||||
rows,
|
||||
setRows,
|
||||
setTotalRows,
|
||||
/*------------Key and grid-mode-------------*/
|
||||
|
||||
// server setters (ONLY used in serverMode)
|
||||
setServerRows,
|
||||
setServerTotal,
|
||||
|
||||
// flags
|
||||
serverMode,
|
||||
rowKey,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user