@omniumretail/component-library 1.1.19 → 1.1.21

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.
@@ -0,0 +1,307 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { Space, TableProps, Select, Dropdown, MenuProps } from 'antd';
3
+ import { Table as AntdTable } from 'antd';
4
+ import type { ColumnsType } from 'antd/es/table/interface';
5
+ import styles from './styles.module.scss';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { MoreOutlined } from '@ant-design/icons';
8
+ import classnames from 'classnames';
9
+ import { Button } from '../Button';
10
+
11
+ export interface FilterTableOptions {
12
+ value: string;
13
+ label: string;
14
+ direction: string;
15
+ }
16
+
17
+ export interface TableActions {
18
+ key: string;
19
+ label: string;
20
+ }
21
+
22
+ export enum sortByOption {
23
+ asc = 'asc',
24
+ desc = 'desc',
25
+ }
26
+
27
+ export interface ResponsiveTableCustomProps extends TableProps<any> {
28
+ fieldsToSort?: any[],
29
+ selectPlaceholder?: string,
30
+ onSort?: (field: any, sortByOption: any) => void;
31
+ sortInfo?: any;
32
+ paginationInfo?: any;
33
+ headingTranslationsKey?: string;
34
+ actionsArray?: any;
35
+ rowSelectionInfo?: any;
36
+ rowKeyValue?: string;
37
+ hiddenColumns?: string[];
38
+ rowSelection?: any;
39
+ onSelectAllButtonClick?: () => void;
40
+ AllItemsShowing?: boolean;
41
+ selectAllStatus?: any;
42
+ isTableDataRefreshed?: any;
43
+ tableLoading?: any;
44
+ tableMaxHeight?: any;
45
+ columnsSortChange?: any;
46
+ sortByColumns?: boolean;
47
+ columnsToSort?: string[];
48
+ fixedColumns?: { dataIndex: string; side: 'left' | 'right' }[];
49
+ customColumnWidths?: { columnName: string; width: string }[];
50
+ }
51
+
52
+ export const ResponsiveTable = (props: ResponsiveTableCustomProps) => {
53
+ const { t } = useTranslation();
54
+
55
+ const {
56
+ dataSource = undefined,
57
+ fieldsToSort,
58
+ selectPlaceholder = 'Sort By',
59
+ onSort,
60
+ headingTranslationsKey,
61
+ actionsArray: items,
62
+ rowKeyValue,
63
+ hiddenColumns,
64
+ rowSelection,
65
+ onSelectAllButtonClick,
66
+ AllItemsShowing,
67
+ selectAllStatus,
68
+ isTableDataRefreshed,
69
+ tableLoading,
70
+ tableMaxHeight,
71
+ sortByColumns,
72
+ columnsToSort,
73
+ fixedColumns,
74
+ customColumnWidths
75
+ } = props;
76
+
77
+ const [customFilters, setCustomFilters] = useState<any>([]);
78
+ const [customColumns, setCustomColumns] = useState<ColumnsType<any>>([]);
79
+ const [sortInfo, setSortInfo] = useState<any>([]);
80
+ const [selectedRowKeys, setselectedRowKeys] = useState<any>(rowSelection?.selectedRowKeys || []);
81
+ const [selectedAllRowKeys, setSelectedAllRowKeys] = useState(false);
82
+ const [deselectAll, setDeselectAll] = useState(false);
83
+
84
+
85
+ const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
86
+ if (rowSelection.type === 'radio') {
87
+ setselectedRowKeys(newSelectedRowKeys);
88
+ return;
89
+ }
90
+
91
+ setselectedRowKeys((prevKeys: any) => {
92
+ const dataSourceIds = dataSource?.map((data) => data[rowKeyValue as any])
93
+
94
+ const oldKeys = prevKeys.filter((key: any) => {
95
+ return !dataSourceIds?.includes(key)
96
+ });
97
+
98
+ return [...oldKeys, ...newSelectedRowKeys];
99
+ });
100
+
101
+ setSelectedAllRowKeys(false);
102
+ setDeselectAll(false);
103
+ };
104
+
105
+ const handleChange: TableProps<any>['onChange'] = (pagination, filters, sorter: any, extra) => {
106
+ const getPagination = {
107
+ currentPage: pagination.current,
108
+ }
109
+
110
+ const getSortAndPaginationInfo = { ...sortInfo, ...getPagination }
111
+ props.paginationInfo(getSortAndPaginationInfo);
112
+
113
+ // SORT
114
+ if (sortByColumns) {
115
+ const { field, order } = sorter;
116
+ let mappedOrder = null;
117
+ if (order === "ascend") {
118
+ mappedOrder = "asc";
119
+ } else if (order === "descend") {
120
+ mappedOrder = "desc";
121
+ }
122
+
123
+ if (field && mappedOrder) {
124
+ props.columnsSortChange({ field, order: mappedOrder });
125
+ }
126
+ }
127
+ };
128
+
129
+ const setSorter = (option: any) => {
130
+ onSort?.(option.value.split('-')[0], option.direction);
131
+ const sortData = {
132
+ sortDirection: option.direction,
133
+ sortValue: option.value.split('-')[0],
134
+ }
135
+
136
+ setSortInfo(sortData)
137
+ };
138
+
139
+ const selectAllRows = () => {
140
+ if (selectedAllRowKeys) {
141
+ setDeselectAll(true);
142
+ } else {
143
+ onSelectAllButtonClick?.(); // Call the onSelectAllButtonClick callback
144
+ }
145
+ };
146
+
147
+ useEffect(() => {
148
+ if (isTableDataRefreshed && !tableLoading || AllItemsShowing) {
149
+ if (selectAllStatus && AllItemsShowing) {
150
+ const allRowKeys = dataSource?.map((record) => record[rowKeyValue as any]);
151
+ setselectedRowKeys(allRowKeys);
152
+ setSelectedAllRowKeys(true);
153
+ }
154
+ }
155
+ }, [isTableDataRefreshed, tableLoading, selectAllStatus, AllItemsShowing]);
156
+
157
+ useEffect(() => {
158
+ if (deselectAll) {
159
+ setselectedRowKeys([]);
160
+ setDeselectAll(false);
161
+ setSelectedAllRowKeys(false);
162
+ }
163
+ }, [deselectAll]);
164
+
165
+ useEffect(() => {
166
+ props.rowSelectionInfo(selectedRowKeys);
167
+ }, [selectedRowKeys]);
168
+
169
+ useEffect(() => {
170
+ if (dataSource && (dataSource as any)?.length > 0) {
171
+ // Columns
172
+ let columns = Object.keys(dataSource?.[0]).map(key => {
173
+ if (hiddenColumns?.includes(key)) {
174
+ return;
175
+ }
176
+
177
+ const isColumnSortable = columnsToSort?.includes(key) ? sortByColumns : false;
178
+
179
+ const column = {
180
+ title: headingTranslationsKey ? t(`${headingTranslationsKey}.${key}`) : key,
181
+ dataIndex: key,
182
+ key: key,
183
+ ellipsis: false,
184
+ sorter: isColumnSortable,
185
+ // No fixed property here, we'll add it later based on the fixedColumns prop
186
+ };
187
+
188
+ return column;
189
+
190
+ }).filter(el => el !== undefined) as any;
191
+
192
+ let columnActions = {
193
+ key: 'action',
194
+ title: headingTranslationsKey ? t(`${headingTranslationsKey}.${'action'}`) : 'action',
195
+ dataIndex: 6,
196
+ ellipsis: false,
197
+ render: () => {
198
+ if (!items?.[0]) return null; // Verifica se o array items é nulo
199
+
200
+ return (
201
+ <Space size="middle">
202
+ <Dropdown menu={{ items }}>
203
+ <a>
204
+ <MoreOutlined style={{ color: 'var(--color-blue)', transform: 'scale(1.6)' }} />
205
+ </a>
206
+ </Dropdown>
207
+ </Space>
208
+ );
209
+ },
210
+ };
211
+
212
+ items && columns.push(columnActions as any);
213
+
214
+ if (fixedColumns) {
215
+ fixedColumns.forEach((column) => {
216
+ const { dataIndex, side } = column;
217
+ const foundColumn = columns.find((col: any) => col.dataIndex === dataIndex);
218
+ if (foundColumn) {
219
+ foundColumn.fixed = side;
220
+ }
221
+ });
222
+ }
223
+
224
+ if (customColumnWidths) {
225
+ customColumnWidths.forEach((column) => {
226
+ const { columnName, width } = column;
227
+ const foundColumn = columns.find((col: any) => col.dataIndex === columnName);
228
+ if (foundColumn) {
229
+ foundColumn.width = width;
230
+ }
231
+ });
232
+ }
233
+
234
+ setCustomColumns(columns);
235
+
236
+ // Filters
237
+ const dataKeysToFilter = Object.keys(dataSource?.[0]).filter((el) => fieldsToSort?.includes(el));
238
+
239
+ const filters = ([] as FilterTableOptions[]).concat(
240
+ ...dataKeysToFilter.map(key => ({
241
+ value: `${key}-${sortByOption.desc}`,
242
+ label: `${headingTranslationsKey ? t(`${headingTranslationsKey}.${key}`) : key} (${sortByOption.desc})`,
243
+ direction: `${sortByOption.desc}`,
244
+ })),
245
+ ...dataKeysToFilter.map(key => ({
246
+ value: `${key}-${sortByOption.asc}`,
247
+ label: `${headingTranslationsKey ? t(`${headingTranslationsKey}.${key}`) : key} (${sortByOption.asc})`,
248
+ direction: `${sortByOption.asc}`,
249
+ }))
250
+ );
251
+
252
+ setCustomFilters(filters);
253
+ }
254
+ }, [dataSource]);
255
+
256
+ const shouldRenderSortDropdown = customFilters.length > 0;
257
+
258
+ const tableWrapperClasses = classnames({
259
+ [styles.tableWrapperNoSelection]: !rowSelection
260
+ }, [styles.tableWrapper]);
261
+
262
+ return (
263
+ <div className={tableWrapperClasses}>
264
+ {shouldRenderSortDropdown &&
265
+ <Space style={{ marginBottom: 16 }}>
266
+ <Select
267
+ style={{ width: 'auto', minWidth: 200 }}
268
+ placeholder={selectPlaceholder}
269
+ onSelect={(_, option: any) => {
270
+ setSorter(option);
271
+ }}
272
+ optionFilterProp="children"
273
+ filterOption={(input, option) => (option?.label ?? '').includes(input)}
274
+ filterSort={(optionA, optionB) =>
275
+ (optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase())
276
+ }
277
+ options={customFilters}
278
+ />
279
+ </Space>
280
+ }
281
+
282
+ <AntdTable
283
+ dataSource={dataSource}
284
+ onChange={handleChange}
285
+ {...props}
286
+ columns={customColumns}
287
+ {...props.rowSelection ? (
288
+ {
289
+ rowSelection: {
290
+ selectedRowKeys: selectedRowKeys,
291
+ onChange: onSelectChange,
292
+ type: props.rowSelection?.type,
293
+ }
294
+ }
295
+ ) : null}
296
+ rowKey={rowKeyValue}
297
+ {...(tableMaxHeight ? { scroll: { y: tableMaxHeight } } : {})}
298
+ />
299
+ {
300
+ onSelectAllButtonClick &&
301
+ <Button onClick={selectAllRows} className={styles.selectAllRows}>
302
+ {selectedAllRowKeys ? t('components.table.deselectAll') : t('components.table.selectAll')}
303
+ </Button>
304
+ }
305
+ </div>
306
+ );
307
+ };
@@ -0,0 +1,153 @@
1
+ .tableWrapper {
2
+ display: flex;
3
+ flex-wrap: wrap;
4
+ flex-direction: column;
5
+
6
+ :global {
7
+ .ant-table-thead > tr > th {
8
+ background-color: transparent;
9
+ border: 0px;
10
+ color: var(--color-blue);
11
+
12
+ &:before {
13
+ display: none;
14
+ }
15
+ }
16
+
17
+ .ant-table-wrapper {
18
+ margin-bottom: 12px;
19
+ }
20
+
21
+ .ant-table-cell {
22
+ word-break: break-word;
23
+ }
24
+
25
+ .ant-table-tbody {
26
+ > tr {
27
+ cursor: pointer;
28
+
29
+ &:last-child {
30
+ > td {
31
+ border-bottom: 1px solid var(--color-grey-light) !important;
32
+ }
33
+ }
34
+
35
+ &:first-child {
36
+ > td {
37
+ border-top: 1px solid var(--color-blue) !important;
38
+ }
39
+ }
40
+
41
+ &:hover {
42
+ td {
43
+ border-radius: 0 !important;
44
+ border-bottom-color: var(--color-grey-light) !important;
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ .ant-space {
51
+ align-self: flex-end;
52
+ }
53
+
54
+ .ant-select-selection-placeholder {
55
+ color: var(--color-black);
56
+ }
57
+
58
+ .ant-select-selector,
59
+ .ant-select-focused .ant-select-selection-search {
60
+ border: none !important;
61
+ box-shadow: none !important;
62
+
63
+ &:focus,
64
+ &:hover {
65
+ border: none !important;
66
+ box-shadow: none !important;
67
+ }
68
+ }
69
+
70
+ .ant-pagination {
71
+ max-width: calc(100% - 200px);
72
+ margin-left: auto !important;
73
+ }
74
+
75
+ button[type="button"].ant-pagination-item-link {
76
+ margin-top: 0 !important;
77
+ }
78
+ }
79
+
80
+ button[type="button"] {
81
+ margin-top: -50px;
82
+ }
83
+
84
+
85
+ @media screen and (max-width: 1024px) {
86
+ :global {
87
+ .ant-table-thead>tr>th {
88
+ font-size: 12px;
89
+ }
90
+
91
+ .ant-table-tbody>tr>td {
92
+ font-size: 12px;
93
+ }
94
+
95
+ .ant-table-wrapper .ant-table-thead>tr>th {
96
+ padding: 8px;
97
+ }
98
+
99
+ .ant-table-wrapper .ant-table-tbody>tr>td {
100
+ padding: 8px;
101
+ }
102
+ }
103
+ }
104
+
105
+ @media screen and (max-width: 767px) {
106
+ :global {
107
+ .ant-table-thead>tr>th {
108
+ font-size: 10px;
109
+ }
110
+
111
+ .ant-table-tbody>tr>td {
112
+ font-size: 10px;
113
+ }
114
+
115
+ .ant-table-content table {
116
+ width: 100%;
117
+ }
118
+
119
+ .ant-table-content {
120
+ width: 100%;
121
+ }
122
+
123
+ .ant-table-wrapper .ant-table .ant-table-title,
124
+ .ant-table-wrapper .ant-table .ant-table-header {
125
+ word-break: break-all;
126
+ }
127
+
128
+ .ant-table-wrapper .ant-table-thead>tr>th {
129
+ padding: 4px;
130
+ }
131
+
132
+ .ant-table-wrapper .ant-table-tbody>tr>td {
133
+ padding: 4px;
134
+ }
135
+
136
+ .ant-table-wrapper .ant-table-column-sorter {
137
+ margin-inline-start: 0px;
138
+ }
139
+
140
+ .ant-table-wrapper .ant-table-column-sorter-up {
141
+ font-size: 8px;
142
+ }
143
+
144
+ .ant-table-wrapper .ant-table-column-sorter-down {
145
+ font-size: 8px;
146
+ }
147
+
148
+ .ant-pagination {
149
+ max-width: unset;
150
+ }
151
+ }
152
+ }
153
+ }
@@ -25,3 +25,4 @@ export * from './CategoryReadOnly';
25
25
  export * from './Notification';
26
26
  export * from './ExportTableData';
27
27
  export * from './DropdownButton';
28
+ export * from './ResponsiveTable';