@addev-be/ui 0.1.24 → 0.1.26

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@addev-be/ui",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "watch": "tsc -b --watch",
@@ -3,6 +3,7 @@
3
3
  import {
4
4
  AdvancedRequestDTO,
5
5
  ConditionDTO,
6
+ FieldDTO,
6
7
  OrderByDTO,
7
8
  } from '../../../../services/advancedRequests';
8
9
  import {
@@ -10,7 +11,6 @@ import {
10
11
  AdvancedRequestDataGridFilters,
11
12
  } from '../types';
12
13
 
13
- import { DataGridColumns } from '../../DataGrid/types';
14
14
  import _ from 'lodash';
15
15
 
16
16
  export const getAdvancedRequestDto = <R>({
@@ -21,21 +21,19 @@ export const getAdvancedRequestDto = <R>({
21
21
  start = 0,
22
22
  length = 100,
23
23
  getTotal = false,
24
- addIdColumn = true,
24
+ idField = { fieldName: 'Id' },
25
25
  }: {
26
26
  type: string;
27
- columns: DataGridColumns<R>;
27
+ columns: AdvancedRequestDataGridColumns<R>;
28
28
  conditions?: ConditionDTO[];
29
29
  orderBy?: OrderByDTO[];
30
30
  start?: number;
31
31
  length?: number;
32
32
  getTotal?: boolean;
33
- addIdColumn?: boolean;
33
+ idField?: FieldDTO | null;
34
34
  }): AdvancedRequestDTO => ({
35
35
  fields: [
36
- ...(Object.keys(columns).includes('Id') || addIdColumn === false
37
- ? []
38
- : [{ fieldName: 'Id' }]),
36
+ ...(idField === null ? [] : [idField]),
39
37
  ...Object.keys(columns).map((key) =>
40
38
  columns[key].field
41
39
  ? {
@@ -49,15 +47,7 @@ export const getAdvancedRequestDto = <R>({
49
47
  }
50
48
  ),
51
49
  ],
52
- conditions: [
53
- ...conditions,
54
- {
55
- field: {
56
- fieldName: 'DeletedAt',
57
- },
58
- operator: 'isNull' as const,
59
- },
60
- ],
50
+ conditions,
61
51
  orderBy,
62
52
  type,
63
53
  start,
@@ -67,13 +57,14 @@ export const getAdvancedRequestDto = <R>({
67
57
 
68
58
  export const convertFiltersToConditions = <R>(
69
59
  filters: AdvancedRequestDataGridFilters,
70
- columns: DataGridColumns<R>
60
+ columns: AdvancedRequestDataGridColumns<R>
71
61
  ): Record<string, ConditionDTO> =>
72
62
  _.mapValues(filters, (filter, columnKey) => ({
73
- field: filter.field ??
74
- columns[columnKey].field ?? {
75
- fieldName: columnKey,
76
- },
63
+ field:
64
+ columns[columnKey].filterField ??
65
+ columns[columnKey].field?.fieldAlias ??
66
+ columns[columnKey].field?.fieldName ??
67
+ columnKey,
77
68
  operator: filter.operator,
78
69
  value: ['inArray', 'inRange'].includes(filter.operator)
79
70
  ? filter.values
@@ -4,23 +4,17 @@ import {
4
4
  AdvancedRequestDataGridColumn,
5
5
  AdvancedRequestDataGridColumns,
6
6
  } from '../types';
7
- import { advancedNumberFilter, advancedTextFilter } from './filters';
8
7
  import {
9
8
  formatMoney,
10
9
  formatNumber,
11
10
  formatPercentage,
12
11
  } from '../../../../helpers/numbers';
12
+ import { numberFilter, textFilter } from '../../DataGrid/helpers';
13
13
 
14
- import { DataGridSettings } from '../../DataGrid/types';
14
+ import { FieldDTO } from '../../../../services/advancedRequests';
15
15
  import _ from 'lodash';
16
16
  import moment from 'moment';
17
17
 
18
- export const isColumnVisible = <R,>(
19
- obj: AdvancedRequestDataGridColumn<R> | DataGridSettings
20
- ): boolean => {
21
- return obj?.order !== -1;
22
- };
23
-
24
18
  export const withGroupBy = <R extends Record<string, any>>(
25
19
  columns: AdvancedRequestDataGridColumns<R>
26
20
  ): AdvancedRequestDataGridColumns<R> =>
@@ -42,7 +36,7 @@ export const advancedTextColumn = <R extends Record<string, any>>(
42
36
  render: (row) => row[key] ?? '',
43
37
  getter: (row) => row[key] ?? '',
44
38
  sortGetter: (row) => row[key] ?? '',
45
- filter: advancedTextFilter(key),
39
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
46
40
  ...options,
47
41
  },
48
42
  });
@@ -70,7 +64,12 @@ export const advancedComposedColumn = <R extends Record<string, any>>(
70
64
  render: (row) => row[key] ?? '',
71
65
  getter: (row) => row[key] ?? '',
72
66
  sortGetter: (row) => row[key] ?? '',
73
- filter: advancedTextFilter(fields[0]),
67
+ filter: {
68
+ ...textFilter(fields[0]),
69
+ getter: (value) => value[fields[0]] ?? 0,
70
+ },
71
+ filterField: fields[0],
72
+ sortField: fields[0],
74
73
  ...options,
75
74
  },
76
75
  });
@@ -85,7 +84,7 @@ export const advancedMailColumn = <R extends Record<string, any>>(
85
84
  render: (row) => <a href={`mailto:${row[key]}`}>{row[key] ?? ''}</a>,
86
85
  getter: (row) => row[key] ?? '',
87
86
  sortGetter: (row) => row[key] ?? '',
88
- filter: advancedTextFilter(key),
87
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
89
88
  ...options,
90
89
  },
91
90
  });
@@ -100,7 +99,7 @@ export const advancedPhoneColumn = <R extends Record<string, any>>(
100
99
  render: (row) => <a href={`tel:${row[key]}`}>{row[key] ?? ''}</a>,
101
100
  getter: (row) => row[key] ?? '',
102
101
  sortGetter: (row) => row[key] ?? '',
103
- filter: advancedTextFilter(key),
102
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
104
103
  ...options,
105
104
  },
106
105
  });
@@ -115,7 +114,7 @@ export const advancedDateColumn = <R extends Record<string, any>>(
115
114
  render: (row) => moment(row[key]).format('DD/MM/YYYY') ?? '',
116
115
  getter: (row) => row[key] ?? '',
117
116
  sortGetter: (row) => row[key] ?? '',
118
- filter: advancedTextFilter(key),
117
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
119
118
  ...options,
120
119
  },
121
120
  });
@@ -130,7 +129,7 @@ export const advancedMonthColumn = <R extends Record<string, any>>(
130
129
  render: (row) => (row[key] ? `${row[key]} mois ` : ''),
131
130
  getter: (row) => row[key] ?? '',
132
131
  sortGetter: (row) => row[key] ?? '',
133
- filter: advancedTextFilter(key),
132
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
134
133
  ...options,
135
134
  },
136
135
  });
