@inceptionbg/iui 2.0.16 → 2.0.17

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.
Files changed (61) hide show
  1. package/dist/index.d.ts +155 -89
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/iui.css +1 -1
  5. package/package.json +3 -5
  6. package/src/assets/icons/duotone/faBell.ts +17 -0
  7. package/src/assets/icons/duotone/faPen.ts +18 -0
  8. package/src/assets/icons/duotone/faTrashCan.ts +18 -0
  9. package/src/assets/icons/light/faBell.ts +15 -0
  10. package/src/assets/icons/light/faEnvelope.ts +15 -0
  11. package/src/assets/icons/regular/faEllipsisVertical.ts +15 -0
  12. package/src/assets/icons/solid/faEnvelopeDot.ts +15 -0
  13. package/src/components/Button/SplitButton.tsx +5 -5
  14. package/src/components/Header/Components/ModuleSelect.tsx +5 -5
  15. package/src/components/Header/Components/Notifications.tsx +208 -0
  16. package/src/components/Header/Header.tsx +5 -4
  17. package/src/components/Inputs/NumberInput.tsx +3 -0
  18. package/src/components/Inputs/Selects/components/SelectWrapper.tsx +48 -29
  19. package/src/components/Loader/ProgressBar.tsx +1 -1
  20. package/src/components/Pullover/Pullover.tsx +12 -7
  21. package/src/components/Table/Table.tsx +5 -3
  22. package/src/components/Table/components/columns/TableColumnsEdit.tsx +5 -9
  23. package/src/components/Table/components/edit/TableEditRow.tsx +23 -12
  24. package/src/components/Table/components/header/TableHeaderRow.tsx +1 -0
  25. package/src/components/Table/components/items/TableItemActions.tsx +18 -13
  26. package/src/components/Table/components/print/TablePrint.tsx +1 -5
  27. package/src/components/Table/components/templates/CreateTemplateDialog.tsx +48 -0
  28. package/src/components/Table/components/templates/TableTemplates.tsx +24 -4
  29. package/src/components/Table/contexts/TableContext.tsx +33 -24
  30. package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +6 -4
  31. package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +17 -11
  32. package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +8 -6
  33. package/src/components/Table/hooks/useTableColumns.ts +1 -3
  34. package/src/components/Table/hooks/useTableEdit.tsx +24 -2
  35. package/src/components/Table/hooks/useTablePrint.ts +12 -4
  36. package/src/components/Table/hooks/useTableSelect.ts +1 -1
  37. package/src/components/Tooltip/Tooltip.tsx +81 -14
  38. package/src/hooks/useIsMenuOpen.ts +3 -3
  39. package/src/hooks/usePopupControl.ts +9 -4
  40. package/src/index.ts +23 -4
  41. package/src/styles/App.scss +1 -0
  42. package/src/styles/components/_badge.scss +7 -0
  43. package/src/styles/components/_header.scss +14 -1
  44. package/src/styles/components/_notifications.scss +71 -0
  45. package/src/styles/components/_page.scss +1 -0
  46. package/src/styles/components/_pullover.scss +1 -1
  47. package/src/styles/components/_sidebar.scss +1 -3
  48. package/src/styles/components/_table.scss +96 -54
  49. package/src/types/IKeyboard.ts +0 -5
  50. package/src/types/IMenu.ts +2 -2
  51. package/src/types/INotifications.ts +15 -0
  52. package/src/types/IPopup.ts +2 -2
  53. package/src/types/ITable.ts +35 -32
  54. package/src/utils/i18n/i18nIUICyrilic.ts +12 -0
  55. package/src/utils/i18n/i18nIUILatin.ts +13 -0
  56. package/src/utils/i18n/i18nIUIMe.ts +12 -0
  57. package/src/utils/objectUtils.ts +19 -0
  58. package/src/utils/tableUtils.ts +1 -1
  59. package/idea/Notifications.tsx +0 -245
  60. package/idea/Table/Components/Columns/ColumnsList.tsx +0 -61
  61. package/idea/Table/Components/Columns/SetColumnsList.tsx +0 -113
