gbs-add-block 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +108 -0
- package/package.json +28 -0
- package/source/components/button/index.tsx +25 -0
- package/source/components/checkbox/index.tsx +9 -0
- package/source/components/darkmode/index.tsx +48 -0
- package/source/components/datepicker/DatePickerHelper.ts +42 -0
- package/source/components/datepicker/index.tsx +258 -0
- package/source/components/datepicker/types.ts +9 -0
- package/source/components/dialog/index.tsx +44 -0
- package/source/components/dialog/types.ts +12 -0
- package/source/components/grid/FilterPopup.tsx +85 -0
- package/source/components/grid/Grid.tsx +615 -0
- package/source/components/grid/GridHelperFunctions.ts +218 -0
- package/source/components/grid/index.tsx +26 -0
- package/source/components/grid/type.ts +28 -0
- package/source/components/input/index.tsx +105 -0
- package/source/components/input/types.ts +9 -0
- package/source/components/modal/index.tsx +58 -0
- package/source/components/modal/types.ts +11 -0
- package/source/components/multiselect/index.tsx +213 -0
- package/source/components/multiselect/types.ts +14 -0
- package/source/components/select/index.tsx +220 -0
- package/source/components/select/types.ts +13 -0
- package/source/components/spinner/Stroke.tsx +89 -0
- package/source/components/spinner/index.tsx +54 -0
- package/source/components/spinner/types.ts +9 -0
- package/source/components/toast/Toast.tsx +61 -0
- package/source/components/toast/index.tsx +36 -0
- package/source/components/toast/toastAtom.ts +23 -0
- package/source/components/toast/types.ts +24 -0
- package/source/components/toast/useToast.ts +24 -0
- package/source/fallback/index.tsx +11 -0
- package/source/icon/Icon.tsx +55 -0
- package/source/icon/iconPaths.ts +92 -0
- package/source/index.ts +15 -0
- package/source/types.ts +108 -0
- package/source/utils.ts +10 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Grampro Business Services and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* Extended Documentation for Grid can be found at
|
|
7
|
+
* https://psychedelic-step-e70.notion.site/Data-GRID-by-GBS-R-D-20ff97c899d24bc590215a6196435fa3
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import React, {
|
|
11
|
+
forwardRef,
|
|
12
|
+
useCallback,
|
|
13
|
+
useEffect,
|
|
14
|
+
useImperativeHandle,
|
|
15
|
+
useState,
|
|
16
|
+
} from "react";
|
|
17
|
+
import FilterPopup from "./FilterPopup";
|
|
18
|
+
import {
|
|
19
|
+
clearFilterHelper,
|
|
20
|
+
exportToExcelHelper,
|
|
21
|
+
exportToPDFHelper,
|
|
22
|
+
} from "./GridHelperFunctions";
|
|
23
|
+
import { handleApplyFilterHelper } from "./GridHelperFunctions";
|
|
24
|
+
import Icon from "../icon/Icon";
|
|
25
|
+
import {
|
|
26
|
+
leftArrows,
|
|
27
|
+
leftArrow,
|
|
28
|
+
rightArrow,
|
|
29
|
+
rightArrows,
|
|
30
|
+
search,
|
|
31
|
+
listFilter,
|
|
32
|
+
} from "../icon/iconPaths";
|
|
33
|
+
import type { GridProps } from "./type";
|
|
34
|
+
import { getSourceData } from "../utils";
|
|
35
|
+
|
|
36
|
+
export const Grid = forwardRef((props: GridProps, ref) => {
|
|
37
|
+
const {
|
|
38
|
+
dataSource,
|
|
39
|
+
columns = [],
|
|
40
|
+
pageSettings,
|
|
41
|
+
enableSearch = false,
|
|
42
|
+
lazy = false,
|
|
43
|
+
enableExcelExport = false,
|
|
44
|
+
excelName = "data",
|
|
45
|
+
enablePdfExport = false,
|
|
46
|
+
pdfName = "data",
|
|
47
|
+
pdfOptions = {},
|
|
48
|
+
gridButtonClass = "px-1 py-2 bg-white border rounded-lg text-xs text-black dark:bg-black dark:text-white",
|
|
49
|
+
selectAll = false,
|
|
50
|
+
onSelectRow,
|
|
51
|
+
isFetching,
|
|
52
|
+
tableHeaderStyle = "text-left border-b border-t bg-gray-50 px-2 py-4 dark:bg-gray-700 dark:text-white",
|
|
53
|
+
gridContainerClass = "flex flex-col min-w-screen border rounded-md overflow-hidden dark:bg-black",
|
|
54
|
+
gridColumnStyleSelectAll = "border-b px-4 text-sm dark:text-white",
|
|
55
|
+
gridColumnStyle = "border-b p-2 text-sm dark:text-white",
|
|
56
|
+
} = props;
|
|
57
|
+
const [workingDataSource, setWorkingDataSource] = useState<any>([]);
|
|
58
|
+
const [fallbackSourceData, setFallbackSourceData] = useState([]);
|
|
59
|
+
const [workingColumns, setWorkingColumns] = useState<any>([]);
|
|
60
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
61
|
+
const [pageStart, setPageStart] = useState(0);
|
|
62
|
+
const [pageEnd, setPageEnd] = useState(10);
|
|
63
|
+
const [totalPages, setTotalPages] = useState(0);
|
|
64
|
+
const [searchParam, setSearchParam] = useState("");
|
|
65
|
+
const [activeFilterArray, setActiveFilterArray] = useState<any>([]);
|
|
66
|
+
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
|
67
|
+
|
|
68
|
+
// Function to handle API datasource
|
|
69
|
+
const getGridData = useCallback(async () => {
|
|
70
|
+
try {
|
|
71
|
+
const sourceData = await getSourceData(dataSource);
|
|
72
|
+
const gridData = sourceData.sourcedata;
|
|
73
|
+
setFallbackSourceData(gridData);
|
|
74
|
+
setWorkingDataSource(gridData);
|
|
75
|
+
const totalPages = Math.ceil(gridData.length / pageSettings.pageNumber);
|
|
76
|
+
setTotalPages(totalPages);
|
|
77
|
+
setPageEnd(Math.min(10, totalPages));
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error("Error fetching grid source data:", error);
|
|
80
|
+
}
|
|
81
|
+
}, [dataSource, pageSettings.pageNumber]);
|
|
82
|
+
|
|
83
|
+
// Calculates total pages and determine dataSource type
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
const handleDataSource = async () => {
|
|
86
|
+
if (Array.isArray(dataSource) && dataSource.length > 0) {
|
|
87
|
+
setWorkingDataSource(dataSource);
|
|
88
|
+
const totalPages = Math.ceil(
|
|
89
|
+
dataSource.length / pageSettings.pageNumber
|
|
90
|
+
);
|
|
91
|
+
setTotalPages(totalPages);
|
|
92
|
+
setPageEnd(Math.min(10, totalPages));
|
|
93
|
+
} else if (typeof dataSource === "string") {
|
|
94
|
+
await getGridData();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
handleDataSource();
|
|
99
|
+
}, [dataSource, pageSettings]);
|
|
100
|
+
|
|
101
|
+
// Adds Filter Column
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
if (columns && columns.length > 0) {
|
|
104
|
+
const filteredColumns = columns.map((column) => ({
|
|
105
|
+
...column,
|
|
106
|
+
showFilterPopup: false,
|
|
107
|
+
isFilterActive: false,
|
|
108
|
+
}));
|
|
109
|
+
setWorkingColumns(filteredColumns);
|
|
110
|
+
}
|
|
111
|
+
}, [columns]);
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (!columns || columns.length === 0) {
|
|
115
|
+
if (
|
|
116
|
+
workingDataSource.length > 0 &&
|
|
117
|
+
Object.keys(workingDataSource[0]).length > 0
|
|
118
|
+
) {
|
|
119
|
+
const inferredColumns = Object.keys(workingDataSource[0]).map(
|
|
120
|
+
(key) => ({
|
|
121
|
+
field: key,
|
|
122
|
+
headerText: key.charAt(0).toUpperCase() + key.slice(1),
|
|
123
|
+
width: 150,
|
|
124
|
+
})
|
|
125
|
+
);
|
|
126
|
+
setWorkingColumns((prevColumns: any) => {
|
|
127
|
+
if (JSON.stringify(prevColumns) !== JSON.stringify(inferredColumns)) {
|
|
128
|
+
return inferredColumns;
|
|
129
|
+
}
|
|
130
|
+
return prevColumns;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}, [columns, workingDataSource]);
|
|
135
|
+
|
|
136
|
+
// *** Page Navigation Helper Methods Starts Here
|
|
137
|
+
const nextPage = () => {
|
|
138
|
+
setCurrentPage((prevPage) => {
|
|
139
|
+
if (prevPage < totalPages - 1) {
|
|
140
|
+
const newPage = prevPage + 1;
|
|
141
|
+
updatePageRange(newPage);
|
|
142
|
+
return newPage;
|
|
143
|
+
}
|
|
144
|
+
return prevPage;
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const prevPage = () => {
|
|
149
|
+
setCurrentPage((prevPage) => {
|
|
150
|
+
if (prevPage > 0) {
|
|
151
|
+
const newPage = prevPage - 1;
|
|
152
|
+
updatePageRange(newPage);
|
|
153
|
+
return newPage;
|
|
154
|
+
}
|
|
155
|
+
return prevPage;
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const goToEndPage = () => {
|
|
160
|
+
const lastPage = totalPages - 1;
|
|
161
|
+
setCurrentPage(lastPage);
|
|
162
|
+
updatePageRange(lastPage);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const goToFirstPage = () => {
|
|
166
|
+
setCurrentPage(0);
|
|
167
|
+
updatePageRange(0);
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const goToPage = (page: number) => {
|
|
171
|
+
setCurrentPage(page);
|
|
172
|
+
updatePageRange(page);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const updatePageRange = (page: number) => {
|
|
176
|
+
const start = Math.floor(page / 10) * 10;
|
|
177
|
+
setPageStart(start);
|
|
178
|
+
setPageEnd(Math.min(start + 10, totalPages));
|
|
179
|
+
};
|
|
180
|
+
// Page Navigation Helper Methods Ends Here ***
|
|
181
|
+
|
|
182
|
+
// *** Functions handling global search starts here
|
|
183
|
+
const handleSearchInput = (e: any) => {
|
|
184
|
+
if (!lazy) {
|
|
185
|
+
const searchValue = e.target.value;
|
|
186
|
+
setSearchParam(searchValue);
|
|
187
|
+
if (searchValue === "") {
|
|
188
|
+
setWorkingDataSource(
|
|
189
|
+
fallbackSourceData.length > 0 ? fallbackSourceData : dataSource
|
|
190
|
+
);
|
|
191
|
+
const fallback =
|
|
192
|
+
fallbackSourceData.length > 0 ? fallbackSourceData : dataSource;
|
|
193
|
+
const totalPages = Math.ceil(fallback.length / pageSettings.pageNumber);
|
|
194
|
+
setTotalPages(totalPages);
|
|
195
|
+
setPageEnd(Math.min(pageStart + 10, totalPages));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handleSearch = (searchParam: string) => {
|
|
201
|
+
const filteredData = workingDataSource.filter((item: any) =>
|
|
202
|
+
Object.values(item).some((val: any) => {
|
|
203
|
+
const trimmedVal = val.toString().toLowerCase().trim();
|
|
204
|
+
const trimmedSearchParam = searchParam.toLowerCase().trim();
|
|
205
|
+
return trimmedVal.includes(trimmedSearchParam);
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
setWorkingDataSource(filteredData);
|
|
209
|
+
const newTotalPages = Math.ceil(
|
|
210
|
+
filteredData.length / pageSettings.pageNumber
|
|
211
|
+
);
|
|
212
|
+
setTotalPages(newTotalPages);
|
|
213
|
+
const newCurrentPage = 0;
|
|
214
|
+
setCurrentPage(newCurrentPage);
|
|
215
|
+
const newPageStart = Math.floor(newCurrentPage / 10) * 10;
|
|
216
|
+
setPageStart(newPageStart);
|
|
217
|
+
setPageEnd(Math.min(newPageStart + 10, newTotalPages));
|
|
218
|
+
};
|
|
219
|
+
// Functions handling global search ends here ***
|
|
220
|
+
|
|
221
|
+
// This will render template passed to Grid
|
|
222
|
+
const renderCell = (rowData: any, column: any, rowIndex: number) => {
|
|
223
|
+
if (column.template) {
|
|
224
|
+
return (
|
|
225
|
+
<column.template
|
|
226
|
+
rowData={rowData}
|
|
227
|
+
rowIndex={rowIndex + currentPage * pageSettings.pageNumber}
|
|
228
|
+
/>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
return rowData[column.field];
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// *** Filter Handling Functions Starts Here
|
|
235
|
+
const toggleFilterPopup = (index: number) => {
|
|
236
|
+
setWorkingColumns((prevColumns: any) =>
|
|
237
|
+
prevColumns.map((column: any, i: any) =>
|
|
238
|
+
i === index
|
|
239
|
+
? { ...column, showFilterPopup: !column.showFilterPopup }
|
|
240
|
+
: column
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Resetting pagination params for updating pagination
|
|
246
|
+
function resetPage(dataSource: any) {
|
|
247
|
+
const newTotalPages = Math.ceil(
|
|
248
|
+
dataSource.length / pageSettings.pageNumber
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
setTotalPages(newTotalPages);
|
|
252
|
+
setCurrentPage(0);
|
|
253
|
+
setPageStart(0);
|
|
254
|
+
setPageEnd(Math.min(10, newTotalPages));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Applying Filter
|
|
258
|
+
function handleApplyFilter(event: any) {
|
|
259
|
+
const {
|
|
260
|
+
columns: updatedColumns,
|
|
261
|
+
workingDataSource: updatedFullDataSource,
|
|
262
|
+
activeFilterArray: updatedActiveFilterArray,
|
|
263
|
+
} = handleApplyFilterHelper(event, columns, workingDataSource);
|
|
264
|
+
|
|
265
|
+
setWorkingColumns(updatedColumns);
|
|
266
|
+
setWorkingDataSource(updatedFullDataSource);
|
|
267
|
+
setActiveFilterArray(updatedActiveFilterArray);
|
|
268
|
+
|
|
269
|
+
setActiveFilterArray(updatedActiveFilterArray);
|
|
270
|
+
resetPage(updatedFullDataSource);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Clearing Filter
|
|
274
|
+
function clearFilter(event: any) {
|
|
275
|
+
const clearDataSource = Array.isArray(dataSource)
|
|
276
|
+
? dataSource
|
|
277
|
+
: fallbackSourceData;
|
|
278
|
+
const {
|
|
279
|
+
columns: updatedColumns,
|
|
280
|
+
workingDataSource: updatedDataSource,
|
|
281
|
+
activeFilterArray: updatedActiveFilterArray,
|
|
282
|
+
} = clearFilterHelper(event, workingColumns, clearDataSource);
|
|
283
|
+
|
|
284
|
+
setWorkingColumns(updatedColumns);
|
|
285
|
+
setWorkingDataSource(updatedDataSource);
|
|
286
|
+
setActiveFilterArray(updatedActiveFilterArray);
|
|
287
|
+
resetPage(updatedDataSource);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const handleFilterAction = (action: any, colIndex: number) => {
|
|
291
|
+
switch (action.type) {
|
|
292
|
+
case "cancel":
|
|
293
|
+
toggleFilterPopup(colIndex);
|
|
294
|
+
break;
|
|
295
|
+
case "applyFilter":
|
|
296
|
+
handleApplyFilter(action);
|
|
297
|
+
break;
|
|
298
|
+
case "clearFilter":
|
|
299
|
+
clearFilter(action);
|
|
300
|
+
break;
|
|
301
|
+
default:
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
// *** Filter Handling Functions Ends Here
|
|
306
|
+
|
|
307
|
+
// *** RowSelection Handling Logic Starts Here
|
|
308
|
+
const handleSelectAll = () => {
|
|
309
|
+
setSelectedRows(workingDataSource);
|
|
310
|
+
if (onSelectRow) onSelectRow(workingDataSource);
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const handleSelect = (rowData: any) => {
|
|
314
|
+
setSelectedRows((prevData) => {
|
|
315
|
+
const isSelected = prevData.includes(rowData);
|
|
316
|
+
let updatedData;
|
|
317
|
+
if (isSelected) {
|
|
318
|
+
updatedData = prevData.filter((item) => item !== rowData);
|
|
319
|
+
} else {
|
|
320
|
+
updatedData = [...prevData, rowData];
|
|
321
|
+
}
|
|
322
|
+
if (onSelectRow) onSelectRow(updatedData);
|
|
323
|
+
return updatedData;
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const isRowSelected = (rowData: any) => {
|
|
328
|
+
return selectedRows.includes(rowData);
|
|
329
|
+
};
|
|
330
|
+
// RowSelection Handling Logic Ends Here ***
|
|
331
|
+
|
|
332
|
+
// Making Grid Functions Accessible in Parent
|
|
333
|
+
useImperativeHandle(ref, () => ({
|
|
334
|
+
goToPage,
|
|
335
|
+
nextPage,
|
|
336
|
+
prevPage,
|
|
337
|
+
goToFirstPage,
|
|
338
|
+
goToEndPage,
|
|
339
|
+
handleSearch,
|
|
340
|
+
handleApplyFilter,
|
|
341
|
+
clearFilter,
|
|
342
|
+
workingDataSource,
|
|
343
|
+
dataSource,
|
|
344
|
+
}));
|
|
345
|
+
|
|
346
|
+
return (
|
|
347
|
+
<div className={gridContainerClass}>
|
|
348
|
+
<React.Fragment>
|
|
349
|
+
{/* Global utility logic */}
|
|
350
|
+
<div
|
|
351
|
+
className={`min-w-full flex justify-between items-center ${
|
|
352
|
+
enableExcelExport || enableSearch || enablePdfExport
|
|
353
|
+
? "block"
|
|
354
|
+
: "hidden"
|
|
355
|
+
}`}
|
|
356
|
+
>
|
|
357
|
+
<div className="flex justify-end gap-2 px-1 py-3 flex-grow">
|
|
358
|
+
{enableExcelExport && (
|
|
359
|
+
<button
|
|
360
|
+
className={gridButtonClass}
|
|
361
|
+
onClick={() => {
|
|
362
|
+
exportToExcelHelper(workingDataSource, columns, excelName);
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
Export as Excel
|
|
366
|
+
</button>
|
|
367
|
+
)}
|
|
368
|
+
{enablePdfExport && (
|
|
369
|
+
<button
|
|
370
|
+
className={gridButtonClass}
|
|
371
|
+
onClick={() => {
|
|
372
|
+
exportToPDFHelper(
|
|
373
|
+
workingDataSource,
|
|
374
|
+
columns,
|
|
375
|
+
pdfName,
|
|
376
|
+
pdfOptions
|
|
377
|
+
);
|
|
378
|
+
}}
|
|
379
|
+
>
|
|
380
|
+
Export as PDF
|
|
381
|
+
</button>
|
|
382
|
+
)}
|
|
383
|
+
{enableSearch && (
|
|
384
|
+
<div className="flex gap-1">
|
|
385
|
+
<input
|
|
386
|
+
type="search"
|
|
387
|
+
value={searchParam}
|
|
388
|
+
onChange={handleSearchInput}
|
|
389
|
+
placeholder="search"
|
|
390
|
+
className="outline-none p-2 text-sm font-normal bg-gray-50 rounded-lg max-sm:hidden dark:bg-black dark:border dark:text-white"
|
|
391
|
+
/>
|
|
392
|
+
<button
|
|
393
|
+
className="bg-white border rounded-lg text-black w-10 flex items-center justify-center dark:bg-black dark:text-white"
|
|
394
|
+
onClick={() => handleSearch(searchParam)}
|
|
395
|
+
>
|
|
396
|
+
<Icon
|
|
397
|
+
elements={search}
|
|
398
|
+
svgClass={"stroke-gray-500 fill-none dark:stroke-white"}
|
|
399
|
+
/>
|
|
400
|
+
</button>
|
|
401
|
+
</div>
|
|
402
|
+
)}
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
<div className="overflow-x-auto">
|
|
407
|
+
<table className="min-w-full">
|
|
408
|
+
<thead>
|
|
409
|
+
<tr>
|
|
410
|
+
{selectAll && (
|
|
411
|
+
<th className="text-left border-b border-t bg-gray-50 px-4 py-4 dark:bg-gray-700 dark:text-white">
|
|
412
|
+
<input type="checkbox" onChange={handleSelectAll} />
|
|
413
|
+
</th>
|
|
414
|
+
)}
|
|
415
|
+
{/* Rendering column headers */}
|
|
416
|
+
{workingColumns.map((columnHeader: any, colIndex: number) => (
|
|
417
|
+
<th
|
|
418
|
+
key={colIndex}
|
|
419
|
+
className={tableHeaderStyle}
|
|
420
|
+
style={{
|
|
421
|
+
width: columnHeader.width
|
|
422
|
+
? `${columnHeader.width}px`
|
|
423
|
+
: "auto",
|
|
424
|
+
}}
|
|
425
|
+
>
|
|
426
|
+
<div className="flex items-center relative">
|
|
427
|
+
{columnHeader.headerText
|
|
428
|
+
? columnHeader.headerText
|
|
429
|
+
: columnHeader.field}
|
|
430
|
+
{columnHeader.filter && !columnHeader.template && (
|
|
431
|
+
<React.Fragment>
|
|
432
|
+
<button
|
|
433
|
+
onClick={() => {
|
|
434
|
+
toggleFilterPopup(colIndex);
|
|
435
|
+
}}
|
|
436
|
+
>
|
|
437
|
+
<Icon
|
|
438
|
+
dimensions={{ width: "12", height: "12" }}
|
|
439
|
+
elements={listFilter}
|
|
440
|
+
svgClass={`ml-2 fill-none dark:stroke-white ${
|
|
441
|
+
activeFilterArray &&
|
|
442
|
+
activeFilterArray.some(
|
|
443
|
+
(filter: any) =>
|
|
444
|
+
filter.filterColumn === columnHeader.field
|
|
445
|
+
)
|
|
446
|
+
? "stroke-red-400"
|
|
447
|
+
: "stroke-black"
|
|
448
|
+
}`}
|
|
449
|
+
/>
|
|
450
|
+
</button>
|
|
451
|
+
<FilterPopup
|
|
452
|
+
show={columnHeader.showFilterPopup}
|
|
453
|
+
columnHeader={columnHeader.field}
|
|
454
|
+
filterAction={(action: any) => {
|
|
455
|
+
handleFilterAction(action, colIndex);
|
|
456
|
+
}}
|
|
457
|
+
/>
|
|
458
|
+
</React.Fragment>
|
|
459
|
+
)}
|
|
460
|
+
</div>
|
|
461
|
+
</th>
|
|
462
|
+
))}
|
|
463
|
+
</tr>
|
|
464
|
+
</thead>
|
|
465
|
+
<tbody>
|
|
466
|
+
{/* rendering body */}
|
|
467
|
+
{workingDataSource.length > 0 && !isFetching ? (
|
|
468
|
+
workingDataSource
|
|
469
|
+
.slice(
|
|
470
|
+
currentPage * pageSettings.pageNumber,
|
|
471
|
+
(currentPage + 1) * pageSettings.pageNumber
|
|
472
|
+
)
|
|
473
|
+
.map((rowData: any, rowIndex: number) => (
|
|
474
|
+
<tr
|
|
475
|
+
key={rowIndex}
|
|
476
|
+
className="hover:bg-gray-50 dark:hover:bg-gray-900 cursor-pointer"
|
|
477
|
+
>
|
|
478
|
+
{selectAll && (
|
|
479
|
+
<td className={gridColumnStyleSelectAll}>
|
|
480
|
+
<input
|
|
481
|
+
type="checkbox"
|
|
482
|
+
checked={isRowSelected(rowData)}
|
|
483
|
+
onChange={() => handleSelect(rowData)}
|
|
484
|
+
/>
|
|
485
|
+
</td>
|
|
486
|
+
)}
|
|
487
|
+
{workingColumns.map((column: any, colIndex: number) => (
|
|
488
|
+
<td
|
|
489
|
+
key={colIndex}
|
|
490
|
+
className={gridColumnStyle}
|
|
491
|
+
style={{
|
|
492
|
+
width: column.width ? `${column.width}px` : "auto",
|
|
493
|
+
}}
|
|
494
|
+
>
|
|
495
|
+
{renderCell(rowData, column, rowIndex)}
|
|
496
|
+
</td>
|
|
497
|
+
))}
|
|
498
|
+
</tr>
|
|
499
|
+
))
|
|
500
|
+
) : (
|
|
501
|
+
<tr>
|
|
502
|
+
<td
|
|
503
|
+
colSpan={workingColumns.length}
|
|
504
|
+
className="text-center p-4 border-b text-sm"
|
|
505
|
+
>
|
|
506
|
+
{isFetching
|
|
507
|
+
? "Fetching Data Please Wait..."
|
|
508
|
+
: "No Data Found"}
|
|
509
|
+
</td>
|
|
510
|
+
</tr>
|
|
511
|
+
)}
|
|
512
|
+
</tbody>
|
|
513
|
+
</table>
|
|
514
|
+
</div>
|
|
515
|
+
{/* Pagination logic */}
|
|
516
|
+
<div className="flex p-2 justify-between dark:text-white">
|
|
517
|
+
<div className="flex gap-4">
|
|
518
|
+
<button
|
|
519
|
+
onClick={goToFirstPage}
|
|
520
|
+
className={`${
|
|
521
|
+
currentPage === 0 ? "text-gray-200 dark:text-gray-700" : ""
|
|
522
|
+
}`}
|
|
523
|
+
>
|
|
524
|
+
<Icon
|
|
525
|
+
elements={leftArrows}
|
|
526
|
+
svgClass={`${
|
|
527
|
+
currentPage === 0
|
|
528
|
+
? "stroke-gray-200 fill-none dark:stroke-gray-700"
|
|
529
|
+
: "stroke-black fill-none dark:stroke-white"
|
|
530
|
+
}`}
|
|
531
|
+
/>
|
|
532
|
+
</button>
|
|
533
|
+
<button onClick={prevPage}>
|
|
534
|
+
<Icon
|
|
535
|
+
elements={leftArrow}
|
|
536
|
+
svgClass={`${
|
|
537
|
+
currentPage === 0
|
|
538
|
+
? "stroke-gray-200 fill-none dark:stroke-gray-700"
|
|
539
|
+
: "stroke-black fill-none dark:stroke-white"
|
|
540
|
+
}`}
|
|
541
|
+
/>
|
|
542
|
+
</button>
|
|
543
|
+
<div className="flex flex-row gap-3 items-center">
|
|
544
|
+
{pageStart > 0 && (
|
|
545
|
+
<button
|
|
546
|
+
className="p-1 w-5 h-5 flex items-center justify-center rounded-full"
|
|
547
|
+
onClick={() => goToPage(pageStart - 1)}
|
|
548
|
+
>
|
|
549
|
+
...
|
|
550
|
+
</button>
|
|
551
|
+
)}
|
|
552
|
+
{workingDataSource.length > 0 &&
|
|
553
|
+
Array.from({ length: pageEnd - pageStart }).map((_, i) => (
|
|
554
|
+
<button
|
|
555
|
+
key={i}
|
|
556
|
+
onClick={() => goToPage(pageStart + i)}
|
|
557
|
+
className={`${
|
|
558
|
+
pageStart + i === currentPage
|
|
559
|
+
? "font-bold text-white p-2 h-6 bg-black flex items-center justify-center rounded-md w-auto dark:bg-white dark:text-black"
|
|
560
|
+
: ""
|
|
561
|
+
}`}
|
|
562
|
+
>
|
|
563
|
+
{pageStart + i + 1}
|
|
564
|
+
</button>
|
|
565
|
+
))}
|
|
566
|
+
{pageEnd < totalPages && (
|
|
567
|
+
<button onClick={() => goToPage(pageEnd)}>...</button>
|
|
568
|
+
)}
|
|
569
|
+
</div>
|
|
570
|
+
<button
|
|
571
|
+
onClick={nextPage}
|
|
572
|
+
className={`${
|
|
573
|
+
currentPage === totalPages - 1 || workingDataSource.length <= 0
|
|
574
|
+
? "text-gray-200 dark:text-gray-700"
|
|
575
|
+
: ""
|
|
576
|
+
}`}
|
|
577
|
+
>
|
|
578
|
+
<Icon
|
|
579
|
+
elements={rightArrow}
|
|
580
|
+
svgClass={`${
|
|
581
|
+
currentPage === totalPages - 1 ||
|
|
582
|
+
workingDataSource.length <= 0
|
|
583
|
+
? "stroke-gray-200 fill-none dark:stroke-gray-700"
|
|
584
|
+
: "stroke-black fill-none dark:stroke-white"
|
|
585
|
+
}`}
|
|
586
|
+
/>
|
|
587
|
+
</button>
|
|
588
|
+
<button
|
|
589
|
+
onClick={goToEndPage}
|
|
590
|
+
className={`${
|
|
591
|
+
currentPage === totalPages - 1 || workingDataSource.length <= 0
|
|
592
|
+
? "text-gray-200 dark:text-gray-700"
|
|
593
|
+
: ""
|
|
594
|
+
}`}
|
|
595
|
+
>
|
|
596
|
+
<Icon
|
|
597
|
+
elements={rightArrows}
|
|
598
|
+
svgClass={`${
|
|
599
|
+
currentPage === totalPages - 1 ||
|
|
600
|
+
workingDataSource.length <= 0
|
|
601
|
+
? "stroke-gray-200 fill-none dark:stroke-gray-700"
|
|
602
|
+
: "stroke-black fill-none dark:stroke-white"
|
|
603
|
+
}`}
|
|
604
|
+
/>
|
|
605
|
+
</button>
|
|
606
|
+
</div>
|
|
607
|
+
<div className="flex text-sm">
|
|
608
|
+
{currentPage + 1} of {totalPages} pages ({workingDataSource.length})
|
|
609
|
+
items
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
</React.Fragment>
|
|
613
|
+
</div>
|
|
614
|
+
);
|
|
615
|
+
});
|