From 3ab70dc86f130f3059fdc1edc237fb6fb263ee7f Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Sat, 27 Dec 2025 00:08:12 +0530 Subject: [PATCH] added hook source for data --- .../collections/PmGridCollection.jsx | 208 +++++++++++++--- src/services/pmsGrid/PmsGrid.jsx | 25 +- src/services/pmsGrid/useGridCore.js | 224 ++++-------------- 3 files changed, 238 insertions(+), 219 deletions(-) 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({});