added hook source for data
This commit is contained in:
parent
468797f823
commit
3ab70dc86f
@ -1,8 +1,9 @@
|
||||
import React from "react";
|
||||
import { PmsGrid } from "../../services/pmsGrid";
|
||||
import React, { useMemo,useEffect } from "react";
|
||||
import { PmsGrid, useGridCore } from "../../services/pmsGrid";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import { formatFigure } from "../../utils/appUtils";
|
||||
import { CollectionRepository } from "../../repositories/ColllectionRepository";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
const columns = [
|
||||
@ -49,23 +50,98 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
{ 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 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;
|
||||
// const api = response.data;
|
||||
|
||||
return {
|
||||
rows: api.data.map((item) => ({
|
||||
// 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({
|
||||
projectId,
|
||||
fromDate,
|
||||
toDate,
|
||||
isPending,
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
sortBy,
|
||||
filter,
|
||||
}) {
|
||||
return useQuery({
|
||||
queryKey: [
|
||||
"collections",
|
||||
projectId,
|
||||
page,
|
||||
pageSize,
|
||||
search,
|
||||
sortBy,
|
||||
filter,
|
||||
fromDate,
|
||||
toDate,
|
||||
isPending,
|
||||
],
|
||||
queryFn: async () => {
|
||||
const res = await CollectionRepository.getCollections(
|
||||
projectId,
|
||||
search || "",
|
||||
fromDate,
|
||||
toDate,
|
||||
pageSize,
|
||||
page,
|
||||
true,
|
||||
isPending,
|
||||
filter
|
||||
);
|
||||
|
||||
const api = res.data;
|
||||
|
||||
return {
|
||||
rows: api.data.map((item) => ({
|
||||
id: item.id,
|
||||
invoiceNumber: item.invoiceNumber,
|
||||
title: item.title,
|
||||
@ -97,36 +173,106 @@ const PmGridCollection = ({ selectedProject, fromDate, toDate, isPending }) => {
|
||||
})),
|
||||
|
||||
total: api.totalEntities,
|
||||
};
|
||||
};
|
||||
};
|
||||
},
|
||||
keepPreviousData: true,
|
||||
});
|
||||
}
|
||||
const grid = useGridCore({
|
||||
columns,
|
||||
serverMode: true,
|
||||
initialPageSize: 25,
|
||||
});
|
||||
|
||||
const filterPayload = useMemo(() => {
|
||||
return JSON.stringify({
|
||||
sortFilters: grid.sortBy.key
|
||||
? [
|
||||
{
|
||||
column: grid.sortBy.key,
|
||||
sortDescending: grid.sortBy.dir === "desc",
|
||||
},
|
||||
]
|
||||
: [],
|
||||
advanceFilters: Object.values(grid.advanceFilters),
|
||||
groupByColumn: grid.groupBy,
|
||||
});
|
||||
}, [grid.sortBy, grid.advanceFilters, grid.groupBy]);
|
||||
|
||||
const { data, isLoading, error } = useGridCollectionQuery({
|
||||
projectId: selectedProject,
|
||||
page: grid.page,
|
||||
pageSize: grid.pageSize,
|
||||
search: grid.debouncedSearch,
|
||||
sortBy: grid.sortBy,
|
||||
filter: filterPayload,
|
||||
fromDate,
|
||||
toDate,
|
||||
isPending,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
grid.setRows(data.rows);
|
||||
grid.setTotalRows(data.total);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
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
|
||||
columns={columns}
|
||||
serverMode
|
||||
fetcher={fetcher}
|
||||
rowKey="id"
|
||||
grid={grid}
|
||||
loading={isLoading}
|
||||
features={{
|
||||
search: true,
|
||||
pagination: true,
|
||||
pinning: true,
|
||||
resizing: true,
|
||||
selection: false,
|
||||
reorder: true,
|
||||
grouping: 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),
|
||||
icon: "bx-edit",
|
||||
onClick: (row) => console.log("Edit", row),
|
||||
},
|
||||
{
|
||||
label: "Delete",
|
||||
|
||||
@ -15,26 +15,16 @@ import FilterApplied from "./FilterApplied";
|
||||
*/
|
||||
export default function PmsGrid({
|
||||
columns = [],
|
||||
data,
|
||||
serverMode = false,
|
||||
fetcher,
|
||||
grid,
|
||||
loading = false,
|
||||
features = {},
|
||||
rowKey = "id",
|
||||
isDropdown = false,
|
||||
features = {},
|
||||
renderExpanded,
|
||||
}) {
|
||||
const [isFullScreen, setFullScreen] = useState(false);
|
||||
const [activeCell, setActiveCell] = useState(null);
|
||||
const grid = useGridCore({
|
||||
data,
|
||||
serverMode,
|
||||
fetcher,
|
||||
rowKey,
|
||||
initialPageSize: features.pageSize || 25,
|
||||
columns,
|
||||
});
|
||||
const wrapperRef = useRef();
|
||||
|
||||
const {
|
||||
rows,
|
||||
page,
|
||||
@ -55,7 +45,6 @@ export default function PmsGrid({
|
||||
visibleColumns,
|
||||
colState,
|
||||
updateColumn,
|
||||
loading,
|
||||
error,
|
||||
totalRows,
|
||||
expanded,
|
||||
@ -67,7 +56,6 @@ export default function PmsGrid({
|
||||
advanceFilters,
|
||||
setColumnAdvanceFilter,
|
||||
} = grid;
|
||||
|
||||
// --- Pin / Unpin helpers ---
|
||||
const pinColumn = (key, side) => {
|
||||
const col = colState.find((c) => c.key === key);
|
||||
@ -539,7 +527,12 @@ export default function PmsGrid({
|
||||
col.pinned
|
||||
? "pinned-left px-3 bg-white pms-grid td pinned"
|
||||
: "px-3"
|
||||
} ${activeCell?.rowId == row.id && activeCell.columnKey === col.key ? "grid-cell-active" : ""} cursor-pointer`}
|
||||
} ${
|
||||
activeCell?.rowId == row.id &&
|
||||
activeCell.columnKey === col.key
|
||||
? "grid-cell-active"
|
||||
: ""
|
||||
} cursor-pointer`}
|
||||
>
|
||||
{col.render ? col.render(row) : row[col.key] ?? ""}
|
||||
</td>
|
||||
|
||||
@ -13,11 +13,9 @@ import {
|
||||
- rowKey
|
||||
- initialPageSize
|
||||
*/
|
||||
|
||||
export function useGridCore({
|
||||
data,
|
||||
data = [],
|
||||
serverMode = false,
|
||||
fetcher,
|
||||
rowKey = "id",
|
||||
initialPageSize = 20,
|
||||
columns = [],
|
||||
@ -28,14 +26,15 @@ export function useGridCore({
|
||||
const [debouncedSearch, setDebouncedSearch] = useState("");
|
||||
const [groupBy, setGroupBy] = useState(null);
|
||||
|
||||
// FIX: store ADVANCED FILTERS PER COLUMN
|
||||
// { amount: { columnKey, operation, value } }
|
||||
const [advanceFilters, setAdvanceFilters] = useState({});
|
||||
|
||||
const [sortBy, setSortBy] = useState({ key: null, dir: "asc" });
|
||||
|
||||
const [selected, setSelected] = useState(new Set());
|
||||
const [expanded, setExpanded] = useState(new Set());
|
||||
|
||||
const [rows, setRows] = useState([]);
|
||||
const [totalRows, setTotalRows] = useState(0);
|
||||
|
||||
const [colState, setColState] = useState(() =>
|
||||
columns.map((c, i) => ({
|
||||
...c,
|
||||
@ -44,24 +43,18 @@ export function useGridCore({
|
||||
}))
|
||||
);
|
||||
|
||||
const [totalRows, setTotalRows] = useState(data ? data.length : 0);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState(null);
|
||||
const [serverRows, setServerRows] = useState([]);
|
||||
|
||||
/* ---------------- SEARCH (DEBOUNCE) ---------------- */
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
const t = setTimeout(() => {
|
||||
setDebouncedSearch(search);
|
||||
setPage(1);
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(handler);
|
||||
}, 400);
|
||||
return () => clearTimeout(t);
|
||||
}, [search]);
|
||||
|
||||
/* ---------------- CLIENT MODE ---------------- */
|
||||
const clientFiltered = useMemo(() => {
|
||||
if (!data) return [];
|
||||
const clientRows = useMemo(() => {
|
||||
if (serverMode) return [];
|
||||
|
||||
let filtered = data;
|
||||
|
||||
@ -69,155 +62,51 @@ export function useGridCore({
|
||||
const q = search.toLowerCase();
|
||||
filtered = filtered.filter((r) =>
|
||||
Object.values(r).some((v) =>
|
||||
String(v ?? "")
|
||||
.toLowerCase()
|
||||
.includes(q)
|
||||
String(v ?? "").toLowerCase().includes(q)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (sortBy.key) {
|
||||
const dir = sortBy.dir === "asc" ? 1 : -1;
|
||||
filtered = [...filtered].sort((a, b) => {
|
||||
const A = a[sortBy.key];
|
||||
const B = b[sortBy.key];
|
||||
if (A == null && B == null) return 0;
|
||||
if (A == null) return -1 * dir;
|
||||
if (B == null) return 1 * dir;
|
||||
if (typeof A === "number" && typeof B === "number")
|
||||
return (A - B) * dir;
|
||||
return String(A).localeCompare(String(B)) * dir;
|
||||
});
|
||||
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]);
|
||||
|
||||
/* ---------------- SERVER MODE ---------------- */
|
||||
const fetchServer = useCallback(async () => {
|
||||
if (!serverMode || typeof fetcher !== "function") return;
|
||||
|
||||
const sortFilters = sortBy.key
|
||||
? [
|
||||
{
|
||||
column: sortBy.key,
|
||||
sortDescending: sortBy.dir === "desc",
|
||||
},
|
||||
]
|
||||
: [];
|
||||
|
||||
// convert map → array
|
||||
const advanceFilterArray = Object.values(advanceFilters);
|
||||
|
||||
const filterPayload = JSON.stringify({
|
||||
sortFilters,
|
||||
groupByColumn: groupBy || null,
|
||||
advanceFilters: advanceFilterArray,
|
||||
});
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const resp = await fetcher({
|
||||
page,
|
||||
pageSize,
|
||||
sortBy,
|
||||
search: debouncedSearch,
|
||||
filter: filterPayload,
|
||||
});
|
||||
|
||||
setServerRows(resp?.rows || []);
|
||||
setTotalRows(resp?.total ?? resp?.rows?.length ?? 0);
|
||||
} catch (err) {
|
||||
setError(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [
|
||||
serverMode,
|
||||
fetcher,
|
||||
page,
|
||||
pageSize,
|
||||
sortBy,
|
||||
debouncedSearch,
|
||||
groupBy,
|
||||
advanceFilters,
|
||||
]);
|
||||
}, [data, search, sortBy, page, pageSize, serverMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (serverMode) fetchServer();
|
||||
}, [serverMode, fetchServer]);
|
||||
if (!serverMode) setRows(clientRows);
|
||||
}, [clientRows, serverMode]);
|
||||
|
||||
/* ---------------- ADVANCED FILTER API ---------------- */
|
||||
/* ---------------- ADVANCED FILTER ---------------- */
|
||||
const setColumnAdvanceFilter = useCallback((column, filter) => {
|
||||
setAdvanceFilters((prev) => {
|
||||
if (!filter) {
|
||||
const copy = { ...prev };
|
||||
delete copy[column];
|
||||
return copy;
|
||||
const c = { ...prev };
|
||||
delete c[column];
|
||||
return c;
|
||||
}
|
||||
|
||||
return {
|
||||
...prev,
|
||||
[column]: {
|
||||
column,
|
||||
...filter,
|
||||
},
|
||||
};
|
||||
return { ...prev, [column]: { column, ...filter } };
|
||||
});
|
||||
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
/* ---------------- 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]
|
||||
);
|
||||
|
||||
/* ---------------- EXPAND ---------------- */
|
||||
const toggleExpand = useCallback((id) => {
|
||||
setExpanded((prev) => {
|
||||
const s = new Set(prev);
|
||||
s.has(id) ? s.delete(id) : s.add(id);
|
||||
return s;
|
||||
});
|
||||
}, []);
|
||||
|
||||
/* ---------------- SORT ---------------- */
|
||||
const changeSort = useCallback((key) => {
|
||||
setSortBy((prev) => {
|
||||
if (prev.key !== key) return { key, dir: "asc" };
|
||||
if (prev.dir === "asc") return { key, dir: "desc" };
|
||||
return { key: null, dir: "asc" };
|
||||
});
|
||||
setSortBy((p) =>
|
||||
p.key !== key
|
||||
? { key, dir: "asc" }
|
||||
: p.dir === "asc"
|
||||
? { key, dir: "desc" }
|
||||
: { key: null, dir: "asc" }
|
||||
);
|
||||
setPage(1);
|
||||
}, []);
|
||||
|
||||
@ -233,64 +122,55 @@ export function useGridCore({
|
||||
);
|
||||
}, []);
|
||||
|
||||
/* ---------------- FINAL ---------------- */
|
||||
const rows = serverMode ? serverRows : clientFiltered;
|
||||
const totalPages = Math.max(1, Math.ceil(totalRows / pageSize));
|
||||
|
||||
return {
|
||||
// paging
|
||||
/* paging */
|
||||
page,
|
||||
setPage,
|
||||
pageSize,
|
||||
setPageSize,
|
||||
totalRows,
|
||||
totalPages,
|
||||
totalPages: Math.max(1, Math.ceil(totalRows / pageSize)),
|
||||
|
||||
// loading & error
|
||||
loading,
|
||||
error,
|
||||
|
||||
// search
|
||||
/* search */
|
||||
search,
|
||||
setSearch,
|
||||
debouncedSearch,
|
||||
|
||||
// sorting
|
||||
/* sorting */
|
||||
sortBy,
|
||||
changeSort,
|
||||
|
||||
// selection
|
||||
/* grouping */
|
||||
groupBy,
|
||||
setGroupBy,
|
||||
|
||||
/* advanced filter */
|
||||
advanceFilters,
|
||||
setColumnAdvanceFilter,
|
||||
|
||||
/* selection */
|
||||
selected,
|
||||
setSelected,
|
||||
toggleSelect,
|
||||
selectAllOnPage,
|
||||
deselectAllOnPage,
|
||||
|
||||
// expand
|
||||
expanded,
|
||||
toggleExpand,
|
||||
setExpanded,
|
||||
|
||||
// columns
|
||||
/* columns */
|
||||
colState,
|
||||
visibleColumns,
|
||||
updateColumn,
|
||||
setColState,
|
||||
|
||||
// grouping
|
||||
groupBy,
|
||||
setGroupBy,
|
||||
|
||||
// advanced filter
|
||||
advanceFilters,
|
||||
setColumnAdvanceFilter,
|
||||
|
||||
// data
|
||||
/* data */
|
||||
rows,
|
||||
setRows,
|
||||
setTotalRows,
|
||||
|
||||
// mode
|
||||
serverMode,
|
||||
rowKey,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export function useDropdownPosition(btnRef, menuRef, isOpen, level = 0) {
|
||||
const [style, setStyle] = useState({});
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user