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