@addev-be/ui 0.10.10 → 0.10.11

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 (177) hide show
  1. package/assets/icons/arrow-down-1-9.svg +1 -1
  2. package/assets/icons/arrow-down-a-z.svg +1 -1
  3. package/assets/icons/arrow-up-z-a.svg +1 -1
  4. package/assets/icons/check.svg +1 -1
  5. package/assets/icons/circle-check.svg +1 -1
  6. package/assets/icons/down.svg +1 -1
  7. package/assets/icons/filter-full.svg +1 -1
  8. package/assets/icons/filter.svg +1 -1
  9. package/assets/icons/hashtag.svg +1 -1
  10. package/assets/icons/image-slash.svg +1 -1
  11. package/assets/icons/left.svg +1 -1
  12. package/assets/icons/magnifier.svg +1 -1
  13. package/assets/icons/phone.svg +1 -1
  14. package/assets/icons/right.svg +1 -1
  15. package/assets/icons/sort-calendar-ascending.svg +5 -5
  16. package/assets/icons/spinner-third.svg +1 -1
  17. package/assets/icons/table-columns.svg +1 -1
  18. package/assets/icons/table-footer-slash.svg +4 -4
  19. package/assets/icons/table-footer.svg +3 -3
  20. package/assets/icons/up.svg +1 -1
  21. package/assets/icons/user-tie.svg +1 -1
  22. package/assets/icons/x-bar.svg +3 -3
  23. package/dist/components/auth/LoginForm.js +0 -1
  24. package/dist/components/data/DataGrid/AdvancedRequestDataGrid.d.ts +10 -0
  25. package/dist/components/data/DataGrid/AdvancedRequestDataGrid.js +173 -0
  26. package/dist/components/data/DataGrid/FilterValuesScroller.d.ts +13 -0
  27. package/dist/components/data/DataGrid/FilterValuesScroller.js +73 -0
  28. package/dist/components/data/DataGrid/VirtualScroller.d.ts +11 -0
  29. package/dist/components/data/DataGrid/VirtualScroller.js +41 -0
  30. package/dist/components/data/DataGrid/helpers/advancedRequests.d.ts +12 -0
  31. package/dist/components/data/DataGrid/helpers/advancedRequests.js +53 -0
  32. package/dist/components/data/DataGrid/helpers.d.ts +28 -0
  33. package/dist/components/data/DataGrid/helpers.js +436 -0
  34. package/dist/config/types.d.ts +11 -0
  35. package/dist/config/types.js +2 -0
  36. package/dist/providers/AuthenticationProvider/index.d.ts +0 -1
  37. package/dist/providers/AuthenticationProvider/index.js +14 -28
  38. package/dist/services/advancedRequests.d.ts +1 -1
  39. package/dist/services/requests/userPermissions.d.ts +4 -0
  40. package/dist/services/requests/userPermissions.js +20 -0
  41. package/dist/services/sqlRequests.d.ts +1 -1
  42. package/package.json +1 -1
  43. package/src/Icons.tsx +128 -128
  44. package/src/components/auth/LoginForm.tsx +84 -84
  45. package/src/components/auth/LoginPage.tsx +32 -32
  46. package/src/components/auth/PasswordRecoveryForm.tsx +52 -52
  47. package/src/components/auth/PasswordResetForm.tsx +112 -112
  48. package/src/components/auth/index.ts +4 -4
  49. package/src/components/auth/styles.ts +14 -14
  50. package/src/components/data/AdvancedRequestDataGrid/helpers/advancedRequests.ts +93 -93
  51. package/src/components/data/AdvancedRequestDataGrid/helpers/columns.tsx +262 -262
  52. package/src/components/data/AdvancedRequestDataGrid/helpers/index.ts +2 -2
  53. package/src/components/data/AdvancedRequestDataGrid/index.tsx +267 -267
  54. package/src/components/data/AdvancedRequestDataGrid/types.ts +47 -47
  55. package/src/components/data/DataGrid/DataGridCell.tsx +73 -73
  56. package/src/components/data/DataGrid/DataGridColumnsModal/helpers.ts +14 -14
  57. package/src/components/data/DataGrid/DataGridColumnsModal/hooks.tsx +59 -59
  58. package/src/components/data/DataGrid/DataGridColumnsModal/index.tsx +181 -181
  59. package/src/components/data/DataGrid/DataGridColumnsModal/styles.ts +104 -104
  60. package/src/components/data/DataGrid/DataGridEditableCell.tsx +43 -43
  61. package/src/components/data/DataGrid/DataGridFilterMenu/FilterValuesScroller.tsx +120 -120
  62. package/src/components/data/DataGrid/DataGridFilterMenu/hooks.tsx +75 -75
  63. package/src/components/data/DataGrid/DataGridFilterMenu/index.tsx +378 -378
  64. package/src/components/data/DataGrid/DataGridFilterMenu/styles.ts +97 -97
  65. package/src/components/data/DataGrid/DataGridFooter.tsx +42 -42
  66. package/src/components/data/DataGrid/DataGridHeader.tsx +126 -126
  67. package/src/components/data/DataGrid/DataGridHeaderCell.tsx +132 -132
  68. package/src/components/data/DataGrid/DataGridRowTemplate.tsx +70 -70
  69. package/src/components/data/DataGrid/FilterModalContent/index.tsx +136 -136
  70. package/src/components/data/DataGrid/FilterModalContent/styles.ts +22 -22
  71. package/src/components/data/DataGrid/helpers/columns.tsx +319 -319
  72. package/src/components/data/DataGrid/helpers/filters.ts +287 -287
  73. package/src/components/data/DataGrid/helpers/index.ts +2 -2
  74. package/src/components/data/DataGrid/hooks/index.ts +30 -30
  75. package/src/components/data/DataGrid/hooks/useDataGrid.tsx +287 -287
  76. package/src/components/data/DataGrid/hooks/useDataGridCopy.ts +175 -175
  77. package/src/components/data/DataGrid/hooks/useDataGridSettings.ts +48 -48
  78. package/src/components/data/DataGrid/index.tsx +83 -83
  79. package/src/components/data/DataGrid/styles.ts +285 -285
  80. package/src/components/data/DataGrid/types.ts +276 -276
  81. package/src/components/data/SqlRequestDataGrid/helpers/columns.tsx +306 -306
  82. package/src/components/data/SqlRequestDataGrid/helpers/index.ts +2 -2
  83. package/src/components/data/SqlRequestDataGrid/helpers/sqlRequests.ts +16 -16
  84. package/src/components/data/SqlRequestDataGrid/index.tsx +385 -385
  85. package/src/components/data/SqlRequestDataGrid/types.ts +48 -48
  86. package/src/components/data/SqlRequestGrid/filters/FiltersSidebar.tsx +106 -106
  87. package/src/components/data/SqlRequestGrid/filters/styles.ts +88 -88
  88. package/src/components/data/SqlRequestGrid/helpers/index.ts +1 -1
  89. package/src/components/data/SqlRequestGrid/helpers/sqlRequests.ts +16 -16
  90. package/src/components/data/SqlRequestGrid/index.tsx +308 -308
  91. package/src/components/data/SqlRequestGrid/styles.ts +20 -20
  92. package/src/components/data/SqlRequestGrid/types.ts +53 -53
  93. package/src/components/data/VirtualScroller/hooks.ts +71 -71
  94. package/src/components/data/VirtualScroller/index.tsx +85 -85
  95. package/src/components/data/VirtualScroller/styles.ts +60 -60
  96. package/src/components/data/VirtualScroller/types.ts +12 -12
  97. package/src/components/data/index.ts +17 -17
  98. package/src/components/forms/AutoTextArea.tsx +41 -41
  99. package/src/components/forms/Button.tsx +133 -133
  100. package/src/components/forms/IconButton.tsx +57 -57
  101. package/src/components/forms/IndeterminateCheckbox.tsx +46 -46
  102. package/src/components/forms/Select.tsx +40 -40
  103. package/src/components/forms/VerticalLabel.tsx +20 -20
  104. package/src/components/forms/index.ts +6 -6
  105. package/src/components/forms/styles.ts +31 -31
  106. package/src/components/index.ts +6 -6
  107. package/src/components/layout/Dropdown/index.tsx +112 -112
  108. package/src/components/layout/Dropdown/styles.ts +45 -45
  109. package/src/components/layout/Loading/index.tsx +29 -29
  110. package/src/components/layout/Loading/styles.ts +29 -29
  111. package/src/components/layout/Modal/index.tsx +51 -51
  112. package/src/components/layout/Modal/styles.ts +121 -121
  113. package/src/components/layout/index.ts +3 -3
  114. package/src/components/search/HighlightedText.tsx +37 -37
  115. package/src/components/search/QuickSearchBar.tsx +86 -86
  116. package/src/components/search/QuickSearchResults.tsx +86 -86
  117. package/src/components/search/index.ts +9 -9
  118. package/src/components/search/styles.ts +96 -96
  119. package/src/components/search/types.ts +26 -26
  120. package/src/components/ui/Avatar/index.tsx +54 -54
  121. package/src/components/ui/Card/index.tsx +14 -14
  122. package/src/components/ui/Card/styles.ts +37 -37
  123. package/src/components/ui/ContextMenu/index.tsx +79 -79
  124. package/src/components/ui/ContextMenu/styles.ts +119 -119
  125. package/src/components/ui/Label.tsx +90 -90
  126. package/src/components/ui/Message/index.tsx +57 -57
  127. package/src/components/ui/Message/styles.ts +40 -40
  128. package/src/components/ui/index.ts +5 -5
  129. package/src/config/index.ts +14 -14
  130. package/src/helpers/dates.ts +17 -17
  131. package/src/helpers/getScrollbarSize.ts +14 -14
  132. package/src/helpers/index.ts +3 -3
  133. package/src/helpers/numbers.ts +26 -26
  134. package/src/helpers/text.ts +13 -13
  135. package/src/hooks/index.ts +3 -3
  136. package/src/hooks/useElementSize.ts +24 -24
  137. package/src/hooks/useShowArchived.ts +11 -12
  138. package/src/hooks/useWindowSize.ts +20 -20
  139. package/src/index.ts +9 -9
  140. package/src/providers/AuthenticationProvider/helpers.ts +3 -3
  141. package/src/providers/AuthenticationProvider/index.tsx +240 -240
  142. package/src/providers/LoadingProvider/index.tsx +47 -47
  143. package/src/providers/PortalsProvider/index.tsx +54 -54
  144. package/src/providers/PortalsProvider/styles.ts +27 -27
  145. package/src/providers/SettingsProvider/index.tsx +70 -70
  146. package/src/providers/ThemeProvider/ThemeProvider.ts +63 -63
  147. package/src/providers/ThemeProvider/defaultTheme.ts +457 -457
  148. package/src/providers/ThemeProvider/index.ts +4 -4
  149. package/src/providers/ThemeProvider/types.ts +131 -131
  150. package/src/providers/TrackingProvider/index.tsx +71 -71
  151. package/src/providers/UiProviders/index.tsx +68 -68
  152. package/src/providers/UiProviders/styles.ts +10 -10
  153. package/src/providers/hooks.ts +12 -12
  154. package/src/providers/index.ts +8 -8
  155. package/src/services/HttpService.ts +92 -92
  156. package/src/services/WebSocketService.ts +137 -137
  157. package/src/services/advancedRequests.ts +102 -102
  158. package/src/services/base.ts +23 -23
  159. package/src/services/globalSearch.ts +29 -29
  160. package/src/services/hooks.ts +44 -44
  161. package/src/services/index.ts +17 -17
  162. package/src/services/requests/auth.ts +44 -44
  163. package/src/services/requests/generic.ts +62 -62
  164. package/src/services/requests/tracking.ts +12 -12
  165. package/src/services/requests/userProfiles.ts +35 -35
  166. package/src/services/requests/users.ts +28 -28
  167. package/src/services/sqlRequests.ts +111 -111
  168. package/src/services/types/auth.ts +131 -131
  169. package/src/services/types/base.ts +10 -10
  170. package/src/services/types/generic.ts +92 -92
  171. package/src/services/types/tracking.ts +39 -39
  172. package/src/services/types/userProfiles.ts +107 -107
  173. package/src/services/types/users.ts +106 -106
  174. package/src/styles/animations.scss +30 -30
  175. package/src/styles/index.scss +42 -42
  176. package/src/typings.d.ts +13 -13
  177. package/tsconfig.json +18 -18
