pf-common-components 1.0.0
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/components.json +17 -0
- package/dist/assets/Arrow.d.ts +7 -0
- package/dist/assets/Arrow.js +5 -0
- package/dist/assets/CalenderIcon.d.ts +2 -0
- package/dist/assets/CalenderIcon.js +5 -0
- package/dist/assets/ClearAll.d.ts +2 -0
- package/dist/assets/ClearAll.js +5 -0
- package/dist/assets/CrossIcon.d.ts +8 -0
- package/dist/assets/CrossIcon.js +7 -0
- package/dist/assets/DropDown.d.ts +4 -0
- package/dist/assets/DropDown.js +5 -0
- package/dist/global.css +3213 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +25 -0
- package/dist/lib/CommonComponentsUtil.d.ts +7 -0
- package/dist/lib/CommonComponentsUtil.js +22 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +5 -0
- package/dist/ui/BaseTable.d.ts +132 -0
- package/dist/ui/BaseTable.js +330 -0
- package/dist/ui/DateCalendar.d.ts +10 -0
- package/dist/ui/DateCalendar.js +47 -0
- package/dist/ui/DateField.d.ts +35 -0
- package/dist/ui/DateField.js +37 -0
- package/dist/ui/DateOfBirthSelector.d.ts +16 -0
- package/dist/ui/DateOfBirthSelector.js +42 -0
- package/dist/ui/DateRangePicker.d.ts +8 -0
- package/dist/ui/DateRangePicker.js +73 -0
- package/dist/ui/DobCalendar.d.ts +17 -0
- package/dist/ui/DobCalendar.js +86 -0
- package/dist/ui/Formfield.d.ts +12 -0
- package/dist/ui/Formfield.js +36 -0
- package/dist/ui/GetScrollAlert.d.ts +9 -0
- package/dist/ui/GetScrollAlert.js +37 -0
- package/dist/ui/RadioGroupContext/RadioGroupContext.d.ts +8 -0
- package/dist/ui/RadioGroupContext/RadioGroupContext.js +11 -0
- package/dist/ui/SelectCommand.d.ts +69 -0
- package/dist/ui/SelectCommand.js +260 -0
- package/dist/ui/SlashIcon.d.ts +2 -0
- package/dist/ui/SlashIcon.js +5 -0
- package/dist/ui/SortingArrows.d.ts +11 -0
- package/dist/ui/SortingArrows.js +11 -0
- package/dist/ui/TextTags.d.ts +39 -0
- package/dist/ui/TextTags.js +73 -0
- package/dist/ui/accordion.d.ts +10 -0
- package/dist/ui/accordion.js +77 -0
- package/dist/ui/alert-dialog.d.ts +20 -0
- package/dist/ui/alert-dialog.js +62 -0
- package/dist/ui/alert.d.ts +8 -0
- package/dist/ui/alert.js +42 -0
- package/dist/ui/avatar.d.ts +6 -0
- package/dist/ui/avatar.js +32 -0
- package/dist/ui/badge.d.ts +10 -0
- package/dist/ui/badge.js +58 -0
- package/dist/ui/button.d.ts +12 -0
- package/dist/ui/button.js +54 -0
- package/dist/ui/calendar.d.ts +8 -0
- package/dist/ui/calendar.js +45 -0
- package/dist/ui/card.d.ts +8 -0
- package/dist/ui/card.js +45 -0
- package/dist/ui/checkbox.d.ts +12 -0
- package/dist/ui/checkbox.js +44 -0
- package/dist/ui/command.d.ts +47 -0
- package/dist/ui/command.js +67 -0
- package/dist/ui/dialog.d.ts +31 -0
- package/dist/ui/dialog.js +57 -0
- package/dist/ui/dropdown-menu.d.ts +27 -0
- package/dist/ui/dropdown-menu.js +72 -0
- package/dist/ui/form.d.ts +23 -0
- package/dist/ui/form.js +72 -0
- package/dist/ui/hover-card.d.ts +7 -0
- package/dist/ui/hover-card.js +29 -0
- package/dist/ui/input.d.ts +3 -0
- package/dist/ui/input.js +20 -0
- package/dist/ui/label.d.ts +5 -0
- package/dist/ui/label.js +24 -0
- package/dist/ui/multi-select.d.ts +44 -0
- package/dist/ui/multi-select.js +191 -0
- package/dist/ui/navigation-menu.d.ts +11 -0
- package/dist/ui/navigation-menu.js +69 -0
- package/dist/ui/popover.d.ts +6 -0
- package/dist/ui/popover.js +24 -0
- package/dist/ui/radio-group.d.ts +7 -0
- package/dist/ui/radio-group.js +40 -0
- package/dist/ui/radioButtonCard.d.ts +9 -0
- package/dist/ui/radioButtonCard.js +23 -0
- package/dist/ui/scroll-area.d.ts +5 -0
- package/dist/ui/scroll-area.js +29 -0
- package/dist/ui/select.d.ts +57 -0
- package/dist/ui/select.js +148 -0
- package/dist/ui/separator.d.ts +4 -0
- package/dist/ui/separator.js +22 -0
- package/dist/ui/sheet.d.ts +25 -0
- package/dist/ui/sheet.js +65 -0
- package/dist/ui/switch.d.ts +10 -0
- package/dist/ui/switch.js +47 -0
- package/dist/ui/table.d.ts +10 -0
- package/dist/ui/table.js +55 -0
- package/dist/ui/tabs.d.ts +7 -0
- package/dist/ui/tabs.js +33 -0
- package/dist/ui/text.d.ts +11 -0
- package/dist/ui/text.js +45 -0
- package/dist/ui/textarea.d.ts +7 -0
- package/dist/ui/textarea.js +21 -0
- package/dist/ui/tooltip.d.ts +11 -0
- package/dist/ui/tooltip.js +26 -0
- package/package.json +123 -0
- package/postcss.config.js +6 -0
- package/src/assets/Arrow.js +5 -0
- package/src/assets/Arrow.tsx +25 -0
- package/src/assets/CalenderIcon.js +5 -0
- package/src/assets/CalenderIcon.tsx +28 -0
- package/src/assets/ClearAll.js +5 -0
- package/src/assets/ClearAll.tsx +20 -0
- package/src/assets/CrossIcon.js +7 -0
- package/src/assets/CrossIcon.tsx +34 -0
- package/src/assets/DropDown.js +5 -0
- package/src/assets/DropDown.tsx +23 -0
- package/src/global.css +560 -0
- package/src/index.ts +34 -0
- package/src/lib/CommonComponentsUtil.js +22 -0
- package/src/lib/CommonComponentsUtil.ts +30 -0
- package/src/lib/utils.js +5 -0
- package/src/lib/utils.ts +6 -0
- package/src/ui/BaseTable.js +330 -0
- package/src/ui/BaseTable.tsx +987 -0
- package/src/ui/DateCalendar.js +47 -0
- package/src/ui/DateCalendar.tsx +111 -0
- package/src/ui/DateField.js +37 -0
- package/src/ui/DateField.tsx +142 -0
- package/src/ui/DateOfBirthSelector.js +42 -0
- package/src/ui/DateOfBirthSelector.tsx +114 -0
- package/src/ui/DateRangePicker.js +73 -0
- package/src/ui/DateRangePicker.tsx +174 -0
- package/src/ui/DobCalendar.js +86 -0
- package/src/ui/DobCalendar.tsx +172 -0
- package/src/ui/Formfield.js +36 -0
- package/src/ui/Formfield.tsx +55 -0
- package/src/ui/GetScrollAlert.js +37 -0
- package/src/ui/GetScrollAlert.tsx +59 -0
- package/src/ui/RadioGroupContext/RadioGroupContext.js +11 -0
- package/src/ui/RadioGroupContext/RadioGroupContext.tsx +21 -0
- package/src/ui/SelectCommand.js +260 -0
- package/src/ui/SelectCommand.tsx +587 -0
- package/src/ui/SlashIcon.js +5 -0
- package/src/ui/SlashIcon.tsx +22 -0
- package/src/ui/SortingArrows.js +11 -0
- package/src/ui/SortingArrows.tsx +29 -0
- package/src/ui/TextTags.js +73 -0
- package/src/ui/TextTags.tsx +149 -0
- package/src/ui/accordion.js +77 -0
- package/src/ui/accordion.tsx +129 -0
- package/src/ui/alert-dialog.js +62 -0
- package/src/ui/alert-dialog.tsx +141 -0
- package/src/ui/alert.js +42 -0
- package/src/ui/alert.tsx +59 -0
- package/src/ui/avatar.js +32 -0
- package/src/ui/avatar.tsx +50 -0
- package/src/ui/badge.js +58 -0
- package/src/ui/badge.tsx +66 -0
- package/src/ui/button.js +54 -0
- package/src/ui/button.tsx +89 -0
- package/src/ui/calendar.js +45 -0
- package/src/ui/calendar.tsx +88 -0
- package/src/ui/card.js +45 -0
- package/src/ui/card.tsx +83 -0
- package/src/ui/checkbox.js +44 -0
- package/src/ui/checkbox.tsx +56 -0
- package/src/ui/command.js +67 -0
- package/src/ui/command.tsx +166 -0
- package/src/ui/dialog.js +57 -0
- package/src/ui/dialog.tsx +154 -0
- package/src/ui/dropdown-menu.js +72 -0
- package/src/ui/dropdown-menu.tsx +200 -0
- package/src/ui/form.js +72 -0
- package/src/ui/form.tsx +177 -0
- package/src/ui/hover-card.js +29 -0
- package/src/ui/hover-card.tsx +63 -0
- package/src/ui/input.js +20 -0
- package/src/ui/input.tsx +22 -0
- package/src/ui/label.js +24 -0
- package/src/ui/label.tsx +26 -0
- package/src/ui/multi-select.js +191 -0
- package/src/ui/multi-select.tsx +518 -0
- package/src/ui/navigation-menu.js +69 -0
- package/src/ui/navigation-menu.tsx +139 -0
- package/src/ui/popover.js +24 -0
- package/src/ui/popover.tsx +31 -0
- package/src/ui/radio-group.js +40 -0
- package/src/ui/radio-group.tsx +97 -0
- package/src/ui/radioButtonCard.js +23 -0
- package/src/ui/radioButtonCard.tsx +57 -0
- package/src/ui/scroll-area.js +29 -0
- package/src/ui/scroll-area.tsx +48 -0
- package/src/ui/select.js +148 -0
- package/src/ui/select.tsx +343 -0
- package/src/ui/separator.js +22 -0
- package/src/ui/separator.tsx +31 -0
- package/src/ui/sheet.js +65 -0
- package/src/ui/sheet.tsx +136 -0
- package/src/ui/switch.js +47 -0
- package/src/ui/switch.tsx +60 -0
- package/src/ui/table.js +55 -0
- package/src/ui/table.tsx +112 -0
- package/src/ui/tabs.js +33 -0
- package/src/ui/tabs.tsx +55 -0
- package/src/ui/text.js +45 -0
- package/src/ui/text.tsx +49 -0
- package/src/ui/textarea.js +21 -0
- package/src/ui/textarea.tsx +28 -0
- package/src/ui/tooltip.js +26 -0
- package/src/ui/tooltip.tsx +54 -0
- package/tailwind.config.js +214 -0
- package/tsconfig.json +35 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,987 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ColumnDef,
|
|
5
|
+
RowSelectionState,
|
|
6
|
+
SortingState,
|
|
7
|
+
VisibilityState,
|
|
8
|
+
flexRender,
|
|
9
|
+
getCoreRowModel,
|
|
10
|
+
useReactTable,
|
|
11
|
+
} from "@tanstack/react-table";
|
|
12
|
+
import {Text} from '../ui/text'
|
|
13
|
+
import {
|
|
14
|
+
Table,
|
|
15
|
+
TableBody,
|
|
16
|
+
TableCell,
|
|
17
|
+
TableHead,
|
|
18
|
+
TableHeader,
|
|
19
|
+
TableRow,
|
|
20
|
+
} from "../ui/table";
|
|
21
|
+
|
|
22
|
+
import ClearAll from "../assets/ClearAll";
|
|
23
|
+
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
24
|
+
import React, { useEffect, useRef, useState } from "react";
|
|
25
|
+
import { Button } from "../ui/button";
|
|
26
|
+
import { Checkbox } from "../ui/checkbox";
|
|
27
|
+
import {
|
|
28
|
+
DropdownMenu,
|
|
29
|
+
DropdownMenuContent,
|
|
30
|
+
DropdownMenuTrigger,
|
|
31
|
+
} from "../ui/dropdown-menu";
|
|
32
|
+
import {
|
|
33
|
+
Select,
|
|
34
|
+
SelectContent,
|
|
35
|
+
SelectItem,
|
|
36
|
+
SelectTrigger,
|
|
37
|
+
SelectValue,
|
|
38
|
+
} from "../ui/select";
|
|
39
|
+
|
|
40
|
+
import DropDown from "../assets/DropDown"
|
|
41
|
+
import { useTranslation } from "next-i18next";
|
|
42
|
+
import { debounce } from "lodash";
|
|
43
|
+
interface IBaseTable<TData, TValue> {
|
|
44
|
+
/**
|
|
45
|
+
* Columns defined for the table
|
|
46
|
+
*/
|
|
47
|
+
columns: ColumnDef<TData, TValue>[];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Array of data objects to be displayed in the table
|
|
51
|
+
*/
|
|
52
|
+
data: TData[];
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Additional CSS classes to apply to the table
|
|
56
|
+
*/
|
|
57
|
+
tableStyles?: {
|
|
58
|
+
/**
|
|
59
|
+
* Additional CSS classes to pass to the table container
|
|
60
|
+
*/
|
|
61
|
+
table?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Additional CSS classes to pass to each row
|
|
64
|
+
*/
|
|
65
|
+
rowStyles?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Additional CSS classes to pass to table container
|
|
68
|
+
*/
|
|
69
|
+
tableContainer?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Additional CSS classes to pass to table header
|
|
72
|
+
*/
|
|
73
|
+
tableHeader?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Additional Css classes to pass to each cell in the table header
|
|
76
|
+
*/
|
|
77
|
+
tableHeaderCell?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Additional Css classes to pass to each cell in the table body
|
|
80
|
+
*/
|
|
81
|
+
tableBodyCell?: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* When there are no results then we have to show this placeholder
|
|
85
|
+
*/
|
|
86
|
+
noRecordsPlaceholder?: string;
|
|
87
|
+
/**
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Function to update the current page number
|
|
91
|
+
*/
|
|
92
|
+
setCurrent?: (value: React.SetStateAction<number>) => void;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* The current page
|
|
96
|
+
*/
|
|
97
|
+
current?: number;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Total number of pages
|
|
101
|
+
*/
|
|
102
|
+
pageCount?: number;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Function to update the page size
|
|
106
|
+
*/
|
|
107
|
+
setPageSize?: (value: React.SetStateAction<number>) => void;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Number of items to display per page
|
|
111
|
+
*/
|
|
112
|
+
pageSize?: number;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Total number of items in the dataset
|
|
116
|
+
*/
|
|
117
|
+
total?: number;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Flag to indicate whether pagination controls should be displayed
|
|
121
|
+
*/
|
|
122
|
+
pagination?: boolean;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Flag to indicate whether checkboxes should be displayed
|
|
126
|
+
*/
|
|
127
|
+
checkboxSelection?: boolean;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Flag to indicate whether sticky coulmns should be displayed
|
|
131
|
+
*/
|
|
132
|
+
columnPinning?: boolean;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* It is used to send the default columns to be selected
|
|
136
|
+
*/
|
|
137
|
+
defaultColumns?: string[];
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Row selection state
|
|
141
|
+
*/
|
|
142
|
+
rowSelection?: RowSelectionState;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Function to update the row selection state to track the selected rows
|
|
146
|
+
*/
|
|
147
|
+
setRowSelection?: (value: React.SetStateAction<RowSelectionState>) => void;
|
|
148
|
+
/**
|
|
149
|
+
* Flag to indicate whether the column selector need to be displayed or not
|
|
150
|
+
*/
|
|
151
|
+
columnSelector?: boolean;
|
|
152
|
+
|
|
153
|
+
setSorting?: any;
|
|
154
|
+
|
|
155
|
+
sorting?: SortingState;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* This variable is used to display the loader in middle of the page and while filtering ideally we dont need to click anything
|
|
159
|
+
*/
|
|
160
|
+
isFiltering?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* This variable is used to disabled the horizontal scrolling.
|
|
163
|
+
*/
|
|
164
|
+
noScroll?: boolean;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* This variable is used pass action component if any. E.g: Bulk Actions in participant listing home page.
|
|
168
|
+
*/
|
|
169
|
+
actionComponent?: React.ReactNode;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* This variable is used to pass the columns preferences selected by the logged in user
|
|
173
|
+
*/
|
|
174
|
+
userColumnPreferences?: { [key: string]: boolean } | null;
|
|
175
|
+
|
|
176
|
+
tableContainerId?: string;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Function to update the columns selected and applied by the user
|
|
180
|
+
*/
|
|
181
|
+
handleUserColumnPreferences?: (
|
|
182
|
+
userColumnPreferences: { [key: string]: boolean } | null
|
|
183
|
+
) => void;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* This is used to export the table for export excel and csv functionality
|
|
187
|
+
*/
|
|
188
|
+
tableId?: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function BaseTable<TData, TValue>({
|
|
192
|
+
columns,
|
|
193
|
+
data,
|
|
194
|
+
tableStyles,
|
|
195
|
+
current,
|
|
196
|
+
setCurrent = () => {},
|
|
197
|
+
pageCount,
|
|
198
|
+
total = 0,
|
|
199
|
+
setPageSize = () => {},
|
|
200
|
+
pageSize = 0,
|
|
201
|
+
pagination = false,
|
|
202
|
+
checkboxSelection,
|
|
203
|
+
columnPinning = false,
|
|
204
|
+
defaultColumns = [],
|
|
205
|
+
rowSelection,
|
|
206
|
+
setRowSelection,
|
|
207
|
+
columnSelector,
|
|
208
|
+
sorting,
|
|
209
|
+
setSorting,
|
|
210
|
+
noRecordsPlaceholder = "No results",
|
|
211
|
+
isFiltering = false,
|
|
212
|
+
noScroll,
|
|
213
|
+
actionComponent,
|
|
214
|
+
userColumnPreferences,
|
|
215
|
+
tableContainerId = "base-table-container",
|
|
216
|
+
handleUserColumnPreferences,
|
|
217
|
+
tableId = "",
|
|
218
|
+
}: IBaseTable<TData, TValue>) {
|
|
219
|
+
// Initial visibility state for column selector
|
|
220
|
+
const initialColumnVisibilityChanges: { [key: string]: boolean } =
|
|
221
|
+
columns.reduce(
|
|
222
|
+
(acc: Record<string, boolean>, { accessorKey, enableHiding }: any) => {
|
|
223
|
+
if (accessorKey) {
|
|
224
|
+
// Determine initial visibility for the current column
|
|
225
|
+
acc[accessorKey] =
|
|
226
|
+
// If the defaultColumns array is empty or includes the current column's accessorKey, set visibility to true
|
|
227
|
+
defaultColumns.length === 0 || defaultColumns.includes(accessorKey)
|
|
228
|
+
? true
|
|
229
|
+
: // If enableHiding is true for the current column, set visibility to false, otherwise set it to true
|
|
230
|
+
enableHiding
|
|
231
|
+
? false
|
|
232
|
+
: true;
|
|
233
|
+
}
|
|
234
|
+
return acc;
|
|
235
|
+
},
|
|
236
|
+
{}
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const [columnVisibility, setColumnVisibility] =
|
|
240
|
+
React.useState<VisibilityState>(
|
|
241
|
+
userColumnPreferences
|
|
242
|
+
? userColumnPreferences
|
|
243
|
+
: initialColumnVisibilityChanges
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
//Local state for column selector to apply chnages when we click on apply button
|
|
247
|
+
const [columnVisibilityChanges, setColumnVisibilityChanges] =
|
|
248
|
+
useState<VisibilityState>(
|
|
249
|
+
userColumnPreferences
|
|
250
|
+
? userColumnPreferences
|
|
251
|
+
: initialColumnVisibilityChanges
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
// whenever userColumnPreferences get changed we need to update the values of those columns
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (userColumnPreferences) {
|
|
257
|
+
setColumnVisibility(userColumnPreferences as VisibilityState);
|
|
258
|
+
setColumnVisibilityChanges(userColumnPreferences as VisibilityState);
|
|
259
|
+
}
|
|
260
|
+
}, [userColumnPreferences]);
|
|
261
|
+
|
|
262
|
+
//initial state for select all checkbox
|
|
263
|
+
const initialSelectAll =
|
|
264
|
+
Object.keys(columnVisibilityChanges).length > 0 &&
|
|
265
|
+
Object.values(columnVisibilityChanges).every(Boolean);
|
|
266
|
+
|
|
267
|
+
const [selectAll, setSelectAll] = useState(initialSelectAll);
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @function getRowId
|
|
271
|
+
* @description this function return id if the row have the id else it will return the index as id
|
|
272
|
+
* @param originalRow
|
|
273
|
+
* @param index
|
|
274
|
+
* @returns index in string format
|
|
275
|
+
*/
|
|
276
|
+
const getRowId = (originalRow: any, index: number) => {
|
|
277
|
+
if (checkboxSelection) {
|
|
278
|
+
return originalRow.id.toString();
|
|
279
|
+
} else {
|
|
280
|
+
return index.toString();
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
// table hook
|
|
284
|
+
const table = useReactTable({
|
|
285
|
+
data,
|
|
286
|
+
columns: columns,
|
|
287
|
+
enableSortingRemoval: true,
|
|
288
|
+
sortDescFirst: false,
|
|
289
|
+
getCoreRowModel: getCoreRowModel(),
|
|
290
|
+
// getPaginationRowModel: getPaginationRowModel(),
|
|
291
|
+
manualPagination: true,
|
|
292
|
+
onColumnVisibilityChange: setColumnVisibility,
|
|
293
|
+
onRowSelectionChange: setRowSelection,
|
|
294
|
+
getRowId,
|
|
295
|
+
manualSorting: true,
|
|
296
|
+
state: {
|
|
297
|
+
columnVisibility,
|
|
298
|
+
rowSelection,
|
|
299
|
+
sorting,
|
|
300
|
+
},
|
|
301
|
+
onSortingChange: setSorting,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Function to handle the select all checkbox changes
|
|
306
|
+
*/
|
|
307
|
+
const handleSelectAllChange = (checked: boolean) => {
|
|
308
|
+
setSelectAll(checked);
|
|
309
|
+
|
|
310
|
+
const newColumnVisibilityChanges: VisibilityState = {};
|
|
311
|
+
|
|
312
|
+
//Logic for not uncheck the columns which cannot be hidden they should be always true
|
|
313
|
+
Object.keys(columnVisibilityChanges).forEach((columnId) => {
|
|
314
|
+
const column = columns?.find(
|
|
315
|
+
(column: any) => column.accessorKey === columnId
|
|
316
|
+
);
|
|
317
|
+
const canHide = column?.enableHiding;
|
|
318
|
+
newColumnVisibilityChanges[columnId] = canHide === false ? true : checked;
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
setColumnVisibilityChanges(newColumnVisibilityChanges);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* function to handle the columns in column selector
|
|
326
|
+
*/
|
|
327
|
+
const handleColumnVisibilityChange = (
|
|
328
|
+
columnId: string,
|
|
329
|
+
isVisible: boolean
|
|
330
|
+
) => {
|
|
331
|
+
setColumnVisibilityChanges((prevState) => ({
|
|
332
|
+
...prevState,
|
|
333
|
+
[columnId]: isVisible,
|
|
334
|
+
}));
|
|
335
|
+
|
|
336
|
+
// when i uncheck the individual check box we need to see if all checkboxes or checked or not and we have to update the select all
|
|
337
|
+
const allChecked = Object.values({
|
|
338
|
+
...columnVisibilityChanges,
|
|
339
|
+
[columnId]: isVisible,
|
|
340
|
+
}).every(Boolean);
|
|
341
|
+
setSelectAll(allChecked);
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* function to handle the columns in column selector
|
|
346
|
+
*/
|
|
347
|
+
const applyColumnVisibilityChanges = () => {
|
|
348
|
+
table.setColumnVisibility(columnVisibilityChanges);
|
|
349
|
+
handleUserColumnPreferences?.(columnVisibilityChanges);
|
|
350
|
+
setOpen(false);
|
|
351
|
+
|
|
352
|
+
requestAnimationFrame(() => {
|
|
353
|
+
handleScroll(); // Recalculate scroll position after layout change
|
|
354
|
+
});
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* functions to clear the columns in column selector
|
|
359
|
+
*/
|
|
360
|
+
const clearColumnVisibilityChanges = () => {
|
|
361
|
+
const finalColumnVisibilityChanges = columns.reduce(
|
|
362
|
+
(acc: Record<string, boolean>, column: any) => {
|
|
363
|
+
//When clearing we need to make sure that columns which are not been hidden need to be true always
|
|
364
|
+
if (column.accessorKey) {
|
|
365
|
+
if (column.enableHiding == false) {
|
|
366
|
+
acc[column.accessorKey] = true;
|
|
367
|
+
} else {
|
|
368
|
+
acc[column.accessorKey] = false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return acc;
|
|
372
|
+
},
|
|
373
|
+
{}
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
setColumnVisibilityChanges(finalColumnVisibilityChanges);
|
|
377
|
+
setColumnVisibility(finalColumnVisibilityChanges);
|
|
378
|
+
handleUserColumnPreferences?.(finalColumnVisibilityChanges);
|
|
379
|
+
setSelectAll(false);
|
|
380
|
+
|
|
381
|
+
requestAnimationFrame(() => {
|
|
382
|
+
handleScroll(); // Recalculate scroll position after layout change
|
|
383
|
+
});
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const [scrollLeft, setScrollLeft] = useState(0);
|
|
387
|
+
const tableRef = useRef<HTMLDivElement>(null);
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* function to move the scroll bar to left using controls in action
|
|
391
|
+
*/
|
|
392
|
+
const handlePrevButtonClick = () => {
|
|
393
|
+
if (tableRef.current) {
|
|
394
|
+
tableRef.current.scrollLeft -= 250;
|
|
395
|
+
setScrollLeft(tableRef.current.scrollLeft);
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* function to move the scroll bar to right using controls in action
|
|
401
|
+
*/
|
|
402
|
+
const handleNextButtonClick = () => {
|
|
403
|
+
if (tableRef.current) {
|
|
404
|
+
tableRef.current.scrollLeft += 250;
|
|
405
|
+
setScrollLeft(
|
|
406
|
+
tableRef.current.scrollWidth - tableRef.current.clientWidth
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
//state variable to control the opening and closing of the column selector
|
|
412
|
+
const [open, setOpen] = useState(false);
|
|
413
|
+
const { t } = useTranslation(["common", "course.find_course", "bx_v1"]);
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* This function will set the drop down to open or close
|
|
417
|
+
* ColumnVisibilityChange is the columns selected in the dropdown
|
|
418
|
+
* While triggering the dropdown we are updated the ColumnVisibilityChange with ColumnVisibility
|
|
419
|
+
* Where ColumnVisibility is the columns selected after the changes are applied
|
|
420
|
+
*/
|
|
421
|
+
const handleColumnDropdownChange = () => {
|
|
422
|
+
setOpen(!open);
|
|
423
|
+
setColumnVisibilityChanges({ ...columnVisibility });
|
|
424
|
+
//If all checkboxes are checked or not and Based on that we have to update the select all
|
|
425
|
+
const allChecked = Object.values({
|
|
426
|
+
...columnVisibility,
|
|
427
|
+
}).every(Boolean);
|
|
428
|
+
|
|
429
|
+
setSelectAll(allChecked);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
*This component manages the scroll state of a scrollable element (referred to as `tableRef`).
|
|
434
|
+
* It tracks whether the element is scrolled to the start (leftmost position) or the end (rightmost position).
|
|
435
|
+
* The `isAtStart` state is true when the scroll position is at the left edge of the element,
|
|
436
|
+
* and the `isAtEnd` state is true when the scroll position is at or beyond the right edge of the element.
|
|
437
|
+
*/
|
|
438
|
+
const [isAtStart, setIsAtStart] = useState(true);
|
|
439
|
+
const [isAtEnd, setIsAtEnd] = useState(false);
|
|
440
|
+
|
|
441
|
+
const handleScroll = () => {
|
|
442
|
+
if (tableRef.current) {
|
|
443
|
+
const { scrollLeft, clientWidth, scrollWidth } = tableRef.current;
|
|
444
|
+
|
|
445
|
+
const roundedScrollLeft = Math.round(scrollLeft);
|
|
446
|
+
const roundedClientWidth = Math.round(clientWidth);
|
|
447
|
+
const roundedScrollWidth = Math.round(scrollWidth);
|
|
448
|
+
|
|
449
|
+
// Add tolerance for floating-point inaccuracies
|
|
450
|
+
const tolerance = 1;
|
|
451
|
+
|
|
452
|
+
setIsAtStart(roundedScrollLeft <= tolerance);
|
|
453
|
+
setIsAtEnd(
|
|
454
|
+
roundedScrollLeft + roundedClientWidth >= roundedScrollWidth - tolerance
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const handleResize = debounce(() => {
|
|
460
|
+
handleScroll();
|
|
461
|
+
}, 100);
|
|
462
|
+
|
|
463
|
+
useEffect(() => {
|
|
464
|
+
const tableElement = tableRef.current;
|
|
465
|
+
|
|
466
|
+
if (tableElement) {
|
|
467
|
+
tableElement.addEventListener("scroll", handleScroll, { passive: true });
|
|
468
|
+
window.addEventListener("resize", handleResize);
|
|
469
|
+
|
|
470
|
+
handleScroll(); // Initial scroll state check
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (isFiltering && tableRef.current) {
|
|
474
|
+
tableRef.current.scrollLeft = 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return () => {
|
|
478
|
+
if (tableElement) {
|
|
479
|
+
tableElement.removeEventListener("scroll", handleScroll);
|
|
480
|
+
}
|
|
481
|
+
window.removeEventListener("resize", handleResize);
|
|
482
|
+
};
|
|
483
|
+
}, [tableRef.current, isFiltering]);
|
|
484
|
+
|
|
485
|
+
return (
|
|
486
|
+
<div className="flex flex-col gap-4">
|
|
487
|
+
<div className="flex max-h-[50px] flex-row items-center justify-between">
|
|
488
|
+
<div className="flex flex-row items-center gap-4">
|
|
489
|
+
{columnSelector && (
|
|
490
|
+
<div>
|
|
491
|
+
<DropdownMenu
|
|
492
|
+
open={open}
|
|
493
|
+
onOpenChange={handleColumnDropdownChange}
|
|
494
|
+
>
|
|
495
|
+
<DropdownMenuTrigger asChild>
|
|
496
|
+
<Button
|
|
497
|
+
onClick={() => setOpen(true)}
|
|
498
|
+
variant="outline"
|
|
499
|
+
className="flex h-10 w-[192px] flex-row justify-between rounded-xl hover:border hover:border-solid hover:border-primary"
|
|
500
|
+
id="base-table-column-selector-button"
|
|
501
|
+
>
|
|
502
|
+
{t("course.find_course:columns")}
|
|
503
|
+
<DropDown />
|
|
504
|
+
</Button>
|
|
505
|
+
</DropdownMenuTrigger>
|
|
506
|
+
<DropdownMenuContent
|
|
507
|
+
className="w-[192px] rounded-xl pl-3 pt-2.5"
|
|
508
|
+
align="start"
|
|
509
|
+
>
|
|
510
|
+
<div>
|
|
511
|
+
<div className="scrollbar column-selector-responsive-container flex flex-col gap-4 overflow-y-auto text-grey">
|
|
512
|
+
<div className="flex flex-row items-center gap-4">
|
|
513
|
+
<Checkbox
|
|
514
|
+
checked={selectAll}
|
|
515
|
+
onCheckedChange={handleSelectAllChange}
|
|
516
|
+
id="base-table-column-selector-select-all-checkbox"
|
|
517
|
+
/>
|
|
518
|
+
<Text className="text-sm font-bold">
|
|
519
|
+
{t("course.find_course:select_all")}
|
|
520
|
+
</Text>
|
|
521
|
+
</div>
|
|
522
|
+
{table
|
|
523
|
+
.getAllColumns()
|
|
524
|
+
.filter((column) => column?.accessorFn)
|
|
525
|
+
// Here we are filtering the columns which have accessorKey
|
|
526
|
+
.map((column: any, index: number) => {
|
|
527
|
+
if (!column.getCanHide()) {
|
|
528
|
+
//display the disabled options
|
|
529
|
+
return (
|
|
530
|
+
<div
|
|
531
|
+
className="flex flex-row items-center gap-4"
|
|
532
|
+
key={index}
|
|
533
|
+
>
|
|
534
|
+
<Checkbox
|
|
535
|
+
key={column.id}
|
|
536
|
+
disabled={!column.getCanHide()}
|
|
537
|
+
//Disabling the checkbox if the column cannot be hidden
|
|
538
|
+
checked={columnVisibilityChanges[column.id]}
|
|
539
|
+
onCheckedChange={(value: boolean) => {
|
|
540
|
+
handleColumnVisibilityChange(
|
|
541
|
+
column.id,
|
|
542
|
+
value
|
|
543
|
+
);
|
|
544
|
+
}}
|
|
545
|
+
id={`column-${column?.columnDef?.column_name}`}
|
|
546
|
+
/>
|
|
547
|
+
{column?.columnDef?.column_name}
|
|
548
|
+
</div>
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
})}
|
|
552
|
+
{table
|
|
553
|
+
.getAllColumns()
|
|
554
|
+
.filter(
|
|
555
|
+
(column) => column?.accessorFn && column.getCanHide()
|
|
556
|
+
)
|
|
557
|
+
// Here we are filtering the columns which have accessorKey
|
|
558
|
+
.map((column: any) => {
|
|
559
|
+
// display the enabled options
|
|
560
|
+
return (
|
|
561
|
+
<div className="flex flex-row items-center gap-4">
|
|
562
|
+
<Checkbox
|
|
563
|
+
key={column.id}
|
|
564
|
+
checked={columnVisibilityChanges[column.id]}
|
|
565
|
+
onCheckedChange={(value: boolean) => {
|
|
566
|
+
handleColumnVisibilityChange(
|
|
567
|
+
column.id,
|
|
568
|
+
value
|
|
569
|
+
);
|
|
570
|
+
}}
|
|
571
|
+
/>
|
|
572
|
+
{column?.columnDef?.column_name}
|
|
573
|
+
</div>
|
|
574
|
+
);
|
|
575
|
+
})}
|
|
576
|
+
</div>
|
|
577
|
+
|
|
578
|
+
<div className="thin-scrollbar relative flex w-full flex-row items-center gap-4 overflow-auto pb-2.5 pt-2">
|
|
579
|
+
<div
|
|
580
|
+
onClick={clearColumnVisibilityChanges}
|
|
581
|
+
className="cursor-pointer rounded-xl border border-primary p-2 hover:border-solid"
|
|
582
|
+
>
|
|
583
|
+
<ClearAll />
|
|
584
|
+
</div>
|
|
585
|
+
<Button
|
|
586
|
+
size="sm"
|
|
587
|
+
variant="primary"
|
|
588
|
+
onClick={applyColumnVisibilityChanges}
|
|
589
|
+
id="base-table-column-selector-apply-button"
|
|
590
|
+
>
|
|
591
|
+
{t("apply_button")}
|
|
592
|
+
</Button>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
</DropdownMenuContent>
|
|
596
|
+
</DropdownMenu>
|
|
597
|
+
</div>
|
|
598
|
+
)}
|
|
599
|
+
{/* column selector */}
|
|
600
|
+
|
|
601
|
+
{actionComponent && actionComponent}
|
|
602
|
+
</div>
|
|
603
|
+
{/* If pagination set true then we have to show pagination */}
|
|
604
|
+
<div>
|
|
605
|
+
{!isFiltering && pagination && total > pageSize && (
|
|
606
|
+
<DataPagination
|
|
607
|
+
setCurrent={setCurrent}
|
|
608
|
+
current={current}
|
|
609
|
+
pageCount={pageCount}
|
|
610
|
+
total={total}
|
|
611
|
+
/>
|
|
612
|
+
)}
|
|
613
|
+
</div>
|
|
614
|
+
</div>
|
|
615
|
+
|
|
616
|
+
{/* Table */}
|
|
617
|
+
<div>
|
|
618
|
+
<div className="h-full overflow-hidden rounded-xl border">
|
|
619
|
+
<div
|
|
620
|
+
ref={tableRef}
|
|
621
|
+
className={`w-full ${tableStyles?.tableContainer} scrollbar ${
|
|
622
|
+
isFiltering
|
|
623
|
+
? "overflow-x-hidden"
|
|
624
|
+
: "overflow-x-auto overflow-y-hidden"
|
|
625
|
+
} relative overflow-x-auto overflow-y-hidden`}
|
|
626
|
+
>
|
|
627
|
+
<Table id={tableId} className={`${tableStyles?.table}`}>
|
|
628
|
+
<TableHeader
|
|
629
|
+
className={`w-full bg-primary-light ${tableStyles?.tableHeader}`}
|
|
630
|
+
>
|
|
631
|
+
{table &&
|
|
632
|
+
table?.getHeaderGroups()?.map((headerGroup) => (
|
|
633
|
+
<TableRow
|
|
634
|
+
className="w-full border-none text-base font-bold"
|
|
635
|
+
key={headerGroup?.id}
|
|
636
|
+
>
|
|
637
|
+
{/* If the checkboxSelection is true then we need to show checkboxes */}
|
|
638
|
+
{checkboxSelection && (
|
|
639
|
+
<TableHead
|
|
640
|
+
className={`${
|
|
641
|
+
columnPinning && "sticky left-0 bg-primary-light"
|
|
642
|
+
}`}
|
|
643
|
+
>
|
|
644
|
+
<Checkbox
|
|
645
|
+
checked={table.getIsAllPageRowsSelected()}
|
|
646
|
+
onCheckedChange={(value: boolean) => {
|
|
647
|
+
table.toggleAllPageRowsSelected(value);
|
|
648
|
+
}}
|
|
649
|
+
aria-label="Select all"
|
|
650
|
+
id="base-table-select-all-checkbox"
|
|
651
|
+
/>
|
|
652
|
+
</TableHead>
|
|
653
|
+
)}
|
|
654
|
+
{headerGroup?.headers?.map((header, index) => {
|
|
655
|
+
return (
|
|
656
|
+
<TableHead
|
|
657
|
+
//If we have column pinning true then we have to make the first and last column sticky
|
|
658
|
+
className={`${
|
|
659
|
+
columnPinning &&
|
|
660
|
+
index === 0 &&
|
|
661
|
+
`sticky ${
|
|
662
|
+
checkboxSelection ? "left-12" : "left-0"
|
|
663
|
+
} bg-primary-light drop-shadow-right`
|
|
664
|
+
} ${
|
|
665
|
+
!noScroll &&
|
|
666
|
+
columnPinning &&
|
|
667
|
+
index === headerGroup.headers.length - 1 &&
|
|
668
|
+
`sticky right-0 w-[50px] bg-primary-light drop-shadow-left`
|
|
669
|
+
} ${tableStyles?.tableHeaderCell ? tableStyles?.tableHeaderCell : ""} text-grey`}
|
|
670
|
+
key={header?.id}
|
|
671
|
+
>
|
|
672
|
+
{header?.isPlaceholder
|
|
673
|
+
? null
|
|
674
|
+
: flexRender(
|
|
675
|
+
header?.column?.columnDef?.header,
|
|
676
|
+
header?.getContext()
|
|
677
|
+
)}
|
|
678
|
+
|
|
679
|
+
{!noScroll &&
|
|
680
|
+
index === headerGroup.headers.length - 1 &&
|
|
681
|
+
columnPinning && (
|
|
682
|
+
<div className="flex flex-row gap-2">
|
|
683
|
+
<ChevronLeft
|
|
684
|
+
onClick={handlePrevButtonClick}
|
|
685
|
+
className={`mr-1 size-6 cursor-pointer rounded-full ${
|
|
686
|
+
isAtStart
|
|
687
|
+
? "bg-white text-primary"
|
|
688
|
+
: "bg-primary text-white"
|
|
689
|
+
}`}
|
|
690
|
+
/>
|
|
691
|
+
<ChevronRight
|
|
692
|
+
onClick={handleNextButtonClick}
|
|
693
|
+
className={`size-6 cursor-pointer rounded-full ${
|
|
694
|
+
isAtEnd
|
|
695
|
+
? "bg-white text-primary"
|
|
696
|
+
: "bg-primary text-white"
|
|
697
|
+
}`}
|
|
698
|
+
id="base-table-columns-right-button"
|
|
699
|
+
/>
|
|
700
|
+
</div>
|
|
701
|
+
)}
|
|
702
|
+
</TableHead>
|
|
703
|
+
);
|
|
704
|
+
})}
|
|
705
|
+
</TableRow>
|
|
706
|
+
))}
|
|
707
|
+
</TableHeader>
|
|
708
|
+
<TableBody>
|
|
709
|
+
{isFiltering ? (
|
|
710
|
+
<TableRow>
|
|
711
|
+
<TableCell
|
|
712
|
+
colSpan={columns?.length}
|
|
713
|
+
className="h-24 text-center"
|
|
714
|
+
>
|
|
715
|
+
<div className="flex w-screen items-center justify-center">
|
|
716
|
+
<div className="loader"></div>
|
|
717
|
+
</div>
|
|
718
|
+
</TableCell>
|
|
719
|
+
</TableRow>
|
|
720
|
+
) : table && table?.getRowModel()?.rows?.length ? (
|
|
721
|
+
<>
|
|
722
|
+
{table?.getRowModel()?.rows?.map((row) => (
|
|
723
|
+
<TableRow
|
|
724
|
+
className={`{${tableStyles?.rowStyles}`}
|
|
725
|
+
key={row?.id}
|
|
726
|
+
// data-state={row?.getIsSelected() && "selected"}
|
|
727
|
+
>
|
|
728
|
+
{/* If the checkboxSelection is true then we need to show checkboxes */}
|
|
729
|
+
{checkboxSelection && (
|
|
730
|
+
<TableCell
|
|
731
|
+
className={`${
|
|
732
|
+
columnPinning && "sticky left-0 bg-white"
|
|
733
|
+
}`}
|
|
734
|
+
>
|
|
735
|
+
<Checkbox
|
|
736
|
+
checked={row?.getIsSelected()}
|
|
737
|
+
onCheckedChange={(value) =>
|
|
738
|
+
row?.toggleSelected(!!value)
|
|
739
|
+
}
|
|
740
|
+
aria-label="Select row"
|
|
741
|
+
/>
|
|
742
|
+
</TableCell>
|
|
743
|
+
)}
|
|
744
|
+
|
|
745
|
+
{row?.getVisibleCells().map((cell, index) => (
|
|
746
|
+
//If we have column pinning true then we have to make the first and last column sticky
|
|
747
|
+
<TableCell
|
|
748
|
+
className={` ${
|
|
749
|
+
columnPinning &&
|
|
750
|
+
index === 0 &&
|
|
751
|
+
`sticky ${
|
|
752
|
+
checkboxSelection ? "left-12" : "left-0"
|
|
753
|
+
} top-0 bg-white drop-shadow-right`
|
|
754
|
+
} ${
|
|
755
|
+
!noScroll &&
|
|
756
|
+
columnPinning &&
|
|
757
|
+
index === row.getVisibleCells().length - 1 &&
|
|
758
|
+
`sticky right-0 top-0 w-[50px] bg-white drop-shadow-left`
|
|
759
|
+
} ${tableStyles?.tableBodyCell ? tableStyles?.tableBodyCell : ""} text-grey`}
|
|
760
|
+
key={cell.id}
|
|
761
|
+
>
|
|
762
|
+
{flexRender(
|
|
763
|
+
cell?.column?.columnDef?.cell,
|
|
764
|
+
cell?.getContext()
|
|
765
|
+
)}
|
|
766
|
+
</TableCell>
|
|
767
|
+
))}
|
|
768
|
+
</TableRow>
|
|
769
|
+
))}
|
|
770
|
+
{/* Render Footer Rows within the TableBody */}
|
|
771
|
+
{table
|
|
772
|
+
?.getFooterGroups()
|
|
773
|
+
?.some((group) =>
|
|
774
|
+
group.headers.some(
|
|
775
|
+
(header) => header.column.columnDef.footer
|
|
776
|
+
)
|
|
777
|
+
) &&
|
|
778
|
+
table?.getFooterGroups()?.map((row) => (
|
|
779
|
+
<TableRow key={row.id} className="bg-primary-light">
|
|
780
|
+
{row?.headers?.map((cell, index) => (
|
|
781
|
+
<TableCell
|
|
782
|
+
key={cell.id}
|
|
783
|
+
className={`${
|
|
784
|
+
columnPinning && index === 0
|
|
785
|
+
? "sticky left-0 bg-primary-light drop-shadow-right"
|
|
786
|
+
: ""
|
|
787
|
+
} ${
|
|
788
|
+
!noScroll &&
|
|
789
|
+
columnPinning &&
|
|
790
|
+
index === row.headers.length - 1
|
|
791
|
+
? "sticky right-0 bg-white drop-shadow-left"
|
|
792
|
+
: ""
|
|
793
|
+
} ${tableStyles?.tableBodyCell ? tableStyles?.tableBodyCell : ""} text-grey`}
|
|
794
|
+
>
|
|
795
|
+
{flexRender(
|
|
796
|
+
cell?.column?.columnDef?.footer,
|
|
797
|
+
cell?.getContext()
|
|
798
|
+
)}
|
|
799
|
+
</TableCell>
|
|
800
|
+
))}
|
|
801
|
+
</TableRow>
|
|
802
|
+
))}
|
|
803
|
+
</>
|
|
804
|
+
) : (
|
|
805
|
+
<TableRow>
|
|
806
|
+
<TableCell
|
|
807
|
+
colSpan={columns?.length}
|
|
808
|
+
className="h-24 text-left"
|
|
809
|
+
>
|
|
810
|
+
{noRecordsPlaceholder}
|
|
811
|
+
</TableCell>
|
|
812
|
+
</TableRow>
|
|
813
|
+
)}
|
|
814
|
+
</TableBody>
|
|
815
|
+
</Table>
|
|
816
|
+
</div>
|
|
817
|
+
</div>
|
|
818
|
+
{!isFiltering && pagination && (
|
|
819
|
+
<div className="my-6 flex justify-center">
|
|
820
|
+
<div className="w-1/3"></div>
|
|
821
|
+
<div className="flex w-1/3 items-center justify-center">
|
|
822
|
+
{/* When there is more than 1 page then only we need to render this */}
|
|
823
|
+
{total > pageSize && (
|
|
824
|
+
<DataPagination
|
|
825
|
+
setCurrent={setCurrent}
|
|
826
|
+
current={current}
|
|
827
|
+
pageCount={pageCount}
|
|
828
|
+
total={total}
|
|
829
|
+
pageSize={pageSize}
|
|
830
|
+
/>
|
|
831
|
+
)}
|
|
832
|
+
</div>
|
|
833
|
+
{total >= 10 && (
|
|
834
|
+
<div
|
|
835
|
+
className="flex w-1/3 items-center justify-end space-x-2"
|
|
836
|
+
id="base-table-pagination-dropdown"
|
|
837
|
+
>
|
|
838
|
+
<Select
|
|
839
|
+
value={pageSize}
|
|
840
|
+
onValueChange={(value) => {
|
|
841
|
+
setCurrent(1);
|
|
842
|
+
setPageSize(Number(value));
|
|
843
|
+
table?.setPageSize(Number(value));
|
|
844
|
+
}}
|
|
845
|
+
>
|
|
846
|
+
<SelectTrigger
|
|
847
|
+
className="h-8 w-[131px]"
|
|
848
|
+
id="base-table-page-size"
|
|
849
|
+
>
|
|
850
|
+
<Text className="text-grey1">
|
|
851
|
+
{t("course.find_course:showing")}
|
|
852
|
+
</Text>
|
|
853
|
+
<SelectValue />
|
|
854
|
+
</SelectTrigger>
|
|
855
|
+
<SelectContent side="top">
|
|
856
|
+
{/* Updated pageSize options to include [10, 25, 50, 100]. */}
|
|
857
|
+
{[10, 25, 50, 100].map(
|
|
858
|
+
(
|
|
859
|
+
pageSize // Till now there is no limit will change after confirming TODO
|
|
860
|
+
) => (
|
|
861
|
+
<SelectItem
|
|
862
|
+
key={pageSize}
|
|
863
|
+
value={`${pageSize}`}
|
|
864
|
+
id={`base-table-${pageSize}`}
|
|
865
|
+
>
|
|
866
|
+
{pageSize}
|
|
867
|
+
</SelectItem>
|
|
868
|
+
)
|
|
869
|
+
)}
|
|
870
|
+
</SelectContent>
|
|
871
|
+
</Select>
|
|
872
|
+
<Text className="text-sm font-normal">
|
|
873
|
+
{t("course.find_course:of")} {total}
|
|
874
|
+
</Text>
|
|
875
|
+
</div>
|
|
876
|
+
)}
|
|
877
|
+
</div>
|
|
878
|
+
)}
|
|
879
|
+
</div>
|
|
880
|
+
</div>
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
interface DataPaginationProps {
|
|
885
|
+
setCurrent?: (value: React.SetStateAction<number>) => void;
|
|
886
|
+
current?: number;
|
|
887
|
+
pageCount?: number;
|
|
888
|
+
total?: number;
|
|
889
|
+
pageSize?: number;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
const DataPagination = ({
|
|
893
|
+
setCurrent = () => {},
|
|
894
|
+
total = 0,
|
|
895
|
+
current = 1,
|
|
896
|
+
pageCount = 1,
|
|
897
|
+
pageSize = 0,
|
|
898
|
+
}: DataPaginationProps) => {
|
|
899
|
+
const PagesArray = [];
|
|
900
|
+
const DOTS = ". . .";
|
|
901
|
+
if (pageCount <= 4) {
|
|
902
|
+
// If there are 4 or fewer pages, show all pages without ellipses
|
|
903
|
+
for (let i = 1; i <= pageCount; i++) {
|
|
904
|
+
PagesArray.push(i);
|
|
905
|
+
}
|
|
906
|
+
} else {
|
|
907
|
+
if (current <= 3) {
|
|
908
|
+
// If current page is 4 or less, show pages 1 to 4, then ellipses, then last page
|
|
909
|
+
PagesArray.push(1, 2, 3, 4, DOTS, pageCount);
|
|
910
|
+
} else if (current >= pageCount - 2) {
|
|
911
|
+
// If current page is near the end, show first page, ellipses, and last 4 pages
|
|
912
|
+
PagesArray.push(
|
|
913
|
+
1,
|
|
914
|
+
DOTS,
|
|
915
|
+
pageCount - 3,
|
|
916
|
+
pageCount - 2,
|
|
917
|
+
pageCount - 1,
|
|
918
|
+
pageCount
|
|
919
|
+
);
|
|
920
|
+
} else {
|
|
921
|
+
// Otherwise,first page , ellipses, current page, ellipses, and last page
|
|
922
|
+
PagesArray.push(
|
|
923
|
+
1,
|
|
924
|
+
DOTS,
|
|
925
|
+
current - 1,
|
|
926
|
+
current,
|
|
927
|
+
current + 1,
|
|
928
|
+
DOTS,
|
|
929
|
+
pageCount
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
const { t } = useTranslation(["common", "bx_v1"]);
|
|
935
|
+
|
|
936
|
+
return (
|
|
937
|
+
<div className="flex flex-row items-center space-x-2 self-center p-2 text-xs">
|
|
938
|
+
{/* prev button */}
|
|
939
|
+
{/* Check if there are more than one page, and if so, display a button for navigating to the previous page. */}
|
|
940
|
+
{pageCount > 1 && (
|
|
941
|
+
<Button
|
|
942
|
+
variant="outline"
|
|
943
|
+
className={`h-8 min-w-8 rounded-sm border-none p-0 text-xs !font-semibold ${current <= 1 ? "text-grey2-light-active" : " "}`}
|
|
944
|
+
onClick={() => setCurrent(current - 1)}
|
|
945
|
+
disabled={current <= 1}
|
|
946
|
+
id="base-table-pagination-prev-button"
|
|
947
|
+
>
|
|
948
|
+
{t("bx_v1:cm_prev")}
|
|
949
|
+
</Button>
|
|
950
|
+
)}
|
|
951
|
+
{/* pages buttons */}
|
|
952
|
+
{total > pageSize &&
|
|
953
|
+
PagesArray.map((page: any, index: any) => (
|
|
954
|
+
<div key={index}>
|
|
955
|
+
{/* Check if the current page is a placeholder for ellipsis.If yes, display the ellipsis.Otherwise, display a button for the page. */}
|
|
956
|
+
{page === DOTS ? (
|
|
957
|
+
<span className="p-2 text-xs">{DOTS}</span>
|
|
958
|
+
) : (
|
|
959
|
+
<Button
|
|
960
|
+
variant={page === current ? "primary" : "outline"}
|
|
961
|
+
onClick={() => {
|
|
962
|
+
setCurrent(page);
|
|
963
|
+
}}
|
|
964
|
+
className="size-8 rounded-lg p-3 text-xs"
|
|
965
|
+
id={`base-table-pagination-page-${page}-button`}
|
|
966
|
+
>
|
|
967
|
+
{page}
|
|
968
|
+
</Button>
|
|
969
|
+
)}
|
|
970
|
+
</div>
|
|
971
|
+
))}
|
|
972
|
+
{/* next button */}
|
|
973
|
+
{/* Check if there are more than one page, and if so, display a button for navigating to the next page. */}
|
|
974
|
+
{pageCount > 1 && (
|
|
975
|
+
<Button
|
|
976
|
+
variant="outline"
|
|
977
|
+
className={`h-8 min-w-8 rounded-sm border-none p-0 text-xs !font-semibold ${current >= pageCount ? "text-grey2-light-active" : " "}`}
|
|
978
|
+
onClick={() => setCurrent(current + 1)}
|
|
979
|
+
disabled={current >= pageCount}
|
|
980
|
+
id="base-table-pagination-next-button"
|
|
981
|
+
>
|
|
982
|
+
{t("next")}
|
|
983
|
+
</Button>
|
|
984
|
+
)}
|
|
985
|
+
</div>
|
|
986
|
+
);
|
|
987
|
+
};
|