@bit.rhplus/ag-grid 0.0.39 → 0.0.41
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/BulkEdit/BulkEditButton.jsx +40 -2
- package/BulkEdit/BulkEditDatePicker.jsx +295 -0
- package/BulkEdit/BulkEditPopover.jsx +2 -2
- package/BulkEdit/index.js +1 -0
- package/BulkEdit/useBulkCellEdit.js +412 -348
- package/BulkEdit/utils.js +62 -21
- package/dist/BulkEdit/BulkEditButton.js +34 -2
- package/dist/BulkEdit/BulkEditButton.js.map +1 -1
- package/dist/BulkEdit/BulkEditDatePicker.d.ts +10 -0
- package/dist/BulkEdit/BulkEditDatePicker.js +154 -0
- package/dist/BulkEdit/BulkEditDatePicker.js.map +1 -0
- package/dist/BulkEdit/BulkEditPopover.js +2 -2
- package/dist/BulkEdit/BulkEditPopover.js.map +1 -1
- package/dist/BulkEdit/index.d.ts +1 -0
- package/dist/BulkEdit/index.js +1 -0
- package/dist/BulkEdit/index.js.map +1 -1
- package/dist/BulkEdit/useBulkCellEdit.js +82 -28
- package/dist/BulkEdit/useBulkCellEdit.js.map +1 -1
- package/dist/BulkEdit/utils.js +58 -19
- package/dist/BulkEdit/utils.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/index.jsx +2 -1
- package/package.json +7 -4
- /package/dist/{preview-1760429814166.js → preview-1760475768249.js} +0 -0
|
@@ -1,348 +1,412 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
validateRangeEditable,
|
|
5
|
-
getLastCellPosition,
|
|
6
|
-
applyBulkChanges,
|
|
7
|
-
applyBulkChangesWithApi,
|
|
8
|
-
} from './utils';
|
|
9
|
-
import useData from '@bit.rhplus/data';
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Hook pro bulk cell edit funkcionalitu v AG Grid
|
|
13
|
-
* @param {Object} gridRef - Reference na AG Grid
|
|
14
|
-
* @param {Object} options - Konfigurace bulk edit
|
|
15
|
-
* @returns {Object} - State a handlery pro bulk edit
|
|
16
|
-
*/
|
|
17
|
-
export const useBulkCellEdit = (gridRef, options = {}) => {
|
|
18
|
-
const {
|
|
19
|
-
enabled = false,
|
|
20
|
-
minCells = 2,
|
|
21
|
-
allowMultiColumn = false,
|
|
22
|
-
buttonPosition = 'bottom-right',
|
|
23
|
-
buttonOffset = { x: 5, y: 5 },
|
|
24
|
-
accessToken = null,
|
|
25
|
-
onBulkEditStart,
|
|
26
|
-
onBulkEditComplete,
|
|
27
|
-
} = options;
|
|
28
|
-
|
|
29
|
-
const { fetchDataUIAsync } = useData();
|
|
30
|
-
|
|
31
|
-
const [floatingButton, setFloatingButton] = useState({
|
|
32
|
-
visible: false,
|
|
33
|
-
position: null,
|
|
34
|
-
range: null,
|
|
35
|
-
column: null,
|
|
36
|
-
cellCount: 0,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const [editPopover, setEditPopover] = useState({
|
|
40
|
-
visible: false,
|
|
41
|
-
value: '',
|
|
42
|
-
loading: false,
|
|
43
|
-
error: null,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const scrollListenerRef = useRef(null);
|
|
47
|
-
const debounceTimeoutRef = useRef(null);
|
|
48
|
-
const pendingEventRef = useRef(null);
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
52
|
-
*/
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (!
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
};
|
|
348
|
-
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
validateRangeEditable,
|
|
5
|
+
getLastCellPosition,
|
|
6
|
+
applyBulkChanges,
|
|
7
|
+
applyBulkChangesWithApi,
|
|
8
|
+
} from './utils';
|
|
9
|
+
import useData from '@bit.rhplus/data';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook pro bulk cell edit funkcionalitu v AG Grid
|
|
13
|
+
* @param {Object} gridRef - Reference na AG Grid
|
|
14
|
+
* @param {Object} options - Konfigurace bulk edit
|
|
15
|
+
* @returns {Object} - State a handlery pro bulk edit
|
|
16
|
+
*/
|
|
17
|
+
export const useBulkCellEdit = (gridRef, options = {}) => {
|
|
18
|
+
const {
|
|
19
|
+
enabled = false,
|
|
20
|
+
minCells = 2,
|
|
21
|
+
allowMultiColumn = false,
|
|
22
|
+
buttonPosition = 'bottom-right',
|
|
23
|
+
buttonOffset = { x: 5, y: 5 },
|
|
24
|
+
accessToken = null,
|
|
25
|
+
onBulkEditStart,
|
|
26
|
+
onBulkEditComplete,
|
|
27
|
+
} = options;
|
|
28
|
+
|
|
29
|
+
const { fetchDataUIAsync } = useData();
|
|
30
|
+
|
|
31
|
+
const [floatingButton, setFloatingButton] = useState({
|
|
32
|
+
visible: false,
|
|
33
|
+
position: null,
|
|
34
|
+
range: null,
|
|
35
|
+
column: null,
|
|
36
|
+
cellCount: 0,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const [editPopover, setEditPopover] = useState({
|
|
40
|
+
visible: false,
|
|
41
|
+
value: '',
|
|
42
|
+
loading: false,
|
|
43
|
+
error: null,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const scrollListenerRef = useRef(null);
|
|
47
|
+
const debounceTimeoutRef = useRef(null);
|
|
48
|
+
const pendingEventRef = useRef(null);
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Helper funkce pro výpočet pozice buttonu s viewport-aware positioning
|
|
52
|
+
*/
|
|
53
|
+
const calculateButtonPosition = useCallback((cellPosition) => {
|
|
54
|
+
const BUTTON_SIZE = 32;
|
|
55
|
+
const POPOVER_WIDTH = 30;
|
|
56
|
+
const POPOVER_HEIGHT = 30;
|
|
57
|
+
const VIEWPORT_MARGIN = 10;
|
|
58
|
+
|
|
59
|
+
const viewportWidth = window.innerWidth;
|
|
60
|
+
const viewportHeight = window.innerHeight;
|
|
61
|
+
|
|
62
|
+
let buttonX, buttonY;
|
|
63
|
+
let adjustedPosition = buttonPosition;
|
|
64
|
+
|
|
65
|
+
switch (buttonPosition) {
|
|
66
|
+
case 'bottom-right':
|
|
67
|
+
buttonX = cellPosition.right + buttonOffset.x;
|
|
68
|
+
buttonY = cellPosition.bottom + buttonOffset.y;
|
|
69
|
+
break;
|
|
70
|
+
case 'bottom-left':
|
|
71
|
+
buttonX = cellPosition.left - buttonOffset.x;
|
|
72
|
+
buttonY = cellPosition.bottom + buttonOffset.y;
|
|
73
|
+
break;
|
|
74
|
+
case 'top-right':
|
|
75
|
+
buttonX = cellPosition.right + buttonOffset.x;
|
|
76
|
+
buttonY = cellPosition.top - buttonOffset.y;
|
|
77
|
+
break;
|
|
78
|
+
case 'top-left':
|
|
79
|
+
buttonX = cellPosition.left - buttonOffset.x;
|
|
80
|
+
buttonY = cellPosition.top - buttonOffset.y;
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
buttonX = cellPosition.right + buttonOffset.x;
|
|
84
|
+
buttonY = cellPosition.bottom + buttonOffset.y;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const buttonRight = buttonX + BUTTON_SIZE;
|
|
88
|
+
const popoverRight = buttonX + POPOVER_WIDTH;
|
|
89
|
+
const popoverBottom = buttonY + BUTTON_SIZE + POPOVER_HEIGHT;
|
|
90
|
+
|
|
91
|
+
if (popoverRight > viewportWidth - VIEWPORT_MARGIN) {
|
|
92
|
+
buttonX = cellPosition.left - buttonOffset.x - BUTTON_SIZE;
|
|
93
|
+
buttonX = Math.max(VIEWPORT_MARGIN, buttonX);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (popoverBottom > viewportHeight - VIEWPORT_MARGIN) {
|
|
97
|
+
buttonY = cellPosition.top - buttonOffset.y - BUTTON_SIZE;
|
|
98
|
+
buttonY = Math.max(VIEWPORT_MARGIN, buttonY);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
buttonX = Math.max(VIEWPORT_MARGIN, Math.min(buttonX, viewportWidth - BUTTON_SIZE - VIEWPORT_MARGIN));
|
|
102
|
+
buttonY = Math.max(VIEWPORT_MARGIN, Math.min(buttonY, viewportHeight - BUTTON_SIZE - VIEWPORT_MARGIN));
|
|
103
|
+
|
|
104
|
+
return { x: buttonX, y: buttonY };
|
|
105
|
+
}, [buttonPosition, buttonOffset]);
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Handler pro změnu range selection s okamžitou + debounced validací
|
|
109
|
+
*/
|
|
110
|
+
const handleRangeChange = useCallback(
|
|
111
|
+
(event) => {
|
|
112
|
+
// Lightweight pre-checks - okamžitě bez debounce
|
|
113
|
+
if (!enabled) {
|
|
114
|
+
setFloatingButton({ visible: false });
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const ranges = event.api.getCellRanges();
|
|
119
|
+
if (!ranges || ranges.length === 0) {
|
|
120
|
+
setFloatingButton({ visible: false });
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const range = ranges[0];
|
|
125
|
+
|
|
126
|
+
// ✨ OKAŽITÁ lightweight validace - zobraz button HNED
|
|
127
|
+
if (allowMultiColumn || range.columns.length === 1) {
|
|
128
|
+
const cellCount = Math.abs(range.endRow.rowIndex - range.startRow.rowIndex) + 1;
|
|
129
|
+
|
|
130
|
+
if (cellCount >= minCells) {
|
|
131
|
+
// Kontrola zda má sloupec bulkEditApi (rychlá kontrola)
|
|
132
|
+
const column = range.columns[0];
|
|
133
|
+
const colDef = column?.getColDef();
|
|
134
|
+
const hasBulkEditApi = colDef?.bulkEditApi || colDef?.bulkEditPopover;
|
|
135
|
+
|
|
136
|
+
// Zobraz button jen pokud má bulkEditApi nebo bulkEditPopover
|
|
137
|
+
if (hasBulkEditApi) {
|
|
138
|
+
const cellPosition = getLastCellPosition(range, event.api);
|
|
139
|
+
if (cellPosition) {
|
|
140
|
+
setFloatingButton({
|
|
141
|
+
visible: true,
|
|
142
|
+
position: calculateButtonPosition(cellPosition),
|
|
143
|
+
range,
|
|
144
|
+
column: column,
|
|
145
|
+
cellCount,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
// Skryj button pokud sloupec nemá bulk edit podporu
|
|
150
|
+
setFloatingButton({ visible: false });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Uložit event pro debounced těžkou validaci (editable check)
|
|
156
|
+
pendingEventRef.current = event;
|
|
157
|
+
|
|
158
|
+
// Debounce logika - těžká validace proběhne na pozadí (50ms)
|
|
159
|
+
if (debounceTimeoutRef.current) {
|
|
160
|
+
clearTimeout(debounceTimeoutRef.current);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
debounceTimeoutRef.current = setTimeout(() => {
|
|
164
|
+
if (pendingEventRef.current) {
|
|
165
|
+
executeRangeValidation(pendingEventRef.current);
|
|
166
|
+
}
|
|
167
|
+
}, 50);
|
|
168
|
+
},
|
|
169
|
+
[enabled, allowMultiColumn, minCells, calculateButtonPosition]
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Těžké validace a výpočty v debounced callbacku
|
|
174
|
+
*/
|
|
175
|
+
const executeRangeValidation = useCallback(
|
|
176
|
+
(event) => {
|
|
177
|
+
const ranges = event.api.getCellRanges();
|
|
178
|
+
if (!ranges || ranges.length === 0) {
|
|
179
|
+
setFloatingButton({ visible: false });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const range = ranges[0];
|
|
184
|
+
|
|
185
|
+
// Kontrola single column
|
|
186
|
+
if (!allowMultiColumn && range.columns.length !== 1) {
|
|
187
|
+
setFloatingButton({ visible: false });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Výpočet počtu buněk
|
|
192
|
+
const cellCount =
|
|
193
|
+
Math.abs(range.endRow.rowIndex - range.startRow.rowIndex) + 1;
|
|
194
|
+
|
|
195
|
+
// Kontrola min počtu buněk
|
|
196
|
+
if (cellCount < minCells) {
|
|
197
|
+
setFloatingButton({ visible: false });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Těžká validace - editable sloupce
|
|
202
|
+
if (!validateRangeEditable(range, event.api)) {
|
|
203
|
+
setFloatingButton({ visible: false });
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Těžký výpočet - pozice buňky
|
|
208
|
+
const cellPosition = getLastCellPosition(range, event.api);
|
|
209
|
+
if (!cellPosition) {
|
|
210
|
+
setFloatingButton({ visible: false });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
setFloatingButton({
|
|
215
|
+
visible: true,
|
|
216
|
+
position: calculateButtonPosition(cellPosition),
|
|
217
|
+
range,
|
|
218
|
+
column: range.columns[0],
|
|
219
|
+
cellCount,
|
|
220
|
+
});
|
|
221
|
+
},
|
|
222
|
+
[minCells, allowMultiColumn, buttonPosition, buttonOffset]
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Handler pro kliknutí na bulk edit button - otevře popover
|
|
227
|
+
*/
|
|
228
|
+
const handleOpenPopover = useCallback(() => {
|
|
229
|
+
if (onBulkEditStart) {
|
|
230
|
+
onBulkEditStart({
|
|
231
|
+
range: floatingButton.range,
|
|
232
|
+
column: floatingButton.column,
|
|
233
|
+
cellCount: floatingButton.cellCount,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
setEditPopover({
|
|
238
|
+
visible: true,
|
|
239
|
+
value: '',
|
|
240
|
+
loading: false,
|
|
241
|
+
error: null,
|
|
242
|
+
});
|
|
243
|
+
}, [floatingButton, onBulkEditStart]);
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Handler pro submit bulk edit změn
|
|
247
|
+
*/
|
|
248
|
+
const handleSubmitEdit = useCallback(
|
|
249
|
+
async (newValue) => {
|
|
250
|
+
if (!gridRef.current || !floatingButton.range) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
setEditPopover((prev) => ({ ...prev, loading: true, error: null }));
|
|
255
|
+
|
|
256
|
+
try {
|
|
257
|
+
const colDef = floatingButton.column?.getColDef();
|
|
258
|
+
const bulkEditApi = colDef?.bulkEditApi;
|
|
259
|
+
|
|
260
|
+
let result;
|
|
261
|
+
|
|
262
|
+
// Pokud je definováno bulkEditApi, použij API volání
|
|
263
|
+
if (bulkEditApi?.endpoint) {
|
|
264
|
+
result = await applyBulkChangesWithApi(
|
|
265
|
+
floatingButton.range,
|
|
266
|
+
newValue,
|
|
267
|
+
gridRef.current.api,
|
|
268
|
+
bulkEditApi,
|
|
269
|
+
accessToken,
|
|
270
|
+
fetchDataUIAsync,
|
|
271
|
+
(result) => {
|
|
272
|
+
if (onBulkEditComplete) {
|
|
273
|
+
onBulkEditComplete({
|
|
274
|
+
...result,
|
|
275
|
+
range: floatingButton.range,
|
|
276
|
+
column: floatingButton.column,
|
|
277
|
+
newValue,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
} else {
|
|
283
|
+
// Pokud není API, použij lokální změnu
|
|
284
|
+
result = applyBulkChanges(
|
|
285
|
+
floatingButton.range,
|
|
286
|
+
newValue,
|
|
287
|
+
gridRef.current.api,
|
|
288
|
+
(result) => {
|
|
289
|
+
if (onBulkEditComplete) {
|
|
290
|
+
onBulkEditComplete({
|
|
291
|
+
...result,
|
|
292
|
+
range: floatingButton.range,
|
|
293
|
+
column: floatingButton.column,
|
|
294
|
+
newValue,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (result.success) {
|
|
302
|
+
// Úspěch - zavřít popover a skrýt button
|
|
303
|
+
setEditPopover({
|
|
304
|
+
visible: false,
|
|
305
|
+
value: '',
|
|
306
|
+
loading: false,
|
|
307
|
+
error: null,
|
|
308
|
+
});
|
|
309
|
+
setFloatingButton({ visible: false });
|
|
310
|
+
} else {
|
|
311
|
+
// Chyba - zobrazit error
|
|
312
|
+
setEditPopover((prev) => ({
|
|
313
|
+
...prev,
|
|
314
|
+
loading: false,
|
|
315
|
+
error: result.error || result.errors?.[0] || 'Chyba při aplikaci změn',
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
} catch (error) {
|
|
319
|
+
setEditPopover((prev) => ({
|
|
320
|
+
...prev,
|
|
321
|
+
loading: false,
|
|
322
|
+
error: error?.message || 'Neznámá chyba',
|
|
323
|
+
}));
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
[gridRef, floatingButton, onBulkEditComplete, accessToken, fetchDataUIAsync]
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Handler pro zrušení bulk edit
|
|
331
|
+
*/
|
|
332
|
+
const handleCancelEdit = useCallback(() => {
|
|
333
|
+
setEditPopover({
|
|
334
|
+
visible: false,
|
|
335
|
+
value: '',
|
|
336
|
+
loading: false,
|
|
337
|
+
error: null,
|
|
338
|
+
});
|
|
339
|
+
setFloatingButton({ visible: false });
|
|
340
|
+
}, []);
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Handler pro změnu hodnoty v popover inputu
|
|
344
|
+
*/
|
|
345
|
+
const handleValueChange = useCallback((value) => {
|
|
346
|
+
setEditPopover((prev) => ({ ...prev, value, error: null }));
|
|
347
|
+
}, []);
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Scroll listener - skrýt button při scrollování
|
|
351
|
+
*/
|
|
352
|
+
useEffect(() => {
|
|
353
|
+
if (!enabled || !gridRef.current) return;
|
|
354
|
+
|
|
355
|
+
const gridElement = gridRef.current.api?.gridBodyCtrl?.eBodyViewport;
|
|
356
|
+
if (!gridElement) return;
|
|
357
|
+
|
|
358
|
+
const handleScroll = () => {
|
|
359
|
+
if (floatingButton.visible) {
|
|
360
|
+
setFloatingButton({ visible: false });
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
scrollListenerRef.current = handleScroll;
|
|
365
|
+
gridElement.addEventListener('scroll', handleScroll);
|
|
366
|
+
|
|
367
|
+
return () => {
|
|
368
|
+
if (gridElement && scrollListenerRef.current) {
|
|
369
|
+
gridElement.removeEventListener('scroll', scrollListenerRef.current);
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}, [enabled, gridRef, floatingButton.visible]);
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Window resize listener - přepočítat pozici
|
|
376
|
+
*/
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
if (!enabled || !floatingButton.visible) return;
|
|
379
|
+
|
|
380
|
+
const handleResize = () => {
|
|
381
|
+
// Při resize okna skryjeme button (user musí znovu označit)
|
|
382
|
+
setFloatingButton({ visible: false });
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
window.addEventListener('resize', handleResize);
|
|
386
|
+
|
|
387
|
+
return () => {
|
|
388
|
+
window.removeEventListener('resize', handleResize);
|
|
389
|
+
};
|
|
390
|
+
}, [enabled, floatingButton.visible]);
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Cleanup timeout on unmount
|
|
394
|
+
*/
|
|
395
|
+
useEffect(() => {
|
|
396
|
+
return () => {
|
|
397
|
+
if (debounceTimeoutRef.current) {
|
|
398
|
+
clearTimeout(debounceTimeoutRef.current);
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
}, []);
|
|
402
|
+
|
|
403
|
+
return {
|
|
404
|
+
floatingButton,
|
|
405
|
+
editPopover,
|
|
406
|
+
handleRangeChange,
|
|
407
|
+
handleOpenPopover,
|
|
408
|
+
handleSubmitEdit,
|
|
409
|
+
handleCancelEdit,
|
|
410
|
+
handleValueChange,
|
|
411
|
+
};
|
|
412
|
+
};
|