@@ -1,378 +1,378 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
3
-
4
- import * as styles from './styles';
5
-
6
- import {
7
- ArrowDown19Icon,
8
- ArrowDownAZIcon,
9
- ArrowDownBigSmallIcon,
10
- ArrowUp91Icon,
11
- ArrowUpBigSmallIcon,
12
- ArrowUpZAIcon,
13
- FilterIcon,
14
- FilterSlashIcon,
15
- IconFC,
16
- MagnifierIcon,
17
- SigmaIcon,
18
- SortCalendarAscendingIcon,
19
- SortCalendarDescendingIcon,
20
- TableFooterIcon,
21
- TableFooterSlashIcon,
22
- TallyIcon,
23
- XBarIcon,
24
- } from '../../../../Icons';
25
- import {
26
- DataGridContext,
27
- DataGridFilterType,
28
- DataGridFilterValue,
29
- DataGridFooterPredefinedFunction,
30
- } from '../types';
31
- import {
32
- applyFilters,
33
- defaultRendererAndFormatter,
34
- getDateGroups,
35
- } from '../helpers';
36
- import { intersection, uniq, without } from 'lodash';
37
- import {
38
- useCallback,
39
- useContext,
40
- useEffect,
41
- useMemo,
42
- useRef,
43
- useState,
44
- } from 'react';
45
-
46
- import { ContextMenu } from '../../../ui/ContextMenu';
47
- import { FilterValuesScroller } from './FilterValuesScroller';
48
- import { Input } from '../../../forms';
49
- import { MenuContainer } from '../../../ui/ContextMenu/styles';
50
- import { useFilterModal } from './hooks';
51
-
52
- type FilterValuesProps<R> = {
53
- columnKey: string;
54
- columnIndex: number;
55
- context: DataGridContext<R>;
56
- onClose?: () => void;
57
- contextMenu?: boolean;
58
- showTotalButton?: boolean;
59
- };
60
-
61
- const sortAsc: Record<DataGridFilterType, [string, IconFC]> = {
62
- number: ['Trier du plus petit au plus grand', ArrowDown19Icon],
63
- text: ['Trier de A à Z', ArrowDownAZIcon],
64
- date: ['Trier du plus ancien au plus récent', SortCalendarAscendingIcon],
65
- };
66
- const sortDesc: Record<DataGridFilterType, [string, IconFC]> = {
67
- number: ['Trier du plus grand au plus petit', ArrowUp91Icon],
68
- text: ['Trier de Z à A', ArrowUpZAIcon],
69
- date: ['Trier du plus récent au plus ancien', SortCalendarDescendingIcon],
70
- };
71
-
72
- const footerFunctionsTexts: Record<DataGridFooterPredefinedFunction, string> = {
73
- average: 'Moyenne',
74
- avg: 'Moyenne',
75
- count: 'Nombre',
76
- max: 'Maximum',
77
- min: 'Minimum',
78
- sum: 'Somme',
79
- };
80
- const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
81
- average: XBarIcon,
82
- avg: XBarIcon,
83
- count: TallyIcon,
84
- max: ArrowUpBigSmallIcon,
85
- min: ArrowDownBigSmallIcon,
86
- sum: SigmaIcon,
87
- };
88
-
89
- export const DataGridFilterMenu = <R,>({
90
- columnKey,
91
- context,
92
- onClose,
93
- contextMenu = true,
94
- showTotalButton = true,
95
- }: FilterValuesProps<R>) => {
96
- const { openModal, modal } = useFilterModal({ columnKey, context });
97
- const {
98
- filters = {},
99
- footers = {},
100
- rows,
101
- columns,
102
- setFilters,
103
- filterValuesLoader,
104
- setSorts,
105
- setFooters,
106
- } = useContext(context);
107
- const column = columns[columnKey] ?? {};
108
- const textFilterInputRef = useRef<HTMLInputElement>(null);
109
- const [textFilter, setTextFilter] = useState('');
110
-
111
- const [availableValues, setAvailableValues] = useState<DataGridFilterValue[]>(
112
- []
113
- );
114
-
115
- useEffect(() => {
116
- if (filterValuesLoader) {
117
- filterValuesLoader(columnKey).then((values) => {
118
- setAvailableValues(() => values);
119
- });
120
- } else {
121
- const otherFilters = Object.entries(filters)
122
- .filter(([key]) => key !== columnKey)
123
- .map(([, filter]) => filter);
124
- const availableRows = applyFilters(rows, otherFilters);
125
- const values = availableRows.map((row) => column.filter!.getter(row));
126
- setAvailableValues(() =>
127
- uniq(values).sort(
128
- column.filter?.type === 'number'
129
- ? (a, b) => (a as number) - (b as number)
130
- : (a, b) => (a as string).localeCompare(b as string)
131
- )
132
- );
133
- }
134
- }, [column.filter, columnKey, filterValuesLoader, filters, rows]);
135
-
136
- const selectedValues = useMemo(
137
- () => filters?.[columnKey]?.values ?? [],
138
- [columnKey, filters]
139
- );
140
-
141
- const clearFilter = useCallback(() => {
142
- const newFilters = { ...filters };
143
- delete newFilters[columnKey];
144
- setFilters(newFilters);
145
- onClose?.();
146
- }, [filters, columnKey, setFilters, onClose]);
147
-
148
- const setValuesChecked = useCallback(
149
- (values: any[], checked?: boolean) => {
150
- setFilters((prevFilters) => {
151
- const newValues = checked
152
- ? [...(prevFilters[columnKey]?.values ?? []), ...values]
153
- : without(prevFilters[columnKey]?.values ?? [], ...values);
154
- const newFilters = {
155
- ...prevFilters,
156
- };
157
- if (newValues.length === 0) {
158
- delete newFilters[columnKey];
159
- } else {
160
- newFilters[columnKey] = {
161
- ...(prevFilters[columnKey] ?? column.filter),
162
- operator: 'inArray',
163
- values: newValues,
164
- };
165
- }
166
- return newFilters;
167
- });
168
- },
169
- [setFilters, columnKey, column.filter]
170
- );
171
-
172
- const toggleValues = useCallback(
173
- (values: DataGridFilterValue[]) => {
174
- const checked =
175
- intersection(selectedValues, values).length === values.length;
176
- setValuesChecked(values, !checked);
177
- },
178
- [setValuesChecked, selectedValues]
179
- );
180
-
181
- const formatter = useMemo(
182
- () => column.filter?.formatter ?? defaultRendererAndFormatter,
183
- [column.filter?.formatter]
184
- );
185
- const renderer = useMemo(
186
- () => column.filter?.renderer ?? defaultRendererAndFormatter,
187
- [column.filter?.renderer]
188
- );
189
-
190
- const filteredAvailableValues = useMemo(
191
- () =>
192
- !textFilter
193
- ? availableValues
194
- : availableValues.filter((value) =>
195
- formatter(value)?.toLowerCase().includes(textFilter.toLowerCase())
196
- ),
197
- [availableValues, formatter, textFilter]
198
- );
199
-
200
- useEffect(() => {
201
- if (textFilterInputRef.current) {
202
- textFilterInputRef.current.focus();
203
- }
204
- }, []);
205
-
206
- const checkboxesComponent = useMemo(() => {
207
- const groups =
208
- column.type === 'date'
209
- ? getDateGroups(filteredAvailableValues)
210
- : undefined;
211
- return (
212
- <FilterValuesScroller
213
- values={filteredAvailableValues}
214
- selectedValues={selectedValues}
215
- onToggle={toggleValues}
216
- formatter={formatter}
217
- renderer={renderer}
218
- groups={groups}
219
- />
220
- );
221
- }, [
222
- column.type,
223
- filteredAvailableValues,
224
- formatter,
225
- renderer,
226
- selectedValues,
227
- toggleValues,
228
- ]);
229
-
230
- const onSortAscClicked = useCallback(() => {
231
- setSorts({ [columnKey]: 'asc' });
232
- onClose?.();
233
- }, [columnKey, onClose, setSorts]);
234
- const onSortDescClicked = useCallback(() => {
235
- setSorts({ [columnKey]: 'desc' });
236
- onClose?.();
237
- }, [columnKey, onClose, setSorts]);
238
-
239
- const hasFilters = filters[columnKey]?.values.length > 0;
240
- const [[sortAscText, SortAscIcon], [sortDescText, SortDescIcon]] = [
241
- sortAsc[column.filter?.type ?? 'text'],
242
- sortDesc[column.filter?.type ?? 'text'],
243
- ];
244
-
245
- const isFooterVisible =
246
- columnKey in footers && footers[columnKey] !== undefined;
247
- const showFooter = useCallback(
248
- (key: string) => {
249
- setFooters((prevFooters) => ({
250
- ...prevFooters,
251
- [columnKey]: key,
252
- }));
253
- onClose?.();
254
- },
255
- [columnKey, onClose, setFooters]
256
- );
257
- const hideFooter = useCallback(() => {
258
- setFooters((prevFooters) => {
259
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
260
- const { [columnKey]: _, ...newFooters } = prevFooters;
261
- return newFooters;
262
- });
263
- onClose?.();
264
- }, [columnKey, onClose, setFooters]);
265
-
266
- const content = (
267
- <>
268
- {modal}
269
- {column.sortGetter && (
270
- <>
271
- <ContextMenu.Item onClick={onSortAscClicked}>
272
- <SortAscIcon />
273
- {sortAscText}
274
- </ContextMenu.Item>
275
- <ContextMenu.Item onClick={onSortDescClicked}>
276
- <SortDescIcon />
277
- {sortDescText}
278
- </ContextMenu.Item>
279
- <ContextMenu.Divider />
280
- </>
281
- )}
282
- {isFooterVisible && typeof column.footer === 'function' && (
283
- <>
284
- <ContextMenu.Item onClick={hideFooter}>
285
- <TableFooterSlashIcon />
286
- Masquer le total
287
- </ContextMenu.Item>
288
- <ContextMenu.Divider />
289
- </>
290
- )}
291
- {showTotalButton && (
292
- <>
293
- {!isFooterVisible && typeof column.footer === 'function' && (
294
- <>
295
- <ContextMenu.Item onClick={() => showFooter('count')}>
296
- <TableFooterIcon />
297
- Afficher le total
298
- </ContextMenu.Item>
299
- <ContextMenu.Divider />
300
- </>
301
- )}
302
- {showTotalButton && typeof column.footer === 'object' && (
303
- <>
304
- <ContextMenu.ParentItem>
305
- <TableFooterIcon />
306
- Afficher le total
307
- <ContextMenu.SubMenu>
308
- {Object.keys(column.footer).map((key) => {
309
- const TotalIcon =
310
- footerFunctionsIcons[
311
- key as DataGridFooterPredefinedFunction
312
- ] ?? TableFooterIcon;
313
- return (
314
- <ContextMenu.Item
315
- key={key}
316
- onClick={() => showFooter(key)}
317
- >
318
- <TotalIcon />
319
- {key in footerFunctionsTexts
320
- ? footerFunctionsTexts[
321
- key as DataGridFooterPredefinedFunction
322
- ]
323
- : key}
324
- </ContextMenu.Item>
325
- );
326
- })}
327
- <ContextMenu.Divider />
328
- <ContextMenu.Item
329
- onClick={hideFooter}
330
- disabled={!isFooterVisible}
331
- >
332
- <TableFooterSlashIcon />
333
- Masquer le total
334
- </ContextMenu.Item>
335
- </ContextMenu.SubMenu>
336
- </ContextMenu.ParentItem>
337
- <ContextMenu.Divider />
338
- </>
339
- )}
340
- </>
341
- )}
342
- <ContextMenu.Item onClick={openModal}>
343
- <FilterIcon />
344
- Filtrer ...
345
- </ContextMenu.Item>
346
- <ContextMenu.Item
347
- $color="danger"
348
- onClick={clearFilter}
349
- disabled={!hasFilters}
350
- >
351
- <FilterSlashIcon />
352
- Supprimer le filtre
353
- </ContextMenu.Item>
354
- <ContextMenu.Divider />
355
- <styles.InputContainer>
356
- <MagnifierIcon />
357
- <Input
358
- ref={textFilterInputRef}
359
- type="text"
360
- name="search"
361
- id="search"
362
- placeholder="Rechercher ..."
363
- value={textFilter}
364
- onChange={(e) => setTextFilter(e.target.value)}
365
- />
366
- </styles.InputContainer>
367
- <styles.CheckboxesContainer>
368
- {checkboxesComponent}
369
- </styles.CheckboxesContainer>
370
- </>
371
- );
372
-
373
- if (!contextMenu) {
374
- return <MenuContainer>{content}</MenuContainer>;
375
- }
376
-
377
- return <ContextMenu>{content}</ContextMenu>;
378
- };
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
3
+
4
+ import * as styles from './styles';
5
+
6
+ import {
7
+ ArrowDown19Icon,
8
+ ArrowDownAZIcon,
9
+ ArrowDownBigSmallIcon,
10
+ ArrowUp91Icon,
11
+ ArrowUpBigSmallIcon,
12
+ ArrowUpZAIcon,
13
+ FilterIcon,
14
+ FilterSlashIcon,
15
+ IconFC,
16
+ MagnifierIcon,
17
+ SigmaIcon,
18
+ SortCalendarAscendingIcon,
19
+ SortCalendarDescendingIcon,
20
+ TableFooterIcon,
21
+ TableFooterSlashIcon,
22
+ TallyIcon,
23
+ XBarIcon,
24
+ } from '../../../../Icons';
25
+ import {
26
+ DataGridContext,
27
+ DataGridFilterType,
28
+ DataGridFilterValue,
29
+ DataGridFooterPredefinedFunction,
30
+ } from '../types';
31
+ import {
32
+ applyFilters,
33
+ defaultRendererAndFormatter,
34
+ getDateGroups,
35
+ } from '../helpers';
36
+ import { intersection, uniq, without } from 'lodash';
37
+ import {
38
+ useCallback,
39
+ useContext,
40
+ useEffect,
41
+ useMemo,
42
+ useRef,
43
+ useState,
44
+ } from 'react';
45
+
46
+ import { ContextMenu } from '../../../ui/ContextMenu';
47
+ import { FilterValuesScroller } from './FilterValuesScroller';
48
+ import { Input } from '../../../forms';
49
+ import { MenuContainer } from '../../../ui/ContextMenu/styles';
50
+ import { useFilterModal } from './hooks';
51
+
52
+ type FilterValuesProps<R> = {
53
+ columnKey: string;
54
+ columnIndex: number;
55
+ context: DataGridContext<R>;
56
+ onClose?: () => void;
57
+ contextMenu?: boolean;
58
+ showTotalButton?: boolean;
59
+ };
60
+
61
+ const sortAsc: Record<DataGridFilterType, [string, IconFC]> = {
62
+ number: ['Trier du plus petit au plus grand', ArrowDown19Icon],
63
+ text: ['Trier de A à Z', ArrowDownAZIcon],
64
+ date: ['Trier du plus ancien au plus récent', SortCalendarAscendingIcon],
65
+ };
66
+ const sortDesc: Record<DataGridFilterType, [string, IconFC]> = {
67
+ number: ['Trier du plus grand au plus petit', ArrowUp91Icon],
68
+ text: ['Trier de Z à A', ArrowUpZAIcon],
69
+ date: ['Trier du plus récent au plus ancien', SortCalendarDescendingIcon],
70
+ };
71
+
72
+ const footerFunctionsTexts: Record<DataGridFooterPredefinedFunction, string> = {
73
+ average: 'Moyenne',
74
+ avg: 'Moyenne',
75
+ count: 'Nombre',
76
+ max: 'Maximum',
77
+ min: 'Minimum',
78
+ sum: 'Somme',
79
+ };
80
+ const footerFunctionsIcons: Record<DataGridFooterPredefinedFunction, IconFC> = {
81
+ average: XBarIcon,
82
+ avg: XBarIcon,
83
+ count: TallyIcon,
84
+ max: ArrowUpBigSmallIcon,
85
+ min: ArrowDownBigSmallIcon,
86
+ sum: SigmaIcon,
87
+ };
88
+
89
+ export const DataGridFilterMenu = <R,>({
90
+ columnKey,
91
+ context,
92
+ onClose,
93
+ contextMenu = true,
94
+ showTotalButton = true,
95
+ }: FilterValuesProps<R>) => {
96
+ const { openModal, modal } = useFilterModal({ columnKey, context });
97
+ const {
98
+ filters = {},
99
+ footers = {},
100
+ rows,
101
+ columns,
102
+ setFilters,
103
+ filterValuesLoader,
104
+ setSorts,
105
+ setFooters,
106
+ } = useContext(context);
107
+ const column = columns[columnKey] ?? {};
108
+ const textFilterInputRef = useRef<HTMLInputElement>(null);
109
+ const [textFilter, setTextFilter] = useState('');
110
+
111
+ const [availableValues, setAvailableValues] = useState<DataGridFilterValue[]>(
112
+ []
113
+ );
114
+
115
+ useEffect(() => {
116
+ if (filterValuesLoader) {
117
+ filterValuesLoader(columnKey).then((values) => {
118
+ setAvailableValues(() => values);
119
+ });
120
+ } else {
121
+ const otherFilters = Object.entries(filters)
122
+ .filter(([key]) => key !== columnKey)
123
+ .map(([, filter]) => filter);
124
+ const availableRows = applyFilters(rows, otherFilters);
125
+ const values = availableRows.map((row) => column.filter!.getter(row));
126
+ setAvailableValues(() =>
127
+ uniq(values).sort(
128
+ column.filter?.type === 'number'
129
+ ? (a, b) => (a as number) - (b as number)
130
+ : (a, b) => (a as string).localeCompare(b as string)
131
+ )
132
+ );
133
+ }
134
+ }, [column.filter, columnKey, filterValuesLoader, filters, rows]);
135
+
136
+ const selectedValues = useMemo(
137
+ () => filters?.[columnKey]?.values ?? [],
138
+ [columnKey, filters]
139
+ );
140
+
141
+ const clearFilter = useCallback(() => {
142
+ const newFilters = { ...filters };
143
+ delete newFilters[columnKey];
144
+ setFilters(newFilters);
145
+ onClose?.();
146
+ }, [filters, columnKey, setFilters, onClose]);
147
+
148
+ const setValuesChecked = useCallback(
149
+ (values: any[], checked?: boolean) => {
150
+ setFilters((prevFilters) => {
151
+ const newValues = checked
152
+ ? [...(prevFilters[columnKey]?.values ?? []), ...values]
153
+ : without(prevFilters[columnKey]?.values ?? [], ...values);
154
+ const newFilters = {
155
+ ...prevFilters,
156
+ };
157
+ if (newValues.length === 0) {
158
+ delete newFilters[columnKey];
159
+ } else {
160
+ newFilters[columnKey] = {
161
+ ...(prevFilters[columnKey] ?? column.filter),
162
+ operator: 'inArray',
163
+ values: newValues,
164
+ };
165
+ }
166
+ return newFilters;
167
+ });
168
+ },
169
+ [setFilters, columnKey, column.filter]
170
+ );
171
+
172
+ const toggleValues = useCallback(
173
+ (values: DataGridFilterValue[]) => {
174
+ const checked =
175
+ intersection(selectedValues, values).length === values.length;
176
+ setValuesChecked(values, !checked);
177
+ },
178
+ [setValuesChecked, selectedValues]
179
+ );
180
+
181
+ const formatter = useMemo(
182
+ () => column.filter?.formatter ?? defaultRendererAndFormatter,
183
+ [column.filter?.formatter]
184
+ );
185
+ const renderer = useMemo(
186
+ () => column.filter?.renderer ?? defaultRendererAndFormatter,
187
+ [column.filter?.renderer]
188
+ );
189
+
190
+ const filteredAvailableValues = useMemo(
191
+ () =>
192
+ !textFilter
193
+ ? availableValues
194
+ : availableValues.filter((value) =>
195
+ formatter(value)?.toLowerCase().includes(textFilter.toLowerCase())
196
+ ),
197
+ [availableValues, formatter, textFilter]
198
+ );
199
+
200
+ useEffect(() => {
201
+ if (textFilterInputRef.current) {
202
+ textFilterInputRef.current.focus();
203
+ }
204
+ }, []);
205
+
206
+ const checkboxesComponent = useMemo(() => {
207
+ const groups =
208
+ column.type === 'date'
209
+ ? getDateGroups(filteredAvailableValues)
210
+ : undefined;
211
+ return (
212
+ <FilterValuesScroller
213
+ values={filteredAvailableValues}
214
+ selectedValues={selectedValues}
215
+ onToggle={toggleValues}
216
+ formatter={formatter}
217
+ renderer={renderer}
218
+ groups={groups}
219
+ />
220
+ );
221
+ }, [
222
+ column.type,
223
+ filteredAvailableValues,
224
+ formatter,
225
+ renderer,
226
+ selectedValues,
227
+ toggleValues,
228
+ ]);
229
+
230
+ const onSortAscClicked = useCallback(() => {
231
+ setSorts({ [columnKey]: 'asc' });
232
+ onClose?.();
233
+ }, [columnKey, onClose, setSorts]);
234
+ const onSortDescClicked = useCallback(() => {
235
+ setSorts({ [columnKey]: 'desc' });
236
+ onClose?.();
237
+ }, [columnKey, onClose, setSorts]);
238
+
239
+ const hasFilters = filters[columnKey]?.values.length > 0;
240
+ const [[sortAscText, SortAscIcon], [sortDescText, SortDescIcon]] = [
241
+ sortAsc[column.filter?.type ?? 'text'],
242
+ sortDesc[column.filter?.type ?? 'text'],
243
+ ];
244
+
245
+ const isFooterVisible =
246
+ columnKey in footers && footers[columnKey] !== undefined;
247
+ const showFooter = useCallback(
248
+ (key: string) => {
249
+ setFooters((prevFooters) => ({
250
+ ...prevFooters,
251
+ [columnKey]: key,
252
+ }));
253
+ onClose?.();
254
+ },
255
+ [columnKey, onClose, setFooters]
256
+ );
257
+ const hideFooter = useCallback(() => {
258
+ setFooters((prevFooters) => {
259
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
260
+ const { [columnKey]: _, ...newFooters } = prevFooters;
261
+ return newFooters;
262
+ });
263
+ onClose?.();
264
+ }, [columnKey, onClose, setFooters]);
265
+
266
+ const content = (
267
+ <>
268
+ {modal}
269
+ {column.sortGetter && (
270
+ <>
271
+ <ContextMenu.Item onClick={onSortAscClicked}>
272
+ <SortAscIcon />
273
+ {sortAscText}
274
+ </ContextMenu.Item>
275
+ <ContextMenu.Item onClick={onSortDescClicked}>
276
+ <SortDescIcon />
277
+ {sortDescText}
278
+ </ContextMenu.Item>
279
+ <ContextMenu.Divider />
280
+ </>
281
+ )}
282
+ {isFooterVisible && typeof column.footer === 'function' && (
283
+ <>
284
+ <ContextMenu.Item onClick={hideFooter}>
285
+ <TableFooterSlashIcon />
286
+ Masquer le total
287
+ </ContextMenu.Item>
288
+ <ContextMenu.Divider />
289
+ </>
290
+ )}
291
+ {showTotalButton && (
292
+ <>
293
+ {!isFooterVisible && typeof column.footer === 'function' && (
294
+ <>
295
+ <ContextMenu.Item onClick={() => showFooter('count')}>
296
+ <TableFooterIcon />
297
+ Afficher le total
298
+ </ContextMenu.Item>
299
+ <ContextMenu.Divider />
300
+ </>
301
+ )}
302
+ {showTotalButton && typeof column.footer === 'object' && (
303
+ <>
304
+ <ContextMenu.ParentItem>
305
+ <TableFooterIcon />
306
+ Afficher le total
307
+ <ContextMenu.SubMenu>
308
+ {Object.keys(column.footer).map((key) => {
309
+ const TotalIcon =
310
+ footerFunctionsIcons[
311
+ key as DataGridFooterPredefinedFunction
312
+ ] ?? TableFooterIcon;
313
+ return (
314
+ <ContextMenu.Item
315
+ key={key}
316
+ onClick={() => showFooter(key)}
317
+ >
318
+ <TotalIcon />
319
+ {key in footerFunctionsTexts
320
+ ? footerFunctionsTexts[
321
+ key as DataGridFooterPredefinedFunction
322
+ ]
323
+ : key}
324
+ </ContextMenu.Item>
325
+ );
326
+ })}
327
+ <ContextMenu.Divider />
328
+ <ContextMenu.Item
329
+ onClick={hideFooter}
330
+ disabled={!isFooterVisible}
331
+ >
332
+ <TableFooterSlashIcon />
333
+ Masquer le total
334
+ </ContextMenu.Item>
335
+ </ContextMenu.SubMenu>
336
+ </ContextMenu.ParentItem>
337
+ <ContextMenu.Divider />
338
+ </>
339
+ )}
340
+ </>
341
+ )}
342
+ <ContextMenu.Item onClick={openModal}>
343
+ <FilterIcon />
344
+ Filtrer ...
345
+ </ContextMenu.Item>
346
+ <ContextMenu.Item
347
+ $color="danger"
348
+ onClick={clearFilter}
349
+ disabled={!hasFilters}
350
+ >
351
+ <FilterSlashIcon />
352
+ Supprimer le filtre
353
+ </ContextMenu.Item>
354
+ <ContextMenu.Divider />
355
+ <styles.InputContainer>
356
+ <MagnifierIcon />
357
+ <Input
358
+ ref={textFilterInputRef}
359
+ type="text"
360
+ name="search"
361
+ id="search"
362
+ placeholder="Rechercher ..."
363
+ value={textFilter}
364
+ onChange={(e) => setTextFilter(e.target.value)}
365
+ />
366
+ </styles.InputContainer>
367
+ <styles.CheckboxesContainer>
368
+ {checkboxesComponent}
369
+ </styles.CheckboxesContainer>
370
+ </>
371
+ );
372
+
373
+ if (!contextMenu) {
374
+ return <MenuContainer>{content}</MenuContainer>;
375
+ }
376
+
377
+ return <ContextMenu>{content}</ContextMenu>;
378
+ };