gbs-add-block 0.0.60 → 0.0.61
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/README.md +3 -3
- package/index.js +5 -1
- package/package.json +1 -1
- package/source/components/datagrid/context/GridContext.tsx +419 -0
- package/source/components/datagrid/hooks/GridHooks.tsx +98 -0
- package/source/components/datagrid/index.tsx +26 -0
- package/source/components/datagrid/layout/FilterPopup.tsx +85 -0
- package/source/components/datagrid/layout/GridBody.tsx +313 -0
- package/source/components/datagrid/layout/GridPagination.tsx +228 -0
- package/source/components/datagrid/layout/GridToolbar.tsx +93 -0
- package/source/components/datagrid/layout/index.tsx +76 -0
- package/source/components/datagrid/type.ts +111 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# GBS Building Blocks 2.0 (v0.0.
|
|
1
|
+
# GBS Building Blocks 2.0 (v0.0.61)
|
|
2
2
|
|
|
3
3
|
Latest and upgraded version of GBS building blocks with headless UI and removed dependencies.
|
|
4
4
|
|
|
@@ -6,11 +6,11 @@ Latest and upgraded version of GBS building blocks with headless UI and removed
|
|
|
6
6
|
|
|
7
7
|
For detailed documentation on usage and props, Please visit: [Building Block Documentation v2.0](https://blackmax-designs.gitbook.io/building-block-v2.0)
|
|
8
8
|
|
|
9
|
-
## What's New 🎉 (Ver 0.0.
|
|
9
|
+
## What's New 🎉 (Ver 0.0.61)
|
|
10
10
|
|
|
11
11
|
- Updated for bug fixes.
|
|
12
12
|
- New component "Skeleton" & "Navbar" Added.
|
|
13
|
-
|
|
13
|
+
- Planned Deprecation of Current Grid Component and Adding Beta version for the New Data Grid.
|
|
14
14
|
|
|
15
15
|
## Authors
|
|
16
16
|
|
package/index.js
CHANGED
|
@@ -26,6 +26,7 @@ const CONFIG = {
|
|
|
26
26
|
"ContextMenu",
|
|
27
27
|
"Skeleton",
|
|
28
28
|
"Navbar",
|
|
29
|
+
"DataGrid",
|
|
29
30
|
],
|
|
30
31
|
// Define component dependencies
|
|
31
32
|
dependencies: {
|
|
@@ -95,7 +96,10 @@ const installComponentWithDependencies = async (component, destPath) => {
|
|
|
95
96
|
|
|
96
97
|
if (pendingInstalls.length === 0) {
|
|
97
98
|
console.log(
|
|
98
|
-
`✓ ${component} and all its dependencies are already installed
|
|
99
|
+
`✓ ${component} and all its dependencies are already installed. ${
|
|
100
|
+
component === "Grid" &&
|
|
101
|
+
"This Version of Grid will be deprecated soon. Please Install The New Data Grid Component"
|
|
102
|
+
}`
|
|
99
103
|
);
|
|
100
104
|
return;
|
|
101
105
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
useContext,
|
|
4
|
+
useState,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
} from "react";
|
|
8
|
+
import { getSourceData } from "../../utils";
|
|
9
|
+
import {
|
|
10
|
+
clearFilterHelper,
|
|
11
|
+
handleApplyFilterHelper,
|
|
12
|
+
} from "@grampro/headless-helpers";
|
|
13
|
+
import type { GridProps } from "../type";
|
|
14
|
+
|
|
15
|
+
interface GridContextType {
|
|
16
|
+
workingDataSource: any[];
|
|
17
|
+
fallbackSourceData: any[];
|
|
18
|
+
workingColumns: any[];
|
|
19
|
+
currentPage: number;
|
|
20
|
+
pageStart: number;
|
|
21
|
+
pageEnd: number;
|
|
22
|
+
totalPages: number;
|
|
23
|
+
searchParam: string;
|
|
24
|
+
activeFilterArray: any[];
|
|
25
|
+
selectedRows: any[];
|
|
26
|
+
isFetching: boolean | undefined;
|
|
27
|
+
|
|
28
|
+
// Navigation methods
|
|
29
|
+
nextPage: () => void;
|
|
30
|
+
prevPage: () => void;
|
|
31
|
+
goToEndPage: () => void;
|
|
32
|
+
goToFirstPage: () => void;
|
|
33
|
+
goToPage: (page: number) => void;
|
|
34
|
+
|
|
35
|
+
// Search methods
|
|
36
|
+
handleSearchInput: (e: any) => void;
|
|
37
|
+
handleSearch: (searchParam: string) => void;
|
|
38
|
+
|
|
39
|
+
// Filter methods
|
|
40
|
+
toggleFilterPopup: (index: number) => void;
|
|
41
|
+
handleApplyFilter: (event: any) => void;
|
|
42
|
+
clearFilter: (event: any) => void;
|
|
43
|
+
handleFilterAction: (action: any, colIndex: number) => void;
|
|
44
|
+
|
|
45
|
+
// Row selection methods
|
|
46
|
+
handleSelectAll: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
|
47
|
+
handleSelect: (rowData: any) => void;
|
|
48
|
+
isRowSelected: (rowData: any) => boolean;
|
|
49
|
+
|
|
50
|
+
// Grid settings
|
|
51
|
+
columns: any[];
|
|
52
|
+
pageSettings: any;
|
|
53
|
+
enableSearch: boolean;
|
|
54
|
+
enableExcelExport: boolean;
|
|
55
|
+
enablePdfExport: boolean;
|
|
56
|
+
excelName: string;
|
|
57
|
+
pdfName: string;
|
|
58
|
+
pdfOptions: any;
|
|
59
|
+
gridButtonClass: string;
|
|
60
|
+
selectAll: boolean;
|
|
61
|
+
tableHeaderStyle: string;
|
|
62
|
+
gridContainerClass: string;
|
|
63
|
+
gridColumnStyleSelectAll: string;
|
|
64
|
+
gridColumnStyle: string;
|
|
65
|
+
rowChange: (rowData: any) => void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const GridContext = createContext<GridContextType | undefined>(undefined);
|
|
69
|
+
|
|
70
|
+
export const GridProvider: React.FC<{
|
|
71
|
+
children: React.ReactNode;
|
|
72
|
+
props: GridProps;
|
|
73
|
+
}> = ({ children, props }) => {
|
|
74
|
+
const {
|
|
75
|
+
dataSource,
|
|
76
|
+
columns = [],
|
|
77
|
+
pageSettings,
|
|
78
|
+
enableSearch = false,
|
|
79
|
+
lazy = false,
|
|
80
|
+
enableExcelExport = false,
|
|
81
|
+
excelName = "data",
|
|
82
|
+
enablePdfExport = false,
|
|
83
|
+
pdfName = "data",
|
|
84
|
+
pdfOptions = {},
|
|
85
|
+
gridButtonClass = "px-1 py-2 text-xs rounded bg-zinc-200 dark:bg-zinc-700",
|
|
86
|
+
selectAll = false,
|
|
87
|
+
onSelectRow,
|
|
88
|
+
isFetching,
|
|
89
|
+
tableHeaderStyle = "text-left px-2 py-4 bg-zinc-200 dark:bg-zinc-800",
|
|
90
|
+
gridContainerClass = "flex flex-col min-w-screen rounded-md overflow-hidden",
|
|
91
|
+
gridColumnStyleSelectAll = "px-4 text-xs",
|
|
92
|
+
gridColumnStyle = "p-2 text-xs",
|
|
93
|
+
rowChange = () => {},
|
|
94
|
+
pageStatus = () => {},
|
|
95
|
+
} = props;
|
|
96
|
+
|
|
97
|
+
// States Handling Grid
|
|
98
|
+
const [workingDataSource, setWorkingDataSource] = useState<any>([]);
|
|
99
|
+
const [fallbackSourceData, setFallbackSourceData] = useState([]);
|
|
100
|
+
const [workingColumns, setWorkingColumns] = useState<any>([]);
|
|
101
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
102
|
+
const [pageStart, setPageStart] = useState(0);
|
|
103
|
+
const [pageEnd, setPageEnd] = useState(10);
|
|
104
|
+
const [totalPages, setTotalPages] = useState(0);
|
|
105
|
+
const [searchParam, setSearchParam] = useState("");
|
|
106
|
+
const [activeFilterArray, setActiveFilterArray] = useState<any>([]);
|
|
107
|
+
const [selectedRows, setSelectedRows] = useState<any[]>([]);
|
|
108
|
+
|
|
109
|
+
// This will returns the Page Navigation Status of Grid
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (pageStatus) {
|
|
112
|
+
pageStatus({ currentPage: currentPage, totalPages: totalPages });
|
|
113
|
+
}
|
|
114
|
+
}, [pageStatus, currentPage, totalPages]);
|
|
115
|
+
|
|
116
|
+
// Function to handle API datasource
|
|
117
|
+
const getGridData = useCallback(async () => {
|
|
118
|
+
try {
|
|
119
|
+
const sourceData = await getSourceData(dataSource);
|
|
120
|
+
const gridData = sourceData.sourcedata;
|
|
121
|
+
setFallbackSourceData(gridData);
|
|
122
|
+
setWorkingDataSource(gridData);
|
|
123
|
+
const totalPages = Math.ceil(gridData.length / pageSettings.pageNumber);
|
|
124
|
+
setTotalPages(totalPages);
|
|
125
|
+
setPageEnd(Math.min(10, totalPages));
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error("Error fetching grid source data:", error);
|
|
128
|
+
}
|
|
129
|
+
}, [dataSource, pageSettings.pageNumber]);
|
|
130
|
+
|
|
131
|
+
// Calculates total pages and determine dataSource type
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
const handleDataSource = async () => {
|
|
134
|
+
if (Array.isArray(dataSource) && dataSource.length > 0) {
|
|
135
|
+
setWorkingDataSource(dataSource);
|
|
136
|
+
const totalPages = Math.ceil(
|
|
137
|
+
dataSource.length / pageSettings.pageNumber
|
|
138
|
+
);
|
|
139
|
+
setTotalPages(totalPages);
|
|
140
|
+
setPageEnd(Math.min(10, totalPages));
|
|
141
|
+
} else if (typeof dataSource === "string") {
|
|
142
|
+
await getGridData();
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
handleDataSource();
|
|
147
|
+
}, [dataSource, pageSettings, getGridData]);
|
|
148
|
+
|
|
149
|
+
// Adds Filter Column
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (columns && columns.length > 0) {
|
|
152
|
+
const filteredColumns = columns.map((column) => ({
|
|
153
|
+
...column,
|
|
154
|
+
showFilterPopup: false,
|
|
155
|
+
isFilterActive: false,
|
|
156
|
+
}));
|
|
157
|
+
setWorkingColumns(filteredColumns);
|
|
158
|
+
}
|
|
159
|
+
}, [columns]);
|
|
160
|
+
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (!columns || columns.length === 0) {
|
|
163
|
+
if (
|
|
164
|
+
workingDataSource.length > 0 &&
|
|
165
|
+
Object.keys(workingDataSource[0]).length > 0
|
|
166
|
+
) {
|
|
167
|
+
const inferredColumns = Object.keys(workingDataSource[0]).map(
|
|
168
|
+
(key) => ({
|
|
169
|
+
field: key,
|
|
170
|
+
headerText: key.charAt(0).toUpperCase() + key.slice(1),
|
|
171
|
+
width: 150,
|
|
172
|
+
})
|
|
173
|
+
);
|
|
174
|
+
setWorkingColumns((prevColumns: any) => {
|
|
175
|
+
if (JSON.stringify(prevColumns) !== JSON.stringify(inferredColumns)) {
|
|
176
|
+
return inferredColumns;
|
|
177
|
+
}
|
|
178
|
+
return prevColumns;
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}, [columns, workingDataSource]);
|
|
183
|
+
|
|
184
|
+
// *** Page Navigation Helper Methods
|
|
185
|
+
const updatePageRange = (page: number) => {
|
|
186
|
+
const start = Math.floor(page / 10) * 10;
|
|
187
|
+
setPageStart(start);
|
|
188
|
+
setPageEnd(Math.min(start + 10, totalPages));
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const nextPage = () => {
|
|
192
|
+
setCurrentPage((prevPage) => {
|
|
193
|
+
if (prevPage < totalPages - 1) {
|
|
194
|
+
const newPage = prevPage + 1;
|
|
195
|
+
updatePageRange(newPage);
|
|
196
|
+
return newPage;
|
|
197
|
+
}
|
|
198
|
+
return prevPage;
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const prevPage = () => {
|
|
203
|
+
setCurrentPage((prevPage) => {
|
|
204
|
+
if (prevPage > 0) {
|
|
205
|
+
const newPage = prevPage - 1;
|
|
206
|
+
updatePageRange(newPage);
|
|
207
|
+
return newPage;
|
|
208
|
+
}
|
|
209
|
+
return prevPage;
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const goToEndPage = () => {
|
|
214
|
+
const lastPage = totalPages - 1;
|
|
215
|
+
setCurrentPage(lastPage);
|
|
216
|
+
updatePageRange(lastPage);
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const goToFirstPage = () => {
|
|
220
|
+
setCurrentPage(0);
|
|
221
|
+
updatePageRange(0);
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const goToPage = (page: number) => {
|
|
225
|
+
setCurrentPage(page);
|
|
226
|
+
updatePageRange(page);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
// *** Search Functions
|
|
230
|
+
const handleSearchInput = (e: any) => {
|
|
231
|
+
if (!lazy) {
|
|
232
|
+
const searchValue = e.target.value;
|
|
233
|
+
setSearchParam(searchValue);
|
|
234
|
+
if (searchValue === "") {
|
|
235
|
+
setWorkingDataSource(
|
|
236
|
+
fallbackSourceData.length > 0 ? fallbackSourceData : dataSource
|
|
237
|
+
);
|
|
238
|
+
const fallback =
|
|
239
|
+
fallbackSourceData.length > 0 ? fallbackSourceData : dataSource;
|
|
240
|
+
const totalPages = Math.ceil(fallback.length / pageSettings.pageNumber);
|
|
241
|
+
setTotalPages(totalPages);
|
|
242
|
+
setPageEnd(Math.min(pageStart + 10, totalPages));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const handleSearch = (searchParam: string) => {
|
|
248
|
+
const filteredData = workingDataSource.filter((item: any) =>
|
|
249
|
+
Object.values(item).some((val: any) => {
|
|
250
|
+
const trimmedVal = val.toString().toLowerCase().trim();
|
|
251
|
+
const trimmedSearchParam = searchParam.toLowerCase().trim();
|
|
252
|
+
return trimmedVal.includes(trimmedSearchParam);
|
|
253
|
+
})
|
|
254
|
+
);
|
|
255
|
+
setWorkingDataSource(filteredData);
|
|
256
|
+
resetPage(filteredData);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// *** Filter Functions
|
|
260
|
+
// Resetting pagination params for updating pagination
|
|
261
|
+
function resetPage(dataSource: any) {
|
|
262
|
+
const newTotalPages = Math.ceil(
|
|
263
|
+
dataSource.length / pageSettings.pageNumber
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
setTotalPages(newTotalPages);
|
|
267
|
+
setCurrentPage(0);
|
|
268
|
+
setPageStart(0);
|
|
269
|
+
setPageEnd(Math.min(10, newTotalPages));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const toggleFilterPopup = (index: number) => {
|
|
273
|
+
setWorkingColumns((prevColumns: any) =>
|
|
274
|
+
prevColumns.map((column: any, i: any) =>
|
|
275
|
+
i === index
|
|
276
|
+
? { ...column, showFilterPopup: !column.showFilterPopup }
|
|
277
|
+
: column
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
function handleApplyFilter(event: any) {
|
|
283
|
+
const {
|
|
284
|
+
columns: updatedColumns,
|
|
285
|
+
workingDataSource: updatedFullDataSource,
|
|
286
|
+
activeFilterArray: updatedActiveFilterArray,
|
|
287
|
+
} = handleApplyFilterHelper(event, columns, workingDataSource);
|
|
288
|
+
|
|
289
|
+
setWorkingColumns(updatedColumns);
|
|
290
|
+
setWorkingDataSource(updatedFullDataSource);
|
|
291
|
+
setActiveFilterArray(updatedActiveFilterArray);
|
|
292
|
+
resetPage(updatedFullDataSource);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function clearFilter(event: any) {
|
|
296
|
+
const clearDataSource = Array.isArray(dataSource)
|
|
297
|
+
? dataSource
|
|
298
|
+
: fallbackSourceData;
|
|
299
|
+
const {
|
|
300
|
+
columns: updatedColumns,
|
|
301
|
+
workingDataSource: updatedDataSource,
|
|
302
|
+
activeFilterArray: updatedActiveFilterArray,
|
|
303
|
+
} = clearFilterHelper(event, workingColumns, clearDataSource);
|
|
304
|
+
|
|
305
|
+
setWorkingColumns(updatedColumns);
|
|
306
|
+
setWorkingDataSource(updatedDataSource);
|
|
307
|
+
setActiveFilterArray(updatedActiveFilterArray);
|
|
308
|
+
resetPage(updatedDataSource);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const handleFilterAction = (action: any, colIndex: number) => {
|
|
312
|
+
switch (action.type) {
|
|
313
|
+
case "cancel":
|
|
314
|
+
toggleFilterPopup(colIndex);
|
|
315
|
+
break;
|
|
316
|
+
case "applyFilter":
|
|
317
|
+
handleApplyFilter(action);
|
|
318
|
+
break;
|
|
319
|
+
case "clearFilter":
|
|
320
|
+
clearFilter(action);
|
|
321
|
+
break;
|
|
322
|
+
default:
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// *** Row Selection Functions
|
|
328
|
+
const handleSelectAll = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
329
|
+
const selected = event.target.checked ? workingDataSource : [];
|
|
330
|
+
setSelectedRows(selected);
|
|
331
|
+
onSelectRow?.(selected);
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const handleSelect = (rowData: any) => {
|
|
335
|
+
setSelectedRows((prevData) => {
|
|
336
|
+
const isSelected = prevData.includes(rowData);
|
|
337
|
+
let updatedData;
|
|
338
|
+
if (isSelected) {
|
|
339
|
+
updatedData = prevData.filter((item) => item !== rowData);
|
|
340
|
+
} else {
|
|
341
|
+
updatedData = [...prevData, rowData];
|
|
342
|
+
}
|
|
343
|
+
if (onSelectRow) onSelectRow(updatedData);
|
|
344
|
+
return updatedData;
|
|
345
|
+
});
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const isRowSelected = (rowData: any) => {
|
|
349
|
+
return selectedRows.includes(rowData);
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// Provide context value
|
|
353
|
+
const contextValue: GridContextType = {
|
|
354
|
+
// State
|
|
355
|
+
workingDataSource,
|
|
356
|
+
fallbackSourceData,
|
|
357
|
+
workingColumns,
|
|
358
|
+
currentPage,
|
|
359
|
+
pageStart,
|
|
360
|
+
pageEnd,
|
|
361
|
+
totalPages,
|
|
362
|
+
searchParam,
|
|
363
|
+
activeFilterArray,
|
|
364
|
+
selectedRows,
|
|
365
|
+
isFetching,
|
|
366
|
+
|
|
367
|
+
// Navigation methods
|
|
368
|
+
nextPage,
|
|
369
|
+
prevPage,
|
|
370
|
+
goToEndPage,
|
|
371
|
+
goToFirstPage,
|
|
372
|
+
goToPage,
|
|
373
|
+
|
|
374
|
+
// Search methods
|
|
375
|
+
handleSearchInput,
|
|
376
|
+
handleSearch,
|
|
377
|
+
|
|
378
|
+
// Filter methods
|
|
379
|
+
toggleFilterPopup,
|
|
380
|
+
handleApplyFilter,
|
|
381
|
+
clearFilter,
|
|
382
|
+
handleFilterAction,
|
|
383
|
+
|
|
384
|
+
// Row selection methods
|
|
385
|
+
handleSelectAll,
|
|
386
|
+
handleSelect,
|
|
387
|
+
isRowSelected,
|
|
388
|
+
|
|
389
|
+
// Grid settings
|
|
390
|
+
columns,
|
|
391
|
+
pageSettings,
|
|
392
|
+
enableSearch,
|
|
393
|
+
enableExcelExport,
|
|
394
|
+
enablePdfExport,
|
|
395
|
+
excelName,
|
|
396
|
+
pdfName,
|
|
397
|
+
pdfOptions,
|
|
398
|
+
gridButtonClass,
|
|
399
|
+
selectAll,
|
|
400
|
+
tableHeaderStyle,
|
|
401
|
+
gridContainerClass,
|
|
402
|
+
gridColumnStyleSelectAll,
|
|
403
|
+
gridColumnStyle,
|
|
404
|
+
rowChange,
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
return (
|
|
408
|
+
<GridContext.Provider value={contextValue}>{children}</GridContext.Provider>
|
|
409
|
+
);
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
// Base context hook
|
|
413
|
+
export const useGridContext = () => {
|
|
414
|
+
const context = useContext(GridContext);
|
|
415
|
+
if (context === undefined) {
|
|
416
|
+
throw new Error("useGridContext must be used within a GridProvider");
|
|
417
|
+
}
|
|
418
|
+
return context;
|
|
419
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { useGridContext } from "../context/GridContext";
|
|
2
|
+
|
|
3
|
+
// Hook for pagination functionality
|
|
4
|
+
export const useGridPagination = () => {
|
|
5
|
+
const {
|
|
6
|
+
currentPage,
|
|
7
|
+
pageStart,
|
|
8
|
+
pageEnd,
|
|
9
|
+
totalPages,
|
|
10
|
+
goToFirstPage,
|
|
11
|
+
prevPage,
|
|
12
|
+
goToPage,
|
|
13
|
+
nextPage,
|
|
14
|
+
goToEndPage,
|
|
15
|
+
workingDataSource,
|
|
16
|
+
} = useGridContext();
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
currentPage,
|
|
20
|
+
pageStart,
|
|
21
|
+
pageEnd,
|
|
22
|
+
totalPages,
|
|
23
|
+
goToFirstPage,
|
|
24
|
+
prevPage,
|
|
25
|
+
goToPage,
|
|
26
|
+
nextPage,
|
|
27
|
+
goToEndPage,
|
|
28
|
+
workingDataSource,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Hook for grid search functionality
|
|
33
|
+
export const useGridSearch = () => {
|
|
34
|
+
const { searchParam, handleSearchInput, handleSearch, enableSearch } =
|
|
35
|
+
useGridContext();
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
searchParam,
|
|
39
|
+
handleSearchInput,
|
|
40
|
+
handleSearch,
|
|
41
|
+
enableSearch,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Hook for grid filter functionality
|
|
46
|
+
export const useGridFilter = () => {
|
|
47
|
+
const {
|
|
48
|
+
workingColumns,
|
|
49
|
+
activeFilterArray,
|
|
50
|
+
toggleFilterPopup,
|
|
51
|
+
handleFilterAction,
|
|
52
|
+
} = useGridContext();
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
workingColumns,
|
|
56
|
+
activeFilterArray,
|
|
57
|
+
toggleFilterPopup,
|
|
58
|
+
handleFilterAction,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// Hook for row selection
|
|
63
|
+
export const useGridRowSelection = () => {
|
|
64
|
+
const { selectAll, handleSelectAll, handleSelect, isRowSelected } =
|
|
65
|
+
useGridContext();
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
selectAll,
|
|
69
|
+
handleSelectAll,
|
|
70
|
+
handleSelect,
|
|
71
|
+
isRowSelected,
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Hook for export functionality
|
|
76
|
+
export const useGridExport = () => {
|
|
77
|
+
const {
|
|
78
|
+
enableExcelExport,
|
|
79
|
+
enablePdfExport,
|
|
80
|
+
workingDataSource,
|
|
81
|
+
columns,
|
|
82
|
+
excelName,
|
|
83
|
+
pdfName,
|
|
84
|
+
pdfOptions,
|
|
85
|
+
gridButtonClass,
|
|
86
|
+
} = useGridContext();
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
enableExcelExport,
|
|
90
|
+
enablePdfExport,
|
|
91
|
+
workingDataSource,
|
|
92
|
+
columns,
|
|
93
|
+
excelName,
|
|
94
|
+
pdfName,
|
|
95
|
+
pdfOptions,
|
|
96
|
+
gridButtonClass,
|
|
97
|
+
};
|
|
98
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
* Here We Will Re-Render Grid as a Memoized Component For Better Performance.
|
|
7
|
+
* Extended Documentation for Grid can be found at
|
|
8
|
+
* https://psychedelic-step-e70.notion.site/Data-GRID-by-GBS-R-D-20ff97c899d24bc590215a6196435fa3
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { GridMemoised as GridComponent } from "./layout";
|
|
12
|
+
import React, { memo } from "react";
|
|
13
|
+
|
|
14
|
+
const Grid = memo(GridComponent, (prevProps, nextProps) => {
|
|
15
|
+
// Custom comparison function
|
|
16
|
+
return (
|
|
17
|
+
prevProps.dataSource === nextProps.dataSource &&
|
|
18
|
+
prevProps.columns === nextProps.columns &&
|
|
19
|
+
prevProps.pageSettings.pageNumber === nextProps.pageSettings.pageNumber &&
|
|
20
|
+
prevProps.enableSearch === nextProps.enableSearch &&
|
|
21
|
+
prevProps.enablePdfExport === nextProps.enablePdfExport &&
|
|
22
|
+
prevProps.enableExcelExport === nextProps.enableExcelExport
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export { Grid };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
|
|
4
|
+
export default function FilterPopup({ show, columnHeader, filterAction }: any) {
|
|
5
|
+
const [filterValue, setFilterValue] = useState("");
|
|
6
|
+
const [filterType, setFilterType] = useState("contains");
|
|
7
|
+
const [isFilterActive, setIsFilterActive] = useState(false);
|
|
8
|
+
|
|
9
|
+
const handleFilterInput = (e: any) => {
|
|
10
|
+
const filterKeyword = e.target.value;
|
|
11
|
+
setFilterValue(filterKeyword);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const onCancel = () => {
|
|
15
|
+
filterAction({ type: "cancel" });
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const applyFilter = () => {
|
|
19
|
+
filterAction({
|
|
20
|
+
type: "applyFilter",
|
|
21
|
+
filterValue,
|
|
22
|
+
filterType,
|
|
23
|
+
columnHeader,
|
|
24
|
+
});
|
|
25
|
+
show = false;
|
|
26
|
+
setIsFilterActive(true);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const clearFilter = () => {
|
|
30
|
+
setIsFilterActive(false);
|
|
31
|
+
filterAction({ type: "clearFilter", columnHeader });
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
show && (
|
|
36
|
+
<div
|
|
37
|
+
className="absolute bg-gray-100 p-2 text-xs z-50 mt-48 flex flex-col shadow-lg gap-2 rounded-md dark:bg-zinc-700"
|
|
38
|
+
role="dialog"
|
|
39
|
+
>
|
|
40
|
+
<select
|
|
41
|
+
name={`${columnHeader}-filter`}
|
|
42
|
+
id={`${columnHeader}-filter-id`}
|
|
43
|
+
className="w-full p-2 rounded-lg bg-gray-200 outline-none dark:bg-gray-600"
|
|
44
|
+
value={filterType}
|
|
45
|
+
onChange={(e: any) => {
|
|
46
|
+
setFilterType(e.target.value);
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<option value="contains">Contains</option>
|
|
50
|
+
<option value="starts_with">Starts With</option>
|
|
51
|
+
<option value="ends_with">Ends With</option>
|
|
52
|
+
</select>
|
|
53
|
+
<input
|
|
54
|
+
type="text"
|
|
55
|
+
placeholder="Enter filter value"
|
|
56
|
+
className="rounded-lg p-2 text-xs bg-gray-200 outline-none dark:bg-gray-600"
|
|
57
|
+
value={filterValue}
|
|
58
|
+
onInput={handleFilterInput}
|
|
59
|
+
/>
|
|
60
|
+
<div className="mt-2 flex space-x-1">
|
|
61
|
+
<button
|
|
62
|
+
className="text-xs bg-red-600 text-white px-2 py-0.5 rounded-lg hover:bg-red-600"
|
|
63
|
+
onClick={onCancel}
|
|
64
|
+
>
|
|
65
|
+
Cancel
|
|
66
|
+
</button>
|
|
67
|
+
{isFilterActive && (
|
|
68
|
+
<button
|
|
69
|
+
className="text-xs bg-black text-white px-2 py-0.5 rounded-lg dark:bg-white dark:text-black"
|
|
70
|
+
onClick={clearFilter}
|
|
71
|
+
>
|
|
72
|
+
Clear Filter
|
|
73
|
+
</button>
|
|
74
|
+
)}
|
|
75
|
+
<button
|
|
76
|
+
className="text-xs bg-black text-white px-2 py-0.5 rounded-lg dark:bg-white dark:text-black"
|
|
77
|
+
onClick={applyFilter}
|
|
78
|
+
>
|
|
79
|
+
Apply Filter
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
}
|