diff --git a/src/components/collections/PmGridCollection.jsx b/src/components/collections/PmGridCollection.jsx
index 21bd4825..84c1a0df 100644
--- a/src/components/collections/PmGridCollection.jsx
+++ b/src/components/collections/PmGridCollection.jsx
@@ -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 ? (
+ //
+ //
+ // Active
+ //
+ // ) : (
+ //
+ //
+ // In-Active
+ //
+ // ),
+ // })),
+
+ // 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 (
+ // console.log("Edit", row, col),
+ // },
+ // {
+ // label: "Delete",
+ // icon: "bx-trash text-danger",
+ // onClick: (row) => console.log("Delete", row),
+ // },
+ // ],
+ // }}
+ // />
+
console.log("Edit", row, col),
+ icon: "bx-edit",
+ onClick: (row) => console.log("Edit", row),
},
{
label: "Delete",
diff --git a/src/services/pmsGrid/PmsGrid.jsx b/src/services/pmsGrid/PmsGrid.jsx
index 772973dd..67dad1f1 100644
--- a/src/services/pmsGrid/PmsGrid.jsx
+++ b/src/services/pmsGrid/PmsGrid.jsx
@@ -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] ?? ""}
diff --git a/src/services/pmsGrid/useGridCore.js b/src/services/pmsGrid/useGridCore.js
index 7fdb388f..f2148813 100644
--- a/src/services/pmsGrid/useGridCore.js
+++ b/src/services/pmsGrid/useGridCore.js
@@ -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({});