@@ -6,23 +6,24 @@ import { IPopupControl } from './IPopup';
6
6
  export interface ITable<T = unknown> {
7
7
  id?: string;
8
8
  columnData: ITableColumnsData;
9
- data: ITableDataItem[];
10
- dataActions?: ITableDataActions;
9
+ data: ITableDataItem<T>[];
10
+ dataActions?: ITableDataActions<T>;
11
11
  rowSelect?: {
12
12
  selectedRows: Set<string>;
13
13
  setSelectedRows: Dispatch<SetStateAction<Set<string>>>;
14
- actions: ITableSelectedAction[];
14
+ actions?: ITableSelectedAction[];
15
15
  };
16
16
  filterData?: ITableFilterData;
17
17
  sortData?: ITableSortData;
18
18
  templateData?: ITableTemplateData;
19
19
  printData?: IPrintData<T>;
20
- sumRows?: ITableDataItem[];
21
- editable?: ITableEdit;
20
+ sumRows?: ITableDataItem<T>[];
21
+ editable?: ITableEdit<T>;
22
22
  selectedRowUuid?: string;
23
+ itemDeleteData?: ITableItemDeleteData;
23
24
  keyboard?: {
24
25
  enabled: boolean;
25
- actions: ITableKeyboardActionsBase;
26
+ actions?: ITableKeyboardActionsBase;
26
27
  };
27
28
  headerWrap?: boolean;
28
29
  customHeader?: ITableColumn[][];
@@ -49,14 +50,16 @@ export interface ITableColumn {
49
50
  label?: string | ReactElement;
50
51
  labelForFilter?: string;
51
52
  align?: 'center' | 'left' | 'right' | 'justify' | undefined;
52
- hidden?: boolean;
53
53
  unavailable?: boolean;
54
+ hidden?: boolean;
55
+ printHidden?: boolean;
54
56
  width?: string;
55
57
  minWidth?: string;
56
58
  colSpan?: number;
57
59
  rowSpan?: number;
58
60
  break?: boolean;
59
61
  color?: 'secondary';
62
+ sticky?: boolean;
60
63
  sortOptions?: {
61
64
  asc: string;
62
65
  desc: string;
@@ -67,11 +70,11 @@ export interface ITableColumn {
67
70
  className?: string;
68
71
  }
69
72
 
70
- export interface ITableDataItem {
73
+ export interface ITableDataItem<T = unknown> {
71
74
  uuid: string;
72
75
  onRowClick?: (event?: MouseEvent<HTMLTableRowElement>) => void;
73
76
  className?: string;
74
- item?: Record<string, any>;
77
+ item?: T;
75
78
  disableSelect?: boolean;
76
79
  cells: ITableDataItemCells;
77
80
  extendable?: {
@@ -93,18 +96,13 @@ export interface ITableDataItemCells {
93
96
  };
94
97
  }
95
98
 
96
- export interface ITableDataActions {
97
- edit?: {
98
- hasAccess: boolean;
99
- };
100
- delete?: {
101
- onClick: (itemUuid: string) => void;
102
- hasAccess: boolean;
103
- };
104
- actions?: {
99
+ export interface ITableDataActions<T = unknown> {
100
+ hasEditAccess: boolean;
101
+ actions?: (item?: T) => {
105
102
  label: string;
106
- onClick: (item: ITableDataItem) => void;
103
+ onClick: () => void;
107
104
  hasAccess: boolean;
105
+ disabled?: boolean;
108
106
  }[];
109
107
  }
110
108
  export interface ITableFilterData {
@@ -156,25 +154,23 @@ export interface ITableSelectedAction {
156
154
  export interface ITableTemplateData {
157
155
  identifier: string;
158
156
  popupController: IPopupControl;
157
+ defaultTemplate?: IReportTemplate;
159
158
  items: IReportTemplate[];
160
159
  isLoading?: boolean;
161
160
  isFetching?: boolean;
162
161
  setSearch?: (search: string) => void;
163
- initiateCreate: () => void;
164
- initiateCreateDefault: () => void;
165
162
  setItemToDeleteUuids: (itemUuids: string[]) => void;
166
-
167
- // data: IReportTemplateData;
168
- // setTemplateName?: (templateName: string) => void;
169
- // onClearFilters: () => void;
170
-
171
- allowPublicCreate?: boolean;
172
- TemplateNode: ReactNode;
163
+ DeleteDialog: ReactNode;
164
+ createItem: {
165
+ allowPublicCreate?: boolean;
166
+ onCreate: (data: Partial<IReportTemplate>) => void;
167
+ onCreateDefault: () => void;
168
+ };
173
169
  }
174
170
  ///// EDIT /////
175
- export interface ITableEdit<T = any> {
176
- selectedItem: T | null;
177
- setSelectedItem: (item: T | null) => void;
171
+ export interface ITableEdit<T = unknown> {
172
+ selectedItem: ITableDataItem<T> | null;
173
+ setSelectedItem: (item: ITableDataItem<T> | null) => void;
178
174
  editData: Partial<T>;
179
175
  setEditData: Dispatch<SetStateAction<Partial<T>>>;
180
176
  onSubmit: (data: T, onSubmitCallback: () => void) => void;
@@ -186,6 +182,14 @@ export interface ITableEdit<T = any> {
186
182
  keepEditOnSubmit?: boolean;
187
183
  }
188
184
 
185
+ ///// DELETE /////
186
+ export interface ITableItemDeleteData {
187
+ hasAccess: boolean;
188
+ itemToDeleteUuids: string[];
189
+ setItemToDeleteUuids: Dispatch<SetStateAction<string[]>>;
190
+ DeleteDialog: ReactNode;
191
+ }
192
+
189
193
  ///// PRINT /////
190
194
  export interface IBasePrintData {
191
195
  label: string;
@@ -211,7 +215,6 @@ export type IGetPrintData<T> = (props: {
211
215
  export interface IPrintData<T = unknown> extends IBasePrintData {
212
216
  printPopupControl: IPopupControl;
213
217
  customHeader?: ITableColumn[][];
214
- excludeColumnIds?: string[];
215
218
  isLoading?: boolean;
216
219
  progress?: number;
217
220
  tableData?: ITableDataItem[];
@@ -91,6 +91,18 @@ export const i18nIUICyrilic = {
91
91
  ErrorMessage: 'Дошло је до грешке!',
92
92
  TryAgain: 'Покушај поново',
93
93
 
94
+ ////// NOTIFICATIONS //////
95
+ InApp: 'U aplikaciji',
96
+ MarkAllAsRead: 'Означи све као прочитано',
97
+ NoNewNotifications: 'Немате нове нотификације',
98
+ Notifications: 'Нотификације',
99
+ NotificationsAll: 'Све',
100
+ NotificationsUnread: 'Непрочитане',
101
+ NotificationsRead: 'Прочитане',
102
+ NotificationSound: 'Звук нотификације',
103
+ // NTitleADD_DOC: 'Додат је документ на платформу',
104
+ // NContentADD_DOC: 'Документ са бројем <documentNumber>{{- documentNumber}}</documentNumber> је додат на платформу',
105
+
94
106
  ////// PAGES //////
95
107
  ReturnToHomepage: 'Повратак на почетну страну',
96
108
  FooterText: `Инцептион ЦА је акредитовано сертификационо тело за квалификовану електронску доставу,
@@ -91,6 +91,19 @@ export const i18nIUILatin = {
91
91
  ErrorMessage: 'Došlo je do greške!',
92
92
  TryAgain: 'Pokušaj ponovo',
93
93
 
94
+ ////// NOTIFICATIONS //////
95
+ InApp: 'In-app',
96
+ // MarkAsRead: 'Označi kao pročitano',
97
+ MarkAllAsRead: 'Označi sve kao pročitano',
98
+ NoNewNotifications: 'Nemate nove notifikacije',
99
+ Notifications: 'Notifikacije',
100
+ NotificationsAll: 'Sve',
101
+ NotificationsUnread: 'Nepročitane',
102
+ NotificationsRead: 'Pročitane',
103
+ NotificationSound: 'Zvuk notifikacije',
104
+ // NTitleADD_DOC: 'Dodat je dokument na platformu',
105
+ // NContentADD_DOC: 'Dokument sa brojem <documentNumber>{{- documentNumber}}</documentNumber> je dodat na platformu',
106
+
94
107
  ////// PAGES //////
95
108
  ReturnToHomepage: 'Povratak na početnu stranu',
96
109
  FooterText: `Inception CA je akreditovano sertifikaciono telo za kvalifikovanu elektronsku dostavu,
@@ -90,6 +90,18 @@ export const i18nIUIMe = {
90
90
  ErrorMessage: 'Došlo je do greške!',
91
91
  TryAgain: 'Pokušajte ponovo',
92
92
 
93
+ ////// NOTIFICATIONS //////
94
+ InApp: 'In-app',
95
+ MarkAllAsRead: 'Označi sve kao pročitano',
96
+ NoNewNotifications: 'Nemate nove notifikacije',
97
+ Notifications: 'Notifikacije',
98
+ NotificationsAll: 'Sve',
99
+ NotificationsUnread: 'Nepročitane',
100
+ NotificationsRead: 'Pročitane',
101
+ NotificationSound: 'Zvuk notifikacije',
102
+ // NTitleADD_DOC: 'Dodat je dokument na platformu',
103
+ // NContentADD_DOC: 'Dokument sa brojem <documentNumber>{{- documentNumber}}</documentNumber> je dodat na platformu',
104
+
93
105
  ////// PAGES //////
94
106
  ReturnToHomepage: 'Povratak na početnu stranicu',
95
107
  FooterText: '',
@@ -1,4 +1,7 @@
1
+ import { TFunction } from 'i18next';
1
2
  import { IBooleanObject } from '../types/IBasic';
3
+ import { formatDate, formatDateAndTime } from './dateUtils';
4
+ import { INotification } from '../types/INotifications';
2
5
 
3
6
  export const hasValue = (value: any) => ![null, undefined, ''].includes(value);
4
7
 
@@ -83,3 +86,19 @@ export const intersectArrays = <T>(
83
86
  const set2 = new Set(arr2);
84
87
  return (arr1 as T[]).filter(item => set2.has(item));
85
88
  };
89
+
90
+ export const getNotificationValues = (
91
+ t: TFunction,
92
+ notificationValues?: INotification['values']
93
+ ) =>
94
+ notificationValues?.reduce((obj, item) => {
95
+ let processedValue = item.value;
96
+ if (item.format === 'TRANSLATE') {
97
+ processedValue = t(processedValue);
98
+ } else if (item.format === 'DATE') {
99
+ processedValue = formatDate(processedValue);
100
+ } else if (item.format === 'DATE_TIME') {
101
+ processedValue = formatDateAndTime(processedValue);
102
+ }
103
+ return { ...obj, [item.key]: processedValue };
104
+ }, {});
@@ -100,7 +100,7 @@ export const setTemplateData = ({
100
100
  newFilters && setFilters?.(newFilters);
101
101
  columnData &&
102
102
  columnData.setColumns?.(
103
- getVisibleColumnsFromList(columnData.columns, template.columns)
103
+ getVisibleColumnsFromList(columnData.defaultColumns, template.columns)
104
104
  );
105
105
  template.sorts && setSort && setSort(template.sorts[0]);
106
106
  };
@@ -1,245 +0,0 @@
1
- import {
2
- FontAwesomeIcon,
3
- ISelectData,
4
- IconButton,
5
- Menu,
6
- MenuItem,
7
- SearchInput,
8
- Trans,
9
- clsx,
10
- formatDate,
11
- formatDateAndTime,
12
- getActiveOrgUuid,
13
- useTranslation,
14
- } from '@inceptionbg/iui';
15
- import { FC, useCallback, useContext, useEffect, useState } from 'react';
16
- import { Link } from 'react-router-dom';
17
- import { faBell } from '../../InceptionMain/src/assets/icons/duotone/faBell';
18
- import { faBell as faBellLight } from '../../InceptionMain/src/assets/icons/light/faBell';
19
- import { faEnvelope } from '../../InceptionMain/src/assets/icons/light/faEnvelope';
20
- import { faCaretDown } from '../../InceptionMain/src/assets/icons/solid/faCaretDown';
21
- import { faEnvelopeDot } from '../../InceptionMain/src/assets/icons/solid/faEnvelopeDot';
22
- import notification from '../../../assets/sound/notification.mp3';
23
- import { UserOrgContext } from '../../InceptionMain/src/context/UserOrgContext';
24
- import {
25
- getNewNotificationCount,
26
- getNotifications,
27
- markAllNotificationsAsSeen,
28
- markNotificationAsSeen,
29
- } from '../../InceptionMain/src/repo/NotificationsRepository';
30
- import { INotification } from '../../InceptionMain/src/types/INotifications';
31
- import { ControledMenu } from '../src/components/ControledMenu/ControledMenu';
32
-
33
- const sound = new Audio(notification);
34
-
35
- export const Notifications: FC = () => {
36
- const [notificationCount, setNotificationCount] = useState(0);
37
- const [notifications, setNotifications] = useState<INotification[]>([]);
38
- const [isOpen, setIsOpen] = useState(false);
39
- const [isActionsOpen, setIsActionsOpen] = useState(false);
40
- const [seen, setSeen] = useState<boolean | null>(null);
41
-
42
- const { t } = useTranslation();
43
- const { userSettings } = useContext(UserOrgContext);
44
-
45
- const handleGetNotificationsCount = useCallback(
46
- (withSound?: boolean) => {
47
- getNewNotificationCount()
48
- .then(newCount => {
49
- setNotificationCount(count => {
50
- userSettings.notificationsSound &&
51
- withSound &&
52
- newCount > count &&
53
- sound.play();
54
- return newCount;
55
- });
56
- })
57
- .catch(() => {});
58
- },
59
- [userSettings.notificationsSound]
60
- );
61
-
62
- const handleGetNotifications = useCallback(() => {
63
- if (isOpen) {
64
- getNotifications(100, seen)
65
- .then(data => setNotifications(data.notifications || []))
66
- .catch(() => {});
67
- }
68
- }, [isOpen, seen]);
69
-
70
- useEffect(() => {
71
- if (getActiveOrgUuid()) {
72
- handleGetNotificationsCount();
73
-
74
- const notificationIntervalId = setInterval(() => {
75
- handleGetNotificationsCount(true);
76
- }, 50000);
77
- return () => {
78
- clearInterval(notificationIntervalId!);
79
- };
80
- }
81
- }, [handleGetNotificationsCount]);
82
-
83
- useEffect(handleGetNotifications, [handleGetNotifications]);
84
-
85
- const seenOptions: ISelectData[] = [
86
- { label: t('NotificationsAll'), value: null },
87
- { label: t('NotificationsUnread'), value: false },
88
- { label: t('NotificationsRead'), value: true },
89
- ];
90
-
91
- return (
92
- <ControledMenu
93
- isOpen={isOpen}
94
- onClose={() => setIsOpen(false)}
95
- placementY="bottom"
96
- placementX="right"
97
- size="l"
98
- renderButton={ref => (
99
- <div
100
- ref={ref}
101
- className="header-button notification-counter"
102
- onClick={() => setIsOpen(true)}
103
- >
104
- <div className="bell">
105
- <FontAwesomeIcon
106
- className="icon24"
107
- icon={!!notificationCount ? faBell : faBellLight}
108
- />
109
- </div>
110
- {!!notificationCount && (
111
- <div className="count">
112
- {notificationCount > 99 ? '99+' : notificationCount}
113
- </div>
114
- )}
115
- </div>
116
- )}
117
- >
118
- <div>
119
- <div className="flex gap-5 justify-between align-center px-3 py-2">
120
- <h1>Notifikacije</h1>
121
- <SearchInput onSearch={() => {}} />
122
- </div>
123
- <div className="flex justify-between px-3 py-2">
124
- <div className="flex gap-2">
125
- {seenOptions.map(({ label, value }) => (
126
- <div
127
- key={label}
128
- className={clsx('link fs-13', {
129
- inactive: seen !== value,
130
- })}
131
- onClick={() => setSeen(value)}
132
- >
133
- {label}
134
- </div>
135
- ))}
136
- </div>
137
- {!!notifications.length && (
138
- <Menu
139
- isOpen={isActionsOpen}
140
- onClose={() => setIsActionsOpen(false)}
141
- placementX="right"
142
- className="user-box-menu"
143
- renderButton={ref => (
144
- <p
145
- ref={ref}
146
- className="link fs-10"
147
- onClick={() => setIsActionsOpen(true)}
148
- >
149
- {t('Actions')}
150
- <FontAwesomeIcon className="ml-1" icon={faCaretDown} />
151
- </p>
152
- )}
153
- >
154
- <MenuItem
155
- label={t('MarkAllAsRead')}
156
- onClick={() => {
157
- markAllNotificationsAsSeen()
158
- .then(() => {
159
- handleGetNotificationsCount();
160
- handleGetNotifications();
161
- })
162
- .catch(() => {});
163
- }}
164
- />
165
- </Menu>
166
- )}
167
- </div>
168
- <div className="notifications-container">
169
- {!!notifications.length ? (
170
- notifications.map(notification => (
171
- <div
172
- key={notification.uuid}
173
- className={clsx('notification', { seen: notification.seen })}
174
- >
175
- <div className="header">
176
- <div>
177
- <p className="title">{t(`NTitle${notification.event}`)}</p>
178
- <p className="date">{formatDateAndTime(notification.createdAt)}</p>
179
- </div>
180
- <IconButton
181
- icon={notification.seen ? faEnvelope : faEnvelopeDot}
182
- className={notification.seen ? 'disabled' : 'unread-icon'}
183
- disabled={notification.seen}
184
- onClick={() =>
185
- markNotificationAsSeen(notification.uuid).then(() => {
186
- handleGetNotificationsCount();
187
- handleGetNotifications();
188
- })
189
- }
190
- />
191
- </div>
192
- <p className="desc">
193
- <Trans
194
- i18nKey={`NContent${notification.event}`}
195
- values={notification.values?.reduce((obj, e) => {
196
- let value = e.value;
197
- if (e.format === 'TRANSLATE') {
198
- value = t(value);
199
- } else if (e.format === 'DATE') {
200
- value = formatDate(value);
201
- } else if (e.format === 'DATE_TIME') {
202
- value = formatDateAndTime(value);
203
- }
204
-
205
- return {
206
- ...obj,
207
- [e.key]: value,
208
- };
209
- }, {})}
210
- t={t}
211
- components={notification.values?.reduce(
212
- (obj, e) =>
213
- e.url
214
- ? {
215
- ...obj,
216
- [e.key]: (
217
- <Link
218
- to={e.url}
219
- className="link"
220
- onClick={() => {
221
- !notification.seen &&
222
- markNotificationAsSeen(notification.uuid).then(
223
- handleGetNotifications
224
- );
225
- }}
226
- />
227
- ),
228
- }
229
- : obj,
230
- {
231
- bold: <span className="bold" />,
232
- }
233
- )}
234
- />
235
- </p>
236
- </div>
237
- ))
238
- ) : (
239
- <p className="text-center fs-13 pt-2">{t('NoNewNotifications')}</p>
240
- )}
241
- </div>
242
- </div>
243
- </ControledMenu>
244
- );
245
- };
@@ -1,61 +0,0 @@
1
- import { FC, useEffect, useState } from 'react';
2
- import { ITableColumn } from '../../../../types/ITable';
3
- import { Draggable, Droppable } from 'react-beautiful-dnd';
4
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5
- import { faGripDotsVertical } from '../../../../assets/icons/solid/faGripDotsVertical';
6
-
7
- interface Props {
8
- id: 'hidden' | 'visible';
9
- items: ITableColumn[];
10
- search: string;
11
- }
12
-
13
- export const ColumnsList: FC<Props> = ({ id, items, search }) => {
14
- const [filteredItems, setFilteredItems] = useState<ITableColumn[]>([]);
15
-
16
- useEffect(() => {
17
- search.length &&
18
- setFilteredItems(
19
- items.filter(e =>
20
- (typeof e.label === 'string' ? e.label : e.labelForFilter ?? '')
21
- .toLocaleLowerCase()
22
- .includes(search.toLocaleLowerCase())
23
- )
24
- );
25
- }, [search, items]);
26
-
27
- return (
28
- <Droppable droppableId={id}>
29
- {({ droppableProps, innerRef, placeholder }) => (
30
- <div {...droppableProps} ref={innerRef} className="list-box">
31
- {(search.length ? filteredItems : items).map(c => (
32
- <Draggable
33
- key={c.id}
34
- draggableId={c.id}
35
- index={items.indexOf(c)}
36
- isDragDisabled
37
- >
38
- {({ innerRef, draggableProps, dragHandleProps }) => (
39
- <div
40
- className="item"
41
- ref={innerRef}
42
- {...draggableProps}
43
- {...dragHandleProps}
44
- style={{
45
- ...draggableProps.style,
46
- top: 'unset',
47
- left: 'unset',
48
- }}
49
- >
50
- {c.label}
51
- <FontAwesomeIcon icon={faGripDotsVertical} />
52
- </div>
53
- )}
54
- </Draggable>
55
- ))}
56
- {placeholder}
57
- </div>
58
- )}
59
- </Droppable>
60
- );
61
- };
@@ -1,113 +0,0 @@
1
- import { FC, useEffect, useState } from 'react';
2
- import { DragDropContext, OnDragEndResponder } from 'react-beautiful-dnd';
3
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
- import { ITableColumn } from '../../../../types/ITable';
5
- import { Dialog } from '../../../Dialog/Dialog';
6
- import { faArrowRightArrowLeft } from '../../../../assets/icons/regular/faArrowRightArrowLeft';
7
- import { useTranslation } from 'react-i18next';
8
- import { ColumnsList } from './ColumnsList';
9
- import { SearchInput } from '../../../Inputs/SearchInput';
10
-
11
- interface Props {
12
- columns: ITableColumn[];
13
- setColumns: (data: ITableColumn[]) => void;
14
- isOpen: boolean;
15
- onClose: () => void;
16
- withSearch?: boolean;
17
- }
18
- export const SetColumnsList: FC<Props> = ({
19
- columns,
20
- setColumns,
21
- isOpen,
22
- onClose,
23
- withSearch,
24
- }) => {
25
- const [hidden, setHidden] = useState<ITableColumn[]>([]);
26
- const [visible, setVisible] = useState<ITableColumn[]>([]);
27
- const [searchHidden, setSearchHidden] = useState('');
28
- const [searchVisible, setSearchVisible] = useState('');
29
-
30
- const { t } = useTranslation();
31
-
32
- useEffect(() => {
33
- if (isOpen) {
34
- let hiddenCols: ITableColumn[] = [];
35
- let visibleCols: ITableColumn[] = [];
36
- columns.forEach(
37
- col =>
38
- col.id !== 'actions' &&
39
- !col.unavailable &&
40
- (!!col.hidden ? hiddenCols.push(col) : visibleCols.push(col))
41
- );
42
- setHidden(hiddenCols);
43
- setVisible(visibleCols);
44
- }
45
- }, [isOpen, columns]);
46
-
47
- const onDragEnd: OnDragEndResponder = ({ source, destination }) => {
48
- if (!destination) return;
49
- const hiddenCols = [...hidden];
50
- const visibleCols = [...visible];
51
- const destinationIsHidden = destination.droppableId === 'hidden';
52
-
53
- const sourceList = source.droppableId === 'hidden' ? hiddenCols : visibleCols;
54
- const destinationList = destinationIsHidden ? hiddenCols : visibleCols;
55
-
56
- const [removed] = sourceList.splice(source.index, 1);
57
- destinationList.splice(destination.index, 0, removed);
58
- if (source.droppableId !== destination.droppableId) {
59
- destinationList[destination.index].hidden = destinationIsHidden;
60
- setHidden(hiddenCols);
61
- setVisible(visibleCols);
62
- } else {
63
- destinationIsHidden ? setHidden(hiddenCols) : setVisible(visibleCols);
64
- }
65
- };
66
-
67
- const onSubmit = () => {
68
- const newColumns = [...visible, ...hidden];
69
- const lastCol = columns[columns.length - 1];
70
- if (lastCol.id === 'actions') {
71
- newColumns.push(lastCol);
72
- }
73
- setColumns(newColumns);
74
- onClose();
75
- };
76
-
77
- return (
78
- <DragDropContext onDragEnd={onDragEnd}>
79
- <Dialog
80
- isOpen={isOpen}
81
- onClose={onClose}
82
- confirmButton={{
83
- label: t('Confirm'),
84
- onClick: onSubmit,
85
- }}
86
- cancelButton={{ label: t('Cancel') }}
87
- noBackgroundClick
88
- >
89
- <div className="dual-list-container">
90
- <p className="pb-3">{t('DragDropListsInfo')}</p>
91
- <div className="dual-list-content">
92
- <p className="bold ml-2">{t('HiddenColumns')}:</p>
93
- <div />
94
- <p className="bold ml-2">{t('SelectedColumns')}:</p>
95
-
96
- {withSearch && (
97
- <>
98
- <SearchInput onSearch={setSearchHidden} />
99
- <div />
100
- <SearchInput onSearch={setSearchVisible} />
101
- </>
102
- )}
103
- <ColumnsList id="hidden" items={hidden} search={searchHidden} />
104
- <div className="exchange-icon">
105
- <FontAwesomeIcon icon={faArrowRightArrowLeft} />
106
- </div>
107
- <ColumnsList id="visible" items={visible} search={searchVisible} />
108
- </div>
109
- </div>
110
- </Dialog>
111
- </DragDropContext>
112
- );
113
- };