@@ -147,7 +146,7 @@ export const advancedNumberColumn = <R extends Record<string, any>>(
147
146
  excelFormatter: () => '#',
148
147
  getter: (row) => row[key] ?? '',
149
148
  sortGetter: (row) => row[key] ?? '',
150
- filter: advancedNumberFilter(key),
149
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
151
150
  ...options,
152
151
  },
153
152
  });
@@ -164,7 +163,7 @@ export const advancedMoneyColumn = <R extends Record<string, any>>(
164
163
  excelFormatter: () => '#0.00',
165
164
  getter: (row) => row[key] ?? '',
166
165
  sortGetter: (row) => row[key] ?? '',
167
- filter: advancedNumberFilter(key),
166
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
168
167
  ...options,
169
168
  },
170
169
  });
@@ -180,7 +179,7 @@ export const advancedPercentageColumn = <R extends Record<string, any>>(
180
179
  excelFormatter: () => '#0.00',
181
180
  getter: (row) => row[key] ?? '',
182
181
  sortGetter: (row) => row[key] ?? '',
183
- filter: advancedNumberFilter(key),
182
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
184
183
  ...options,
185
184
  },
186
185
  });
@@ -200,7 +199,7 @@ export const advancedCheckboxColumn = <R extends Record<string, any>>(
200
199
  ),
201
200
  getter: (row) => row[key] ?? '',
202
201
  sortGetter: (row) => row[key] ?? '',
203
- filter: advancedNumberFilter(key),
202
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
204
203
  ...options,
205
204
  },
206
205
  });
@@ -217,7 +216,47 @@ export const advancedColorColumn = <R extends Record<string, any>>(
217
216
  ),
218
217
  getter: (row) => row[key] ?? '',
219
218
  sortGetter: (row) => row[key] ?? '',
220
- filter: advancedTextFilter(key),
219
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
221
220
  ...options,
222
221
  },
223
222
  });
223
+
224
+ export const getColumnField = <R,>(
225
+ columns: AdvancedRequestDataGridColumns<R>,
226
+ columnKey: string
227
+ ): FieldDTO => {
228
+ return columns[columnKey].field
229
+ ? {
230
+ fieldName: columns[columnKey].field?.fieldName ?? columnKey,
231
+ fieldAlias: columnKey,
232
+ }
233
+ : {
234
+ fieldName: columnKey,
235
+ fieldAlias: columnKey,
236
+ };
237
+ };
238
+ export const getColumnSortField = <R,>(
239
+ columns: AdvancedRequestDataGridColumns<R>,
240
+ columnKey: string
241
+ ): FieldDTO => {
242
+ return columns[columnKey].sortField
243
+ ? {
244
+ fieldName: columns[columnKey].sortField ?? columnKey,
245
+ fieldAlias: columnKey,
246
+ }
247
+ : {
248
+ fieldName: columnKey,
249
+ fieldAlias: columnKey,
250
+ };
251
+ };
252
+ export const getFirstColumnField = <R,>(
253
+ columns: AdvancedRequestDataGridColumns<R>
254
+ ): FieldDTO => {
255
+ return getColumnField(columns, Object.keys(columns)[0]);
256
+ };
257
+
258
+ export const getFirstColumnSortField = <R,>(
259
+ columns: AdvancedRequestDataGridColumns<R>
260
+ ): FieldDTO => {
261
+ return getColumnSortField(columns, Object.keys(columns)[0]);
262
+ };
@@ -1,3 +1,2 @@
1
1
  export * from './advancedRequests';
2
2
  export * from './columns';
3
- export * from './filters';
@@ -13,6 +13,7 @@ import _, { debounce } from 'lodash';
13
13
  import {
14
14
  convertFiltersToConditions,
15
15
  getAdvancedRequestDto,
16
+ getColumnSortField,
16
17
  parseJsonObjectFields,
17
18
  } from './helpers';
18
19
  import { useCallback, useEffect, useRef, useState } from 'react';
@@ -20,45 +21,23 @@ import { useCallback, useEffect, useRef, useState } from 'react';
20
21
  import { AdvancedRequestDataGridProps } from './types';
21
22
  import { DataGrid } from '../DataGrid';
22
23
 
