@buerokratt-ria/common-gui-components 0.0.1

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 (122) hide show
  1. package/.eslintrc.json +18 -0
  2. package/CHANGELOG.md +7 -0
  3. package/MAKING_CHANGES.md +8 -0
  4. package/README.md +49 -0
  5. package/assets/ding.mp3 +0 -0
  6. package/assets/logo-white.svg +29 -0
  7. package/assets/logo.svg +31 -0
  8. package/assets/newMessageSound.mp3 +0 -0
  9. package/constants/config.ts +12 -0
  10. package/constants/index.ts +1 -0
  11. package/context/index.ts +1 -0
  12. package/context/toastContext.tsx +60 -0
  13. package/hooks/index.ts +3 -0
  14. package/hooks/useAudio.tsx +30 -0
  15. package/hooks/useDocumentEscapeListener.tsx +17 -0
  16. package/hooks/useToast.tsx +5 -0
  17. package/i18n.ts +26 -0
  18. package/index.ts +6 -0
  19. package/package.json +122 -0
  20. package/project.json +52 -0
  21. package/services/api.ts +74 -0
  22. package/services/index.ts +3 -0
  23. package/services/sse-service.ts +30 -0
  24. package/services/users.ts +58 -0
  25. package/store/index.ts +253 -0
  26. package/templates/history-page/index.ts +1 -0
  27. package/templates/history-page/src/History.scss +47 -0
  28. package/templates/history-page/src/index.tsx +998 -0
  29. package/templates/history-page/src/unfiyDate.tsx +7 -0
  30. package/translations/en/common.json +467 -0
  31. package/translations/et/common.json +467 -0
  32. package/tsconfig.base.json +21 -0
  33. package/tsconfig.json +17 -0
  34. package/tsconfig.spec.json +19 -0
  35. package/types/authorities.ts +8 -0
  36. package/types/botConfig.ts +7 -0
  37. package/types/chat.ts +126 -0
  38. package/types/customerSupportActivity.ts +5 -0
  39. package/types/deleteChatSettings.ts +9 -0
  40. package/types/emergencyNotice.ts +10 -0
  41. package/types/establishment.ts +4 -0
  42. package/types/index.ts +18 -0
  43. package/types/mainNavigation.ts +11 -0
  44. package/types/message.ts +74 -0
  45. package/types/organizationWorkingTime.ts +27 -0
  46. package/types/router.ts +4 -0
  47. package/types/service.ts +6 -0
  48. package/types/session.ts +7 -0
  49. package/types/skmConfig.ts +8 -0
  50. package/types/user.ts +40 -0
  51. package/types/userInfo.ts +16 -0
  52. package/types/userProfileSettings.ts +10 -0
  53. package/types/widgetConfig.ts +8 -0
  54. package/ui-components/Button/Button.scss +150 -0
  55. package/ui-components/Button/index.tsx +41 -0
  56. package/ui-components/ButtonMessage/ButtonMessage.scss +16 -0
  57. package/ui-components/ButtonMessage/index.tsx +19 -0
  58. package/ui-components/Card/Card.scss +69 -0
  59. package/ui-components/Card/index.tsx +39 -0
  60. package/ui-components/Chat/Chat.scss +447 -0
  61. package/ui-components/Chat/ChatMessage.tsx +270 -0
  62. package/ui-components/Chat/ChatTextArea.scss +110 -0
  63. package/ui-components/Chat/ChatTextArea.tsx +97 -0
  64. package/ui-components/Chat/LoaderOverlay.tsx +39 -0
  65. package/ui-components/Chat/Markdownify.tsx +49 -0
  66. package/ui-components/Chat/PreviewMessage.tsx +39 -0
  67. package/ui-components/Chat/Typing.scss +46 -0
  68. package/ui-components/Chat/index.tsx +1111 -0
  69. package/ui-components/ChatEvent/Chat.scss +40 -0
  70. package/ui-components/ChatEvent/index.tsx +216 -0
  71. package/ui-components/DataTable/CloseIcon.tsx +22 -0
  72. package/ui-components/DataTable/DataTable.scss +188 -0
  73. package/ui-components/DataTable/DeboucedInput.scss +11 -0
  74. package/ui-components/DataTable/DebouncedInput.tsx +54 -0
  75. package/ui-components/DataTable/Filter.tsx +121 -0
  76. package/ui-components/DataTable/index.tsx +432 -0
  77. package/ui-components/Dialog/Dialog.scss +63 -0
  78. package/ui-components/Dialog/index.tsx +44 -0
  79. package/ui-components/Drawer/Drawer.scss +40 -0
  80. package/ui-components/Drawer/index.tsx +42 -0
  81. package/ui-components/FormElements/FormCheckbox/FormCheckbox.scss +57 -0
  82. package/ui-components/FormElements/FormCheckbox/index.tsx +39 -0
  83. package/ui-components/FormElements/FormCheckboxes/FormCheckboxes.scss +63 -0
  84. package/ui-components/FormElements/FormCheckboxes/index.tsx +44 -0
  85. package/ui-components/FormElements/FormDatepicker/FormDatepicker.scss +154 -0
  86. package/ui-components/FormElements/FormDatepicker/index.tsx +123 -0
  87. package/ui-components/FormElements/FormInput/FormInput.scss +90 -0
  88. package/ui-components/FormElements/FormInput/index.tsx +47 -0
  89. package/ui-components/FormElements/FormRadios/FormRadios.scss +72 -0
  90. package/ui-components/FormElements/FormRadios/index.tsx +36 -0
  91. package/ui-components/FormElements/FormSelect/FormMultiselect.tsx +124 -0
  92. package/ui-components/FormElements/FormSelect/FormSelect.scss +121 -0
  93. package/ui-components/FormElements/FormSelect/index.tsx +100 -0
  94. package/ui-components/FormElements/FormTextarea/FormTextarea.scss +109 -0
  95. package/ui-components/FormElements/FormTextarea/index.tsx +154 -0
  96. package/ui-components/FormElements/Switch/Switch.scss +69 -0
  97. package/ui-components/FormElements/Switch/index.tsx +65 -0
  98. package/ui-components/FormElements/SwitchBox/SwitchBox.scss +45 -0
  99. package/ui-components/FormElements/SwitchBox/index.tsx +44 -0
  100. package/ui-components/FormElements/index.tsx +23 -0
  101. package/ui-components/HistoricalChat/ChatMessage.tsx +67 -0
  102. package/ui-components/HistoricalChat/HistoricalChat.scss +225 -0
  103. package/ui-components/HistoricalChat/index.tsx +282 -0
  104. package/ui-components/Icon/Icon.scss +17 -0
  105. package/ui-components/Icon/index.tsx +26 -0
  106. package/ui-components/Label/Label.scss +76 -0
  107. package/ui-components/Label/index.tsx +40 -0
  108. package/ui-components/OptionMessage/OptionMessage.scss +16 -0
  109. package/ui-components/OptionMessage/index.tsx +16 -0
  110. package/ui-components/Toast/Toast.scss +73 -0
  111. package/ui-components/Toast/index.tsx +54 -0
  112. package/ui-components/Tooltip/Tooltip.scss +17 -0
  113. package/ui-components/Tooltip/index.tsx +28 -0
  114. package/ui-components/Track/index.tsx +57 -0
  115. package/ui-components/index.tsx +53 -0
  116. package/utils/constants.ts +19 -0
  117. package/utils/format-bytes.ts +8 -0
  118. package/utils/generateUEID.ts +8 -0
  119. package/utils/local-storage-utils.ts +17 -0
  120. package/utils/parse-utils.ts +23 -0
  121. package/utils/state-management-utils.ts +13 -0
  122. package/vite.config.ts +67 -0
