@inceptionbg/iui 2.0.16 → 2.0.19

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 +156 -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/light/faBell.ts +15 -0
  8. package/src/assets/icons/light/faEnvelope.ts +15 -0
  9. package/src/assets/icons/solid/faEnvelopeDot.ts +15 -0
  10. package/src/components/Button/SplitButton.tsx +5 -5
  11. package/src/components/Header/Components/ModuleSelect.tsx +5 -5
  12. package/src/components/Header/Components/Notifications.tsx +208 -0
  13. package/src/components/Header/Header.tsx +5 -4
  14. package/src/components/Inputs/NumberInput.tsx +3 -0
  15. package/src/components/Inputs/Selects/components/SelectWrapper.tsx +20 -30
  16. package/src/components/Loader/ProgressBar.tsx +1 -1
  17. package/src/components/Pullover/Pullover.tsx +44 -33
  18. package/src/components/Table/Table.tsx +5 -3
  19. package/src/components/Table/components/columns/TableColumnsEdit.tsx +5 -9
  20. package/src/components/Table/components/edit/TableEditRow.tsx +23 -12
  21. package/src/components/Table/components/header/TableHeaderRow.tsx +1 -0
  22. package/src/components/Table/components/items/TableItemActions.tsx +14 -13
  23. package/src/components/Table/components/print/TablePrint.tsx +1 -5
  24. package/src/components/Table/components/templates/CreateTemplateDialog.tsx +48 -0
  25. package/src/components/Table/components/templates/TableTemplates.tsx +24 -4
  26. package/src/components/Table/contexts/TableContext.tsx +33 -24
  27. package/src/components/Table/hooks/localHooks/useLocalTableColumns.tsx +6 -4
  28. package/src/components/Table/hooks/localHooks/useLocalTableData.tsx +17 -11
  29. package/src/components/Table/hooks/localHooks/useLocalTableKeyboard.ts +8 -6
  30. package/src/components/Table/hooks/useTableColumns.ts +1 -3
  31. package/src/components/Table/hooks/useTableEdit.tsx +24 -2
  32. package/src/components/Table/hooks/useTablePrint.ts +12 -4
  33. package/src/components/Table/hooks/useTableSelect.ts +1 -1
  34. package/src/components/Tooltip/Tooltip.tsx +81 -14
  35. package/src/components/Wrappers/FormWrapper.tsx +1 -1
  36. package/src/hooks/useIsMenuOpen.ts +3 -3
  37. package/src/hooks/usePopupControl.ts +9 -4
  38. package/src/index.ts +23 -4
  39. package/src/styles/App.scss +1 -0
  40. package/src/styles/components/_accordions.scss +1 -0
  41. package/src/styles/components/_badge.scss +7 -0
  42. package/src/styles/components/_header.scss +14 -1
  43. package/src/styles/components/_notifications.scss +71 -0
  44. package/src/styles/components/_page.scss +1 -0
  45. package/src/styles/components/_pullover.scss +1 -1
  46. package/src/styles/components/_sidebar.scss +1 -3
  47. package/src/styles/components/_table.scss +96 -54
  48. package/src/types/IKeyboard.ts +0 -5
  49. package/src/types/IMenu.ts +2 -2
  50. package/src/types/INotifications.ts +15 -0
  51. package/src/types/IPopup.ts +2 -2
  52. package/src/types/ISelect.ts +1 -0
  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
@@ -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
- };