23
- const getColumnField = <R,>(
24
- columns: DataGridColumns<R>,
25
- columnKey: string
26
- ): FieldDTO => {
27
- return columns[columnKey].field
28
- ? {
29
- fieldName: columns[columnKey].field?.fieldName ?? columnKey,
30
- fieldAlias: columnKey,
31
- }
32
- : {
33
- fieldName: columnKey,
34
- fieldAlias: columnKey,
35
- };
36
- };
37
- const getFirstColumnField = <R,>(columns: DataGridColumns<R>): FieldDTO => {
38
- return getColumnField(columns, Object.keys(columns)[0]);
39
- };
40
-
41
- export const AdvancedRequestDataGrid = <R,>(
42
- props: AdvancedRequestDataGridProps<R>
43
- ) => {
24
+ export const AdvancedRequestDataGrid = <R,>({
25
+ onSelectionChange: onSelectionChangeFromProps,
26
+ idField,
27
+ ...props
28
+ }: AdvancedRequestDataGridProps<R>) => {
44
29
  const currentRows = useRef<R[]>([]);
45
30
  const [rows, setRows] = useState<R[]>([]);
46
31
  const [start, setStart] = useState(0);
47
32
  const [length, setLength] = useState(50);
48
33
  const [total, setTotal] = useState(-1);
49
34
  const advancedRequest = useAdvancedRequestHandler<R>();
35
+ const idAdvancedRequest = useAdvancedRequestHandler<{ Id: string }>();
50
36
 
51
37
  const [conditions, setConditions] = useState<Record<string, ConditionDTO>>(
52
38
  {}
53
39
  );
54
- const [orderBy, setOrderBy] = useState<OrderByDTO[]>(
55
- props.orderBy ?? [
56
- {
57
- field: getFirstColumnField(props.columns),
58
- direction: 'ASC',
59
- },
60
- ]
61
- );
40
+ const [orderBy, setOrderBy] = useState<OrderByDTO[]>([]);
62
41
 
63
42
  const refresh = useCallback(() => {
64
43
  setRows([]);
@@ -83,7 +62,7 @@ export const AdvancedRequestDataGrid = <R,>(
83
62
  Object.entries(sorts).map(
84
63
  ([columnKey, direction]) =>
85
64
  ({
86
- field: getColumnField(props.columns, columnKey),
65
+ field: getColumnSortField(props.columns, columnKey),
87
66
  direction: direction.toUpperCase(),
88
67
  } as OrderByDTO)
89
68
  )
@@ -100,6 +79,7 @@ export const AdvancedRequestDataGrid = <R,>(
100
79
  orderBy: OrderByDTO[],
101
80
  start: number,
102
81
  length: number,
82
+ idField: FieldDTO | null | undefined,
103
83
  getTotal = false
104
84
  ) => {
105
85
  advancedRequest(
@@ -111,6 +91,7 @@ export const AdvancedRequestDataGrid = <R,>(
111
91
  start,
112
92
  length,
113
93
  getTotal,
94
+ idField,
114
95
  })
115
96
  ).then((response) => {
116
97
  if (getTotal) {
@@ -134,33 +115,23 @@ export const AdvancedRequestDataGrid = <R,>(
134
115
  (columnKey: string) => {
135
116
  return advancedRequest({
136
117
  fields: [
137
- props.columns[columnKey].filter?.field ??
138
- props.columns[columnKey].field ?? {
139
- fieldName: columnKey,
140
- },
118
+ props.columns[columnKey].field ?? {
119
+ fieldName: columnKey,
120
+ },
141
121
  ],
142
122
  conditions: [
143
123
  ...(props.conditions ?? []),
144
124
  ...Object.values(
145
125
  _.pickBy(conditions, (condition, key) => key !== columnKey)
146
126
  ),
147
- {
148
- field: {
149
- fieldName: 'DeletedAt',
150
- },
151
- operator: 'isNull' as const,
152
- },
153
- ].filter(
154
- (condition) =>
155
- (condition.field.fieldAlias ?? condition.field.fieldName) !==
156
- columnKey
157
- ),
127
+ ].filter((condition) => condition.field !== columnKey),
158
128
  orderBy: [
159
129
  {
160
- field: props.columns[columnKey].filter?.field ??
161
- props.columns[columnKey].field ?? {
162
- fieldName: columnKey,
163
- },
130
+ field:
131
+ props.columns[columnKey].filterField ??
132
+ props.columns[columnKey].field?.fieldAlias ??
133
+ props.columns[columnKey].field?.fieldName ??
134
+ columnKey,
164
135
  direction: 'ASC',
165
136
  },
166
137
  ],
@@ -184,9 +155,19 @@ export const AdvancedRequestDataGrid = <R,>(
184
155
  orderBy,
185
156
  start,
186
157
  length,
158
+ idField,
187
159
  total < 0
188
160
  ),
189
- [props.columns, conditions, orderBy, start, length, total, props.conditions]
161
+ [
162
+ props.columns,
163
+ conditions,
164
+ orderBy,
165
+ start,
166
+ length,
167
+ total,
168
+ props.conditions,
169
+ idField,
170
+ ]
190
171
  );
191
172
 
192
173
  const loadCopyRows = useCallback(
@@ -202,6 +183,7 @@ export const AdvancedRequestDataGrid = <R,>(
202
183
  orderBy,
203
184
  start: 0,
204
185
  length: total,
186
+ idField,
205
187
  })
206
188
  ).then((response) =>
207
189
  parseJsonObjectFields(response.data, props.columns, props.parser)
@@ -209,6 +191,7 @@ export const AdvancedRequestDataGrid = <R,>(
209
191
  [
210
192
  advancedRequest,
211
193
  conditions,
194
+ idField,
212
195
  orderBy,
213
196
  props.columns,
214
197
  props.conditions,
@@ -218,6 +201,38 @@ export const AdvancedRequestDataGrid = <R,>(
218
201
  ]
219
202
  );
220
203
 
204
+ const loadAllIds = useCallback(
205
+ () =>
206
+ idAdvancedRequest(
207
+ getAdvancedRequestDto({
208
+ type: props.type,
209
+ columns: {
210
+ Id: {
211
+ name: 'Id',
212
+ field: idField ?? { fieldName: 'Id' },
213
+ },
214
+ },
215
+ conditions: [
216
+ ...(props.conditions ?? []),
217
+ ...(Object.values(conditions) ?? []),
218
+ ],
219
+ orderBy,
220
+ start: 0,
221
+ length: total,
222
+ idField: null,
223
+ })
224
+ ).then((response) => response.data.map((row) => row['Id'])),
225
+ [
226
+ conditions,
227
+ idAdvancedRequest,
228
+ idField,
229
+ orderBy,
230
+ props.conditions,
231
+ props.type,
232
+ total,
233
+ ]
234
+ );
235
+
221
236
  const onVisibleRowsChanged = useCallback(
222
237
  (newStart: number, newLength: number) => {
223
238
  if (newStart !== start || newLength !== length) {
@@ -228,6 +243,13 @@ export const AdvancedRequestDataGrid = <R,>(
228
243
  [length, start]
229
244
  );
230
245
 
246
+ const onSelectionChange = useCallback(
247
+ (selectedKeys: string[]) => {
248
+ onSelectionChangeFromProps?.(selectedKeys);
249
+ },
250
+ [onSelectionChangeFromProps]
251
+ );
252
+
231
253
  return (
232
254
  <DataGrid
233
255
  onVisibleRowsChange={onVisibleRowsChanged}
@@ -239,6 +261,8 @@ export const AdvancedRequestDataGrid = <R,>(
239
261
  rows={rows}
240
262
  loadCopyRows={loadCopyRows}
241
263
  refresh={refresh}
264
+ onSelectionChange={onSelectionChange}
265
+ getAllIds={loadAllIds}
242
266
  {...props}
243
267
  />
244
268
  );
@@ -24,6 +24,9 @@ export type AdvancedRequestDataGridFilters = Record<
24
24
 
25
25
  export type AdvancedRequestDataGridColumn<R> = DataGridColumn<R> & {
26
26
  filter?: AdvancedRequestDataGridFilter;
27
+ field?: FieldDTO;
28
+ filterField?: string;
29
+ sortField?: string;
27
30
  };
28
31
 
29
32
  export type AdvancedRequestDataGridColumns<R> = Record<
@@ -39,6 +42,6 @@ export type AdvancedRequestDataGridProps<R> = Omit<
39
42
  type: string;
40
43
  orderBy?: OrderByDTO[];
41
44
  conditions?: ConditionDTO[];
42
- addIdColumn?: boolean;
45
+ idField?: FieldDTO | null;
43
46
  parser?: (row: AdvancedRequestRow<R>) => R;
44
47
  };
@@ -17,7 +17,7 @@ export const useFilterModal = <R,>({
17
17
  const [isVisible, setIsVisible] = useState(false);
18
18
  const { filters = {}, columns, setFilters } = useDataGridContext<R>(context);
19
19
  const column = columns[columnKey];
20
- const [currentFilter, setCurrentFilter] = useState<DataGridFilter<R>>(
20
+ const [currentFilter, setCurrentFilter] = useState<DataGridFilter>(
21
21
  filters[columnKey] ?? column?.filter
22
22
  );
23
23
 
@@ -37,6 +37,7 @@ export const DataGridHeader = <R,>({
37
37
  headerColor,
38
38
  rowKeyGetter,
39
39
  gridTemplateColumns,
40
+ getAllIds,
40
41
  } = useDataGridContext(context);
41
42
  const [visibleFilter, setVisibleFilter] = useState<string | undefined>();
42
43
 
@@ -49,10 +50,11 @@ export const DataGridHeader = <R,>({
49
50
  ? true
50
51
  : undefined;
51
52
  const toggleAll = useCallback(
52
- (newStatus: boolean) => {
53
- setSelectedKeys(newStatus ? rows.map(rowKeyGetter) : []);
53
+ async (newStatus: boolean) => {
54
+ const allIds = getAllIds ? await getAllIds() : rows.map(rowKeyGetter);
55
+ setSelectedKeys(newStatus ? allIds : []);
54
56
  },
55
- [rowKeyGetter, rows, setSelectedKeys]
57
+ [getAllIds, rowKeyGetter, rows, setSelectedKeys]
56
58
  );
57
59
 
58
60
  const onFilterButtonClicked = useCallback((columnKey: string) => {
@@ -13,6 +13,7 @@ import moment from 'moment';
13
13
  export const isColumnVisible = <R,>(
14
14
  obj: DataGridColumn<R> | DataGridSettings
15
15
  ): boolean => {
16
+ console.log('isColumnVisible obj=', obj);
16
17
  return obj?.order !== -1;
17
18
  };
18
19
 
@@ -86,8 +86,8 @@ export const useDataGrid = <R,>(
86
86
  );
87
87
 
88
88
  useEffect(() => {
89
- onSelectionChange?.(selectedRows);
90
- }, [onSelectionChange, selectedRows]);
89
+ onSelectionChange?.(selectedKeys);
90
+ }, [onSelectionChange, selectedKeys]);
91
91
 
92
92
  /** ROWS FILTERING **/
93
93
 
@@ -54,7 +54,7 @@ export const useDataGridCopy = <R>(
54
54
  }, []);
55
55
 
56
56
  const generateCellHtml = useCallback(
57
- (col: DataGridColumn<R, any>, value: any) => `<td style="
57
+ (col: DataGridColumn<R>, value: any) => `<td style="
58
58
  ${
59
59
  col.excelFormatter
60
60
  ? "mso-number-format: '" + col.excelFormatter(col) + "';"
@@ -11,7 +11,6 @@ import {
11
11
  SetStateAction,
12
12
  } from 'react';
13
13
 
14
- import { FieldDTO } from '../../../services/advancedRequests';
15
14
  import { SettingsContextProps } from '../../../providers/SettingsProvider';
16
15
  import { ThemeColor } from '../../../providers/ThemeProvider/types';
17
16
 
@@ -23,8 +22,6 @@ export type DataGridColumn<R> = {
23
22
  editable?: boolean;
24
23
  excelFormatter?: (value: any) => string;
25
24
  excelValue?: (value: any) => string;
26
- field?: FieldDTO;
27
- filterField?: FieldDTO;
28
25
  filter?: DataGridFilter;
29
26
  footer?: (allRows: R[], filteredRows: R[], selectedRows: R[]) => ReactNode;
30
27
  footerClassName?: string;
@@ -57,7 +54,8 @@ export type DataGridProps<R> = {
57
54
  selectable?: boolean;
58
55
  editable?: boolean;
59
56
  onRowDoubleClick?: (row: R, e: MouseEvent) => void;
60
- onSelectionChange?: (selectedRows: R[]) => void;
57
+ onSelectionChange?: (keys: string[]) => void;
58
+ getAllIds?: () => Promise<string[]>;
61
59
  onFiltersChanged?: (filters: DataGridFilters) => void;
62
60
  onSortsChanged?: (sorts: Record<string, DataGridSort>) => void;
63
61
  onVisibleRowsChange?: (startIndex: number, length: number) => void;
@@ -0,0 +1,206 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import { SqlRequestDataGridColumn, SqlRequestDataGridColumns } from '../types';
4
+ import {
5
+ formatMoney,
6
+ formatNumber,
7
+ formatPercentage,
8
+ } from '../../../../helpers/numbers';
9
+ import { numberFilter, textFilter } from '../../DataGrid/helpers';
10
+
11
+ import moment from 'moment';
12
+
13
+ export const sqlTextColumn = <R extends Record<string, any>>(
14
+ key: string,
15
+ title: string,
16
+ options?: Partial<SqlRequestDataGridColumn<R>>
17
+ ): SqlRequestDataGridColumns<R> => ({
18
+ [key]: {
19
+ name: title,
20
+ render: (row) => row[key] ?? '',
21
+ getter: (row) => row[key] ?? '',
22
+ sortGetter: (row) => row[key] ?? '',
23
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
24
+ ...options,
25
+ },
26
+ });
27
+
28
+ /**
29
+ * Creates a column with a composed value from multiple fields,
30
+ * and filtered by a text filter on the first field
31
+ */
32
+ export const sqlComposedColumn = <R extends Record<string, any>>(
33
+ key: string,
34
+ title: string,
35
+ fields: string[],
36
+ options?: Partial<SqlRequestDataGridColumn<R>>
37
+ ): SqlRequestDataGridColumns<R> => ({
38
+ [key]: {
39
+ field: {
40
+ fieldAlias: key,
41
+ operator: 'jsonObject',
42
+ operands: fields.flatMap((field) => [
43
+ { constantValue: field },
44
+ { fieldName: field },
45
+ ]),
46
+ },
47
+ name: title,
48
+ render: (row) => row[key] ?? '',
49
+ getter: (row) => row[key] ?? '',
50
+ sortGetter: (row) => row[key] ?? '',
51
+ filter: {
52
+ ...textFilter(fields[0]),
53
+ getter: (value) => value[fields[0]] ?? 0,
54
+ },
55
+ filterField: fields[0],
56
+ sortField: fields[0],
57
+ ...options,
58
+ },
59
+ });
60
+
61
+ export const sqlMailColumn = <R extends Record<string, any>>(
62
+ key: string,
63
+ title: string,
64
+ options?: Partial<SqlRequestDataGridColumn<R>>
65
+ ): SqlRequestDataGridColumns<R> => ({
66
+ [key]: {
67
+ name: title,
68
+ render: (row) => <a href={`mailto:${row[key]}`}>{row[key] ?? ''}</a>,
69
+ getter: (row) => row[key] ?? '',
70
+ sortGetter: (row) => row[key] ?? '',
71
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
72
+ ...options,
73
+ },
74
+ });
75
+
76
+ export const sqlPhoneColumn = <R extends Record<string, any>>(
77
+ key: string,
78
+ title: string,
79
+ options?: Partial<SqlRequestDataGridColumn<R>>
80
+ ): SqlRequestDataGridColumns<R> => ({
81
+ [key]: {
82
+ name: title,
83
+ render: (row) => <a href={`tel:${row[key]}`}>{row[key] ?? ''}</a>,
84
+ getter: (row) => row[key] ?? '',
85
+ sortGetter: (row) => row[key] ?? '',
86
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
87
+ ...options,
88
+ },
89
+ });
90
+
91
+ export const sqlDateColumn = <R extends Record<string, any>>(
92
+ key: string,
93
+ title: string,
94
+ options?: Partial<SqlRequestDataGridColumn<R>>
95
+ ): SqlRequestDataGridColumns<R> => ({
96
+ [key]: {
97
+ name: title,
98
+ render: (row) => moment(row[key]).format('DD/MM/YYYY') ?? '',
99
+ getter: (row) => row[key] ?? '',
100
+ sortGetter: (row) => row[key] ?? '',
101
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
102
+ ...options,
103
+ },
104
+ });
105
+
106
+ export const sqlMonthColumn = <R extends Record<string, any>>(
107
+ key: string,
108
+ title: string,
109
+ options?: Partial<SqlRequestDataGridColumn<R>>
110
+ ): SqlRequestDataGridColumns<R> => ({
111
+ [key]: {
112
+ name: title,
113
+ render: (row) => (row[key] ? `${row[key]} mois ` : ''),
114
+ getter: (row) => row[key] ?? '',
115
+ sortGetter: (row) => row[key] ?? '',
116
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
117
+ ...options,
118
+ },
119
+ });
120
+
121
+ export const sqlNumberColumn = <R extends Record<string, any>>(
122
+ key: string,
123
+ title: string,
124
+ decimals = 2,
125
+ options?: Partial<SqlRequestDataGridColumn<R>>
126
+ ): SqlRequestDataGridColumns<R> => ({
127
+ [key]: {
128
+ name: title,
129
+ render: (row) => formatNumber(row[key], decimals) ?? '',
130
+ excelFormatter: () => '#',
131
+ getter: (row) => row[key] ?? '',
132
+ sortGetter: (row) => row[key] ?? '',
133
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
134
+ ...options,
135
+ },
136
+ });
137
+
138
+ export const sqlMoneyColumn = <R extends Record<string, any>>(
139
+ key: string,
140
+ title: string,
141
+ decimals = 2,
142
+ options?: Partial<SqlRequestDataGridColumn<R>>
143
+ ): SqlRequestDataGridColumns<R> => ({
144
+ [key]: {
145
+ name: title,
146
+ render: (row) => formatMoney(row[key], decimals) ?? '',
147
+ excelFormatter: () => '#0.00',
148
+ getter: (row) => row[key] ?? '',
149
+ sortGetter: (row) => row[key] ?? '',
150
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
151
+ ...options,
152
+ },
153
+ });
154
+
155
+ export const sqlPercentageColumn = <R extends Record<string, any>>(
156
+ key: string,
157
+ title: string,
158
+ options?: Partial<SqlRequestDataGridColumn<R>>
159
+ ): SqlRequestDataGridColumns<R> => ({
160
+ [key]: {
161
+ name: title,
162
+ render: (row) => formatPercentage(row[key]) ?? '',
163
+ excelFormatter: () => '#0.00',
164
+ getter: (row) => row[key] ?? '',
165
+ sortGetter: (row) => row[key] ?? '',
166
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
167
+ ...options,
168
+ },
169
+ });
170
+
171
+ export const sqlCheckboxColumn = <R extends Record<string, any>>(
172
+ key: string,
173
+ title: string,
174
+ options?: Partial<SqlRequestDataGridColumn<R>>
175
+ ): SqlRequestDataGridColumns<R> => ({
176
+ [key]: {
177
+ name: title,
178
+ render: (row) => (
179
+ <>
180
+ <input type="checkbox" checked={row[key]} />
181
+ <span>{row[key] ? ' Oui' : ' Non'}</span>
182
+ </>
183
+ ),
184
+ getter: (row) => row[key] ?? '',
185
+ sortGetter: (row) => row[key] ?? '',
186
+ filter: { ...numberFilter(key), getter: (value) => value[key] ?? 0 },
187
+ ...options,
188
+ },
189
+ });
190
+
191
+ export const sqlColorColumn = <R extends Record<string, any>>(
192
+ key: string,
193
+ title: string,
194
+ options?: Partial<SqlRequestDataGridColumn<R>>
195
+ ): SqlRequestDataGridColumns<R> => ({
196
+ [key]: {
197
+ name: title,
198
+ render: (row) => (
199
+ <div style={{ backgroundColor: row[key] }}>{row[key] ?? ''}</div>
200
+ ),
201
+ getter: (row) => row[key] ?? '',
202
+ sortGetter: (row) => row[key] ?? '',
203
+ filter: { ...textFilter(key), getter: (value) => value[key] ?? '' },
204
+ ...options,
205
+ },
206
+ });
@@ -0,0 +1,2 @@
1
+ export * from './sqlRequests';
2
+ export * from './columns';
@@ -0,0 +1,16 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import { ConditionDTO } from '../../../../services/sqlRequests';
4
+ import { SqlRequestDataGridFilters } from '../types';
5
+ import _ from 'lodash';
6
+
7
+ export const convertSqlFiltersToConditions = (
8
+ filters: SqlRequestDataGridFilters
9
+ ): Record<string, ConditionDTO> =>
10
+ _.mapValues(filters, (filter, columnKey) => ({
11
+ field: columnKey,
12
+ operator: filter.operator,
13
+ value: ['inArray', 'inRange'].includes(filter.operator)
14
+ ? filter.values
15
+ : _.castArray<string | number | null>(filter.values)[0],
16
+ }));
@@ -0,0 +1,221 @@
1
+ import {
2
+ ConditionDTO,
3
+ OrderByDTO,
4
+ useSqlRequestHandler,
5
+ } from '../../../services/sqlRequests';
6
+ import {
7
+ DataGridColumns,
8
+ DataGridFilters,
9
+ DataGridSort,
10
+ } from '../DataGrid/types';
11
+ import { useCallback, useEffect, useRef, useState } from 'react';
12
+
13
+ import { DataGrid } from '../DataGrid';
14
+ import { SqlRequestDataGridProps } from './types';
15
+ import _ from 'lodash';
16
+ import { convertSqlFiltersToConditions } from './helpers';
17
+ import { debounce } from 'lodash';
18
+ import { isColumnVisible } from '../DataGrid/helpers';
19
+
20
+ export const SqlRequestDataGrid = <R,>({
21
+ onSelectionChange: onSelectionChangeFromProps,
22
+ ...props
23
+ }: SqlRequestDataGridProps<R>) => {
24
+ const currentRows = useRef<R[]>([]);
25
+ const [rows, setRows] = useState<R[]>([]);
26
+ const [start, setStart] = useState(0);
27
+ const [length, setLength] = useState(50);
28
+ const [total, setTotal] = useState(-1);
29
+ const [sqlRequest, sqlIdRequest] = useSqlRequestHandler<R>(props.type);
30
+
31
+ const [conditions, setConditions] = useState<Record<string, ConditionDTO>>(
32
+ {}
33
+ );
34
+ const [orderBy, setOrderBy] = useState<OrderByDTO[]>([]);
35
+
36
+ const refresh = useCallback(() => {
37
+ setRows([]);
38
+ setStart(0);
39
+ setLength(50);
40
+ setTotal(-1);
41
+ }, []);
42
+
43
+ const onFiltersChanged = useCallback((filters: DataGridFilters) => {
44
+ const newConditions = convertSqlFiltersToConditions(filters);
45
+ setTotal(-1);
46
+ setConditions(newConditions);
47
+ }, []);
48
+
49
+ const onSortsChanged = useCallback(
50
+ (sorts: Record<string, DataGridSort>) => {
51
+ refresh();
52
+ const newOrderBy = Object.entries(sorts).map(
53
+ ([columnKey, direction]) =>
54
+ ({
55
+ field: columnKey,
56
+ direction: direction.toUpperCase(),
57
+ } as OrderByDTO)
58
+ );
59
+ console.log('newOrderBy=', newOrderBy);
60
+ setOrderBy(newOrderBy);
61
+ },
62
+ [refresh]
63
+ );
64
+
65
+ const loadRows = useRef(
66
+ debounce(
67
+ (
68
+ columns: DataGridColumns<R>,
69
+ conditions: ConditionDTO[] = [],
70
+ orderBy: OrderByDTO[] = [],
71
+ start = 0,
72
+ length = 100,
73
+ getTotal = false
74
+ ) => {
75
+ const columnsKeys = Object.keys(columns).filter((key) =>
76
+ isColumnVisible(columns[key])
77
+ );
78
+ if (!columnsKeys.includes('Id')) columnsKeys.push('Id');
79
+ sqlRequest({
80
+ columns: columnsKeys,
81
+ conditions,
82
+ orderBy,
83
+ start,
84
+ length,
85
+ getTotal,
86
+ }).then((response) => {
87
+ if (getTotal) {
88
+ currentRows.current = Array(response.total).fill(null);
89
+ if (getTotal) setTotal(response.total ?? 0);
90
+ }
91
+ const parsedRows = props.parser
92
+ ? response.data.map(props.parser)
93
+ : (response.data as R[]);
94
+ currentRows.current.splice(start, length, ...parsedRows);
95
+ setRows([...currentRows.current]);
96
+ });
97
+ },
98
+ 100
99
+ )
100
+ );
101
+
102
+ const loadFilterValues = useCallback(
103
+ (columnKey: string) => {
104
+ return sqlRequest({
105
+ columns: [columnKey],
106
+ conditions: [
107
+ ...(props.conditions ?? []),
108
+ ...Object.values(
109
+ _.pickBy(conditions, (condition, key) => key !== columnKey)
110
+ ),
111
+ ].filter((condition) => condition.field !== columnKey),
112
+ orderBy: [
113
+ {
114
+ field:
115
+ props.columns[columnKey].filterField ??
116
+ props.columns[columnKey].field?.fieldAlias ??
117
+ props.columns[columnKey].field?.fieldName ??
118
+ columnKey,
119
+ direction: 'ASC',
120
+ },
121
+ ],
122
+ getTotal: false,
123
+ unique: true,
124
+ }).then((response) =>
125
+ response.data.map(
126
+ (row) => props.columns[columnKey].filter?.getter?.(row) ?? null
127
+ )
128
+ );
129
+ },
130
+ [conditions, props.columns, props.conditions, sqlRequest]
131
+ );
132
+
133
+ useEffect(
134
+ () =>
135
+ loadRows.current(
136
+ props.columns,
137
+ [...(props.conditions ?? []), ...(Object.values(conditions) ?? [])],
138
+ orderBy,
139
+ start,
140
+ length,
141
+ total < 0
142
+ ),
143
+ [props.columns, conditions, orderBy, start, length, total, props.conditions]
144
+ );
145
+
146
+ const loadCopyRows = useCallback(
147
+ () =>
148
+ sqlRequest({
149
+ columns: Object.keys(props.columns).filter((key) =>
150
+ isColumnVisible(props.columns[key])
151
+ ),
152
+ conditions: [
153
+ ...(props.conditions ?? []),
154
+ ...(Object.values(conditions) ?? []),
155
+ ],
156
+ orderBy,
157
+ start: 0,
158
+ length: total,
159
+ }).then((response) =>
160
+ props.parser ? response.data.map(props.parser) : (response.data as R[])
161
+ ),
162
+ [
163
+ sqlRequest,
164
+ props.columns,
165
+ props.conditions,
166
+ props.parser,
167
+ conditions,
168
+ orderBy,
169
+ total,
170
+ ]
171
+ );
172
+
173
+ const loadAllIds = useCallback(
174
+ () =>
175
+ sqlIdRequest({
176
+ columns: ['Id'],
177
+ conditions: [
178
+ ...(props.conditions ?? []),
179
+ ...(Object.values(conditions) ?? []),
180
+ ],
181
+ orderBy,
182
+ start: 0,
183
+ length: total,
184
+ }).then((response) => response.data.map((row) => row['Id'])),
185
+ [conditions, orderBy, props.conditions, sqlIdRequest, total]
186
+ );
187
+
188
+ const onVisibleRowsChanged = useCallback(
189
+ (newStart: number, newLength: number) => {
190
+ if (newStart !== start || newLength !== length) {
191
+ setStart(newStart);
192
+ setLength(newLength);
193
+ }
194
+ },
195
+ [length, start]
196
+ );
197
+
198
+ const onSelectionChange = useCallback(
199
+ (selectedKeys: string[]) => {
200
+ onSelectionChangeFromProps?.(selectedKeys);
201
+ },
202
+ [onSelectionChangeFromProps]
203
+ );
204
+
205
+ return (
206
+ <DataGrid
207
+ onVisibleRowsChange={onVisibleRowsChanged}
208
+ filter={false}
209
+ sort={false}
210
+ onFiltersChanged={onFiltersChanged}
211
+ onSortsChanged={onSortsChanged}
212
+ filterValuesLoader={loadFilterValues}
213
+ rows={rows}
214
+ loadCopyRows={loadCopyRows}
215
+ refresh={refresh}
216
+ onSelectionChange={onSelectionChange}
217
+ getAllIds={loadAllIds}
218
+ {...props}
219
+ />
220
+ );
221
+ };
@@ -0,0 +1,46 @@
1
+ import {
2
+ ConditionDTO,
3
+ FieldDTO,
4
+ OrderByDTO,
5
+ SqlRequestRow,
6
+ } from '../../../services/sqlRequests';
7
+ import {
8
+ DataGridColumn,
9
+ DataGridFilter,
10
+ DataGridFilterType,
11
+ DataGridProps,
12
+ } from '../DataGrid/types';
13
+
14
+ export type SqlRequestDataGridFilter<
15
+ T extends DataGridFilterType = DataGridFilterType
16
+ > = DataGridFilter<T> & {
17
+ field?: FieldDTO;
18
+ };
19
+
20
+ export type SqlRequestDataGridFilters = Record<
21
+ string,
22
+ SqlRequestDataGridFilter
23
+ >;
24
+
25
+ export type SqlRequestDataGridColumn<R> = DataGridColumn<R> & {
26
+ filter?: SqlRequestDataGridFilter;
27
+ field?: FieldDTO;
28
+ filterField?: string;
29
+ sortField?: string;
30
+ };
31
+
32
+ export type SqlRequestDataGridColumns<R> = Record<
33
+ string,
34
+ SqlRequestDataGridColumn<R>
35
+ >;
36
+
37
+ export type SqlRequestDataGridProps<R> = Omit<
38
+ DataGridProps<R>,
39
+ 'rows' | 'columns'
40
+ > & {
41
+ columns: SqlRequestDataGridColumns<R>;
42
+ type: string;
43
+ orderBy?: OrderByDTO[];
44
+ conditions?: ConditionDTO[];
45
+ parser?: (row: SqlRequestRow<R>) => R;
46
+ };
@@ -1,4 +1,6 @@
1
1
  export * from './DataGrid';
2
2
  export * from './DataGrid/helpers';
3
3
  export * from './AdvancedRequestDataGrid';
4
+ export * from './SqlRequestDataGrid';
5
+ export * from './SqlRequestDataGrid/helpers';
4
6
  export * from './AdvancedRequestDataGrid/helpers';
@@ -23,7 +23,7 @@ export type FieldDTO<T extends string = string> = {
23
23
  };
24
24
 
25
25
  export type ConditionDTO = {
26
- field: FieldDTO;
26
+ field: string;
27
27
  operator:
28
28
  | 'lessThan'
29
29
  | 'lessThanOrEqual'
@@ -57,7 +57,7 @@ export type ConditionDTO = {
57
57
  };
58
58
 
59
59
  export type OrderByDTO = {
60
- field: FieldDTO;
60
+ field: string;
61
61
  direction?: 'ASC' | 'DESC';
62
62
  };
63
63
 
@@ -0,0 +1,96 @@
1
+ import { useRequestHandler } from './hooks';
2
+
3
+ export type FieldDTO<T extends string = string> = {
4
+ fieldName?: T;
5
+ fieldAlias?: string;
6
+ operator?:
7
+ | 'add'
8
+ | 'concat'
9
+ | 'divide'
10
+ | 'groupConcat'
11
+ | 'if'
12
+ | 'ifNull'
13
+ | 'jsonObject'
14
+ | 'length'
15
+ | 'modulo'
16
+ | 'multiply'
17
+ | 'subtract'
18
+ | 'sum'
19
+ | 'trim';
20
+ operands?: FieldDTO[];
21
+ constantValue?: string | number | boolean | null;
22
+ groupBy?: boolean;
23
+ };
24
+
25
+ export type ConditionDTO = {
26
+ field: string;
27
+ operator:
28
+ | 'lessThan'
29
+ | 'lessThanOrEqual'
30
+ | 'lessThanOrEquals'
31
+ | 'equals'
32
+ | 'notEquals'
33
+ | 'greaterThanOrEqual'
34
+ | 'greaterThanOrEquals'
35
+ | 'greaterThan'
36
+ | 'like'
37
+ | 'contains'
38
+ | 'notContains'
39
+ | 'startsWith'
40
+ | 'endsWith'
41
+ | 'notLike'
42
+ | 'inRange'
43
+ | 'between'
44
+ | 'isNull'
45
+ | 'inArray'
46
+ | 'in'
47
+ | 'not'
48
+ | 'and'
49
+ | 'or';
50
+ value?:
51
+ | string
52
+ | number
53
+ | boolean
54
+ | null
55
+ | (string | number | boolean | null)[];
56
+ children?: boolean;
57
+ };
58
+
59
+ export type OrderByDTO = {
60
+ field: string;
61
+ direction?: 'ASC' | 'DESC';
62
+ };
63
+
64
+ export type SqlRequestDTO = {
65
+ columns?: string[];
66
+ conditions?: ConditionDTO[];
67
+ orderBy?: OrderByDTO[];
68
+ start?: number;
69
+ length?: number;
70
+ getTotal?: boolean;
71
+ unique?: boolean;
72
+ };
73
+
74
+ export type SqlRequestRow<R> = {
75
+ [K in keyof R]: R[K] extends string | number | null
76
+ ? R[K]
77
+ : string | number | null;
78
+ };
79
+
80
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
81
+ export type SqlResponseDTO<T = any> = {
82
+ data: SqlRequestRow<T>[];
83
+ total?: number;
84
+ };
85
+
86
+ type SqlRequestHandler<T> = (
87
+ request: SqlRequestDTO
88
+ ) => Promise<SqlResponseDTO<T>>;
89
+
90
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
91
+ export const useSqlRequestHandler = <T = any>(
92
+ name: string
93
+ ): [SqlRequestHandler<T>, SqlRequestHandler<{ Id: string }>] => [
94
+ useRequestHandler<SqlRequestDTO, SqlResponseDTO<T>>(name),
95
+ useRequestHandler<SqlRequestDTO, SqlResponseDTO<{ Id: string }>>(name),
96
+ ];
@@ -1,19 +0,0 @@
1
- import { numberFilter, textFilter } from '../../DataGrid/helpers';
2
-
3
- import { AdvancedRequestDataGridFilter } from '../types';
4
-
5
- export const advancedTextFilter = (
6
- key: string
7
- ): AdvancedRequestDataGridFilter<'text'> => ({
8
- ...textFilter(key),
9
- field: { fieldName: key },
10
- getter: (value) => value[key] ?? '',
11
- });
12
-
13
- export const advancedNumberFilter = (
14
- key: string
15
- ): AdvancedRequestDataGridFilter<'number'> => ({
16
- ...numberFilter(key),
17
- field: { fieldName: key },
18
- getter: (value) => value[key] ?? 0,
19
- });