@@ -0,0 +1,40 @@
1
+ @import 'src/styles/tools/spacing';
2
+ @import 'src/styles/tools/color';
3
+ @import 'src/styles/settings/variables/other';
4
+ @import 'src/styles/settings/variables/typography';
5
+
6
+ .active-chat {
7
+ $self: &;
8
+ display: flex;
9
+ justify-content: flex-end;
10
+ position: relative;
11
+ height: 100%;
12
+
13
+ &__event-message {
14
+ display: flex;
15
+ position: relative;
16
+ isolation: isolate;
17
+ padding: 6px 0;
18
+
19
+ p {
20
+ color: get-color(black-coral-12);
21
+ font-size: $veera-font-size-80;
22
+ line-height: $veera-line-height-500;
23
+ padding: 4px 8px 4px 0;
24
+ background-color: get-color(white);
25
+ }
26
+
27
+ &::after {
28
+ content: '';
29
+ display: block;
30
+ height: 1px;
31
+ background-color: get-color(black-coral-2);
32
+ position: absolute;
33
+ top: 50%;
34
+ left: 56px;
35
+ right: 0;
36
+ transform: translateY(-50%);
37
+ z-index: -1;
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,216 @@
1
+ import React, { FC } from 'react';
2
+ import { useTranslation } from 'react-i18next';
3
+
4
+ import { Message } from '../../types/message';
5
+ import { CHAT_EVENTS } from '../../types/chat';
6
+ import { format } from 'date-fns';
7
+ import './Chat.scss';
8
+
9
+ type ChatEventProps = {
10
+ message: Message;
11
+ };
12
+
13
+ const ChatEvent: FC<ChatEventProps> = ({ message }) => {
14
+ const { t } = useTranslation();
15
+ const {
16
+ event,
17
+ authorTimestamp,
18
+ forwardedByUser,
19
+ forwardedFromCsa,
20
+ forwardedToCsa,
21
+ } = message;
22
+
23
+ let EVENT_PARAMS;
24
+
25
+ switch (event) {
26
+ case CHAT_EVENTS.REDIRECTED:
27
+ if (forwardedByUser === forwardedFromCsa) {
28
+ EVENT_PARAMS = t('chat.redirectedMessageByOwner', {
29
+ from: forwardedFromCsa,
30
+ to: forwardedToCsa,
31
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
32
+ });
33
+ } else if (forwardedByUser === forwardedToCsa) {
34
+ EVENT_PARAMS = t('chat.redirectedMessageClaimed', {
35
+ from: forwardedFromCsa,
36
+ to: forwardedToCsa,
37
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
38
+ });
39
+ } else {
40
+ EVENT_PARAMS = t('chat.redirectedMessage', {
41
+ user: forwardedByUser,
42
+ from: forwardedFromCsa,
43
+ to: forwardedToCsa,
44
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
45
+ });
46
+ }
47
+
48
+ break;
49
+ case CHAT_EVENTS.ANSWERED:
50
+ EVENT_PARAMS = t('chat.events.answered', {
51
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
52
+ });
53
+ break;
54
+ case CHAT_EVENTS.TERMINATED:
55
+ EVENT_PARAMS = t('chat.events.terminated', {
56
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
57
+ });
58
+ break;
59
+ case CHAT_EVENTS.CLIENT_LEFT:
60
+ EVENT_PARAMS = t('chat.events.client-left', {
61
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
62
+ });
63
+ break;
64
+ case CHAT_EVENTS.CLIENT_LEFT_WITH_ACCEPTED:
65
+ EVENT_PARAMS = t('chat.events.client-left-with-accepted', {
66
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
67
+ });
68
+ break;
69
+ case CHAT_EVENTS.CLIENT_LEFT_WITH_NO_RESOLUTION:
70
+ EVENT_PARAMS = t('chat.events.client-left-with-no-resolution', {
71
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
72
+ });
73
+ break;
74
+ case CHAT_EVENTS.CLIENT_LEFT_FOR_UNKNOWN_REASONS:
75
+ EVENT_PARAMS = t('chat.events.client-left-for-unknown-reason', {
76
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
77
+ });
78
+ break;
79
+ case CHAT_EVENTS.ACCEPTED:
80
+ EVENT_PARAMS = t('chat.events.accepted', {
81
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
82
+ });
83
+ break;
84
+ case CHAT_EVENTS.HATE_SPEECH:
85
+ EVENT_PARAMS = t('chat.events.hate-speech', {
86
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
87
+ });
88
+ break;
89
+ case CHAT_EVENTS.OTHER:
90
+ EVENT_PARAMS = t('chat.events.other', {
91
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
92
+ });
93
+ break;
94
+ case CHAT_EVENTS.RESPONSE_SENT_TO_CLIENT_EMAIL:
95
+ EVENT_PARAMS = t('chat.events.response-sent-to-client-email', {
96
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
97
+ });
98
+ break;
99
+ case CHAT_EVENTS.GREETING:
100
+ EVENT_PARAMS = t('chat.events.greeting', {
101
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
102
+ });
103
+ break;
104
+ case CHAT_EVENTS.REQUESTED_AUTHENTICATION:
105
+ EVENT_PARAMS = t('chat.events.requested-authentication', {
106
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
107
+ });
108
+ break;
109
+ case CHAT_EVENTS.AUTHENTICATION_SUCCESSFUL:
110
+ EVENT_PARAMS = t('chat.events.authentication-successful', {
111
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
112
+ });
113
+ break;
114
+ case CHAT_EVENTS.AUTHENTICATION_FAILED:
115
+ EVENT_PARAMS = t('chat.events.authentication-failed', {
116
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
117
+ });
118
+ break;
119
+ case CHAT_EVENTS.ASK_PERMISSION:
120
+ EVENT_PARAMS = t('chat.events.ask-permission', {
121
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
122
+ });
123
+ break;
124
+ case CHAT_EVENTS.ASK_PERMISSION_ACCEPTED:
125
+ EVENT_PARAMS = t('chat.events.ask-permission-accepted', {
126
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
127
+ });
128
+ break;
129
+ case CHAT_EVENTS.ASK_PERMISSION_REJECTED:
130
+ EVENT_PARAMS = t('chat.events.ask-permission-rejected', {
131
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
132
+ });
133
+ break;
134
+ case CHAT_EVENTS.ASK_PERMISSION_IGNORED:
135
+ EVENT_PARAMS = t('chat.events.ask-permission-ignored', {
136
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
137
+ });
138
+ break;
139
+ case CHAT_EVENTS.RATING:
140
+ EVENT_PARAMS = t('chat.events.rating', {
141
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
142
+ });
143
+ break;
144
+ case CHAT_EVENTS.CONTACT_INFORMATION:
145
+ EVENT_PARAMS = t('chat.events.contact-information', {
146
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
147
+ });
148
+ break;
149
+ case CHAT_EVENTS.CONTACT_INFORMATION_REJECTED:
150
+ EVENT_PARAMS = t('chat.events.contact-information-rejected', {
151
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
152
+ });
153
+ break;
154
+ case CHAT_EVENTS.CONTACT_INFORMATION_FULFILLED:
155
+ EVENT_PARAMS = t('chat.events.contact-information-fulfilled', {
156
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
157
+ });
158
+ break;
159
+ case CHAT_EVENTS.REQUESTED_CHAT_FORWARD:
160
+ EVENT_PARAMS = t('chat.events.requested-chat-forward', {
161
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
162
+ });
163
+ break;
164
+ case CHAT_EVENTS.REQUESTED_CHAT_FORWARD_ACCEPTED:
165
+ EVENT_PARAMS = t('chat.events.requested-chat-forward-accepted', {
166
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
167
+ });
168
+ break;
169
+ case CHAT_EVENTS.REQUESTED_CHAT_FORWARD_REJECTED:
170
+ EVENT_PARAMS = t('chat.events.requested-chat-forward-rejected', {
171
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
172
+ });
173
+ break;
174
+ case CHAT_EVENTS.ASSIGN_PENDING_CHAT_CSA:
175
+ EVENT_PARAMS = t('chat.events.pending-assigned', {
176
+ name: message.authorFirstName ?? 'CSA',
177
+ });
178
+ break;
179
+ case CHAT_EVENTS.PENDING_USER_REACHED:
180
+ EVENT_PARAMS = t('chat.events.user-reached', {
181
+ name: message.authorFirstName ?? 'CSA',
182
+ });
183
+ break;
184
+ case CHAT_EVENTS.PENDING_USER_NOT_REACHED:
185
+ EVENT_PARAMS = t('chat.events.user-not-reached', {
186
+ name: message.authorFirstName ?? 'CSA',
187
+ });
188
+ break;
189
+ case CHAT_EVENTS.USER_AUTHENTICATED:
190
+ EVENT_PARAMS = t('chat.events.user-authenticated', {
191
+ name: `${message.authorFirstName ?? ''} ${
192
+ message.authorLastName ?? ''
193
+ }`,
194
+ date: format(new Date(message.authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
195
+ });
196
+ break;
197
+ case CHAT_EVENTS.READ:
198
+ EVENT_PARAMS = t('chat.events.read', {
199
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
200
+ });
201
+ break;
202
+ default:
203
+ EVENT_PARAMS = t(`chat.events.${event?.toLowerCase()}`, {
204
+ date: format(new Date(authorTimestamp), 'dd.MM.yyyy HH:mm:ss'),
205
+ });
206
+ break;
207
+ }
208
+
209
+ return (
210
+ <div className="active-chat__event-message">
211
+ <p>{EVENT_PARAMS}</p>
212
+ </div>
213
+ );
214
+ };
215
+
216
+ export default ChatEvent;
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import './DeboucedInput.scss';
3
+
4
+ const CloseIcon: React.FC = () => (
5
+ <svg
6
+ className="search-icon"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ viewBox="0 0 24 24"
9
+ height="17"
10
+ width="17"
11
+ fill="none"
12
+ stroke="currentColor"
13
+ strokeWidth="2"
14
+ strokeLinecap="round"
15
+ strokeLinejoin="round"
16
+ >
17
+ <line x1="18" y1="6" x2="6" y2="18" />
18
+ <line x1="6" y1="6" x2="18" y2="18" />
19
+ </svg>
20
+ );
21
+
22
+ export default CloseIcon;
@@ -0,0 +1,188 @@
1
+ @import 'src/styles/tools/spacing';
2
+ @import 'src/styles/tools/color';
3
+ @import 'src/styles/settings/variables/typography';
4
+
5
+ .data-table {
6
+ width: 100%;
7
+ color: get-color(black-coral-20);
8
+ text-align: left;
9
+ margin-bottom: 0;
10
+ display: table;
11
+
12
+ &__scrollWrapper {
13
+ height: 100%;
14
+ white-space: nowrap;
15
+ overflow-x: auto;
16
+ display: block;
17
+ max-height: 60vh;
18
+ }
19
+
20
+ thead, tbody {
21
+ width: 100%;
22
+ }
23
+
24
+ th {
25
+ padding: 12px 14.5px;
26
+ color: get-color(black-coral-12);
27
+ border-bottom: 1px solid get-color(black-coral-10);
28
+ font-weight: $veera-font-weight-beta;
29
+ vertical-align: middle;
30
+ position: relative;
31
+ }
32
+
33
+ td {
34
+ padding: 12px 24px 12px 16px;
35
+ border-bottom: 1px solid get-color(black-coral-2);
36
+ vertical-align: middle;
37
+ max-width: fit-content;
38
+
39
+ p{
40
+ white-space: break-spaces;
41
+ }
42
+
43
+ .entity {
44
+ display: inline-flex;
45
+ align-items: center;
46
+ padding-left: 4px;
47
+ background-color: get-color(sapphire-blue-2);
48
+ border-radius: 4px;
49
+
50
+ span {
51
+ display: inline-flex;
52
+ font-size: $veera-font-size-80;
53
+ background-color: get-color(white);
54
+ padding: 0 4px;
55
+ border-radius: 4px;
56
+ margin: 2px 2px 2px 4px;
57
+ }
58
+ }
59
+ }
60
+
61
+ tbody {
62
+ tr {
63
+ &:last-child {
64
+ td {
65
+ border-bottom: 0;
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ &__filter {
72
+ input {
73
+ width: 120px;
74
+ display: block;
75
+ appearance: none;
76
+ background-color: get-color(white);
77
+ border: 1px solid get-color(black-coral-6);
78
+ border-radius: 5px;
79
+ color: var(--color-black);
80
+ font-size: $veera-font-size-100;
81
+ height: 32px;
82
+ line-height: 24px;
83
+ padding: get-spacing(paldiski);
84
+
85
+ &::placeholder {
86
+ color: get-color(black-coral-6);
87
+ }
88
+
89
+ &:focus {
90
+ outline: none;
91
+ border-color: get-color(sapphire-blue-10);
92
+ }
93
+ }
94
+ }
95
+
96
+ &__pagination-wrapper {
97
+ display: flex;
98
+ border-top: 1px solid get-color(black-coral-10);
99
+ padding: 6px 16px;
100
+ }
101
+
102
+ &__pagination {
103
+ display: flex;
104
+ align-items: center;
105
+ gap: 15px;
106
+ margin: 0 auto;
107
+
108
+ + .data-table__page-size {
109
+ margin-left: 0;
110
+ }
111
+
112
+ .next,
113
+ .previous {
114
+ display: flex;
115
+ color: get-color(sapphire-blue-10);
116
+
117
+ &[disabled] {
118
+ color: get-color(black-coral-11);
119
+ cursor: initial;
120
+ }
121
+ }
122
+
123
+ .links {
124
+ display: flex;
125
+ align-items: center;
126
+ gap: 5px;
127
+ font-size: $veera-font-size-80;
128
+ color: get-color(black-coral-10);
129
+
130
+ li {
131
+ display: block;
132
+
133
+ a, span {
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ width: 25px;
138
+ height: 25px;
139
+ border-radius: 50%;
140
+
141
+ &:hover {
142
+ text-decoration: none;
143
+ }
144
+ }
145
+
146
+ &.active {
147
+ a, span {
148
+ color: get-color(white);
149
+ background-color: get-color(sapphire-blue-10);
150
+ }
151
+ }
152
+ }
153
+ }
154
+ }
155
+
156
+ &__page-size {
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 8px;
160
+ font-size: $veera-font-size-80;
161
+ line-height: 16px;
162
+ color: get-color(black-coral-11);
163
+ margin-left: auto;
164
+
165
+ select {
166
+ appearance: none;
167
+ font-size: $veera-font-size-70;
168
+ line-height: 16px;
169
+ height: 30px;
170
+ min-width: 50px;
171
+ padding: 6px 10px;
172
+ border: 1px solid #8F91A8;
173
+ border-radius: 2px;
174
+ background-color: get-color(white);
175
+ background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNiIgdmlld0JveD0iMCAwIDEwIDYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNNS4zMTMwNiA1LjgwODIyQzUuMTU2ODUgNS45NjQ0MyA0LjkwMzU4IDUuOTY0NDMgNC43NDczNyA1LjgwODIyTDAuMjgyNzMgMS4zNDM1OEMwLjEyNjUyIDEuMTg3MzcgMC4xMjY1MiAwLjkzNDEwMiAwLjI4MjczIDAuNzc3ODkzTDAuNzc3NzA0IDAuMjgyOTE4QzAuOTMzOTE0IDAuMTI2NzA4IDEuMTg3MTggMC4xMjY3MDggMS4zNDMzOSAwLjI4MjkxN0w1LjAzMDIyIDMuOTY5NzRMOC43MTcwNCAwLjI4MjkxN0M4Ljg3MzI1IDAuMTI2NzA4IDkuMTI2NTIgMC4xMjY3MDggOS4yODI3MyAwLjI4MjkxN0w5Ljc3NzcgMC43Nzc4OTJDOS45MzM5MSAwLjkzNDEwMiA5LjkzMzkxIDEuMTg3MzcgOS43Nzc3IDEuMzQzNThMNS4zMTMwNiA1LjgwODIyWiIgZmlsbD0iIzU1NTg2NyIvPgo8L3N2Zz4K');
176
+ background-repeat: no-repeat;
177
+ background-position: top 11px right 10px;
178
+ }
179
+ }
180
+ }
181
+
182
+ .highlighted {
183
+ background-color: get-color(sapphire-blue-1);
184
+ }
185
+
186
+ .default {
187
+ background-color: white;
188
+ }
@@ -0,0 +1,11 @@
1
+ .input-container {
2
+ position: relative;
3
+ }
4
+
5
+ .search-icon {
6
+ position: absolute;
7
+ top: 50%;
8
+ right: 10px;
9
+ margin-left: 10px;
10
+ transform: translateY(-50%);
11
+ }
@@ -0,0 +1,54 @@
1
+ import React, { FC, InputHTMLAttributes, useEffect, useState } from 'react';
2
+ import './DeboucedInput.scss';
3
+ import CloseIcon from './CloseIcon';
4
+
5
+ type DebouncedInputProps = Omit<
6
+ InputHTMLAttributes<HTMLInputElement>,
7
+ 'onChange'
8
+ > & {
9
+ value: string | number | string[];
10
+ onChange: (value: string | number | string[]) => void;
11
+ debounce?: number;
12
+ };
13
+
14
+ const DebouncedInput: FC<DebouncedInputProps> = ({
15
+ value: initialValue,
16
+ onChange,
17
+ debounce = 500,
18
+ ...props
19
+ }) => {
20
+ const [value, setValue] = useState(initialValue);
21
+
22
+ useEffect(() => {
23
+ setValue(initialValue);
24
+ }, [initialValue]);
25
+
26
+ useEffect(() => {
27
+ const timeout = setTimeout(() => {
28
+ onChange(value);
29
+ }, debounce);
30
+
31
+ return () => clearTimeout(timeout);
32
+ }, [value]);
33
+
34
+ return (
35
+ <div className="input-container">
36
+ <input
37
+ style={{ paddingRight: '30px' }}
38
+ {...props}
39
+ value={value}
40
+ onChange={(e) => setValue(e.target.value)}
41
+ />
42
+ {value && (
43
+ <button
44
+ style={{ position: 'absolute', right: '0px', bottom: '15px' }}
45
+ onClick={() => setValue('')}
46
+ >
47
+ <CloseIcon />
48
+ </button>
49
+ )}
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default DebouncedInput;
@@ -0,0 +1,121 @@
1
+ import React, { FC, useState, MouseEvent } from 'react';
2
+ import { Column, Table } from '@tanstack/react-table';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { MdOutlineSearch } from 'react-icons/md';
5
+
6
+ import { Icon } from '../';
7
+ import useDocumentEscapeListener from '../../hooks/useDocumentEscapeListener';
8
+ import DebouncedInput from './DebouncedInput';
9
+
10
+ type FilterProps = {
11
+ column: Column<any, unknown>;
12
+ table: Table<any>;
13
+ };
14
+
15
+ const Filter: FC<FilterProps> = ({ column, table }) => {
16
+ const { t } = useTranslation();
17
+ const [filterOpen, setFilterOpen] = useState(false);
18
+ const firstValue = table
19
+ .getPreFilteredRowModel()
20
+ .flatRows[0]?.getValue(column.id);
21
+
22
+ const columnFilterValue = column.getFilterValue();
23
+
24
+ useDocumentEscapeListener(() => setFilterOpen(false));
25
+
26
+ const handleFilterToggle = (e: MouseEvent) => {
27
+ e.stopPropagation();
28
+ setFilterOpen(!filterOpen);
29
+ };
30
+
31
+ return (
32
+ <>
33
+ <button onClick={handleFilterToggle}>
34
+ <Icon icon={<MdOutlineSearch fontSize={16} />} size="medium" />
35
+ </button>
36
+ {filterOpen && (
37
+ <div className="data-table__filter">
38
+ {typeof firstValue === 'number' ? (
39
+ <DebouncedInput
40
+ type="number"
41
+ min={Number(column.getFacetedMinMaxValues()?.[0] ?? '')}
42
+ max={Number(column.getFacetedMinMaxValues()?.[1] ?? '')}
43
+ value={(columnFilterValue as [number, number])?.[0] ?? ''}
44
+ onChange={(value) =>
45
+ column.setFilterValue((old: [number, number]) => [
46
+ value,
47
+ old?.[1],
48
+ ])
49
+ }
50
+ />
51
+ ) : (
52
+ <DebouncedInput
53
+ type="text"
54
+ value={''}
55
+ onChange={(value) => column.setFilterValue(value)}
56
+ placeholder={t('global.search') + '...'}
57
+ // list={column.id + 'list'}
58
+ />
59
+ )}
60
+ </div>
61
+ )}
62
+ </>
63
+ );
64
+
65
+ // return typeof firstValue === 'number' ? (
66
+ // <div>
67
+ // <div className='flex space-x-2'>
68
+ // <DebouncedInput
69
+ // type='number'
70
+ // min={Number(column.getFacetedMinMaxValues()?.[0] ?? '')}
71
+ // max={Number(column.getFacetedMinMaxValues()?.[1] ?? '')}
72
+ // value={(columnFilterValue as [number, number])?.[0] ?? ''}
73
+ // onChange={value =>
74
+ // column.setFilterValue((old: [number, number]) => [value, old?.[1]])
75
+ // }
76
+ // placeholder={`Min ${
77
+ // column.getFacetedMinMaxValues()?.[0]
78
+ // ? `(${column.getFacetedMinMaxValues()?.[0]})`
79
+ // : ''
80
+ // }`}
81
+ // className='w-24 border shadow rounded'
82
+ // />
83
+ // <DebouncedInput
84
+ // type='number'
85
+ // min={Number(column.getFacetedMinMaxValues()?.[0] ?? '')}
86
+ // max={Number(column.getFacetedMinMaxValues()?.[1] ?? '')}
87
+ // value={(columnFilterValue as [number, number])?.[1] ?? ''}
88
+ // onChange={value =>
89
+ // column.setFilterValue((old: [number, number]) => [old?.[0], value])
90
+ // }
91
+ // placeholder={`Max ${
92
+ // column.getFacetedMinMaxValues()?.[1]
93
+ // ? `(${column.getFacetedMinMaxValues()?.[1]})`
94
+ // : ''
95
+ // }`}
96
+ // className='w-24 border shadow rounded'
97
+ // />
98
+ // </div>
99
+ // <div className='h-1' />
100
+ // </div>
101
+ // ) : (
102
+ // <>
103
+ // <datalist id={column.id + 'list'}>
104
+ // {sortedUniqueValues.slice(0, 5000).map((value: any) => (
105
+ // <option value={value} key={value} />
106
+ // ))}
107
+ // </datalist>
108
+ // <DebouncedInput
109
+ // type='text'
110
+ // value={(columnFilterValue ?? '') as string}
111
+ // onChange={value => column.setFilterValue(value)}
112
+ // placeholder={`Search... (${column.getFacetedUniqueValues().size})`}
113
+ // className='w-36 border shadow rounded'
114
+ // list={column.id + 'list'}
115
+ // />
116
+ // <div className='h-1' />
117
+ // </>
118
+ // );
119
+ };
120
+
121
+ export default Filter;