@fctc/widget-logic 5.3.7-beta.15 → 5.3.7-beta.16

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/dist/widget.js DELETED
@@ -1,2379 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
21
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
- // If the importer is in node compatibility mode or this is not an ESM
23
- // file that has been converted to a CommonJS file using a Babel-
24
- // compatible transform (i.e. "__esModule" has not been set), then set
25
- // "default" to the CommonJS "module.exports" for node compatibility.
26
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
- mod
28
- ));
29
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
-
31
- // src/widget.ts
32
- var widget_exports = {};
33
- __export(widget_exports, {
34
- binaryFieldController: () => binaryFieldController,
35
- colorFieldController: () => colorFieldController,
36
- copyLinkButtonController: () => copyLinkButtonController,
37
- downLoadBinaryController: () => downLoadBinaryController,
38
- downloadFileController: () => downloadFileController,
39
- durationController: () => durationController,
40
- many2manyBinaryController: () => many2manyBinaryController,
41
- many2manyFieldController: () => many2manyFieldController,
42
- many2manyTagsController: () => many2manyTagsController,
43
- many2oneButtonController: () => many2oneButtonController,
44
- many2oneFieldController: () => many2oneFieldController,
45
- priorityFieldController: () => priorityFieldController,
46
- providerEinvoiceFieldController: () => providerEinvoiceFieldController,
47
- searchController: () => searchController,
48
- statusDropdownController: () => statusDropdownController,
49
- tableController: () => tableController,
50
- tableGroupController: () => tableGroupController,
51
- tableHeadController: () => tableHeadController
52
- });
53
- module.exports = __toCommonJS(widget_exports);
54
-
55
- // src/widget/basic/status-dropdown-field/controller.ts
56
- var import_react = require("react");
57
- var import_environment = require("@fctc/interface-logic/environment");
58
- var import_hooks = require("@fctc/interface-logic/hooks");
59
- var statusDropdownController = (props) => {
60
- const { selection, isForm, id, model, name, state, onRefetch } = props;
61
- const env = (0, import_environment.getEnv)();
62
- const colors = {
63
- normal: "bg-[#e9ecef]",
64
- done: "bg-primary",
65
- blocked: "bg-red-500"
66
- };
67
- const [isOpen, setIsOpen] = (0, import_react.useState)(false);
68
- const buttonRef = (0, import_react.useRef)(null);
69
- (0, import_react.useEffect)(() => {
70
- const handleClickOutside = (event) => {
71
- if (buttonRef.current && !buttonRef.current.contains(event.target)) {
72
- setIsOpen(false);
73
- }
74
- };
75
- document.addEventListener("mousedown", handleClickOutside);
76
- return () => {
77
- document.removeEventListener("mousedown", handleClickOutside);
78
- };
79
- }, []);
80
- const { mutate: onSave } = (0, import_hooks.useSave)();
81
- const handleClick = async (status) => {
82
- setIsOpen(!isOpen);
83
- onSave(
84
- {
85
- ids: id ? [id] : [],
86
- model: model ?? "",
87
- data: { [name ?? ""]: status },
88
- context: env.context
89
- },
90
- {
91
- onSuccess: () => {
92
- onRefetch && onRefetch();
93
- }
94
- }
95
- );
96
- };
97
- return {
98
- handleClick,
99
- buttonRef,
100
- isForm,
101
- setIsOpen,
102
- isOpen,
103
- selection,
104
- state,
105
- colors
106
- };
107
- };
108
-
109
- // src/widget/basic/many2one-field/controller.ts
110
- var import_react15 = require("react");
111
-
112
- // src/hooks.ts
113
- var import_hooks3 = require("@fctc/interface-logic/hooks");
114
-
115
- // src/hooks/core/use-app-provider.tsx
116
- var import_react9 = require("react");
117
-
118
- // src/hooks/core/use-menu.ts
119
- var import_react4 = require("react");
120
-
121
- // src/hooks/core/use-call-action.ts
122
- var import_react2 = require("react");
123
-
124
- // src/provider.ts
125
- var provider_exports = {};
126
- __reExport(provider_exports, require("@fctc/interface-logic/provider"));
127
-
128
- // src/utils.ts
129
- var utils_exports = {};
130
- __export(utils_exports, {
131
- STORAGES: () => STORAGES,
132
- countSum: () => countSum,
133
- guessTypeFromUrl: () => guessTypeFromUrl,
134
- isObjectEmpty: () => isObjectEmpty,
135
- languages: () => languages,
136
- mergeButtons: () => mergeButtons,
137
- setStorageItemAsync: () => setStorageItemAsync,
138
- useStorageState: () => useStorageState,
139
- validateAndParseDate: () => validateAndParseDate
140
- });
141
-
142
- // src/utils/constants.ts
143
- var languages = [
144
- { id: "vi_VN", name: "VIE" },
145
- { id: "en_US", name: "ENG" }
146
- ];
147
- var isBlobUrl = (url) => url.startsWith("blob:");
148
-
149
- // src/utils/function.ts
150
- var import_react3 = require("react");
151
- var countSum = (data, field) => {
152
- if (!data || !field) return 0;
153
- return data.reduce(
154
- (total, item) => total + (item?.[`${field}_count`] || 0),
155
- 0
156
- );
157
- };
158
- var isObjectEmpty = (obj) => {
159
- return Object.keys(obj).length === 0;
160
- };
161
- function mergeButtons(fields) {
162
- const buttons = fields?.filter((f) => f.type_co === "button");
163
- const others = fields?.filter((f) => f.type_co !== "button");
164
- if (buttons?.length) {
165
- others.push({
166
- type_co: "buttons",
167
- buttons
168
- });
169
- }
170
- return others;
171
- }
172
- var STORAGES = {
173
- TOKEN: "accessToken",
174
- USER_INFO: "USER_INFO"
175
- };
176
- function useAsyncState(initialValue = [true, null]) {
177
- return (0, import_react3.useReducer)(
178
- (_state, action = null) => [false, action],
179
- initialValue
180
- );
181
- }
182
- async function setStorageItemAsync(key, value) {
183
- try {
184
- if (value === null) {
185
- localStorage.removeItem(key);
186
- } else {
187
- localStorage.setItem(key, value);
188
- }
189
- } catch (e) {
190
- console.error("Local storage is unavailable:", e);
191
- }
192
- }
193
- function useStorageState(key) {
194
- const [state, setState] = useAsyncState();
195
- (0, import_react3.useEffect)(() => {
196
- try {
197
- const storedValue = localStorage.getItem(key);
198
- setState(storedValue);
199
- } catch (e) {
200
- console.error("Local storage is unavailable:", e);
201
- }
202
- }, [key]);
203
- const setValue = (0, import_react3.useCallback)(
204
- (value) => {
205
- setState(value);
206
- setStorageItemAsync(key, value);
207
- },
208
- [key]
209
- );
210
- return [state, setValue];
211
- }
212
- var guessTypeFromUrl = (url) => {
213
- const ext = url.split(".").pop()?.toLowerCase();
214
- if (!ext) return null;
215
- const map = {
216
- jpg: "image/jpeg",
217
- jpeg: "image/jpeg",
218
- png: "image/png",
219
- webp: "image/webp",
220
- gif: "image/gif",
221
- svg: "image/svg+xml",
222
- bmp: "image/bmp",
223
- tiff: "image/tiff",
224
- pdf: "application/pdf",
225
- zip: "application/zip",
226
- rar: "application/x-rar-compressed",
227
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
228
- xls: "application/vnd.ms-excel",
229
- mp4: "video/mp4",
230
- mov: "video/quicktime"
231
- };
232
- return map[ext] || null;
233
- };
234
-
235
- // src/utils/format-date.ts
236
- var import_moment = __toESM(require("moment"));
237
- var validateAndParseDate = (input, isDateTime = false) => {
238
- if (!input || typeof input !== "string") return null;
239
- const cleanInput = input.replace(/[^0-9-\/:\s]/g, "");
240
- const dateFormat = "YYYY-MM-DD";
241
- const dateTimeFormat = "YYYY-MM-DD HH:mm:ss";
242
- const currentDay = (0, import_moment.default)().format("DD");
243
- const currentMonth = (0, import_moment.default)().format("MM");
244
- const currentYear = (0, import_moment.default)().format("YYYY");
245
- const defaultTime = "00:00:00";
246
- const maxYear = parseInt(currentYear) + 10;
247
- const isValidDate = (day, month, year) => {
248
- const date = (0, import_moment.default)(`${day}-${month}-${year}`, "DD-MM-YYYY", true);
249
- return date.isValid();
250
- };
251
- const isValidTime = (hour, minute = "00", second = "00") => {
252
- const h = parseInt(hour, 10);
253
- const m = parseInt(minute, 10);
254
- const s = parseInt(second, 10);
255
- return h >= 0 && h <= 23 && m >= 0 && m <= 59 && s >= 0 && s <= 59;
256
- };
257
- const formatOutput = (day, month, year, time = defaultTime) => {
258
- let result = (0, import_moment.default)(
259
- `${day}-${month}-${year} ${time}`,
260
- "DD-MM-YYYY HH:mm:ss"
261
- );
262
- if (!result.isValid()) return null;
263
- if (isDateTime) {
264
- result = result.subtract(7, "hours");
265
- return result.format(dateTimeFormat);
266
- }
267
- return result.format(dateFormat);
268
- };
269
- if (isDateTime && input.match(
270
- /^\d{1,2}[\/-]\d{1,2}[\/-]\d{2,4}\s+\d{1,2}(:\d{1,2}(:\d{1,2})?)?$/
271
- )) {
272
- const [datePart, timePart] = input.split(/\s+/);
273
- const dateParts = datePart.split(/[\/-]/);
274
- const timeParts = timePart.split(":");
275
- const day = dateParts[0].padStart(2, "0");
276
- const month = dateParts[1].padStart(2, "0");
277
- const year = dateParts[2].length <= 2 ? `20${dateParts[2].padStart(2, "0")}` : dateParts[2].padStart(4, "0");
278
- const hour = timeParts[0].padStart(2, "0");
279
- const minute = timeParts[1] ? timeParts[1].padStart(2, "0") : "00";
280
- const second = timeParts[2] ? timeParts[2].padStart(2, "0") : "00";
281
- if (isValidDate(day, month, year) && isValidTime(hour, minute, second)) {
282
- let result = (0, import_moment.default)(
283
- `${day}-${month}-${year} ${hour}:${minute}:${second}`,
284
- "DD-MM-YYYY HH:mm:ss"
285
- );
286
- if (!result.isValid()) return null;
287
- result = result.subtract(7, "hours");
288
- return result.format(dateTimeFormat);
289
- }
290
- return null;
291
- }
292
- if (cleanInput.match(/^\d{4}-\d{2}-\d{2}$/)) {
293
- const [year, month, day] = cleanInput.split("-");
294
- if (isValidDate(day, month, year)) {
295
- return formatOutput(day, month, year);
296
- }
297
- return null;
298
- }
299
- if (cleanInput.match(/^\d{1,2}\/\d{1,2}\/\d{2,4}$/)) {
300
- const [day, month, year] = cleanInput.split("/");
301
- const paddedDay = day.padStart(2, "0");
302
- const paddedMonth = month.padStart(2, "0");
303
- const fullYear = year.length <= 2 ? `20${year.padStart(2, "0")}` : year.padStart(4, "0");
304
- if (isValidDate(paddedDay, paddedMonth, fullYear)) {
305
- return formatOutput(paddedDay, paddedMonth, fullYear);
306
- }
307
- return null;
308
- }
309
- if (cleanInput.match(/^\d{1,2}-\d{1,2}-\d{2,4}$/)) {
310
- const [day, month, year] = cleanInput.split("-");
311
- const paddedDay = day.padStart(2, "0");
312
- const paddedMonth = month.padStart(2, "0");
313
- const fullYear = year.length <= 2 ? `20${year.padStart(2, "0")}` : year.padStart(4, "0");
314
- if (isValidDate(paddedDay, paddedMonth, fullYear)) {
315
- return formatOutput(paddedDay, paddedMonth, fullYear);
316
- }
317
- return null;
318
- }
319
- if (cleanInput.match(/^\d{1,2}[\/-]\d{1,2}$/)) {
320
- const [day, month] = cleanInput.split(/[\/-]/);
321
- const paddedDay = day.padStart(2, "0");
322
- const paddedMonth = month.padStart(2, "0");
323
- if (isValidDate(paddedDay, paddedMonth, currentYear)) {
324
- return formatOutput(paddedDay, paddedMonth, currentYear);
325
- }
326
- return null;
327
- }
328
- if (cleanInput.match(/^\d{4}$/)) {
329
- const num = parseInt(cleanInput, 10);
330
- if (num >= 2e3 && num <= maxYear) {
331
- if (isValidDate(currentDay, currentMonth, num.toString())) {
332
- return formatOutput(currentDay, currentMonth, num.toString());
333
- }
334
- return null;
335
- }
336
- const day = cleanInput.slice(0, 2);
337
- const month = cleanInput.slice(2, 4);
338
- if (isValidDate(day, month, currentYear)) {
339
- return formatOutput(day, month, currentYear);
340
- }
341
- return null;
342
- }
343
- if (cleanInput.startsWith("-") && /^\-\d+$/.test(cleanInput)) {
344
- const daysToSubtract = Math.abs(parseInt(cleanInput, 10));
345
- let result = (0, import_moment.default)().subtract(daysToSubtract, "days");
346
- if (isDateTime) {
347
- result = result.subtract(7, "hours");
348
- }
349
- if (result.isValid()) {
350
- return isDateTime ? result.format(dateTimeFormat) : result.format(dateFormat);
351
- }
352
- return null;
353
- }
354
- if (input.match(/^\d{1,2}[^0-9-\/]+\d{1,2}[^0-9-\/]+\d{2,4}.*$/)) {
355
- const parts = input.split(/[^0-9-\/]+/).filter(Boolean);
356
- const day = parts[0].padStart(2, "0");
357
- const month = parts[1].padStart(2, "0");
358
- let year = parts[2];
359
- year = year.length === 2 ? `20${year}` : year.padStart(4, "0");
360
- if (isValidDate(day, month, year)) {
361
- return formatOutput(day, month, year);
362
- }
363
- return null;
364
- }
365
- if (isDateTime) {
366
- if (cleanInput.length === 9) {
367
- const day = cleanInput.slice(0, 2);
368
- const month = cleanInput.slice(2, 4);
369
- const year = cleanInput.slice(4, 8);
370
- const hour = cleanInput.slice(8, 9).padStart(2, "0");
371
- if (isValidDate(day, month, year) && isValidTime(hour)) {
372
- let result = (0, import_moment.default)(
373
- `${day}-${month}-${year} ${hour}:00:00`,
374
- "DD-MM-YYYY HH:mm:ss"
375
- );
376
- if (!result.isValid()) return null;
377
- result = result.subtract(7, "hours");
378
- return result.format(dateTimeFormat);
379
- }
380
- return null;
381
- }
382
- if (cleanInput.length === 10) {
383
- const day = cleanInput.slice(0, 2);
384
- const month = cleanInput.slice(2, 4);
385
- const year = cleanInput.slice(4, 8);
386
- const hour = cleanInput.slice(8, 10);
387
- if (isValidDate(day, month, year) && isValidTime(hour)) {
388
- let result = (0, import_moment.default)(
389
- `${day}-${month}-${year} ${hour}:00:00`,
390
- "DD-MM-YYYY HH:mm:ss"
391
- );
392
- if (!result.isValid()) return null;
393
- result = result.subtract(7, "hours");
394
- return result.format(dateTimeFormat);
395
- }
396
- return null;
397
- }
398
- if (cleanInput.length === 11) {
399
- const day = cleanInput.slice(0, 2);
400
- const month = cleanInput.slice(2, 4);
401
- const year = cleanInput.slice(4, 8);
402
- const hour = cleanInput.slice(8, 10);
403
- const minute = cleanInput.slice(10, 11).padStart(2, "0");
404
- if (isValidDate(day, month, year) && isValidTime(hour, minute)) {
405
- let result = (0, import_moment.default)(
406
- `${day}-${month}-${year} ${hour}:${minute}:00`,
407
- "DD-MM-YYYY HH:mm:ss"
408
- );
409
- if (!result.isValid()) return null;
410
- result = result.subtract(7, "hours");
411
- return result.format(dateTimeFormat);
412
- }
413
- return null;
414
- }
415
- if (cleanInput.length === 12) {
416
- const day = cleanInput.slice(0, 2);
417
- const month = cleanInput.slice(2, 4);
418
- const year = cleanInput.slice(4, 8);
419
- const hour = cleanInput.slice(8, 10);
420
- const minute = cleanInput.slice(10, 12);
421
- if (isValidDate(day, month, year) && isValidTime(hour, minute)) {
422
- let result = (0, import_moment.default)(
423
- `${day}-${month}-${year} ${hour}:${minute}:00`,
424
- "DD-MM-YYYY HH:mm:ss"
425
- );
426
- if (!result.isValid()) return null;
427
- result = result.subtract(7, "hours");
428
- return result.format(dateTimeFormat);
429
- }
430
- return null;
431
- }
432
- if (cleanInput.length === 13) {
433
- const day = cleanInput.slice(0, 2);
434
- const month = cleanInput.slice(2, 4);
435
- const year = cleanInput.slice(4, 8);
436
- const hour = cleanInput.slice(8, 10);
437
- const minute = cleanInput.slice(10, 12);
438
- const second = cleanInput.slice(12, 13).padStart(2, "0");
439
- if (isValidDate(day, month, year) && isValidTime(hour, minute, second)) {
440
- let result = (0, import_moment.default)(
441
- `${day}-${month}-${year} ${hour}:${minute}:${second}`,
442
- "DD-MM-YYYY HH:mm:ss"
443
- );
444
- if (!result.isValid()) return null;
445
- result = result.subtract(7, "hours");
446
- return result.format(dateTimeFormat);
447
- }
448
- return null;
449
- }
450
- if (cleanInput.length === 14) {
451
- const day = cleanInput.slice(0, 2);
452
- const month = cleanInput.slice(2, 4);
453
- const year = cleanInput.slice(4, 8);
454
- const hour = cleanInput.slice(8, 10);
455
- const minute = cleanInput.slice(10, 12);
456
- const second = cleanInput.slice(12, 14);
457
- if (isValidDate(day, month, year) && isValidTime(hour, minute, second)) {
458
- let result = (0, import_moment.default)(
459
- `${day}-${month}-${year} ${hour}:${minute}:${second}`,
460
- "DD-MM-YYYY HH:mm:ss"
461
- );
462
- if (!result.isValid()) return null;
463
- result = result.subtract(7, "hours");
464
- return result.format(dateTimeFormat);
465
- }
466
- return null;
467
- }
468
- }
469
- const len = cleanInput.length;
470
- if (len === 1 || len === 2) {
471
- const paddedDay = cleanInput.padStart(2, "0");
472
- if (isValidDate(paddedDay, currentMonth, currentYear)) {
473
- return formatOutput(paddedDay, currentMonth, currentYear);
474
- }
475
- return null;
476
- }
477
- if (len === 3) {
478
- const day = cleanInput.slice(0, 2);
479
- const month = cleanInput.slice(2, 3).padStart(2, "0");
480
- if (isValidDate(day, month, currentYear)) {
481
- return formatOutput(day, month, currentYear);
482
- }
483
- return null;
484
- }
485
- if (len === 6) {
486
- const day = cleanInput.slice(0, 2);
487
- const month = cleanInput.slice(2, 4);
488
- let year = cleanInput.slice(4, 6);
489
- year = `20${year}`;
490
- if (parseInt(month) > 12) {
491
- if (isValidDate(day, currentMonth, currentYear)) {
492
- return formatOutput(day, currentMonth, currentYear);
493
- }
494
- return null;
495
- }
496
- if (isValidDate(day, month, year)) {
497
- return formatOutput(day, month, year);
498
- }
499
- return null;
500
- }
501
- if (len === 7) {
502
- return null;
503
- }
504
- if (len === 8) {
505
- const day = cleanInput.slice(0, 2);
506
- const month = cleanInput.slice(2, 4);
507
- const year = cleanInput.slice(4, 8);
508
- if (isValidDate(day, month, year)) {
509
- return formatOutput(day, month, year);
510
- }
511
- return null;
512
- }
513
- if (len > 8 && !isDateTime) {
514
- return null;
515
- }
516
- return null;
517
- };
518
-
519
- // src/utils.ts
520
- __reExport(utils_exports, require("@fctc/interface-logic/utils"));
521
-
522
- // src/hooks/core/use-detail.ts
523
- var import_react_query = require("@tanstack/react-query");
524
- var import_react5 = require("react");
525
-
526
- // src/hooks/core/use-profile.ts
527
- var import_react_query2 = require("@tanstack/react-query");
528
- var import_react6 = require("react");
529
-
530
- // src/hooks/core/use-view-v2.ts
531
- var import_react7 = require("react");
532
-
533
- // src/hooks/core/use-company.ts
534
- var import_react_query3 = require("@tanstack/react-query");
535
- var import_react8 = require("react");
536
-
537
- // src/hooks/core/use-app-provider.tsx
538
- var import_jsx_runtime = require("react/jsx-runtime");
539
- var AppProviderInitialValue = {
540
- user: {},
541
- company: {},
542
- action: {},
543
- menu: {},
544
- view: {}
545
- };
546
- var ReactContext = (0, import_react9.createContext)(AppProviderInitialValue);
547
- var useAppProvider = () => {
548
- const context = (0, import_react9.useContext)(ReactContext);
549
- if (!context) {
550
- return AppProviderInitialValue;
551
- }
552
- return context;
553
- };
554
-
555
- // src/hooks/core/use-config.ts
556
- var import_react10 = require("react");
557
-
558
- // src/hooks/core/use-get-specification.ts
559
- var import_react11 = require("react");
560
- var useGetSpecification = ({
561
- model,
562
- viewData,
563
- fields
564
- }) => {
565
- const baseModel = (0, import_react11.useMemo)(
566
- () => ({
567
- name: String(model),
568
- view: viewData,
569
- fields
570
- }),
571
- [model, viewData, fields]
572
- );
573
- const initModel = (0, import_hooks3.useModel)();
574
- const modelInstance = (0, import_react11.useMemo)(() => {
575
- if (viewData) {
576
- return initModel.initModel(baseModel);
577
- }
578
- return null;
579
- }, [baseModel, viewData, model]);
580
- const specification = (0, import_react11.useMemo)(() => {
581
- if (modelInstance) {
582
- return modelInstance.getSpecification();
583
- }
584
- return null;
585
- }, [modelInstance, model]);
586
- return { specification };
587
- };
588
-
589
- // src/hooks/core/use-list-data.ts
590
- var import_react14 = require("react");
591
- var import_utils5 = require("@fctc/interface-logic/utils");
592
-
593
- // src/hooks/utils/use-debounce.ts
594
- var import_react12 = require("react");
595
- function useDebounce(value, delay) {
596
- const [debouncedValue, setDebouncedValue] = (0, import_react12.useState)(value);
597
- (0, import_react12.useEffect)(() => {
598
- const handler = setTimeout(() => {
599
- setDebouncedValue(value);
600
- }, delay);
601
- return () => {
602
- clearTimeout(handler);
603
- };
604
- }, [value, delay]);
605
- return [debouncedValue];
606
- }
607
-
608
- // src/hooks/utils/use-get-rowids.ts
609
- var import_react13 = require("react");
610
- var useGetRowIds = (tableRef) => {
611
- function isElementVisible(el) {
612
- const style = window.getComputedStyle(el);
613
- return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0";
614
- }
615
- function arraysAreEqual(a, b) {
616
- if (a.length !== b.length) return false;
617
- if (a.length === 0 && b.length === 0) return true;
618
- const setA = new Set(a);
619
- const setB = new Set(b);
620
- if (setA.size !== setB.size) return false;
621
- for (const val of setA) {
622
- if (!setB.has(val)) return false;
623
- }
624
- return true;
625
- }
626
- const [rowIds, setRowIds] = (0, import_react13.useState)([]);
627
- const lastRowIdsRef = (0, import_react13.useRef)([]);
628
- const updateVisibleRowIds = (0, import_react13.useCallback)(() => {
629
- const table = tableRef.current;
630
- if (!table) return;
631
- const rows = table.querySelectorAll("tr[data-row-id]");
632
- const ids = [];
633
- rows.forEach((row) => {
634
- const el = row;
635
- if (isElementVisible(el)) {
636
- const id = el.getAttribute("data-row-id");
637
- if (id) ids.push(id);
638
- }
639
- });
640
- const uniqueIds = Array.from(new Set(ids));
641
- if (!arraysAreEqual(lastRowIdsRef.current, uniqueIds)) {
642
- lastRowIdsRef.current = uniqueIds;
643
- setRowIds(uniqueIds);
644
- }
645
- }, [tableRef]);
646
- (0, import_react13.useEffect)(() => {
647
- const table = tableRef.current;
648
- if (!table) return;
649
- const mutationObserver = new MutationObserver(() => {
650
- updateVisibleRowIds();
651
- });
652
- mutationObserver.observe(table, {
653
- childList: true,
654
- subtree: true,
655
- attributes: true,
656
- attributeFilter: ["style", "class"]
657
- });
658
- const resizeObserver = new ResizeObserver(() => {
659
- updateVisibleRowIds();
660
- });
661
- resizeObserver.observe(table);
662
- const handleScroll = () => updateVisibleRowIds();
663
- table.addEventListener("scroll", handleScroll, true);
664
- updateVisibleRowIds();
665
- return () => {
666
- mutationObserver.disconnect();
667
- resizeObserver.disconnect();
668
- table.removeEventListener("scroll", handleScroll, true);
669
- };
670
- }, [updateVisibleRowIds, tableRef?.current]);
671
- return { rowIds, refresh: updateVisibleRowIds };
672
- };
673
-
674
- // src/hooks/core/use-list-data.ts
675
- var useListData = ({
676
- action,
677
- context,
678
- viewData,
679
- model,
680
- service,
681
- xNode,
682
- mode,
683
- limit = 10
684
- }) => {
685
- const { useGetListData: useGetListData2 } = (0, provider_exports.useService)();
686
- const [page, setPage] = (0, import_react14.useState)(0);
687
- const [pageLimit, setPageLimit] = (0, import_react14.useState)(limit);
688
- const [groupByList, setGroupByList] = (0, import_react14.useState)(null);
689
- const [domain, setDomain] = (0, import_react14.useState)(null);
690
- const [order, setOrder] = (0, import_react14.useState)("");
691
- const [selectedRowKeys, setSelectedRowKeys] = (0, import_react14.useState)([]);
692
- const [debouncedPage] = useDebounce(page, 500);
693
- const [debouncedDomain] = useDebounce(domain, 500);
694
- const { specification } = useGetSpecification({
695
- model,
696
- viewData,
697
- fields: mode === "kanban" ? viewData?.views?.kanban?.fields : viewData?.views?.list?.fields
698
- });
699
- const listDataProps = (0, import_react14.useMemo)(() => {
700
- if (!viewData || !action || !context) {
701
- return null;
702
- }
703
- const domainParse = domain ? [...domain] : action?.domain ? Array.isArray(action?.domain) ? [...action?.domain] : (0, import_utils5.evalJSONDomain)(action?.domain, context) : [];
704
- const limit2 = pageLimit;
705
- const offset = debouncedPage * pageLimit;
706
- const fields = typeof groupByList === "object" ? groupByList?.fields : void 0;
707
- const groupby = typeof groupByList === "object" ? [groupByList?.contexts?.[0]?.group_by] : [];
708
- const sort = order ?? (0, import_utils5.formatSortingString)(
709
- (mode === "kanban" ? viewData?.views?.kanban : viewData?.views?.list)?.default_order
710
- ) ?? "";
711
- return {
712
- model: action?.res_model,
713
- specification,
714
- domain: domainParse,
715
- limit: limit2,
716
- offset,
717
- fields,
718
- groupby,
719
- context,
720
- sort,
721
- mode
722
- };
723
- }, [
724
- action,
725
- groupByList,
726
- order,
727
- debouncedPage,
728
- pageLimit,
729
- debouncedDomain,
730
- context,
731
- model
732
- ]);
733
- const list = useGetListData2(
734
- { ...listDataProps },
735
- [
736
- listDataProps?.domain,
737
- listDataProps?.groupby,
738
- listDataProps?.limit,
739
- listDataProps?.offset,
740
- listDataProps?.sort,
741
- listDataProps?.context,
742
- listDataProps?.specification,
743
- listDataProps?.mode
744
- ],
745
- !!listDataProps && !!specification && !isObjectEmpty(specification) && !!domain,
746
- service,
747
- xNode
748
- );
749
- return {
750
- ...list,
751
- state: {
752
- specification,
753
- page,
754
- order,
755
- domain: listDataProps?.domain,
756
- pageLimit,
757
- groupByList,
758
- selectedRowKeys,
759
- setPage,
760
- setOrder,
761
- setDomain,
762
- setPageLimit,
763
- setGroupByList,
764
- setSelectedRowKeys
765
- }
766
- };
767
- };
768
-
769
- // src/widget/basic/many2one-field/controller.ts
770
- var MANY2ONE_EXTERNAL = "many2one_external";
771
- var many2oneFieldController = (props) => {
772
- const {
773
- methods,
774
- relation,
775
- domain,
776
- formValues,
777
- value: propValue,
778
- onChange,
779
- name,
780
- context: fieldContext,
781
- options: fieldOptions,
782
- showDetail,
783
- service,
784
- xNode,
785
- isForm,
786
- widget,
787
- in_list_view,
788
- isEditTable
789
- } = props;
790
- const { env } = (0, provider_exports.useEnv)();
791
- const { action } = useAppProvider();
792
- const { useGetSelection: useGetSelection3, useGetDetail: useGetDetail2 } = (0, provider_exports.useService)();
793
- const [listOptions, setListOptions] = (0, import_react15.useState)([]);
794
- const [inputValue, setInputValue] = (0, import_react15.useState)("");
795
- const [debouncedInputValue] = useDebounce(inputValue, 1e3);
796
- const [isShowModalMany2Many, setIsShowModalMany2Many] = (0, import_react15.useState)(false);
797
- const [tempSelectedOption, setTempSelectedOption] = (0, import_react15.useState)(null);
798
- const [domainModal, setDomainModal] = (0, import_react15.useState)(null);
799
- const [domainObject, setDomainObject] = (0, import_react15.useState)(null);
800
- const initValue = methods?.getValues(name);
801
- const contextObject = {
802
- ...(typeof action?.context === "string" ? (0, utils_exports.evalJSONContext)(action?.context) : action?.context) || {},
803
- ...fieldContext,
804
- ...env?.context
805
- };
806
- const optionsObject = typeof fieldOptions === "string" ? (0, utils_exports.evalJSONContext)(fieldOptions, {
807
- ...formValues,
808
- ...contextObject,
809
- context: contextObject,
810
- parent: { ...formValues }
811
- }) : fieldOptions;
812
- const fetchGetDetail = useGetDetail2();
813
- const data = {
814
- model: widget === MANY2ONE_EXTERNAL ? optionsObject?.model : relation,
815
- domain: widget === MANY2ONE_EXTERNAL ? optionsObject?.domain : domainObject,
816
- context: {
817
- ...contextObject,
818
- ...optionsObject?.context
819
- },
820
- specification: widget === MANY2ONE_EXTERNAL ? optionsObject?.specification : {
821
- id: {},
822
- name: {},
823
- display_name: {}
824
- }
825
- };
826
- const {
827
- data: dataOfSelection,
828
- refetch,
829
- isFetching
830
- } = useGetSelection3({
831
- data,
832
- queryKey: [`data_${relation}`, domainObject],
833
- enabled: false,
834
- service: widget === MANY2ONE_EXTERNAL ? optionsObject?.service : service,
835
- xNode
836
- });
837
- const selectOptions = (0, import_react15.useMemo)(() => {
838
- return dataOfSelection?.records?.map((val) => ({
839
- value: val?.id,
840
- label: val?.display_name || val?.name,
841
- ...widget === MANY2ONE_EXTERNAL ? val : {}
842
- })) || [];
843
- }, [dataOfSelection]);
844
- (0, import_react15.useEffect)(() => {
845
- setListOptions(selectOptions);
846
- setDomainModal(domainObject);
847
- }, [selectOptions]);
848
- const parsedFormValues = (0, import_react15.useMemo)(
849
- () => JSON.parse(
850
- JSON.stringify({
851
- ...formValues,
852
- ...contextObject,
853
- context: contextObject
854
- })
855
- ) ?? {},
856
- [formValues, contextObject]
857
- );
858
- (0, import_react15.useEffect)(() => {
859
- const newDomain = (0, utils_exports.evalJSONDomain)(domain, parsedFormValues);
860
- const parsedDomain = typeof newDomain === "string" ? JSON.parse(
861
- newDomain.replace(/\(/g, "[").replace(/\)/g, "]").replace(/'/g, '"')
862
- ) : newDomain;
863
- setDomainObject((prev) => {
864
- const prevStr = JSON.stringify(prev);
865
- const nextStr = JSON.stringify(parsedDomain);
866
- return prevStr === nextStr ? prev : parsedDomain;
867
- });
868
- }, [domain, parsedFormValues]);
869
- (0, import_react15.useEffect)(() => {
870
- if (!propValue && tempSelectedOption) {
871
- methods?.setValue(name, null, { shouldDirty: true });
872
- setTempSelectedOption(null);
873
- } else if (propValue) {
874
- if (isForm && !isEditTable && optionsObject?.service && optionsObject?.model && !propValue?.display_name && !in_list_view) {
875
- fetchGetDetail.mutate(
876
- {
877
- model: optionsObject?.model,
878
- ids: propValue?.id ?? propValue,
879
- specification: widget === MANY2ONE_EXTERNAL ? optionsObject?.specification : {
880
- id: {},
881
- display_name: {}
882
- },
883
- context: { ...env.context },
884
- service: optionsObject ? optionsObject?.service : service,
885
- xNode
886
- },
887
- {
888
- onSuccess: (dataResponse) => {
889
- const detailData = dataResponse?.[0];
890
- setTempSelectedOption({
891
- value: detailData?.id,
892
- label: detailData?.display_name
893
- });
894
- if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
895
- Object.keys(optionsObject?.values_included)?.forEach(
896
- (field) => {
897
- methods?.setValue(
898
- optionsObject?.values_included[field]?.name,
899
- detailData?.[field]
900
- );
901
- }
902
- );
903
- methods?.setValue(name, detailData);
904
- }
905
- },
906
- onError: (error) => {
907
- console.log("error", error);
908
- }
909
- }
910
- );
911
- return;
912
- }
913
- setTempSelectedOption({
914
- value: propValue?.id,
915
- label: propValue?.display_name
916
- });
917
- }
918
- }, [propValue]);
919
- const fetchMoreOptions = (0, import_react15.useCallback)(() => {
920
- refetch();
921
- }, [refetch]);
922
- (0, import_react15.useEffect)(() => {
923
- if (debouncedInputValue) {
924
- const filteredDomain = [...domainObject ?? []]?.filter(
925
- (d) => !(Array.isArray(d) && d[0] === "name" && d[1] === "ilike")
926
- ) || [];
927
- const newDomain = [
928
- ...filteredDomain,
929
- ...debouncedInputValue ? [["name", "ilike", debouncedInputValue]] : []
930
- ];
931
- setDomainObject(newDomain);
932
- setTimeout(() => {
933
- fetchMoreOptions();
934
- }, 50);
935
- }
936
- }, [debouncedInputValue]);
937
- const handleChooseRecord = (0, import_react15.useCallback)(
938
- (idRecord) => {
939
- const newOption = listOptions?.find(
940
- (option) => option.value === idRecord
941
- );
942
- const newValue = widget === MANY2ONE_EXTERNAL && optionsObject?.field_name ? newOption?.[optionsObject?.field_name] : newOption.value;
943
- if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
944
- Object.keys(optionsObject?.values_included)?.forEach((field) => {
945
- methods?.setValue(
946
- optionsObject?.values_included[field]?.name,
947
- newOption?.[field],
948
- { shouldDirty: true }
949
- );
950
- });
951
- }
952
- if (newOption) {
953
- methods?.setValue(
954
- name,
955
- {
956
- ...newOption,
957
- id: newValue,
958
- display_name: newOption?.label
959
- },
960
- { shouldDirty: true }
961
- );
962
- setTempSelectedOption(newOption);
963
- onChange && onChange(String(name), {
964
- ...newOption,
965
- id: newValue,
966
- display_name: newOption?.label
967
- });
968
- methods.trigger(name);
969
- }
970
- setIsShowModalMany2Many(false);
971
- },
972
- [listOptions, methods, name, onChange]
973
- );
974
- const handleClose = (0, import_react15.useCallback)(() => setIsShowModalMany2Many(false), []);
975
- const handleSelectChange = (0, import_react15.useCallback)(
976
- (selectedOption) => {
977
- if (!selectedOption) {
978
- if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
979
- Object.keys(optionsObject?.values_included)?.forEach((field) => {
980
- methods?.setValue(
981
- optionsObject?.values_included[field]?.name,
982
- null,
983
- { shouldDirty: true }
984
- );
985
- });
986
- }
987
- methods.setValue(name, null, { shouldDirty: true });
988
- setTempSelectedOption(null);
989
- onChange && onChange(String(name), null);
990
- methods.trigger(name);
991
- return;
992
- }
993
- const newValue = widget === MANY2ONE_EXTERNAL && optionsObject?.field_name ? selectedOption?.[optionsObject?.field_name] : selectedOption.value;
994
- if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
995
- Object.keys(optionsObject?.values_included)?.forEach((field) => {
996
- methods?.setValue(
997
- optionsObject?.values_included[field]?.name,
998
- selectedOption?.[field],
999
- { shouldDirty: true }
1000
- );
1001
- });
1002
- }
1003
- methods?.setValue(
1004
- name,
1005
- {
1006
- id: newValue,
1007
- display_name: selectedOption?.label
1008
- },
1009
- { shouldDirty: true }
1010
- );
1011
- setTempSelectedOption(selectedOption);
1012
- onChange && onChange(String(name), {
1013
- id: newValue,
1014
- display_name: selectedOption.label
1015
- });
1016
- methods.trigger(name);
1017
- },
1018
- [methods, name, onChange]
1019
- );
1020
- const allowShowDetail = showDetail && contextObject?.form_view_ref && (!optionsObject || !("no_open" in optionsObject) || optionsObject.no_open === false);
1021
- return {
1022
- isShowModalMany2Many,
1023
- isFetching,
1024
- initValue,
1025
- handleChooseRecord,
1026
- handleClose,
1027
- handleSelectChange,
1028
- domainModal,
1029
- setInputValue,
1030
- allowShowDetail,
1031
- contextObject: {
1032
- ...contextObject,
1033
- ...optionsObject?.context
1034
- },
1035
- tempSelectedOption,
1036
- listOptions,
1037
- fetchMoreOptions,
1038
- domainObject: widget === MANY2ONE_EXTERNAL ? optionsObject?.domain : domainObject,
1039
- setIsShowModalMany2Many,
1040
- setDomainObject,
1041
- options: optionsObject,
1042
- relation: widget === MANY2ONE_EXTERNAL ? optionsObject?.model : relation,
1043
- service: widget === MANY2ONE_EXTERNAL ? optionsObject?.service : service
1044
- };
1045
- };
1046
-
1047
- // src/widget/basic/many2one-button-field/controller.ts
1048
- var import_environment2 = require("@fctc/interface-logic/environment");
1049
- var import_hooks6 = require("@fctc/interface-logic/hooks");
1050
- var import_utils9 = require("@fctc/interface-logic/utils");
1051
- var many2oneButtonController = (props) => {
1052
- const { domain, methods, relation, service, xNode } = props;
1053
- const actionDataString = sessionStorage.getItem("actionData");
1054
- const env = (0, import_environment2.getEnv)();
1055
- const domainObject = (0, import_utils9.evalJSONDomain)(domain, methods?.getValues() || {});
1056
- const actionData = actionDataString && actionDataString !== "undefined" ? JSON.parse(actionDataString) : {};
1057
- const { data: dataOfSelection } = (0, import_hooks6.useGetSelection)({
1058
- data: {
1059
- model: relation ?? "",
1060
- domain: domainObject,
1061
- context: { ...env.context, ...(0, import_utils9.evalJSONContext)(actionData?.context) }
1062
- },
1063
- queryKey: [`data_${relation}`, domainObject],
1064
- service,
1065
- xNode
1066
- });
1067
- const options = dataOfSelection?.records?.map((val) => ({
1068
- value: val.id,
1069
- label: val.name
1070
- })) || [];
1071
- return {
1072
- options
1073
- };
1074
- };
1075
-
1076
- // src/widget/basic/many2many-field/controller.ts
1077
- var import_react16 = require("react");
1078
- var import_utils10 = require("@fctc/interface-logic/utils");
1079
- var many2manyFieldController = (props) => {
1080
- const {
1081
- relation,
1082
- domain,
1083
- context,
1084
- options,
1085
- enabled: enabledCallAPI,
1086
- service
1087
- } = props;
1088
- const { env } = (0, provider_exports.useEnv)();
1089
- const { user } = useAppProvider();
1090
- const { useGetView: useGetView2 } = (0, provider_exports.useService)();
1091
- const dataUser = user?.userProfile?.data;
1092
- const contextObject = (0, import_react16.useMemo)(
1093
- () => ({
1094
- ...env.context,
1095
- ...context || {}
1096
- }),
1097
- [env?.context, context]
1098
- );
1099
- const viewParams = (0, import_react16.useMemo)(
1100
- () => ({
1101
- model: relation,
1102
- views: [
1103
- [false, "list"],
1104
- [false, "search"]
1105
- ],
1106
- context: contextObject,
1107
- service,
1108
- xNode: service == "wesap" && dataUser?.x_node
1109
- }),
1110
- [relation, contextObject, service, dataUser?.x_node]
1111
- );
1112
- const { data: viewResponse } = useGetView2({
1113
- viewParams,
1114
- enabled: enabledCallAPI
1115
- });
1116
- const default_order = viewResponse && viewResponse?.views?.list?.default_order;
1117
- const optionsObject = (0, import_react16.useMemo)(
1118
- () => (options && typeof options === "string" ? (0, import_utils10.evalJSONContext)(options) : options) || {},
1119
- [options]
1120
- );
1121
- const {
1122
- data: dataResponse,
1123
- isFetched,
1124
- isLoading,
1125
- state,
1126
- isPlaceholderData
1127
- } = useListData({
1128
- action: {
1129
- domain,
1130
- res_model: relation
1131
- },
1132
- context: contextObject,
1133
- model: relation ?? "",
1134
- viewData: viewResponse,
1135
- service,
1136
- xNode: service == "wesap" && dataUser?.x_node
1137
- });
1138
- const {
1139
- selectedRowKeys,
1140
- groupByList,
1141
- domain: domainList,
1142
- page,
1143
- pageLimit,
1144
- setDomain,
1145
- setOrder,
1146
- setPage,
1147
- setSelectedRowKeys,
1148
- setGroupByList,
1149
- setPageLimit,
1150
- specification
1151
- } = state;
1152
- (0, import_react16.useEffect)(() => {
1153
- return () => {
1154
- setDomain(null);
1155
- setOrder("");
1156
- setGroupByList(null);
1157
- setPageLimit(10);
1158
- };
1159
- }, []);
1160
- const { rows, columns, typeTable, onToggleColumnOptional } = tableController({
1161
- data: {
1162
- fields: viewResponse?.views?.list?.fields,
1163
- records: dataResponse?.records ?? dataResponse?.groups,
1164
- dataModel: viewResponse?.models?.[String(relation)],
1165
- context: contextObject,
1166
- typeTable: dataResponse?.groups ? "group" : "list"
1167
- }
1168
- });
1169
- const searchControllers = searchController({
1170
- viewData: viewResponse,
1171
- model: relation ?? "",
1172
- context: contextObject,
1173
- domain,
1174
- fieldsList: [
1175
- ...columns?.filter(
1176
- (col) => col?.field?.type_co === "field" && col?.optional !== "hide"
1177
- )?.map((col) => ({ ...col.field })) ?? []
1178
- ]
1179
- });
1180
- const handleCreateNewOnPage = async () => {
1181
- };
1182
- return {
1183
- rows,
1184
- columns,
1185
- optionsObject,
1186
- viewData: viewResponse,
1187
- totalRows: dataResponse?.length ?? 0,
1188
- onToggleColumnOptional,
1189
- typeTable,
1190
- isLoading,
1191
- isFetched,
1192
- isPlaceholderData,
1193
- page,
1194
- pageLimit,
1195
- groupByList,
1196
- selectedRowKeys,
1197
- domain: domainList,
1198
- setPage,
1199
- setDomain,
1200
- setPageLimit,
1201
- setGroupByList,
1202
- setSelectedRowKeys,
1203
- searchController: searchControllers,
1204
- handleCreateNewOnPage,
1205
- specification
1206
- };
1207
- };
1208
-
1209
- // src/widget/basic/many2many-tags-field/controller.ts
1210
- var import_react17 = require("react");
1211
- var import_constants2 = require("@fctc/interface-logic/constants");
1212
- var import_utils11 = require("@fctc/interface-logic/utils");
1213
- var many2manyTagsController = (props) => {
1214
- const {
1215
- relation,
1216
- domain,
1217
- options: optionsFields,
1218
- widget,
1219
- formValues,
1220
- service,
1221
- xNode,
1222
- context: fieldContext,
1223
- onChange,
1224
- methods,
1225
- name
1226
- } = props;
1227
- const isUser = relation === "res.users" || relation === "res.partner";
1228
- const { env } = (0, provider_exports.useEnv)();
1229
- const { action } = useAppProvider();
1230
- const { useGetSelection: useGetSelection3 } = (0, provider_exports.useService)();
1231
- const [options, setOptions] = (0, import_react17.useState)([]);
1232
- const [domainObject, setDomainObject] = (0, import_react17.useState)(null);
1233
- const [isShowModalMany2Many, setIsShowModalMany2Many] = (0, import_react17.useState)(false);
1234
- const addtionalFields = optionsFields ? (0, import_utils11.evalJSONContext)(optionsFields) : null;
1235
- const contextObject = {
1236
- ...(0, import_utils11.evalJSONContext)(action?.context) || {},
1237
- ...fieldContext ?? {},
1238
- ...env?.context
1239
- };
1240
- const parsedFormValues = (0, import_react17.useMemo)(
1241
- () => JSON.parse(
1242
- JSON.stringify({
1243
- ...formValues,
1244
- ...contextObject,
1245
- context: contextObject,
1246
- parent: { ...formValues }
1247
- })
1248
- ) ?? {},
1249
- [formValues, contextObject]
1250
- );
1251
- (0, import_react17.useEffect)(() => {
1252
- const newDomain = (0, import_utils11.evalJSONDomain)(domain, parsedFormValues);
1253
- setDomainObject(
1254
- (prev) => JSON.stringify(prev) === JSON.stringify(newDomain) ? prev : newDomain
1255
- );
1256
- }, [domain, parsedFormValues]);
1257
- const data = {
1258
- model: relation ?? "",
1259
- domain: domainObject,
1260
- specification: {
1261
- id: {},
1262
- name: {},
1263
- display_name: {},
1264
- ...widget && import_constants2.WIDGETAVATAR[widget] ? { image_256: {} } : {},
1265
- ...widget && import_constants2.WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
1266
- },
1267
- context: env.context
1268
- };
1269
- const queryKey = [`data_${relation}`, domainObject];
1270
- const {
1271
- data: dataOfSelection,
1272
- refetch,
1273
- isFetching
1274
- } = useGetSelection3({
1275
- data,
1276
- queryKey,
1277
- service,
1278
- xNode,
1279
- enabled: false
1280
- });
1281
- const selectOptions = (0, import_react17.useMemo)(() => {
1282
- return dataOfSelection?.records?.map((val) => ({
1283
- value: val.id,
1284
- label: val.name ?? val.display_name,
1285
- ...val
1286
- })) || [];
1287
- }, [dataOfSelection]);
1288
- (0, import_react17.useEffect)(() => {
1289
- setOptions(selectOptions);
1290
- }, [selectOptions]);
1291
- const fetchMoreOptions = (0, import_react17.useCallback)(() => {
1292
- refetch();
1293
- }, [refetch]);
1294
- const transfer = (data2) => {
1295
- return data2?.map((val) => ({
1296
- id: val.value,
1297
- display_name: val.label
1298
- })) || [];
1299
- };
1300
- const handleChooseRecord = (0, import_react17.useCallback)(
1301
- (idRecord) => {
1302
- const newOption = options.find(
1303
- (option) => option.value === idRecord
1304
- );
1305
- setIsShowModalMany2Many(false);
1306
- },
1307
- [options, methods, name, onChange]
1308
- );
1309
- const handleClose = (0, import_react17.useCallback)(() => setIsShowModalMany2Many(false), []);
1310
- return {
1311
- options,
1312
- transfer,
1313
- isUser,
1314
- isFetching,
1315
- fetchMoreOptions,
1316
- domainObject,
1317
- setDomainObject,
1318
- handleChooseRecord,
1319
- handleClose,
1320
- isShowModalMany2Many,
1321
- setIsShowModalMany2Many
1322
- };
1323
- };
1324
-
1325
- // src/widget/basic/status-bar-field/controller.ts
1326
- var import_react18 = require("react");
1327
- var import_utils12 = require("@fctc/interface-logic/utils");
1328
- var durationController = (props) => {
1329
- const { relation, domain, formValues, name, id, model, onRefetch, enabled } = props;
1330
- const specification = {
1331
- id: 0,
1332
- name: "",
1333
- fold: ""
1334
- };
1335
- const { useGetListData: useGetListData2, useChangeStatus: useChangeStatus2 } = (0, provider_exports.useService)();
1336
- const { env } = (0, provider_exports.useEnv)();
1337
- const [disabled, setDisabled] = (0, import_react18.useState)(false);
1338
- const [modelStatus, setModalStatus] = (0, import_react18.useState)(false);
1339
- const queryKey = [`data-status-duration`, specification];
1340
- const listDataProps = {
1341
- model: relation,
1342
- specification,
1343
- domain: (0, import_utils12.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues))),
1344
- limit: 10,
1345
- offset: 0,
1346
- fields: "",
1347
- groupby: [],
1348
- context: {
1349
- lang: env.context.lang
1350
- },
1351
- sort: ""
1352
- };
1353
- const { data: dataResponse } = useGetListData2(
1354
- listDataProps,
1355
- queryKey,
1356
- enabled
1357
- );
1358
- const { mutate: fetchChangeStatus } = useChangeStatus2();
1359
- const handleClick = async (stage_id) => {
1360
- setDisabled(true);
1361
- if (stage_id) {
1362
- fetchChangeStatus(
1363
- {
1364
- data: {
1365
- stage_id,
1366
- name,
1367
- id,
1368
- model,
1369
- lang: env.context.lang
1370
- }
1371
- },
1372
- {
1373
- onSuccess: (res) => {
1374
- if (res) {
1375
- setDisabled(false);
1376
- onRefetch && onRefetch();
1377
- }
1378
- }
1379
- }
1380
- );
1381
- }
1382
- };
1383
- return {
1384
- dataResponse,
1385
- handleClick,
1386
- disabled,
1387
- modelStatus,
1388
- setModalStatus
1389
- };
1390
- };
1391
-
1392
- // src/widget/basic/priority-field/controller.ts
1393
- var import_utils13 = require("@fctc/interface-logic/utils");
1394
- var priorityFieldController = (props) => {
1395
- const { name, model, index, actionData, context, onChange, specification } = props;
1396
- const _context = { ...(0, import_utils13.evalJSONContext)(actionData?.context) };
1397
- const contextObject = { ...context, ..._context };
1398
- const { useSave: useSave3 } = (0, provider_exports.useService)();
1399
- const { mutateAsync: fetchSave } = useSave3();
1400
- const savePriorities = async ({
1401
- value,
1402
- resetPriority
1403
- }) => {
1404
- const priorityValue = value <= 0 ? 0 : value - 1;
1405
- try {
1406
- fetchSave({
1407
- ids: index ? [index] : [],
1408
- data: { [String(name)]: String(priorityValue) },
1409
- model: String(model),
1410
- context: contextObject,
1411
- specification
1412
- });
1413
- if (typeof onChange === "function") {
1414
- onChange(String(name), String(priorityValue));
1415
- }
1416
- } catch (error) {
1417
- if (resetPriority) {
1418
- resetPriority();
1419
- }
1420
- }
1421
- };
1422
- return {
1423
- savePriorities
1424
- };
1425
- };
1426
-
1427
- // src/widget/basic/download-file-field/controller.ts
1428
- var import_react19 = require("react");
1429
- var downloadFileController = () => {
1430
- const inputId = (0, import_react19.useId)();
1431
- const [file, setFile] = (0, import_react19.useState)(null);
1432
- const handleFileChange = (e) => {
1433
- setFile(e.target.files[0]);
1434
- };
1435
- const handleFileDownload = () => {
1436
- const url = URL.createObjectURL(file);
1437
- const link = document.createElement("a");
1438
- link.href = url;
1439
- link.download = file.name;
1440
- document.body.appendChild(link);
1441
- link.click();
1442
- document.body.removeChild(link);
1443
- };
1444
- return {
1445
- inputId,
1446
- file,
1447
- handleFileChange,
1448
- handleFileDownload
1449
- };
1450
- };
1451
-
1452
- // src/widget/basic/download-binary-field/controller.ts
1453
- var downLoadBinaryController = (props) => {
1454
- const { value, defaultValue, formValues } = props;
1455
- const downloadFile = async (url, filename) => {
1456
- try {
1457
- const response = await fetch(url);
1458
- if (!response.ok) throw new Error(`Failed to fetch ${url}`);
1459
- const contentType = response.headers.get("Content-Type") || "";
1460
- let ext = "";
1461
- if (contentType.includes("pdf")) ext = ".pdf";
1462
- else if (contentType.includes("png")) ext = ".png";
1463
- else if (contentType.includes("jpeg") || contentType.includes("jpg"))
1464
- ext = ".jpg";
1465
- else if (contentType.includes("zip")) ext = ".zip";
1466
- else if (contentType.includes("msword")) ext = ".doc";
1467
- else if (contentType.includes("spreadsheet")) ext = ".xls";
1468
- else if (contentType.includes("json")) ext = ".json";
1469
- else if (contentType.includes("text")) ext = ".txt";
1470
- else {
1471
- ext = "";
1472
- }
1473
- const blob = await response.blob();
1474
- const urlBlob = window.URL.createObjectURL(blob);
1475
- const link = document.createElement("a");
1476
- link.href = urlBlob;
1477
- link.download = (filename || "file") + ext;
1478
- document.body.appendChild(link);
1479
- link.click();
1480
- document.body.removeChild(link);
1481
- window.URL.revokeObjectURL(urlBlob);
1482
- } catch (error) {
1483
- console.error("File download failed:", error);
1484
- }
1485
- };
1486
- const handleFileDownload = async (e) => {
1487
- e.stopPropagation();
1488
- await downloadFile(value || defaultValue, formValues?.name);
1489
- };
1490
- return {
1491
- handleFileDownload
1492
- };
1493
- };
1494
-
1495
- // src/widget/basic/copy-link-button/controller.ts
1496
- var import_react20 = require("react");
1497
- var copyTextToClipboard = async (text) => {
1498
- if ("clipboard" in navigator) {
1499
- return await navigator.clipboard.writeText(text);
1500
- } else {
1501
- const textArea = document.createElement("textarea");
1502
- textArea.value = text;
1503
- textArea.style.position = "fixed";
1504
- document.body.appendChild(textArea);
1505
- textArea.focus();
1506
- textArea.select();
1507
- try {
1508
- document.execCommand("copy");
1509
- } finally {
1510
- document.body.removeChild(textArea);
1511
- }
1512
- }
1513
- };
1514
- var copyLinkButtonController = (props) => {
1515
- const { value, defaultValue } = props;
1516
- const [isCopied, setIsCopied] = (0, import_react20.useState)(false);
1517
- const handleCopyToClipboard = async (value2) => {
1518
- await copyTextToClipboard(value2);
1519
- setIsCopied(true);
1520
- setTimeout(() => setIsCopied(false), 2e3);
1521
- };
1522
- const propValue = value || defaultValue;
1523
- return {
1524
- isCopied,
1525
- handleCopyToClipboard,
1526
- propValue
1527
- };
1528
- };
1529
-
1530
- // src/widget/basic/color-field/color-controller.ts
1531
- var import_utils14 = require("@fctc/interface-logic/utils");
1532
- var colorFieldController = (props) => {
1533
- const { value, isForm, name, formValues, idForm, model, actionData } = props;
1534
- const { env } = (0, provider_exports.useEnv)();
1535
- const { useSave: useSave3 } = (0, provider_exports.useService)();
1536
- const _context = { ...(0, import_utils14.evalJSONContext)(actionData?.context) || {} };
1537
- const contextObject = { ...env.context, ..._context };
1538
- const idDefault = isForm ? idForm : formValues?.id;
1539
- const { mutate: onSave } = useSave3();
1540
- const savePickColor = async (colorObject) => {
1541
- const { id } = colorObject;
1542
- if (value === id) return;
1543
- try {
1544
- onSave({
1545
- ids: idDefault !== null ? [idDefault] : [],
1546
- model: String(model),
1547
- data: { [String(name)]: id },
1548
- specification: {
1549
- name: {},
1550
- color: {}
1551
- },
1552
- context: contextObject
1553
- });
1554
- } catch (error) {
1555
- console.log(error);
1556
- }
1557
- };
1558
- return {
1559
- savePickColor
1560
- };
1561
- };
1562
-
1563
- // src/widget/basic/binary-field/controller.ts
1564
- var import_react21 = require("react");
1565
- var binaryFieldController = (props) => {
1566
- const {
1567
- name,
1568
- methods,
1569
- readonly = false,
1570
- filename,
1571
- onChange: handleOnchange,
1572
- service,
1573
- xNode,
1574
- path,
1575
- rootField,
1576
- index,
1577
- value
1578
- } = props;
1579
- const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
1580
- const { mutateAsync } = useUploadFile2();
1581
- const [url, setUrl] = (0, import_react21.useState)(value || null);
1582
- const [fileInfo, setFileInfo] = (0, import_react21.useState)(null);
1583
- (0, import_react21.useEffect)(() => {
1584
- if (!value) {
1585
- setUrl(null);
1586
- setFileInfo(null);
1587
- return;
1588
- }
1589
- fetchFileMeta(value);
1590
- }, [value]);
1591
- const formatSize = (bytes) => {
1592
- if (bytes < 1024) return bytes + " B";
1593
- let kb = bytes / 1024;
1594
- if (kb < 1024) return kb.toFixed(2) + " KB";
1595
- let mb = kb / 1024;
1596
- if (mb < 1024) return mb.toFixed(2) + " MB";
1597
- return (mb / 1024).toFixed(2) + " GB";
1598
- };
1599
- const fetchFileMeta = async (url2) => {
1600
- try {
1601
- const res = await fetch(url2, { method: "HEAD" });
1602
- const size = res.headers.get("content-length") || "";
1603
- let type = res.headers.get("content-type") || "";
1604
- const date = res.headers.get("last-modified") || "";
1605
- const guessed = guessTypeFromUrl(url2);
1606
- if (guessed) type = guessed;
1607
- setFileInfo({
1608
- size: size ? formatSize(Number(size)) : "--",
1609
- type,
1610
- date: date ? new Date(date).toLocaleString() : "--"
1611
- });
1612
- setUrl(url2);
1613
- } catch (e) {
1614
- console.error(e);
1615
- }
1616
- };
1617
- const onUploadFile = async (formData) => {
1618
- const res = await mutateAsync({
1619
- formData,
1620
- service,
1621
- xNode,
1622
- path
1623
- });
1624
- const url2 = res?.url;
1625
- methods?.setValue(name, url2, { shouldDirty: true });
1626
- handleOnchange && handleOnchange(name ?? "", url2);
1627
- if (filename) {
1628
- methods?.setValue(
1629
- rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1630
- url2?.split("/").pop(),
1631
- { shouldDirty: true }
1632
- );
1633
- handleOnchange && handleOnchange(
1634
- rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1635
- url2?.split("/").pop()
1636
- );
1637
- }
1638
- setUrl(url2);
1639
- fetchFileMeta(url2);
1640
- return url2;
1641
- };
1642
- const onDeleteFile = () => {
1643
- if (filename) {
1644
- methods?.setValue(
1645
- rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1646
- null,
1647
- { shouldDirty: true }
1648
- );
1649
- handleOnchange && handleOnchange(
1650
- rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1651
- null
1652
- );
1653
- }
1654
- setUrl(null);
1655
- setFileInfo(null);
1656
- methods?.setValue(name, null, { shouldDirty: true });
1657
- handleOnchange && handleOnchange(name ?? "", null);
1658
- };
1659
- return {
1660
- onUploadFile,
1661
- onDeleteFile,
1662
- fileInfo,
1663
- url
1664
- };
1665
- };
1666
-
1667
- // src/widget/basic/many2many-binary-field/controller.tsx
1668
- var import_react22 = require("react");
1669
- var many2manyBinaryController = (props) => {
1670
- const {
1671
- name,
1672
- methods,
1673
- value,
1674
- onChange: handleOnchange,
1675
- service,
1676
- xNode,
1677
- path
1678
- } = props;
1679
- const inputId = (0, import_react22.useId)();
1680
- const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
1681
- const { mutateAsync } = useUploadFile2();
1682
- const binaryRef = (0, import_react22.useRef)(null);
1683
- const [initialFiles, setInitialFiles] = (0, import_react22.useState)(
1684
- Array.isArray(value) ? value : value ? [value] : []
1685
- );
1686
- const checkIsImageLink = (url) => {
1687
- const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
1688
- return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
1689
- };
1690
- const sanitizeForBE = (list) => list.filter((x) => x?.datas && !isBlobUrl(x.datas)).map((x) => ({ name: x.name, datas: x.datas, mimetype: x.mimetype }));
1691
- const isBase64Image = (str) => {
1692
- const base64Regex = /^data:image\/(png|jpeg|jpg|gif|webp);base64,/;
1693
- if (!base64Regex.test(str)) {
1694
- return false;
1695
- }
1696
- try {
1697
- const base64Data = str.split(",")[1];
1698
- return !!base64Data && atob(base64Data).length > 0;
1699
- } catch (error) {
1700
- return false;
1701
- }
1702
- };
1703
- const handleFileChange = async (files, e, oldValues) => {
1704
- try {
1705
- const uploadedUrls = await Promise.all(
1706
- files.map(async (f) => {
1707
- const formData = new FormData();
1708
- formData.append("file", f);
1709
- const res = await mutateAsync({ formData, service, xNode, path });
1710
- return res?.url;
1711
- })
1712
- );
1713
- const uploadedItems = files.map((f, i) => ({
1714
- name: f.name,
1715
- datas: uploadedUrls[i] ?? "",
1716
- mimetype: f.type
1717
- }));
1718
- const finalList = [...oldValues, ...uploadedItems];
1719
- methods?.setValue(name, finalList, { shouldDirty: true });
1720
- const payloadForBE = sanitizeForBE(finalList);
1721
- handleOnchange && handleOnchange(name ?? "", payloadForBE);
1722
- } catch (err) {
1723
- console.error(err);
1724
- } finally {
1725
- e.target.value = "";
1726
- }
1727
- };
1728
- const handleRemoveAt = (idx) => {
1729
- const current = methods?.getValues(name) || [];
1730
- const next = current.filter((_, i) => i !== idx);
1731
- setInitialFiles((p) => p.filter((_, i) => i !== idx));
1732
- methods?.setValue(name, next.length ? next : null, { shouldDirty: true });
1733
- const payloadForBE = next.length ? sanitizeForBE(next) : null;
1734
- handleOnchange && handleOnchange(name ?? "", payloadForBE);
1735
- };
1736
- const handleRemoveAll = () => {
1737
- setInitialFiles([]);
1738
- methods?.setValue(name, null, { shouldDirty: true });
1739
- handleOnchange && handleOnchange(name ?? "", null);
1740
- };
1741
- return {
1742
- inputId,
1743
- initialFiles,
1744
- binaryRef,
1745
- handleFileChange,
1746
- handleRemoveAt,
1747
- handleRemoveAll,
1748
- checkIsImageLink,
1749
- setInitialFiles
1750
- };
1751
- };
1752
-
1753
- // src/widget/basic/provider-einvoice-field/controller.ts
1754
- var providerEinvoiceFieldController = (props) => {
1755
- const { relation, formValues, options: fieldOptions, xNode } = props;
1756
- const { env } = (0, provider_exports.useEnv)();
1757
- const { action } = useAppProvider();
1758
- const { useGetSelection: useGetSelection3 } = (0, provider_exports.useService)();
1759
- const contextObject = {
1760
- ...(typeof action?.context === "string" ? (0, utils_exports.evalJSONContext)(action?.context) : action?.context) || {},
1761
- ...env?.context
1762
- };
1763
- const optionsObject = typeof fieldOptions === "string" ? (0, utils_exports.evalJSONContext)(fieldOptions, {
1764
- ...formValues,
1765
- ...contextObject,
1766
- context: contextObject,
1767
- parent: { ...formValues }
1768
- }) : fieldOptions;
1769
- const data = {
1770
- model: optionsObject?.model,
1771
- domain: optionsObject?.domain,
1772
- context: {
1773
- ...contextObject,
1774
- ...optionsObject?.context
1775
- },
1776
- specification: optionsObject?.specification
1777
- };
1778
- const { data: listDataCard } = useGetSelection3({
1779
- data,
1780
- queryKey: [`data_${relation}`],
1781
- enabled: true,
1782
- service: optionsObject?.service,
1783
- xNode
1784
- });
1785
- return {
1786
- listDataCard
1787
- };
1788
- };
1789
-
1790
- // src/widget/advance/table/table-head/controller.ts
1791
- var import_react23 = require("react");
1792
- var tableHeadController = (props) => {
1793
- const {
1794
- typeTable,
1795
- rows,
1796
- tableRef,
1797
- groupByList,
1798
- selectedRowKeys,
1799
- setSelectedRowKeys
1800
- } = props;
1801
- const { rowIds: recordIds } = useGetRowIds(tableRef);
1802
- const selectedRowKeysRef = (0, import_react23.useRef)(recordIds);
1803
- const isGroupTable = typeTable === "group";
1804
- const recordsCheckedGroup = (0, import_react23.useMemo)(() => {
1805
- if (!rows || !groupByList) return 0;
1806
- const groupBy = typeof groupByList === "object" ? groupByList?.contexts?.[0]?.group_by : void 0;
1807
- return countSum(rows, groupBy);
1808
- }, [rows, groupByList]);
1809
- const isAllGroupChecked = (0, import_react23.useMemo)(() => {
1810
- if (!isGroupTable || !selectedRowKeys?.length) return false;
1811
- const selectedLength = selectedRowKeys.filter((id) => id !== -1).length;
1812
- const allRecordsSelected = recordIds.length === selectedRowKeys.length ? recordIds.length === selectedLength : false;
1813
- const allGroupsSelected = recordsCheckedGroup === selectedRowKeys.length;
1814
- return allGroupsSelected || allRecordsSelected;
1815
- }, [isGroupTable, selectedRowKeys, recordIds, recordsCheckedGroup]);
1816
- const isAllNormalChecked = (0, import_react23.useMemo)(() => {
1817
- if (isGroupTable || !selectedRowKeys?.length || !rows?.length) return false;
1818
- return selectedRowKeys.length === rows.length && selectedRowKeys.every(
1819
- (id) => rows.some((record) => record.id === id)
1820
- );
1821
- }, [isGroupTable, selectedRowKeys, rows]);
1822
- const checkedAll = isAllGroupChecked || isAllNormalChecked;
1823
- const handleCheckBoxAll = (event) => {
1824
- if (event?.target?.checked && typeTable === "list") {
1825
- const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
1826
- setSelectedRowKeys(allRowKeys);
1827
- } else if (event?.target?.checked && typeTable === "group") {
1828
- const rowsIDs = document.querySelectorAll("tr[data-row-id]");
1829
- const ids = Array.from(rowsIDs)?.map(
1830
- (row) => Number(row?.getAttribute("data-row-id"))
1831
- );
1832
- if (ids?.length > 0) {
1833
- setSelectedRowKeys(ids);
1834
- } else {
1835
- const sum = countSum(
1836
- rows,
1837
- typeof groupByList === "object" ? groupByList?.contexts?.[0]?.group_by : void 0
1838
- );
1839
- const keys = Array.from({ length: sum }, (_) => void 0);
1840
- setSelectedRowKeys(keys);
1841
- }
1842
- if (selectedRowKeysRef) {
1843
- selectedRowKeysRef.current = [];
1844
- }
1845
- } else {
1846
- setSelectedRowKeys([]);
1847
- }
1848
- };
1849
- return {
1850
- handleCheckBoxAll,
1851
- checkedAll,
1852
- selectedRowKeysRef
1853
- };
1854
- };
1855
-
1856
- // src/widget/advance/table/table-view/controller.ts
1857
- var import_react24 = require("react");
1858
- var import_utils18 = require("@fctc/interface-logic/utils");
1859
- var tableController = ({ data }) => {
1860
- const [rows, setRows] = (0, import_react24.useState)([]);
1861
- const [columnVisibility, setColumnVisibility] = (0, import_react24.useState)({});
1862
- const dataModelFields = (0, import_react24.useMemo)(() => {
1863
- return data?.fields?.map((field) => ({
1864
- ...data.dataModel?.[field?.name],
1865
- ...field,
1866
- string: field?.string || data.dataModel?.[field?.name]?.string
1867
- })) ?? [];
1868
- }, [data?.fields, data?.dataModel]);
1869
- const mergeFields = (0, import_react24.useMemo)(
1870
- () => mergeButtons(dataModelFields),
1871
- [dataModelFields]
1872
- );
1873
- const transformData = (0, import_react24.useCallback)(
1874
- (dataList) => {
1875
- if (!dataList) return [];
1876
- return dataList.map((item) => {
1877
- const transformedItem = { ...item };
1878
- Object.keys(item).forEach((field) => {
1879
- if (field !== "__domain") {
1880
- if (item[field] && typeof item[field] === "object" && item[field].display_name) {
1881
- transformedItem[field] = item[field];
1882
- } else if (Array.isArray(item[field]) && item[field].length > 0) {
1883
- if (data.typeTable === "group" && item[field]?.length === 2 && typeof item[field]?.[1] === "string") {
1884
- transformedItem["string"] = item[field]?.[1];
1885
- }
1886
- transformedItem[field] = item[field];
1887
- }
1888
- }
1889
- });
1890
- return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
1891
- });
1892
- },
1893
- [data?.typeTable]
1894
- );
1895
- (0, import_react24.useEffect)(() => {
1896
- setRows(transformData(data?.records));
1897
- }, [data?.records, transformData]);
1898
- const columns = (0, import_react24.useMemo)(() => {
1899
- try {
1900
- return mergeFields?.filter((item) => {
1901
- return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? import_utils18.domainHelper.matchDomains(
1902
- data.context,
1903
- item?.column_invisible
1904
- ) : item?.invisible ? import_utils18.domainHelper.matchDomains(data.context, item?.invisible) : false);
1905
- })?.map((field) => {
1906
- const overridden = columnVisibility[field?.name];
1907
- return {
1908
- name: field?.name,
1909
- optional: overridden ?? field?.optional,
1910
- title: field?.type_co === "button" ? "" : field?.string,
1911
- field: { ...field }
1912
- };
1913
- }) ?? [];
1914
- } catch (error) {
1915
- console.error("Error in useTable:", error);
1916
- return [];
1917
- }
1918
- }, [mergeFields, data?.context, columnVisibility]);
1919
- const onToggleColumnOptional = (0, import_react24.useCallback)((item) => {
1920
- setColumnVisibility((prev) => ({
1921
- ...prev,
1922
- [item?.name]: item?.optional === "show" ? "hide" : "show"
1923
- }));
1924
- }, []);
1925
- return {
1926
- rows,
1927
- columns,
1928
- onToggleColumnOptional,
1929
- typeTable: data?.typeTable
1930
- };
1931
- };
1932
-
1933
- // src/widget/advance/table/table-group/controller.ts
1934
- var import_react25 = require("react");
1935
- var tableGroupController = (props) => {
1936
- const { env } = (0, provider_exports.useEnv)();
1937
- const { useGetListData: useGetListData2 } = (0, provider_exports.useService)();
1938
- const {
1939
- columns,
1940
- row,
1941
- model,
1942
- viewData,
1943
- level,
1944
- specification,
1945
- context,
1946
- checkedAll,
1947
- groupByList,
1948
- setSelectedRowKeys
1949
- } = props;
1950
- const [pageGroup, setPageGroup] = (0, import_react25.useState)(0);
1951
- const [isShowGroup, setIsShowGroup] = (0, import_react25.useState)(false);
1952
- const [colEmptyGroup, setColEmptyGroup] = (0, import_react25.useState)({
1953
- fromStart: 1,
1954
- fromEnd: 1
1955
- });
1956
- const domain = row?.__domain;
1957
- const processedData = (0, import_react25.useMemo)(() => {
1958
- const calculateColSpanEmpty = () => {
1959
- const startIndex = columns.findIndex(
1960
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
1961
- );
1962
- const endIndex = columns.findLastIndex(
1963
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
1964
- );
1965
- const fromStart = startIndex === -1 ? columns.length : startIndex;
1966
- const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
1967
- setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
1968
- return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
1969
- };
1970
- return calculateColSpanEmpty();
1971
- }, [columns, row]);
1972
- const shouldFetchData = (0, import_react25.useMemo)(() => {
1973
- return !!isShowGroup;
1974
- }, [isShowGroup]);
1975
- const enabled = shouldFetchData && !!processedData;
1976
- const listDataProps = {
1977
- model,
1978
- specification,
1979
- domain,
1980
- context,
1981
- offset: pageGroup * 10,
1982
- fields: groupByList?.fields,
1983
- groupby: [groupByList?.contexts[level]?.group_by],
1984
- limit: 10
1985
- };
1986
- const queryKey = [
1987
- `data-${model}-level_${level}-row-${row?.id}`,
1988
- specification,
1989
- domain,
1990
- pageGroup
1991
- ];
1992
- const {
1993
- data: dataGroup,
1994
- isFetched: isDataGroupFetched,
1995
- isLoading,
1996
- isFetching,
1997
- isPlaceholderData: isDataPlaceHolder
1998
- } = useGetListData2(listDataProps, queryKey, enabled);
1999
- const {
2000
- columns: columnsGroup,
2001
- rows: rowsGroup,
2002
- typeTable: typeTableGroup
2003
- } = tableController({
2004
- data: {
2005
- fields: viewData?.views?.list?.fields,
2006
- records: dataGroup?.records ?? dataGroup?.groups,
2007
- dataModel: viewData?.models?.[model],
2008
- context: env.context,
2009
- typeTable: dataGroup?.groups ? "group" : "list"
2010
- }
2011
- });
2012
- const group_by_field_name = groupByList?.contexts[level - 1]?.group_by;
2013
- const nameGroup = Array.isArray(row[group_by_field_name]) ? row?.string ?? row[`${group_by_field_name}`][1] : viewData?.models?.[model]?.[group_by_field_name]?.selection ? viewData.models[model][group_by_field_name].selection.find(
2014
- (selectItem) => selectItem?.[0] === row[group_by_field_name]
2015
- )?.[1] : row[group_by_field_name];
2016
- const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
2017
- return {
2018
- // onExpandChildGroup,
2019
- colEmptyGroup,
2020
- isShowGroup,
2021
- isDataGroupFetched,
2022
- isDataPlaceHolder,
2023
- // nameGroupWithCount,
2024
- columnsGroup,
2025
- rowsGroup,
2026
- dataGroup,
2027
- pageGroup,
2028
- setPageGroup,
2029
- typeTableGroup
2030
- };
2031
- };
2032
-
2033
- // src/widget/advance/search/controller.ts
2034
- var import_moment2 = __toESM(require("moment"));
2035
- var import_react26 = require("react");
2036
-
2037
- // src/constants.ts
2038
- var constants_exports = {};
2039
- __reExport(constants_exports, require("@fctc/interface-logic/constants"));
2040
-
2041
- // src/widget/advance/search/controller.ts
2042
- var searchController = ({
2043
- viewData,
2044
- model,
2045
- domain,
2046
- context,
2047
- fieldsList
2048
- }) => {
2049
- const { env } = (0, provider_exports.useEnv)();
2050
- const [filterBy, setFilterBy] = (0, import_react26.useState)(null);
2051
- const [searchBy, setSearchBy] = (0, import_react26.useState)(null);
2052
- const [groupBy, setGroupBy] = (0, import_react26.useState)(null);
2053
- const [selectedTags, setSelectedTags] = (0, import_react26.useState)(null);
2054
- const [searchString, setSearchString] = (0, import_react26.useState)("");
2055
- const [searchMap, setSearchMap] = (0, import_react26.useState)({});
2056
- const [hoveredIndex, setHoveredIndex] = (0, import_react26.useState)(0);
2057
- const [hoveredIndexSearchList, setHoveredIndexSearchList] = (0, import_react26.useState)(0);
2058
- const actionContext = typeof context === "string" ? (0, utils_exports.evalJSONContext)(context) : context;
2059
- const contextSearch = { ...env.context, ...actionContext };
2060
- const domainAction = domain ? Array.isArray(domain) ? [...domain] : (0, utils_exports.evalJSONDomain)(domain, contextSearch) : [];
2061
- const clearSearch = () => {
2062
- setFilterBy([]);
2063
- setGroupBy([]);
2064
- setSearchBy([]);
2065
- setSelectedTags(null);
2066
- setSearchString("");
2067
- setSearchMap({});
2068
- };
2069
- const fetchData = async () => {
2070
- if (viewData) {
2071
- try {
2072
- const dataModel = viewData?.models?.[model];
2073
- const searchViews = viewData?.views?.search;
2074
- const searchByItems = searchViews?.search_by?.filter(
2075
- (item) => !utils_exports.domainHelper.matchDomains(contextSearch, item.invisible)
2076
- )?.map(
2077
- ({ string, name, filter_domain, operator, widget }, index) => ({
2078
- dataIndex: index,
2079
- title: string ?? dataModel?.[name]?.string,
2080
- name: name ?? dataModel?.[name]?.name,
2081
- filter_domain,
2082
- operator,
2083
- widget,
2084
- type: dataModel?.[name]?.type
2085
- })
2086
- );
2087
- const filterByItems = searchViews?.filter_by.filter((item) => {
2088
- return !utils_exports.domainHelper.matchDomains(contextSearch, item?.invisible);
2089
- })?.map((item) => ({ ...item, active: false }));
2090
- const groupByItems = searchViews?.group_by.filter(
2091
- (item) => !utils_exports.domainHelper.matchDomains(contextSearch, item?.invisible)
2092
- ).map((item) => ({
2093
- ...item,
2094
- string: item.string ?? viewData?.models?.[model]?.[item?.name?.split("group_by_")?.[1]]?.string
2095
- }));
2096
- setSearchBy(searchByItems);
2097
- setFilterBy(filterByItems);
2098
- setGroupBy(groupByItems);
2099
- } catch (error) {
2100
- console.error("Error fetching data:", error);
2101
- }
2102
- }
2103
- };
2104
- (0, import_react26.useEffect)(() => {
2105
- fetchData();
2106
- }, [model, viewData]);
2107
- const onChangeSearchInput = (search_string) => {
2108
- setSearchString(search_string);
2109
- };
2110
- const removeKeyFromSearchMap = ({
2111
- key,
2112
- item
2113
- }) => {
2114
- const values = searchMap[key];
2115
- if (!values) return searchMap;
2116
- const newSearchMap = { ...searchMap };
2117
- if (item) {
2118
- const filtered = values.filter((value) => value.name !== item.name);
2119
- if (filtered.length > 0) {
2120
- newSearchMap[key] = filtered;
2121
- } else {
2122
- delete newSearchMap[key];
2123
- }
2124
- } else {
2125
- delete newSearchMap[key];
2126
- }
2127
- setSearchMap(newSearchMap);
2128
- };
2129
- const updateSearchMap = ({ key, item }) => {
2130
- const newSearchMap = { ...searchMap };
2131
- const currentValues = searchMap[key] ?? [];
2132
- newSearchMap[key] = [...currentValues, item];
2133
- setSearchMap(newSearchMap);
2134
- };
2135
- const removeSearchItems = (key, item) => {
2136
- removeKeyFromSearchMap({ key: String(key), item });
2137
- };
2138
- const addSearchItems = (key, newItem) => {
2139
- updateSearchMap({ key, item: newItem });
2140
- };
2141
- const formatDomain = () => {
2142
- if (domainAction) {
2143
- const domain2 = [];
2144
- if (Array.isArray(domainAction) && domainAction.length > 0) {
2145
- if (Object.keys(searchMap).some((key) => !key.includes(constants_exports.SearchType.GROUP))) {
2146
- domain2.push("&");
2147
- }
2148
- domainAction.forEach((domainItem) => {
2149
- domain2.push(domainItem);
2150
- });
2151
- }
2152
- Object.keys(searchMap).forEach((key, keyIndex, keys) => {
2153
- if (!key?.includes(constants_exports.SearchType.GROUP)) {
2154
- if (keys.length > 1 && keyIndex < keys.length - 1) {
2155
- domain2.push("&");
2156
- }
2157
- const valuesOfKey = searchMap[key];
2158
- valuesOfKey.forEach((value, index) => {
2159
- if (index < valuesOfKey.length - 1) {
2160
- domain2.push("|");
2161
- }
2162
- if (value.domain) {
2163
- domain2.push(...value.domain);
2164
- return;
2165
- }
2166
- let valueDomainItem = value?.value;
2167
- if (value?.modelType === "date") {
2168
- valueDomainItem = validateAndParseDate(value?.value);
2169
- } else if (value?.modelType === "datetime") {
2170
- if (value?.operator === "<=" || value?.operator === "<") {
2171
- const parsedDate = validateAndParseDate(value?.value, true);
2172
- const hasTime = (0, import_moment2.default)(value?.value).format("HH:mm:ss") !== "00:00:00";
2173
- valueDomainItem = hasTime ? (0, import_moment2.default)(parsedDate).format("YYYY-MM-DD HH:mm:ss") : (0, import_moment2.default)(parsedDate).add(1, "day").subtract(1, "second").format("YYYY-MM-DD HH:mm:ss");
2174
- } else {
2175
- valueDomainItem = validateAndParseDate(value?.value, true);
2176
- }
2177
- }
2178
- const operator = value?.modelType === "date" || value?.modelType === "datetime" || value?.modelType === "boolean" || value?.modelType === "integer" ? value?.operator ?? "=" : value.operator ?? "ilike";
2179
- domain2.push([value.name, operator, valueDomainItem]);
2180
- });
2181
- }
2182
- });
2183
- return [...domain2];
2184
- }
2185
- };
2186
- const setTagSearch = (0, import_react26.useCallback)(
2187
- (updatedMap) => {
2188
- if (!updatedMap) return;
2189
- const tagsSearch = Object.entries(updatedMap).map(
2190
- ([key, objValues]) => {
2191
- const {
2192
- title,
2193
- name,
2194
- groupIndex,
2195
- type,
2196
- widget,
2197
- modelType,
2198
- dataIndex
2199
- } = objValues[0];
2200
- if (!key?.includes(constants_exports.SearchType.GROUP)) {
2201
- const values = objValues?.map((objValue) => objValue.value);
2202
- return {
2203
- title,
2204
- name: type === constants_exports.SearchType.SEARCH ? `${constants_exports.SearchType.SEARCH}_${String(dataIndex)}` : groupIndex ?? name,
2205
- values,
2206
- type,
2207
- widget,
2208
- modelType
2209
- };
2210
- } else {
2211
- const contexts = [];
2212
- let groupValues = [];
2213
- objValues?.forEach((objValue) => {
2214
- const { context: context2, value, active, groupIndex: groupIndex2, isDefault } = objValue;
2215
- const indexAppend = groupIndex2 != null ? groupIndex2 : viewData?.views?.search?.filters_by?.length ?? 0;
2216
- contexts.push(
2217
- ...Array.isArray(context2?.group_by) ? context2.group_by.map((item) => ({ group_by: item })) : [context2]
2218
- );
2219
- groupValues[indexAppend] = {
2220
- contexts: [
2221
- ...Array.isArray(context2?.group_by) ? context2.group_by.map((item) => ({
2222
- group_by: item
2223
- })) : [context2]
2224
- ],
2225
- strings: isDefault ? [value] : [...groupValues[indexAppend]?.strings ?? [], value]
2226
- };
2227
- });
2228
- const fields = [
2229
- ...new Set(fieldsList?.map((item) => item?.name))
2230
- ];
2231
- const groupByTag = {
2232
- title,
2233
- values: groupValues?.filter(
2234
- (item) => item !== void 0
2235
- ),
2236
- type,
2237
- contexts,
2238
- fields
2239
- };
2240
- return groupByTag;
2241
- }
2242
- }
2243
- );
2244
- setSelectedTags(tagsSearch);
2245
- setSearchString("");
2246
- },
2247
- [searchMap]
2248
- );
2249
- (0, import_react26.useEffect)(() => {
2250
- setTagSearch(searchMap);
2251
- }, [searchMap]);
2252
- const handleAddTagSearch = (tag) => {
2253
- const { domain: domain2, groupIndex, value, type, context: context2, dataIndex } = tag;
2254
- const domainFormat = new utils_exports.domainHelper.Domain(domain2);
2255
- if (type === constants_exports.SearchType.FILTER) {
2256
- addSearchItems(`${constants_exports.SearchType.FILTER}_${groupIndex}`, {
2257
- ...tag,
2258
- domain: domain2 ? domainFormat.toList(context2) : null
2259
- });
2260
- } else if (type === constants_exports.SearchType.SEARCH) {
2261
- addSearchItems(`${constants_exports.SearchType.SEARCH}_${String(dataIndex)}`, {
2262
- ...tag,
2263
- domain: domain2 ? domainFormat.toList({
2264
- ...context2,
2265
- self: value
2266
- }) : null
2267
- });
2268
- } else if (type === constants_exports.SearchType.GROUP) {
2269
- addSearchItems(`${constants_exports.SearchType.GROUP}`, {
2270
- ...tag,
2271
- domain: domain2 ? domainFormat.toList({
2272
- context: context2,
2273
- self: value
2274
- }) : null
2275
- });
2276
- }
2277
- };
2278
- const onKeyDown = (e) => {
2279
- if (!searchBy || searchBy.length === 0) return;
2280
- switch (e.key) {
2281
- case "Backspace": {
2282
- if (!searchString && selectedTags && selectedTags.length > 0) {
2283
- const lastTag = selectedTags[selectedTags.length - 1];
2284
- if (!lastTag) return;
2285
- const key = lastTag.type === constants_exports.SearchType.GROUP ? constants_exports.SearchType.GROUP : lastTag.name;
2286
- removeKeyFromSearchMap({ key: String(key) });
2287
- }
2288
- break;
2289
- }
2290
- case "ArrowDown": {
2291
- e.preventDefault();
2292
- setHoveredIndex((prev) => {
2293
- const maxIndex = searchBy.length - 1;
2294
- const next = prev < maxIndex ? prev + 1 : prev;
2295
- setHoveredIndexSearchList(next);
2296
- return next;
2297
- });
2298
- break;
2299
- }
2300
- case "ArrowUp": {
2301
- e.preventDefault();
2302
- setHoveredIndex((prev) => {
2303
- const next = prev > 0 ? prev - 1 : prev;
2304
- setHoveredIndexSearchList(next);
2305
- return next;
2306
- });
2307
- break;
2308
- }
2309
- case "Enter": {
2310
- e.preventDefault();
2311
- if (!searchString.trim()) return;
2312
- const head = searchBy[hoveredIndex];
2313
- if (!head) return;
2314
- handleAddTagSearch({
2315
- title: head.title,
2316
- name: head.name,
2317
- value: searchString,
2318
- type: constants_exports.SearchType.SEARCH,
2319
- domain: head.filter_domain,
2320
- operator: head.operator,
2321
- dataIndex: head.dataIndex,
2322
- widget: head.widget,
2323
- modelType: head.type
2324
- });
2325
- break;
2326
- }
2327
- default:
2328
- break;
2329
- }
2330
- };
2331
- const handleMouseEnter = (index) => {
2332
- setHoveredIndexSearchList(index);
2333
- };
2334
- const handleMouseLeave = () => {
2335
- setHoveredIndexSearchList(null);
2336
- };
2337
- return {
2338
- groupBy,
2339
- searchBy,
2340
- filterBy,
2341
- selectedTags,
2342
- searchString,
2343
- setFilterBy,
2344
- setGroupBy,
2345
- setSearchBy,
2346
- clearSearch,
2347
- setSelectedTags,
2348
- removeSearchItems,
2349
- onSearchString: onChangeSearchInput,
2350
- handleAddTagSearch,
2351
- domain: formatDomain(),
2352
- context: contextSearch,
2353
- onKeyDown,
2354
- handleMouseEnter,
2355
- handleMouseLeave,
2356
- hoveredIndexSearchList
2357
- };
2358
- };
2359
- // Annotate the CommonJS export names for ESM import in node:
2360
- 0 && (module.exports = {
2361
- binaryFieldController,
2362
- colorFieldController,
2363
- copyLinkButtonController,
2364
- downLoadBinaryController,
2365
- downloadFileController,
2366
- durationController,
2367
- many2manyBinaryController,
2368
- many2manyFieldController,
2369
- many2manyTagsController,
2370
- many2oneButtonController,
2371
- many2oneFieldController,
2372
- priorityFieldController,
2373
- providerEinvoiceFieldController,
2374
- searchController,
2375
- statusDropdownController,
2376
- tableController,
2377
- tableGroupController,
2378
- tableHeadController
2379
- });