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

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/index.mjs ADDED
@@ -0,0 +1,2814 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
18
+
19
+ // src/index.ts
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ AppProvider: () => AppProvider,
23
+ STORAGES: () => STORAGES,
24
+ binaryFieldController: () => binaryFieldController,
25
+ colorFieldController: () => colorFieldController,
26
+ copyLinkButtonController: () => copyLinkButtonController,
27
+ countSum: () => countSum,
28
+ downLoadBinaryController: () => downLoadBinaryController,
29
+ downloadFileController: () => downloadFileController,
30
+ durationController: () => durationController,
31
+ guessTypeFromUrl: () => guessTypeFromUrl,
32
+ isObjectEmpty: () => isObjectEmpty,
33
+ languages: () => languages,
34
+ many2manyBinaryController: () => many2manyBinaryController,
35
+ many2manyFieldController: () => many2manyFieldController,
36
+ many2manyTagsController: () => many2manyTagsController,
37
+ many2oneButtonController: () => many2oneButtonController,
38
+ many2oneFieldController: () => many2oneFieldController,
39
+ mergeButtons: () => mergeButtons,
40
+ priorityFieldController: () => priorityFieldController,
41
+ providerEinvoiceFieldController: () => providerEinvoiceFieldController,
42
+ searchController: () => searchController,
43
+ setStorageItemAsync: () => setStorageItemAsync,
44
+ statusDropdownController: () => statusDropdownController,
45
+ tableController: () => tableController,
46
+ tableGroupController: () => tableGroupController,
47
+ tableHeadController: () => tableHeadController,
48
+ useAddEntity: () => useAddEntity,
49
+ useAppProvider: () => useAppProvider,
50
+ useButton: () => useButton,
51
+ useCallAction: () => useCallAction,
52
+ useChangeOrderPreparationState: () => useChangeOrderPreparationState,
53
+ useChangeStatus: () => useChangeStatus,
54
+ useCheckPayment: () => useCheckPayment,
55
+ useCompany: () => useCompany,
56
+ useConfig: () => useConfig,
57
+ useCreateEntity: () => useCreateEntity,
58
+ useCreatePosConfig: () => useCreatePosConfig,
59
+ useCreateSession: () => useCreateSession,
60
+ useDebounce: () => useDebounce,
61
+ useDelete: () => useDelete,
62
+ useDeleteComment: () => useDeleteComment,
63
+ useDeleteEntity: () => useDeleteEntity,
64
+ useDetail: () => useDetail,
65
+ useDuplicateRecord: () => useDuplicateRecord,
66
+ useExecuteImport: () => useExecuteImport,
67
+ useExportExcel: () => useExportExcel,
68
+ useForgotPassword: () => useForgotPassword,
69
+ useForgotPasswordSSO: () => useForgotPasswordSSO,
70
+ useGenSerialNumber: () => useGenSerialNumber,
71
+ useGeneratePaymentQrInfo: () => useGeneratePaymentQrInfo,
72
+ useGet2FAMethods: () => useGet2FAMethods,
73
+ useGetASession: () => useGetASession,
74
+ useGetAccessByCode: () => useGetAccessByCode,
75
+ useGetAction: () => useGetAction,
76
+ useGetActionDetail: () => useGetActionDetail,
77
+ useGetAll: () => useGetAll,
78
+ useGetCalendar: () => useGetCalendar,
79
+ useGetComment: () => useGetComment,
80
+ useGetCompanyInfo: () => useGetCompanyInfo,
81
+ useGetConversionRate: () => useGetConversionRate,
82
+ useGetCurrency: () => useGetCurrency,
83
+ useGetCurrentCompany: () => useGetCurrentCompany,
84
+ useGetDetail: () => useGetDetail,
85
+ useGetExternalTabs: () => useGetExternalTabs,
86
+ useGetFieldExport: () => useGetFieldExport,
87
+ useGetFieldOnChange: () => useGetFieldOnChange,
88
+ useGetFileExcel: () => useGetFileExcel,
89
+ useGetFormView: () => useGetFormView,
90
+ useGetGroups: () => useGetGroups,
91
+ useGetList: () => useGetList,
92
+ useGetListCompany: () => useGetListCompany,
93
+ useGetListData: () => useGetListData,
94
+ useGetListMyBankAccount: () => useGetListMyBankAccount,
95
+ useGetMenu: () => useGetMenu,
96
+ useGetOrderLine: () => useGetOrderLine,
97
+ useGetPinCode: () => useGetPinCode,
98
+ useGetPrintReport: () => useGetPrintReport,
99
+ useGetProGressBar: () => useGetProGressBar,
100
+ useGetProfile: () => useGetProfile,
101
+ useGetProvider: () => useGetProvider,
102
+ useGetResequence: () => useGetResequence,
103
+ useGetRowIds: () => useGetRowIds,
104
+ useGetSelection: () => useGetSelection,
105
+ useGetSpecification: () => useGetSpecification,
106
+ useGetUser: () => useGetUser,
107
+ useGetView: () => useGetView,
108
+ useGrantAccess: () => useGrantAccess,
109
+ useIsValidToken: () => useIsValidToken,
110
+ useListData: () => useListData,
111
+ useLoadAction: () => useLoadAction,
112
+ useLoadMessage: () => useLoadMessage,
113
+ useLoginCredential: () => useLoginCredential,
114
+ useLoginSocial: () => useLoginSocial,
115
+ useLogout: () => useLogout,
116
+ useMenu: () => useMenu,
117
+ useModel: () => useModel,
118
+ useOdooDataTransform: () => useOdooDataTransform,
119
+ useOnChangeForm: () => useOnChangeForm,
120
+ useParsePreview: () => useParsePreview,
121
+ usePrint: () => usePrint,
122
+ useProfile: () => useProfile,
123
+ useReadGroup: () => useReadGroup,
124
+ useRemoveRow: () => useRemoveRow,
125
+ useRemoveTotpSetup: () => useRemoveTotpSetup,
126
+ useRequestSetupTotp: () => useRequestSetupTotp,
127
+ useResetPassword: () => useResetPassword,
128
+ useResetPasswordSSO: () => useResetPasswordSSO,
129
+ useRunAction: () => useRunAction,
130
+ useSave: () => useSave,
131
+ useSendComment: () => useSendComment,
132
+ useSettingsWebRead2fa: () => useSettingsWebRead2fa,
133
+ useSignInSSO: () => useSignInSSO,
134
+ useStorageState: () => useStorageState,
135
+ useSwitchLocale: () => useSwitchLocale,
136
+ useUpdatePassword: () => useUpdatePassword,
137
+ useUploadFile: () => useUploadFile,
138
+ useUploadFileExcel: () => useUploadFileExcel,
139
+ useUploadIdFile: () => useUploadIdFile,
140
+ useUploadImage: () => useUploadImage,
141
+ useUser: () => useUser,
142
+ useValidateActionToken: () => useValidateActionToken,
143
+ useVerify2FA: () => useVerify2FA,
144
+ useVerifyTotp: () => useVerifyTotp,
145
+ useViewV2: () => useViewV2
146
+ });
147
+
148
+ // src/hooks.ts
149
+ import {
150
+ useModel,
151
+ useButton,
152
+ useChangeStatus,
153
+ useDelete,
154
+ useDeleteComment,
155
+ useDuplicateRecord,
156
+ useExecuteImport,
157
+ useExportExcel,
158
+ useForgotPassword,
159
+ useForgotPasswordSSO,
160
+ useGet2FAMethods,
161
+ useGetAccessByCode,
162
+ useGetActionDetail,
163
+ useGetAll,
164
+ useGetCalendar,
165
+ useGetComment,
166
+ useGetCompanyInfo,
167
+ useGetConversionRate,
168
+ useGetCurrency,
169
+ useGetCurrentCompany,
170
+ useGetDetail,
171
+ useGetFieldExport,
172
+ useGetFieldOnChange,
173
+ useGetFileExcel,
174
+ useGetFormView,
175
+ useGetGroups,
176
+ useGetListCompany,
177
+ useGetListData,
178
+ useGetListMyBankAccount,
179
+ useGetMenu,
180
+ useGetPrintReport,
181
+ useGetProGressBar,
182
+ useGetProfile,
183
+ useGetProvider,
184
+ useGetResequence,
185
+ useGetSelection,
186
+ useGetUser,
187
+ useGetView,
188
+ useGrantAccess,
189
+ useIsValidToken,
190
+ useLoadAction,
191
+ useLoadMessage,
192
+ useLoginCredential,
193
+ useLoginSocial,
194
+ useLogout,
195
+ useOdooDataTransform,
196
+ useOnChangeForm,
197
+ useParsePreview,
198
+ usePrint,
199
+ useRemoveRow,
200
+ useRemoveTotpSetup,
201
+ useRequestSetupTotp,
202
+ useResetPassword,
203
+ useResetPasswordSSO,
204
+ useRunAction,
205
+ useSave,
206
+ useSendComment,
207
+ useSettingsWebRead2fa,
208
+ useSignInSSO,
209
+ useSwitchLocale,
210
+ useUpdatePassword,
211
+ useUploadFile,
212
+ useUploadFileExcel,
213
+ useUploadIdFile,
214
+ useUploadImage,
215
+ useValidateActionToken,
216
+ useVerify2FA,
217
+ useVerifyTotp,
218
+ useAddEntity,
219
+ useChangeOrderPreparationState,
220
+ useCheckPayment,
221
+ useCreateEntity,
222
+ useCreatePosConfig,
223
+ useCreateSession,
224
+ useDeleteEntity,
225
+ useGenSerialNumber,
226
+ useGeneratePaymentQrInfo,
227
+ useGetASession,
228
+ useGetExternalTabs,
229
+ useGetList,
230
+ useGetOrderLine,
231
+ useReadGroup,
232
+ useGetPinCode
233
+ } from "@fctc/interface-logic/hooks";
234
+
235
+ // src/hooks/core/use-app-provider.tsx
236
+ import { createContext, useContext, useMemo as useMemo4 } from "react";
237
+
238
+ // src/hooks/core/use-menu.ts
239
+ import { useState as useState2 } from "react";
240
+
241
+ // src/hooks/core/use-call-action.ts
242
+ import { useCallback, useState } from "react";
243
+
244
+ // src/provider.ts
245
+ var provider_exports = {};
246
+ __reExport(provider_exports, provider_star);
247
+ import * as provider_star from "@fctc/interface-logic/provider";
248
+
249
+ // src/hooks/core/use-call-action.ts
250
+ var useCallAction = () => {
251
+ const { env } = (0, provider_exports.useEnv)();
252
+ const { useLoadAction: useLoadAction2, useRunAction: useRunAction2 } = (0, provider_exports.useService)();
253
+ const queryLoadAction = useLoadAction2();
254
+ const queryRunAction = useRunAction2();
255
+ const [actionData, setActionData] = useState(
256
+ void 0
257
+ );
258
+ const callAction = useCallback(
259
+ async ({
260
+ aid,
261
+ service,
262
+ xNode,
263
+ context
264
+ }) => {
265
+ try {
266
+ const menuContext = {
267
+ ...env?.context,
268
+ ...context
269
+ };
270
+ const loadRes = await queryLoadAction.mutateAsync({
271
+ idAction: aid,
272
+ context: menuContext,
273
+ service,
274
+ xNode
275
+ });
276
+ if (loadRes?.result?.type === "ir.actions.server") {
277
+ const runRes = await queryRunAction.mutateAsync({
278
+ idAction: aid,
279
+ context: menuContext,
280
+ service,
281
+ xNode
282
+ });
283
+ setActionData(runRes?.result);
284
+ return runRes?.result;
285
+ } else {
286
+ setActionData(loadRes?.result);
287
+ return loadRes?.result;
288
+ }
289
+ } catch (err) {
290
+ console.error("callAction error:", err);
291
+ return void 0;
292
+ }
293
+ },
294
+ [env?.context?.lang]
295
+ );
296
+ return [actionData, callAction];
297
+ };
298
+
299
+ // src/utils.ts
300
+ var utils_exports = {};
301
+ __export(utils_exports, {
302
+ STORAGES: () => STORAGES,
303
+ countSum: () => countSum,
304
+ guessTypeFromUrl: () => guessTypeFromUrl,
305
+ isObjectEmpty: () => isObjectEmpty,
306
+ languages: () => languages,
307
+ mergeButtons: () => mergeButtons,
308
+ setStorageItemAsync: () => setStorageItemAsync,
309
+ useStorageState: () => useStorageState
310
+ });
311
+
312
+ // src/utils/constants.ts
313
+ var languages = [
314
+ { id: "vi_VN", name: "VIE" },
315
+ { id: "en_US", name: "ENG" }
316
+ ];
317
+ var isBlobUrl = (url) => url.startsWith("blob:");
318
+
319
+ // src/utils/function.ts
320
+ import { useCallback as useCallback2, useEffect, useReducer } from "react";
321
+ var countSum = (data, field) => {
322
+ if (!data || !field) return 0;
323
+ return data.reduce(
324
+ (total, item) => total + (item?.[`${field}_count`] || 0),
325
+ 0
326
+ );
327
+ };
328
+ var isObjectEmpty = (obj) => {
329
+ return Object.keys(obj).length === 0;
330
+ };
331
+ function mergeButtons(fields) {
332
+ const buttons = fields?.filter((f) => f.type_co === "button");
333
+ const others = fields?.filter((f) => f.type_co !== "button");
334
+ if (buttons?.length) {
335
+ others.push({
336
+ type_co: "buttons",
337
+ buttons
338
+ });
339
+ }
340
+ return others;
341
+ }
342
+ var STORAGES = {
343
+ TOKEN: "accessToken",
344
+ USER_INFO: "USER_INFO"
345
+ };
346
+ function useAsyncState(initialValue = [true, null]) {
347
+ return useReducer(
348
+ (_state, action = null) => [false, action],
349
+ initialValue
350
+ );
351
+ }
352
+ async function setStorageItemAsync(key, value) {
353
+ try {
354
+ if (value === null) {
355
+ localStorage.removeItem(key);
356
+ } else {
357
+ localStorage.setItem(key, value);
358
+ }
359
+ } catch (e) {
360
+ console.error("Local storage is unavailable:", e);
361
+ }
362
+ }
363
+ function useStorageState(key) {
364
+ const [state, setState] = useAsyncState();
365
+ useEffect(() => {
366
+ try {
367
+ const storedValue = localStorage.getItem(key);
368
+ setState(storedValue);
369
+ } catch (e) {
370
+ console.error("Local storage is unavailable:", e);
371
+ }
372
+ }, [key]);
373
+ const setValue = useCallback2(
374
+ (value) => {
375
+ setState(value);
376
+ setStorageItemAsync(key, value);
377
+ },
378
+ [key]
379
+ );
380
+ return [state, setValue];
381
+ }
382
+ var guessTypeFromUrl = (url) => {
383
+ const ext = url.split(".").pop()?.toLowerCase();
384
+ if (!ext) return null;
385
+ const map = {
386
+ jpg: "image/jpeg",
387
+ jpeg: "image/jpeg",
388
+ png: "image/png",
389
+ webp: "image/webp",
390
+ gif: "image/gif",
391
+ svg: "image/svg+xml",
392
+ bmp: "image/bmp",
393
+ tiff: "image/tiff",
394
+ pdf: "application/pdf",
395
+ zip: "application/zip",
396
+ rar: "application/x-rar-compressed",
397
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
398
+ xls: "application/vnd.ms-excel",
399
+ mp4: "video/mp4",
400
+ mov: "video/quicktime"
401
+ };
402
+ return map[ext] || null;
403
+ };
404
+
405
+ // src/utils.ts
406
+ __reExport(utils_exports, utils_star);
407
+ import * as utils_star from "@fctc/interface-logic/utils";
408
+
409
+ // src/hooks/core/use-menu.ts
410
+ var useMenu = ({
411
+ context,
412
+ specification,
413
+ domain,
414
+ defaultService
415
+ }) => {
416
+ const { useGetMenu: useGetMenu2 } = (0, provider_exports.useService)();
417
+ const [action, callAction] = useCallAction();
418
+ const [service, setService] = useState2("");
419
+ const [xNode, setXNode] = useState2("");
420
+ const menuData = useGetMenu2(
421
+ context,
422
+ specification,
423
+ !!context && !isObjectEmpty(context) && !!context?.uid && !!context?.lang,
424
+ domain,
425
+ defaultService
426
+ );
427
+ const [menuId, setMenuId] = useState2(void 0);
428
+ const handleChangeMenu = async ({
429
+ menu,
430
+ service: service2,
431
+ xNode: xNode2,
432
+ context: context2
433
+ }) => {
434
+ const aidMenu = menu?.action?.external_xml_id || menu?.action?.id?.id;
435
+ if (menu) {
436
+ setMenuId(menu.id?.toString() ?? "");
437
+ }
438
+ if (aidMenu) {
439
+ const actionResponse = await callAction({
440
+ aid: aidMenu,
441
+ service: service2 ?? "",
442
+ xNode: xNode2,
443
+ context: context2
444
+ });
445
+ setService(service2 ?? "");
446
+ setXNode(xNode2 ?? "");
447
+ return actionResponse;
448
+ }
449
+ };
450
+ return {
451
+ ...menuData,
452
+ service,
453
+ xNode,
454
+ data: menuData?.data,
455
+ action: { handleChangeMenu },
456
+ state: { menuId, action },
457
+ context,
458
+ isLoading: menuData.isLoading,
459
+ isError: menuData.isError,
460
+ error: menuData.error,
461
+ refetch: menuData.refetch
462
+ };
463
+ };
464
+
465
+ // src/hooks/core/use-detail.ts
466
+ import { useQuery } from "@tanstack/react-query";
467
+ import { useEffect as useEffect2 } from "react";
468
+ var useDetail = (sub) => {
469
+ const { setUserInfo, env } = (0, provider_exports.useEnv)();
470
+ const { useGetDetail: useGetDetail2 } = (0, provider_exports.useService)();
471
+ const fetchGetDetail = useGetDetail2();
472
+ const userDetailQuery = useQuery({
473
+ queryKey: ["userDetailQuery", sub],
474
+ queryFn: () => {
475
+ return fetchGetDetail.mutateAsync({
476
+ model: "res.users",
477
+ ids: [sub],
478
+ specification: { image_256: {} },
479
+ service: env?.default_service
480
+ });
481
+ },
482
+ enabled: !!sub
483
+ });
484
+ useEffect2(() => {
485
+ if (userDetailQuery.data) {
486
+ const userPicture = userDetailQuery.data;
487
+ setUserInfo({ ...env?.user, image: userPicture?.[0]?.image_256 });
488
+ }
489
+ }, [userDetailQuery.isFetched]);
490
+ return { ...userDetailQuery };
491
+ };
492
+
493
+ // src/hooks/core/use-profile.ts
494
+ import { useQuery as useQuery2 } from "@tanstack/react-query";
495
+ import { useEffect as useEffect3, useMemo } from "react";
496
+ var useProfile = ({
497
+ service,
498
+ i18n
499
+ }) => {
500
+ const { setUid, setLang, setUserInfo, env } = (0, provider_exports.useEnv)();
501
+ const { useGetProfile: useGetProfile2 } = (0, provider_exports.useService)();
502
+ const getProfile = useGetProfile2(service);
503
+ const userInfoQuery = useQuery2({
504
+ queryKey: ["userInfo"],
505
+ queryFn: () => getProfile.mutateAsync(),
506
+ enabled: isObjectEmpty(env?.user)
507
+ });
508
+ useEffect3(() => {
509
+ if (userInfoQuery.data) {
510
+ const userInfo = userInfoQuery.data;
511
+ utils_exports.sessionStorageUtils.setXNode(userInfo?.x_node);
512
+ setUid(userInfo?.sub);
513
+ setUserInfo(userInfo);
514
+ const userLocale = languages.find((lang) => lang?.id === userInfo?.locale);
515
+ setLang(userLocale?.id);
516
+ i18n.changeLanguage(userLocale?.id.split("_")[0]);
517
+ }
518
+ }, [userInfoQuery.isFetched]);
519
+ const context = useMemo(() => {
520
+ if (userInfoQuery.data?.sub && userInfoQuery.data?.locale) {
521
+ return {
522
+ uid: Number(userInfoQuery.data.sub),
523
+ lang: String(userInfoQuery.data.locale),
524
+ tz: "Asia/Saigon"
525
+ };
526
+ }
527
+ return void 0;
528
+ }, [userInfoQuery.isFetched]);
529
+ if (userInfoQuery.isLoading || !userInfoQuery.data) {
530
+ return null;
531
+ }
532
+ return {
533
+ ...userInfoQuery,
534
+ context
535
+ };
536
+ };
537
+
538
+ // src/hooks/core/use-user.ts
539
+ var useUser = ({ service, i18n }) => {
540
+ const userProfile = useProfile({ service, i18n });
541
+ const userDetail = useDetail(userProfile?.data?.sub);
542
+ return { userProfile, userDetail, context: userProfile?.context };
543
+ };
544
+
545
+ // src/hooks/core/use-view-v2.ts
546
+ import { useMemo as useMemo2 } from "react";
547
+ var useViewV2 = ({
548
+ action,
549
+ context,
550
+ aid,
551
+ service,
552
+ xNode
553
+ }) => {
554
+ const { useGetView: useGetView2 } = (0, provider_exports.useService)();
555
+ const viewParams = useMemo2(() => {
556
+ if (!action || !action?.res_model) {
557
+ return void 0;
558
+ }
559
+ const actionResult = action;
560
+ return {
561
+ aid,
562
+ model: String(actionResult?.res_model),
563
+ views: [
564
+ ...Array.isArray(actionResult?.views) ? actionResult?.views.map(
565
+ (view2) => view2[1] === "list" ? [view2[0], "list"] : view2
566
+ ) : [],
567
+ [
568
+ Array.isArray(actionResult?.search_view_id) ? actionResult?.search_view_id[0] : actionResult?.search_view_id,
569
+ "search"
570
+ ]
571
+ ],
572
+ context,
573
+ id: isNaN(Number(aid)) ? action?.id : aid,
574
+ service,
575
+ xNode
576
+ };
577
+ }, [action, context, aid]);
578
+ const view = useGetView2({
579
+ viewParams: viewParams ?? {},
580
+ enabled: !!viewParams
581
+ });
582
+ return {
583
+ ...view,
584
+ context
585
+ };
586
+ };
587
+
588
+ // src/hooks/core/use-company.ts
589
+ import { useQuery as useQuery3 } from "@tanstack/react-query";
590
+ import { useEffect as useEffect4, useMemo as useMemo3 } from "react";
591
+ var useCompany = ({ service }) => {
592
+ const { setCompanies, setDefaultCompany, env } = (0, provider_exports.useEnv)();
593
+ const { useGetCurrentCompany: useGetCurrentCompany2, useGetCompanyInfo: useGetCompanyInfo2 } = (0, provider_exports.useService)();
594
+ const getCurrentCompany = useGetCurrentCompany2();
595
+ const fetchCurrentCompany = async () => {
596
+ return await getCurrentCompany.mutateAsync({
597
+ service
598
+ });
599
+ };
600
+ const currentCompany = useQuery3({
601
+ queryKey: ["currentCompany"],
602
+ queryFn: fetchCurrentCompany,
603
+ enabled: !!env?.defaultCompany
604
+ });
605
+ const current_company_id = useMemo3(() => {
606
+ return currentCompany.data?.current_company_id;
607
+ }, [currentCompany.data]);
608
+ useEffect4(() => {
609
+ if (current_company_id) {
610
+ const companyIDs = [current_company_id];
611
+ setCompanies(companyIDs);
612
+ }
613
+ }, [current_company_id]);
614
+ const getCompanyInfo = useGetCompanyInfo2();
615
+ const companyInfo = useQuery3({
616
+ queryKey: ["companyInfoQuery", current_company_id],
617
+ queryFn: () => getCompanyInfo.mutateAsync({
618
+ service,
619
+ id: Number(current_company_id)
620
+ }),
621
+ enabled: !!current_company_id
622
+ });
623
+ useEffect4(() => {
624
+ if (companyInfo.data) {
625
+ const companyInfoData = companyInfo.data;
626
+ if (companyInfoData?.length) {
627
+ setDefaultCompany(companyInfoData[0]);
628
+ }
629
+ }
630
+ }, [companyInfo.data]);
631
+ if (!companyInfo?.data || !currentCompany?.data) return;
632
+ return {
633
+ currentCompany: { ...currentCompany },
634
+ companyInfo: { ...companyInfo }
635
+ };
636
+ };
637
+
638
+ // src/hooks/core/use-app-provider.tsx
639
+ import { jsx } from "react/jsx-runtime";
640
+ var AppProviderInitialValue = {
641
+ user: {},
642
+ company: {},
643
+ action: {},
644
+ menu: {},
645
+ view: {}
646
+ };
647
+ var ReactContext = createContext(AppProviderInitialValue);
648
+ var AppProvider = ({
649
+ children,
650
+ menuParams,
651
+ aid,
652
+ i18n
653
+ }) => {
654
+ const { env } = (0, provider_exports.useEnv)();
655
+ const user = useUser({ service: env.default_service, i18n });
656
+ const company = useCompany({ service: env.default_service });
657
+ const menuContext = useMemo4(() => {
658
+ return (0, utils_exports.combineContexts)([
659
+ {
660
+ ...user?.context,
661
+ ...!isObjectEmpty(env?.user) ? { lang: env?.context?.lang } : {},
662
+ ...menuParams?.context ?? {}
663
+ }
664
+ ]);
665
+ }, [user?.context, company?.companyInfo?.isFetched, env?.context?.lang]);
666
+ const menu = useMenu({
667
+ context: {
668
+ ...menuContext
669
+ },
670
+ specification: menuParams?.specification,
671
+ domain: menuParams?.domain,
672
+ defaultService: env.default_service
673
+ });
674
+ const action = useMemo4(() => {
675
+ return menu?.state?.action;
676
+ }, [menu?.state?.action, env?.context?.lang]);
677
+ const viewContext = useMemo4(() => {
678
+ return (0, utils_exports.combineContexts)([
679
+ menuContext,
680
+ { ...(0, utils_exports.evalJSONContext)(action?.context) }
681
+ ]);
682
+ }, [menuContext, action?.context, env?.context?.lang]);
683
+ const view = useViewV2({
684
+ action,
685
+ context: viewContext,
686
+ aid,
687
+ service: menu?.service,
688
+ xNode: menu?.xNode
689
+ });
690
+ return /* @__PURE__ */ jsx(
691
+ ReactContext.Provider,
692
+ {
693
+ value: {
694
+ user,
695
+ company,
696
+ menu,
697
+ action,
698
+ view
699
+ },
700
+ children
701
+ }
702
+ );
703
+ };
704
+ var useAppProvider = () => {
705
+ const context = useContext(ReactContext);
706
+ if (!context) {
707
+ return AppProviderInitialValue;
708
+ }
709
+ return context;
710
+ };
711
+
712
+ // src/hooks/core/use-config.ts
713
+ import { useEffect as useEffect5 } from "react";
714
+ var useConfig = ({
715
+ envConfig,
716
+ config,
717
+ localStorageUtils,
718
+ sessionStorageUtils: sessionStorageUtils2
719
+ }) => {
720
+ const { setupEnv, setEnvFile } = (0, provider_exports.useEnv)();
721
+ useEffect5(() => {
722
+ try {
723
+ setupEnv({
724
+ baseUrl: envConfig.baseUrl,
725
+ config: envConfig.config,
726
+ default_service: "",
727
+ localStorageUtils: localStorageUtils && localStorageUtils(),
728
+ sessionStorageUtils: localStorageUtils && sessionStorageUtils2()
729
+ });
730
+ setEnvFile(config);
731
+ } catch (error) {
732
+ console.error("Error loading env or config:", error);
733
+ }
734
+ }, [envConfig, config]);
735
+ return { envConfig, config };
736
+ };
737
+
738
+ // src/hooks/core/use-get-action.ts
739
+ var useGetAction = ({
740
+ aid,
741
+ context
742
+ }) => {
743
+ const { useLoadAction: useLoadAction2, useRunAction: useRunAction2 } = (0, provider_exports.useService)();
744
+ const queryLoadAction = useLoadAction2();
745
+ const queryRunAction = useRunAction2();
746
+ const handleActionResult = (data) => {
747
+ if (data && data.result && data.result.views && Array.isArray(data.result.views) && data.result.views.length > 0) {
748
+ }
749
+ };
750
+ const onLoadAction = () => {
751
+ queryLoadAction.mutate(
752
+ {
753
+ idAction: aid,
754
+ context
755
+ },
756
+ {
757
+ onSuccess: (data) => {
758
+ if (data?.result?.type === "ir.actions.act_window") {
759
+ handleActionResult(data);
760
+ } else if (data?.result?.type === "ir.actions.server") {
761
+ queryRunAction.mutate(
762
+ {
763
+ idAction: aid,
764
+ context
765
+ },
766
+ {
767
+ onSuccess: handleActionResult
768
+ }
769
+ );
770
+ }
771
+ }
772
+ }
773
+ );
774
+ };
775
+ return {
776
+ onLoadAction
777
+ };
778
+ };
779
+
780
+ // src/hooks/core/use-get-specification.ts
781
+ import { useMemo as useMemo5 } from "react";
782
+ var useGetSpecification = ({
783
+ model,
784
+ viewData,
785
+ fields
786
+ }) => {
787
+ const baseModel = useMemo5(
788
+ () => ({
789
+ name: String(model),
790
+ view: viewData,
791
+ fields
792
+ }),
793
+ [model, viewData, fields]
794
+ );
795
+ const initModel = useModel();
796
+ const modelInstance = useMemo5(() => {
797
+ if (viewData) {
798
+ return initModel.initModel(baseModel);
799
+ }
800
+ return null;
801
+ }, [baseModel, viewData, model]);
802
+ const specification = useMemo5(() => {
803
+ if (modelInstance) {
804
+ return modelInstance.getSpecification();
805
+ }
806
+ return null;
807
+ }, [modelInstance, model]);
808
+ return { specification };
809
+ };
810
+
811
+ // src/hooks/core/use-list-data.ts
812
+ import { useMemo as useMemo6, useState as useState5 } from "react";
813
+
814
+ // src/hooks/utils/use-debounce.ts
815
+ import { useEffect as useEffect6, useState as useState3 } from "react";
816
+ function useDebounce(value, delay) {
817
+ const [debouncedValue, setDebouncedValue] = useState3(value);
818
+ useEffect6(() => {
819
+ const handler = setTimeout(() => {
820
+ setDebouncedValue(value);
821
+ }, delay);
822
+ return () => {
823
+ clearTimeout(handler);
824
+ };
825
+ }, [value, delay]);
826
+ return [debouncedValue];
827
+ }
828
+
829
+ // src/hooks/utils/use-get-rowids.ts
830
+ import { useCallback as useCallback3, useEffect as useEffect7, useRef, useState as useState4 } from "react";
831
+ var useGetRowIds = (tableRef) => {
832
+ function isElementVisible(el) {
833
+ const style = window.getComputedStyle(el);
834
+ return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0";
835
+ }
836
+ function arraysAreEqual(a, b) {
837
+ if (a.length !== b.length) return false;
838
+ if (a.length === 0 && b.length === 0) return true;
839
+ const setA = new Set(a);
840
+ const setB = new Set(b);
841
+ if (setA.size !== setB.size) return false;
842
+ for (const val of setA) {
843
+ if (!setB.has(val)) return false;
844
+ }
845
+ return true;
846
+ }
847
+ const [rowIds, setRowIds] = useState4([]);
848
+ const lastRowIdsRef = useRef([]);
849
+ const updateVisibleRowIds = useCallback3(() => {
850
+ const table = tableRef.current;
851
+ if (!table) return;
852
+ const rows = table.querySelectorAll("tr[data-row-id]");
853
+ const ids = [];
854
+ rows.forEach((row) => {
855
+ const el = row;
856
+ if (isElementVisible(el)) {
857
+ const id = el.getAttribute("data-row-id");
858
+ if (id) ids.push(id);
859
+ }
860
+ });
861
+ const uniqueIds = Array.from(new Set(ids));
862
+ if (!arraysAreEqual(lastRowIdsRef.current, uniqueIds)) {
863
+ lastRowIdsRef.current = uniqueIds;
864
+ setRowIds(uniqueIds);
865
+ }
866
+ }, [tableRef]);
867
+ useEffect7(() => {
868
+ const table = tableRef.current;
869
+ if (!table) return;
870
+ const mutationObserver = new MutationObserver(() => {
871
+ updateVisibleRowIds();
872
+ });
873
+ mutationObserver.observe(table, {
874
+ childList: true,
875
+ subtree: true,
876
+ attributes: true,
877
+ attributeFilter: ["style", "class"]
878
+ });
879
+ const resizeObserver = new ResizeObserver(() => {
880
+ updateVisibleRowIds();
881
+ });
882
+ resizeObserver.observe(table);
883
+ const handleScroll = () => updateVisibleRowIds();
884
+ table.addEventListener("scroll", handleScroll, true);
885
+ updateVisibleRowIds();
886
+ return () => {
887
+ mutationObserver.disconnect();
888
+ resizeObserver.disconnect();
889
+ table.removeEventListener("scroll", handleScroll, true);
890
+ };
891
+ }, [updateVisibleRowIds, tableRef?.current]);
892
+ return { rowIds, refresh: updateVisibleRowIds };
893
+ };
894
+
895
+ // src/hooks/core/use-list-data.ts
896
+ var useListData = ({
897
+ action,
898
+ context,
899
+ viewData,
900
+ model,
901
+ service,
902
+ xNode,
903
+ mode,
904
+ limit = 10
905
+ }) => {
906
+ const { useGetListData: useGetListData2 } = (0, provider_exports.useService)();
907
+ const [page, setPage] = useState5(0);
908
+ const [pageLimit, setPageLimit] = useState5(limit);
909
+ const [groupByList, setGroupByList] = useState5(null);
910
+ const [domain, setDomain] = useState5(null);
911
+ const [order, setOrder] = useState5("");
912
+ const [selectedRowKeys, setSelectedRowKeys] = useState5([]);
913
+ const [debouncedPage] = useDebounce(page, 500);
914
+ const [debouncedDomain] = useDebounce(domain, 500);
915
+ const { specification } = useGetSpecification({
916
+ model,
917
+ viewData,
918
+ fields: mode === "kanban" ? viewData?.views?.kanban?.fields : viewData?.views?.list?.fields
919
+ });
920
+ const listDataProps = useMemo6(() => {
921
+ if (!viewData || !action || !context) {
922
+ return null;
923
+ }
924
+ const domainParse = domain ? [...domain] : action?.domain ? Array.isArray(action?.domain) ? [...action?.domain] : (0, utils_exports.evalJSONDomain)(action?.domain, context) : [];
925
+ const limit2 = pageLimit;
926
+ const offset = debouncedPage * pageLimit;
927
+ const fields = typeof groupByList === "object" ? groupByList?.fields : void 0;
928
+ const groupby = typeof groupByList === "object" ? [groupByList?.contexts?.[0]?.group_by] : [];
929
+ const sort = order ?? (0, utils_exports.formatSortingString)(
930
+ (mode === "kanban" ? viewData?.views?.kanban : viewData?.views?.list)?.default_order
931
+ ) ?? "";
932
+ return {
933
+ model: action?.res_model,
934
+ specification,
935
+ domain: domainParse,
936
+ limit: limit2,
937
+ offset,
938
+ fields,
939
+ groupby,
940
+ context,
941
+ sort,
942
+ mode
943
+ };
944
+ }, [
945
+ action,
946
+ groupByList,
947
+ order,
948
+ debouncedPage,
949
+ pageLimit,
950
+ debouncedDomain,
951
+ context,
952
+ model
953
+ ]);
954
+ const list = useGetListData2(
955
+ { ...listDataProps },
956
+ [
957
+ listDataProps?.domain,
958
+ listDataProps?.groupby,
959
+ listDataProps?.limit,
960
+ listDataProps?.offset,
961
+ listDataProps?.sort,
962
+ listDataProps?.context,
963
+ listDataProps?.specification,
964
+ listDataProps?.mode
965
+ ],
966
+ !!listDataProps && !!specification && !isObjectEmpty(specification) && !!domain,
967
+ service,
968
+ xNode
969
+ );
970
+ return {
971
+ ...list,
972
+ state: {
973
+ specification,
974
+ page,
975
+ order,
976
+ domain: listDataProps?.domain,
977
+ pageLimit,
978
+ groupByList,
979
+ selectedRowKeys,
980
+ setPage,
981
+ setOrder,
982
+ setDomain,
983
+ setPageLimit,
984
+ setGroupByList,
985
+ setSelectedRowKeys
986
+ }
987
+ };
988
+ };
989
+
990
+ // src/config.ts
991
+ var config_exports = {};
992
+ __reExport(config_exports, configs_star);
993
+ import * as configs_star from "@fctc/interface-logic/configs";
994
+
995
+ // src/index.ts
996
+ __reExport(index_exports, config_exports);
997
+
998
+ // src/widget/basic/status-dropdown-field/controller.ts
999
+ import { useEffect as useEffect8, useRef as useRef2, useState as useState6 } from "react";
1000
+
1001
+ // src/environment.ts
1002
+ var environment_exports = {};
1003
+ __reExport(environment_exports, environment_star);
1004
+ import * as environment_star from "@fctc/interface-logic/environment";
1005
+
1006
+ // src/widget/basic/status-dropdown-field/controller.ts
1007
+ var statusDropdownController = (props) => {
1008
+ const { selection, isForm, id, model, name, state, onRefetch } = props;
1009
+ const env = (0, environment_exports.getEnv)();
1010
+ const colors = {
1011
+ normal: "bg-[#e9ecef]",
1012
+ done: "bg-primary",
1013
+ blocked: "bg-red-500"
1014
+ };
1015
+ const [isOpen, setIsOpen] = useState6(false);
1016
+ const buttonRef = useRef2(null);
1017
+ useEffect8(() => {
1018
+ const handleClickOutside = (event) => {
1019
+ if (buttonRef.current && !buttonRef.current.contains(event.target)) {
1020
+ setIsOpen(false);
1021
+ }
1022
+ };
1023
+ document.addEventListener("mousedown", handleClickOutside);
1024
+ return () => {
1025
+ document.removeEventListener("mousedown", handleClickOutside);
1026
+ };
1027
+ }, []);
1028
+ const { mutate: onSave } = useSave();
1029
+ const handleClick = async (status) => {
1030
+ setIsOpen(!isOpen);
1031
+ onSave(
1032
+ {
1033
+ ids: id ? [id] : [],
1034
+ model: model ?? "",
1035
+ data: { [name ?? ""]: status },
1036
+ context: env.context
1037
+ },
1038
+ {
1039
+ onSuccess: () => {
1040
+ onRefetch && onRefetch();
1041
+ }
1042
+ }
1043
+ );
1044
+ };
1045
+ return {
1046
+ handleClick,
1047
+ buttonRef,
1048
+ isForm,
1049
+ setIsOpen,
1050
+ isOpen,
1051
+ selection,
1052
+ state,
1053
+ colors
1054
+ };
1055
+ };
1056
+
1057
+ // src/widget/basic/many2one-field/controller.ts
1058
+ import { useCallback as useCallback4, useEffect as useEffect9, useMemo as useMemo7, useState as useState7 } from "react";
1059
+ var MANY2ONE_EXTERNAL = "many2one_external";
1060
+ var many2oneFieldController = (props) => {
1061
+ const {
1062
+ methods,
1063
+ relation,
1064
+ domain,
1065
+ formValues,
1066
+ value: propValue,
1067
+ onChange,
1068
+ name,
1069
+ context: fieldContext,
1070
+ options: fieldOptions,
1071
+ showDetail,
1072
+ service,
1073
+ xNode,
1074
+ isForm,
1075
+ widget,
1076
+ in_list_view,
1077
+ isEditTable
1078
+ } = props;
1079
+ const { env } = (0, provider_exports.useEnv)();
1080
+ const { action } = useAppProvider();
1081
+ const { useGetSelection: useGetSelection2, useGetDetail: useGetDetail2 } = (0, provider_exports.useService)();
1082
+ const [listOptions, setListOptions] = useState7([]);
1083
+ const [inputValue, setInputValue] = useState7("");
1084
+ const [debouncedInputValue] = useDebounce(inputValue, 1e3);
1085
+ const [isShowModalMany2Many, setIsShowModalMany2Many] = useState7(false);
1086
+ const [tempSelectedOption, setTempSelectedOption] = useState7(null);
1087
+ const [domainModal, setDomainModal] = useState7(null);
1088
+ const [domainObject, setDomainObject] = useState7(null);
1089
+ const initValue = methods?.getValues(name);
1090
+ const contextObject = {
1091
+ ...(typeof action?.context === "string" ? (0, utils_exports.evalJSONContext)(action?.context) : action?.context) || {},
1092
+ ...fieldContext,
1093
+ ...env?.context
1094
+ };
1095
+ const optionsObject = typeof fieldOptions === "string" ? (0, utils_exports.evalJSONContext)(fieldOptions, {
1096
+ ...formValues,
1097
+ ...contextObject,
1098
+ context: contextObject,
1099
+ parent: { ...formValues }
1100
+ }) : fieldOptions;
1101
+ const fetchGetDetail = useGetDetail2();
1102
+ const data = {
1103
+ model: widget === MANY2ONE_EXTERNAL ? optionsObject?.model : relation,
1104
+ domain: widget === MANY2ONE_EXTERNAL ? optionsObject?.domain : domainObject,
1105
+ context: {
1106
+ ...contextObject,
1107
+ ...optionsObject?.context
1108
+ },
1109
+ specification: widget === MANY2ONE_EXTERNAL ? optionsObject?.specification : {
1110
+ id: {},
1111
+ name: {},
1112
+ display_name: {}
1113
+ }
1114
+ };
1115
+ const {
1116
+ data: dataOfSelection,
1117
+ refetch,
1118
+ isFetching
1119
+ } = useGetSelection2({
1120
+ data,
1121
+ queryKey: [`data_${relation}`, domainObject],
1122
+ enabled: false,
1123
+ service: widget === MANY2ONE_EXTERNAL ? optionsObject?.service : service,
1124
+ xNode
1125
+ });
1126
+ const selectOptions = useMemo7(() => {
1127
+ return dataOfSelection?.records?.map((val) => ({
1128
+ value: val?.id,
1129
+ label: val?.display_name || val?.name,
1130
+ ...widget === MANY2ONE_EXTERNAL ? val : {}
1131
+ })) || [];
1132
+ }, [dataOfSelection]);
1133
+ useEffect9(() => {
1134
+ setListOptions(selectOptions);
1135
+ setDomainModal(domainObject);
1136
+ }, [selectOptions]);
1137
+ const parsedFormValues = useMemo7(
1138
+ () => JSON.parse(
1139
+ JSON.stringify({
1140
+ ...formValues,
1141
+ ...contextObject,
1142
+ context: contextObject
1143
+ })
1144
+ ) ?? {},
1145
+ [formValues, contextObject]
1146
+ );
1147
+ useEffect9(() => {
1148
+ const newDomain = (0, utils_exports.evalJSONDomain)(domain, parsedFormValues);
1149
+ const parsedDomain = typeof newDomain === "string" ? JSON.parse(
1150
+ newDomain.replace(/\(/g, "[").replace(/\)/g, "]").replace(/'/g, '"')
1151
+ ) : newDomain;
1152
+ setDomainObject((prev) => {
1153
+ const prevStr = JSON.stringify(prev);
1154
+ const nextStr = JSON.stringify(parsedDomain);
1155
+ return prevStr === nextStr ? prev : parsedDomain;
1156
+ });
1157
+ }, [domain, parsedFormValues]);
1158
+ useEffect9(() => {
1159
+ if (!propValue && tempSelectedOption) {
1160
+ methods?.setValue(name, null, { shouldDirty: true });
1161
+ setTempSelectedOption(null);
1162
+ } else if (propValue) {
1163
+ if (isForm && !isEditTable && optionsObject?.service && optionsObject?.model && !propValue?.display_name && !in_list_view) {
1164
+ fetchGetDetail.mutate(
1165
+ {
1166
+ model: optionsObject?.model,
1167
+ ids: propValue?.id ?? propValue,
1168
+ specification: widget === MANY2ONE_EXTERNAL ? optionsObject?.specification : {
1169
+ id: {},
1170
+ display_name: {}
1171
+ },
1172
+ context: { ...env.context },
1173
+ service: optionsObject ? optionsObject?.service : service,
1174
+ xNode
1175
+ },
1176
+ {
1177
+ onSuccess: (dataResponse) => {
1178
+ const detailData = dataResponse?.[0];
1179
+ setTempSelectedOption({
1180
+ value: detailData?.id,
1181
+ label: detailData?.display_name
1182
+ });
1183
+ if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
1184
+ Object.keys(optionsObject?.values_included)?.forEach(
1185
+ (field) => {
1186
+ methods?.setValue(
1187
+ optionsObject?.values_included[field]?.name,
1188
+ detailData?.[field]
1189
+ );
1190
+ }
1191
+ );
1192
+ methods?.setValue(name, detailData);
1193
+ }
1194
+ },
1195
+ onError: (error) => {
1196
+ console.log("error", error);
1197
+ }
1198
+ }
1199
+ );
1200
+ return;
1201
+ }
1202
+ setTempSelectedOption({
1203
+ value: propValue?.id,
1204
+ label: propValue?.display_name
1205
+ });
1206
+ }
1207
+ }, [propValue]);
1208
+ const fetchMoreOptions = useCallback4(() => {
1209
+ refetch();
1210
+ }, [refetch]);
1211
+ useEffect9(() => {
1212
+ if (debouncedInputValue) {
1213
+ const filteredDomain = [...domainObject ?? []]?.filter(
1214
+ (d) => !(Array.isArray(d) && d[0] === "name" && d[1] === "ilike")
1215
+ ) || [];
1216
+ const newDomain = [
1217
+ ...filteredDomain,
1218
+ ...debouncedInputValue ? [["name", "ilike", debouncedInputValue]] : []
1219
+ ];
1220
+ setDomainObject(newDomain);
1221
+ setTimeout(() => {
1222
+ fetchMoreOptions();
1223
+ }, 50);
1224
+ }
1225
+ }, [debouncedInputValue]);
1226
+ const handleChooseRecord = useCallback4(
1227
+ (idRecord) => {
1228
+ const newOption = listOptions?.find(
1229
+ (option) => option.value === idRecord
1230
+ );
1231
+ const newValue = widget === MANY2ONE_EXTERNAL && optionsObject?.field_name ? newOption?.[optionsObject?.field_name] : newOption.value;
1232
+ if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
1233
+ Object.keys(optionsObject?.values_included)?.forEach((field) => {
1234
+ methods?.setValue(
1235
+ optionsObject?.values_included[field]?.name,
1236
+ newOption?.[field],
1237
+ { shouldDirty: true }
1238
+ );
1239
+ });
1240
+ }
1241
+ if (newOption) {
1242
+ methods?.setValue(
1243
+ name,
1244
+ {
1245
+ ...newOption,
1246
+ id: newValue,
1247
+ display_name: newOption?.label
1248
+ },
1249
+ { shouldDirty: true }
1250
+ );
1251
+ setTempSelectedOption(newOption);
1252
+ onChange && onChange(String(name), {
1253
+ ...newOption,
1254
+ id: newValue,
1255
+ display_name: newOption?.label
1256
+ });
1257
+ methods.trigger(name);
1258
+ }
1259
+ setIsShowModalMany2Many(false);
1260
+ },
1261
+ [listOptions, methods, name, onChange]
1262
+ );
1263
+ const handleClose = useCallback4(() => setIsShowModalMany2Many(false), []);
1264
+ const handleSelectChange = useCallback4(
1265
+ (selectedOption) => {
1266
+ if (!selectedOption) {
1267
+ if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
1268
+ Object.keys(optionsObject?.values_included)?.forEach((field) => {
1269
+ methods?.setValue(
1270
+ optionsObject?.values_included[field]?.name,
1271
+ null,
1272
+ { shouldDirty: true }
1273
+ );
1274
+ });
1275
+ }
1276
+ methods.setValue(name, null, { shouldDirty: true });
1277
+ setTempSelectedOption(null);
1278
+ onChange && onChange(String(name), null);
1279
+ methods.trigger(name);
1280
+ return;
1281
+ }
1282
+ const newValue = widget === MANY2ONE_EXTERNAL && optionsObject?.field_name ? selectedOption?.[optionsObject?.field_name] : selectedOption.value;
1283
+ if (widget === MANY2ONE_EXTERNAL && optionsObject?.values_included) {
1284
+ Object.keys(optionsObject?.values_included)?.forEach((field) => {
1285
+ methods?.setValue(
1286
+ optionsObject?.values_included[field]?.name,
1287
+ selectedOption?.[field],
1288
+ { shouldDirty: true }
1289
+ );
1290
+ });
1291
+ }
1292
+ methods?.setValue(
1293
+ name,
1294
+ {
1295
+ id: newValue,
1296
+ display_name: selectedOption?.label
1297
+ },
1298
+ { shouldDirty: true }
1299
+ );
1300
+ setTempSelectedOption(selectedOption);
1301
+ onChange && onChange(String(name), {
1302
+ id: newValue,
1303
+ display_name: selectedOption.label
1304
+ });
1305
+ methods.trigger(name);
1306
+ },
1307
+ [methods, name, onChange]
1308
+ );
1309
+ const allowShowDetail = showDetail && contextObject?.form_view_ref && (!optionsObject || !("no_open" in optionsObject) || optionsObject.no_open === false);
1310
+ return {
1311
+ isShowModalMany2Many,
1312
+ isFetching,
1313
+ initValue,
1314
+ handleChooseRecord,
1315
+ handleClose,
1316
+ handleSelectChange,
1317
+ domainModal,
1318
+ setInputValue,
1319
+ allowShowDetail,
1320
+ contextObject: {
1321
+ ...contextObject,
1322
+ ...optionsObject?.context
1323
+ },
1324
+ tempSelectedOption,
1325
+ listOptions,
1326
+ fetchMoreOptions,
1327
+ domainObject: widget === MANY2ONE_EXTERNAL ? optionsObject?.domain : domainObject,
1328
+ setIsShowModalMany2Many,
1329
+ setDomainObject,
1330
+ options: optionsObject,
1331
+ relation: widget === MANY2ONE_EXTERNAL ? optionsObject?.model : relation,
1332
+ service: widget === MANY2ONE_EXTERNAL ? optionsObject?.service : service
1333
+ };
1334
+ };
1335
+
1336
+ // src/widget/basic/many2one-button-field/controller.ts
1337
+ var many2oneButtonController = (props) => {
1338
+ const { domain, methods, relation, service, xNode } = props;
1339
+ const actionDataString = sessionStorage.getItem("actionData");
1340
+ const env = (0, environment_exports.getEnv)();
1341
+ const domainObject = (0, utils_exports.evalJSONDomain)(domain, methods?.getValues() || {});
1342
+ const actionData = actionDataString && actionDataString !== "undefined" ? JSON.parse(actionDataString) : {};
1343
+ const { data: dataOfSelection } = useGetSelection({
1344
+ data: {
1345
+ model: relation ?? "",
1346
+ domain: domainObject,
1347
+ context: { ...env.context, ...(0, utils_exports.evalJSONContext)(actionData?.context) }
1348
+ },
1349
+ queryKey: [`data_${relation}`, domainObject],
1350
+ service,
1351
+ xNode
1352
+ });
1353
+ const options = dataOfSelection?.records?.map((val) => ({
1354
+ value: val.id,
1355
+ label: val.name
1356
+ })) || [];
1357
+ return {
1358
+ options
1359
+ };
1360
+ };
1361
+
1362
+ // src/widget/basic/many2many-field/controller.ts
1363
+ import { useEffect as useEffect10, useMemo as useMemo8 } from "react";
1364
+ var many2manyFieldController = (props) => {
1365
+ const {
1366
+ relation,
1367
+ domain,
1368
+ context,
1369
+ options,
1370
+ enabled: enabledCallAPI,
1371
+ service,
1372
+ validateAndParseDate,
1373
+ moment
1374
+ } = props;
1375
+ const { env } = (0, provider_exports.useEnv)();
1376
+ const { user } = useAppProvider();
1377
+ const { useGetView: useGetView2 } = (0, provider_exports.useService)();
1378
+ const dataUser = user?.userProfile?.data;
1379
+ const contextObject = useMemo8(
1380
+ () => ({
1381
+ ...env.context,
1382
+ ...context || {}
1383
+ }),
1384
+ [env?.context, context]
1385
+ );
1386
+ const viewParams = useMemo8(
1387
+ () => ({
1388
+ model: relation,
1389
+ views: [
1390
+ [false, "list"],
1391
+ [false, "search"]
1392
+ ],
1393
+ context: contextObject,
1394
+ service,
1395
+ xNode: service == "wesap" && dataUser?.x_node
1396
+ }),
1397
+ [relation, contextObject, service, dataUser?.x_node]
1398
+ );
1399
+ const { data: viewResponse } = useGetView2({
1400
+ viewParams,
1401
+ enabled: enabledCallAPI
1402
+ });
1403
+ const default_order = viewResponse && viewResponse?.views?.list?.default_order;
1404
+ const optionsObject = useMemo8(
1405
+ () => (options && typeof options === "string" ? (0, utils_exports.evalJSONContext)(options) : options) || {},
1406
+ [options]
1407
+ );
1408
+ const {
1409
+ data: dataResponse,
1410
+ isFetched,
1411
+ isLoading,
1412
+ state,
1413
+ isPlaceholderData
1414
+ } = useListData({
1415
+ action: {
1416
+ domain,
1417
+ res_model: relation
1418
+ },
1419
+ context: contextObject,
1420
+ model: relation ?? "",
1421
+ viewData: viewResponse,
1422
+ service,
1423
+ xNode: service == "wesap" && dataUser?.x_node
1424
+ });
1425
+ const {
1426
+ selectedRowKeys,
1427
+ groupByList,
1428
+ domain: domainList,
1429
+ page,
1430
+ pageLimit,
1431
+ setDomain,
1432
+ setOrder,
1433
+ setPage,
1434
+ setSelectedRowKeys,
1435
+ setGroupByList,
1436
+ setPageLimit,
1437
+ specification
1438
+ } = state;
1439
+ useEffect10(() => {
1440
+ return () => {
1441
+ setDomain(null);
1442
+ setOrder("");
1443
+ setGroupByList(null);
1444
+ setPageLimit(10);
1445
+ };
1446
+ }, []);
1447
+ const { rows, columns, typeTable, onToggleColumnOptional } = tableController({
1448
+ data: {
1449
+ fields: viewResponse?.views?.list?.fields,
1450
+ records: dataResponse?.records ?? dataResponse?.groups,
1451
+ dataModel: viewResponse?.models?.[String(relation)],
1452
+ context: contextObject,
1453
+ typeTable: dataResponse?.groups ? "group" : "list"
1454
+ }
1455
+ });
1456
+ const searchControllers = searchController({
1457
+ viewData: viewResponse,
1458
+ model: relation ?? "",
1459
+ context: contextObject,
1460
+ domain,
1461
+ fieldsList: [
1462
+ ...columns?.filter(
1463
+ (col) => col?.field?.type_co === "field" && col?.optional !== "hide"
1464
+ )?.map((col) => ({ ...col.field })) ?? []
1465
+ ],
1466
+ validateAndParseDate,
1467
+ moment
1468
+ });
1469
+ return {
1470
+ rows,
1471
+ columns,
1472
+ optionsObject,
1473
+ viewData: viewResponse,
1474
+ totalRows: dataResponse?.length ?? 0,
1475
+ onToggleColumnOptional,
1476
+ typeTable,
1477
+ isLoading,
1478
+ isFetched,
1479
+ isPlaceholderData,
1480
+ page,
1481
+ pageLimit,
1482
+ groupByList,
1483
+ selectedRowKeys,
1484
+ domain: domainList,
1485
+ setPage,
1486
+ setDomain,
1487
+ setPageLimit,
1488
+ setGroupByList,
1489
+ setSelectedRowKeys,
1490
+ searchController: searchControllers,
1491
+ specification
1492
+ };
1493
+ };
1494
+
1495
+ // src/widget/basic/many2many-tags-field/controller.ts
1496
+ import { useCallback as useCallback5, useEffect as useEffect11, useMemo as useMemo9, useState as useState8 } from "react";
1497
+
1498
+ // src/constants.ts
1499
+ var constants_exports = {};
1500
+ __reExport(constants_exports, constants_star);
1501
+ import * as constants_star from "@fctc/interface-logic/constants";
1502
+
1503
+ // src/widget/basic/many2many-tags-field/controller.ts
1504
+ var many2manyTagsController = (props) => {
1505
+ const {
1506
+ relation,
1507
+ domain,
1508
+ options: optionsFields,
1509
+ widget,
1510
+ formValues,
1511
+ service,
1512
+ xNode,
1513
+ context: fieldContext,
1514
+ onChange,
1515
+ methods,
1516
+ name
1517
+ } = props;
1518
+ const isUser = relation === "res.users" || relation === "res.partner";
1519
+ const { env } = (0, provider_exports.useEnv)();
1520
+ const { action } = useAppProvider();
1521
+ const { useGetSelection: useGetSelection2 } = (0, provider_exports.useService)();
1522
+ const [options, setOptions] = useState8([]);
1523
+ const [domainObject, setDomainObject] = useState8(null);
1524
+ const [isShowModalMany2Many, setIsShowModalMany2Many] = useState8(false);
1525
+ const addtionalFields = optionsFields ? (0, utils_exports.evalJSONContext)(optionsFields) : null;
1526
+ const contextObject = {
1527
+ ...(0, utils_exports.evalJSONContext)(action?.context) || {},
1528
+ ...fieldContext ?? {},
1529
+ ...env?.context
1530
+ };
1531
+ const parsedFormValues = useMemo9(
1532
+ () => JSON.parse(
1533
+ JSON.stringify({
1534
+ ...formValues,
1535
+ ...contextObject,
1536
+ context: contextObject,
1537
+ parent: { ...formValues }
1538
+ })
1539
+ ) ?? {},
1540
+ [formValues, contextObject]
1541
+ );
1542
+ useEffect11(() => {
1543
+ const newDomain = (0, utils_exports.evalJSONDomain)(domain, parsedFormValues);
1544
+ setDomainObject(
1545
+ (prev) => JSON.stringify(prev) === JSON.stringify(newDomain) ? prev : newDomain
1546
+ );
1547
+ }, [domain, parsedFormValues]);
1548
+ const data = {
1549
+ model: relation ?? "",
1550
+ domain: domainObject,
1551
+ specification: {
1552
+ id: {},
1553
+ name: {},
1554
+ display_name: {},
1555
+ ...widget && constants_exports.WIDGETAVATAR[widget] ? { image_256: {} } : {},
1556
+ ...widget && constants_exports.WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
1557
+ },
1558
+ context: env.context
1559
+ };
1560
+ const queryKey = [`data_${relation}`, domainObject];
1561
+ const {
1562
+ data: dataOfSelection,
1563
+ refetch,
1564
+ isFetching
1565
+ } = useGetSelection2({
1566
+ data,
1567
+ queryKey,
1568
+ service,
1569
+ xNode,
1570
+ enabled: false
1571
+ });
1572
+ const selectOptions = useMemo9(() => {
1573
+ return dataOfSelection?.records?.map((val) => ({
1574
+ value: val.id,
1575
+ label: val.name ?? val.display_name,
1576
+ ...val
1577
+ })) || [];
1578
+ }, [dataOfSelection]);
1579
+ useEffect11(() => {
1580
+ setOptions(selectOptions);
1581
+ }, [selectOptions]);
1582
+ const fetchMoreOptions = useCallback5(() => {
1583
+ refetch();
1584
+ }, [refetch]);
1585
+ const transfer = (data2) => {
1586
+ return data2?.map((val) => ({
1587
+ id: val.value,
1588
+ display_name: val.label
1589
+ })) || [];
1590
+ };
1591
+ const handleChooseRecord = useCallback5(
1592
+ (idRecord) => {
1593
+ const newOption = options.find(
1594
+ (option) => option.value === idRecord
1595
+ );
1596
+ setIsShowModalMany2Many(false);
1597
+ },
1598
+ [options, methods, name, onChange]
1599
+ );
1600
+ const handleClose = useCallback5(() => setIsShowModalMany2Many(false), []);
1601
+ return {
1602
+ options,
1603
+ transfer,
1604
+ isUser,
1605
+ isFetching,
1606
+ fetchMoreOptions,
1607
+ domainObject,
1608
+ setDomainObject,
1609
+ handleChooseRecord,
1610
+ handleClose,
1611
+ isShowModalMany2Many,
1612
+ setIsShowModalMany2Many
1613
+ };
1614
+ };
1615
+
1616
+ // src/widget/basic/status-bar-field/controller.ts
1617
+ import { useState as useState9 } from "react";
1618
+ var durationController = (props) => {
1619
+ const { relation, domain, formValues, name, id, model, onRefetch, enabled } = props;
1620
+ const specification = {
1621
+ id: 0,
1622
+ name: "",
1623
+ fold: ""
1624
+ };
1625
+ const { useGetListData: useGetListData2, useChangeStatus: useChangeStatus2 } = (0, provider_exports.useService)();
1626
+ const { env } = (0, provider_exports.useEnv)();
1627
+ const [disabled, setDisabled] = useState9(false);
1628
+ const [modelStatus, setModalStatus] = useState9(false);
1629
+ const queryKey = [`data-status-duration`, specification];
1630
+ const listDataProps = {
1631
+ model: relation,
1632
+ specification,
1633
+ domain: (0, utils_exports.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues))),
1634
+ limit: 10,
1635
+ offset: 0,
1636
+ fields: "",
1637
+ groupby: [],
1638
+ context: {
1639
+ lang: env.context.lang
1640
+ },
1641
+ sort: ""
1642
+ };
1643
+ const { data: dataResponse } = useGetListData2(
1644
+ listDataProps,
1645
+ queryKey,
1646
+ enabled
1647
+ );
1648
+ const { mutate: fetchChangeStatus } = useChangeStatus2();
1649
+ const handleClick = async (stage_id) => {
1650
+ setDisabled(true);
1651
+ if (stage_id) {
1652
+ fetchChangeStatus(
1653
+ {
1654
+ data: {
1655
+ stage_id,
1656
+ name,
1657
+ id,
1658
+ model,
1659
+ lang: env.context.lang
1660
+ }
1661
+ },
1662
+ {
1663
+ onSuccess: (res) => {
1664
+ if (res) {
1665
+ setDisabled(false);
1666
+ onRefetch && onRefetch();
1667
+ }
1668
+ }
1669
+ }
1670
+ );
1671
+ }
1672
+ };
1673
+ return {
1674
+ dataResponse,
1675
+ handleClick,
1676
+ disabled,
1677
+ modelStatus,
1678
+ setModalStatus
1679
+ };
1680
+ };
1681
+
1682
+ // src/widget/basic/priority-field/controller.ts
1683
+ var priorityFieldController = (props) => {
1684
+ const { name, model, index, actionData, context, onChange, specification } = props;
1685
+ const _context = { ...(0, utils_exports.evalJSONContext)(actionData?.context) };
1686
+ const contextObject = { ...context, ..._context };
1687
+ const { useSave: useSave2 } = (0, provider_exports.useService)();
1688
+ const { mutateAsync: fetchSave } = useSave2();
1689
+ const savePriorities = async ({
1690
+ value,
1691
+ resetPriority
1692
+ }) => {
1693
+ const priorityValue = value <= 0 ? 0 : value - 1;
1694
+ try {
1695
+ fetchSave({
1696
+ ids: index ? [index] : [],
1697
+ data: { [String(name)]: String(priorityValue) },
1698
+ model: String(model),
1699
+ context: contextObject,
1700
+ specification
1701
+ });
1702
+ if (typeof onChange === "function") {
1703
+ onChange(String(name), String(priorityValue));
1704
+ }
1705
+ } catch (error) {
1706
+ if (resetPriority) {
1707
+ resetPriority();
1708
+ }
1709
+ }
1710
+ };
1711
+ return {
1712
+ savePriorities
1713
+ };
1714
+ };
1715
+
1716
+ // src/widget/basic/download-file-field/controller.ts
1717
+ import { useId, useState as useState10 } from "react";
1718
+ var downloadFileController = () => {
1719
+ const inputId = useId();
1720
+ const [file, setFile] = useState10(null);
1721
+ const handleFileChange = (e) => {
1722
+ setFile(e.target.files[0]);
1723
+ };
1724
+ const handleFileDownload = () => {
1725
+ const url = URL.createObjectURL(file);
1726
+ const link = document.createElement("a");
1727
+ link.href = url;
1728
+ link.download = file.name;
1729
+ document.body.appendChild(link);
1730
+ link.click();
1731
+ document.body.removeChild(link);
1732
+ };
1733
+ return {
1734
+ inputId,
1735
+ file,
1736
+ handleFileChange,
1737
+ handleFileDownload
1738
+ };
1739
+ };
1740
+
1741
+ // src/widget/basic/download-binary-field/controller.ts
1742
+ var downLoadBinaryController = (props) => {
1743
+ const { value, defaultValue, formValues } = props;
1744
+ const downloadFile = async (url, filename) => {
1745
+ try {
1746
+ const response = await fetch(url);
1747
+ if (!response.ok) throw new Error(`Failed to fetch ${url}`);
1748
+ const contentType = response.headers.get("Content-Type") || "";
1749
+ let ext = "";
1750
+ if (contentType.includes("pdf")) ext = ".pdf";
1751
+ else if (contentType.includes("png")) ext = ".png";
1752
+ else if (contentType.includes("jpeg") || contentType.includes("jpg"))
1753
+ ext = ".jpg";
1754
+ else if (contentType.includes("zip")) ext = ".zip";
1755
+ else if (contentType.includes("msword")) ext = ".doc";
1756
+ else if (contentType.includes("spreadsheet")) ext = ".xls";
1757
+ else if (contentType.includes("json")) ext = ".json";
1758
+ else if (contentType.includes("text")) ext = ".txt";
1759
+ else {
1760
+ ext = "";
1761
+ }
1762
+ const blob = await response.blob();
1763
+ const urlBlob = window.URL.createObjectURL(blob);
1764
+ const link = document.createElement("a");
1765
+ link.href = urlBlob;
1766
+ link.download = (filename || "file") + ext;
1767
+ document.body.appendChild(link);
1768
+ link.click();
1769
+ document.body.removeChild(link);
1770
+ window.URL.revokeObjectURL(urlBlob);
1771
+ } catch (error) {
1772
+ console.error("File download failed:", error);
1773
+ }
1774
+ };
1775
+ const handleFileDownload = async (e) => {
1776
+ e.stopPropagation();
1777
+ await downloadFile(value || defaultValue, formValues?.name);
1778
+ };
1779
+ return {
1780
+ handleFileDownload
1781
+ };
1782
+ };
1783
+
1784
+ // src/widget/basic/copy-link-button/controller.ts
1785
+ import { useState as useState11 } from "react";
1786
+ var copyTextToClipboard = async (text) => {
1787
+ if ("clipboard" in navigator) {
1788
+ return await navigator.clipboard.writeText(text);
1789
+ } else {
1790
+ const textArea = document.createElement("textarea");
1791
+ textArea.value = text;
1792
+ textArea.style.position = "fixed";
1793
+ document.body.appendChild(textArea);
1794
+ textArea.focus();
1795
+ textArea.select();
1796
+ try {
1797
+ document.execCommand("copy");
1798
+ } finally {
1799
+ document.body.removeChild(textArea);
1800
+ }
1801
+ }
1802
+ };
1803
+ var copyLinkButtonController = (props) => {
1804
+ const { value, defaultValue } = props;
1805
+ const [isCopied, setIsCopied] = useState11(false);
1806
+ const handleCopyToClipboard = async (value2) => {
1807
+ await copyTextToClipboard(value2);
1808
+ setIsCopied(true);
1809
+ setTimeout(() => setIsCopied(false), 2e3);
1810
+ };
1811
+ const propValue = value || defaultValue;
1812
+ return {
1813
+ isCopied,
1814
+ handleCopyToClipboard,
1815
+ propValue
1816
+ };
1817
+ };
1818
+
1819
+ // src/widget/basic/color-field/color-controller.ts
1820
+ var colorFieldController = (props) => {
1821
+ const { value, isForm, name, formValues, idForm, model, actionData } = props;
1822
+ const { env } = (0, provider_exports.useEnv)();
1823
+ const { useSave: useSave2 } = (0, provider_exports.useService)();
1824
+ const _context = { ...(0, utils_exports.evalJSONContext)(actionData?.context) || {} };
1825
+ const contextObject = { ...env.context, ..._context };
1826
+ const idDefault = isForm ? idForm : formValues?.id;
1827
+ const { mutate: onSave } = useSave2();
1828
+ const savePickColor = async (colorObject) => {
1829
+ const { id } = colorObject;
1830
+ if (value === id) return;
1831
+ try {
1832
+ onSave({
1833
+ ids: idDefault !== null ? [idDefault] : [],
1834
+ model: String(model),
1835
+ data: { [String(name)]: id },
1836
+ specification: {
1837
+ name: {},
1838
+ color: {}
1839
+ },
1840
+ context: contextObject
1841
+ });
1842
+ } catch (error) {
1843
+ console.log(error);
1844
+ }
1845
+ };
1846
+ return {
1847
+ savePickColor
1848
+ };
1849
+ };
1850
+
1851
+ // src/widget/basic/binary-field/controller.ts
1852
+ import { useEffect as useEffect12, useState as useState12 } from "react";
1853
+ var binaryFieldController = (props) => {
1854
+ const {
1855
+ name,
1856
+ methods,
1857
+ readonly = false,
1858
+ filename,
1859
+ onChange: handleOnchange,
1860
+ service,
1861
+ xNode,
1862
+ path,
1863
+ rootField,
1864
+ index,
1865
+ value
1866
+ } = props;
1867
+ const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
1868
+ const { mutateAsync } = useUploadFile2();
1869
+ const [url, setUrl] = useState12(value || null);
1870
+ const [fileInfo, setFileInfo] = useState12(null);
1871
+ useEffect12(() => {
1872
+ if (!value) {
1873
+ setUrl(null);
1874
+ setFileInfo(null);
1875
+ return;
1876
+ }
1877
+ fetchFileMeta(value);
1878
+ }, [value]);
1879
+ const formatSize = (bytes) => {
1880
+ if (bytes < 1024) return bytes + " B";
1881
+ let kb = bytes / 1024;
1882
+ if (kb < 1024) return kb.toFixed(2) + " KB";
1883
+ let mb = kb / 1024;
1884
+ if (mb < 1024) return mb.toFixed(2) + " MB";
1885
+ return (mb / 1024).toFixed(2) + " GB";
1886
+ };
1887
+ const fetchFileMeta = async (url2) => {
1888
+ try {
1889
+ const res = await fetch(url2, { method: "HEAD" });
1890
+ const size = res.headers.get("content-length") || "";
1891
+ let type = res.headers.get("content-type") || "";
1892
+ const date = res.headers.get("last-modified") || "";
1893
+ const guessed = guessTypeFromUrl(url2);
1894
+ if (guessed) type = guessed;
1895
+ setFileInfo({
1896
+ size: size ? formatSize(Number(size)) : "--",
1897
+ type,
1898
+ date: date ? new Date(date).toLocaleString() : "--"
1899
+ });
1900
+ setUrl(url2);
1901
+ } catch (e) {
1902
+ console.error(e);
1903
+ }
1904
+ };
1905
+ const onUploadFile = async (formData) => {
1906
+ const res = await mutateAsync({
1907
+ formData,
1908
+ service,
1909
+ xNode,
1910
+ path
1911
+ });
1912
+ const url2 = res?.url;
1913
+ methods?.setValue(name, url2, { shouldDirty: true });
1914
+ handleOnchange && handleOnchange(name ?? "", url2);
1915
+ if (filename) {
1916
+ methods?.setValue(
1917
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1918
+ url2?.split("/").pop(),
1919
+ { shouldDirty: true }
1920
+ );
1921
+ handleOnchange && handleOnchange(
1922
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1923
+ url2?.split("/").pop()
1924
+ );
1925
+ }
1926
+ setUrl(url2);
1927
+ fetchFileMeta(url2);
1928
+ return url2;
1929
+ };
1930
+ const onDeleteFile = () => {
1931
+ if (filename) {
1932
+ methods?.setValue(
1933
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1934
+ null,
1935
+ { shouldDirty: true }
1936
+ );
1937
+ handleOnchange && handleOnchange(
1938
+ rootField ? `${rootField?.name}.${index}.${filename}` : filename,
1939
+ null
1940
+ );
1941
+ }
1942
+ setUrl(null);
1943
+ setFileInfo(null);
1944
+ methods?.setValue(name, null, { shouldDirty: true });
1945
+ handleOnchange && handleOnchange(name ?? "", null);
1946
+ };
1947
+ return {
1948
+ onUploadFile,
1949
+ onDeleteFile,
1950
+ fileInfo,
1951
+ url
1952
+ };
1953
+ };
1954
+
1955
+ // src/widget/basic/many2many-binary-field/controller.tsx
1956
+ import { useId as useId2, useRef as useRef3, useState as useState13 } from "react";
1957
+ var many2manyBinaryController = (props) => {
1958
+ const {
1959
+ name,
1960
+ methods,
1961
+ value,
1962
+ onChange: handleOnchange,
1963
+ service,
1964
+ xNode,
1965
+ path
1966
+ } = props;
1967
+ const inputId = useId2();
1968
+ const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
1969
+ const { mutateAsync } = useUploadFile2();
1970
+ const binaryRef = useRef3(null);
1971
+ const [initialFiles, setInitialFiles] = useState13(
1972
+ Array.isArray(value) ? value : value ? [value] : []
1973
+ );
1974
+ const checkIsImageLink = (url) => {
1975
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
1976
+ return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
1977
+ };
1978
+ const sanitizeForBE = (list) => list.filter((x) => x?.datas && !isBlobUrl(x.datas)).map((x) => ({ name: x.name, datas: x.datas, mimetype: x.mimetype }));
1979
+ const isBase64Image = (str) => {
1980
+ const base64Regex = /^data:image\/(png|jpeg|jpg|gif|webp);base64,/;
1981
+ if (!base64Regex.test(str)) {
1982
+ return false;
1983
+ }
1984
+ try {
1985
+ const base64Data = str.split(",")[1];
1986
+ return !!base64Data && atob(base64Data).length > 0;
1987
+ } catch (error) {
1988
+ return false;
1989
+ }
1990
+ };
1991
+ const handleFileChange = async (files, e, oldValues) => {
1992
+ try {
1993
+ const uploadedUrls = await Promise.all(
1994
+ files.map(async (f) => {
1995
+ const formData = new FormData();
1996
+ formData.append("file", f);
1997
+ const res = await mutateAsync({ formData, service, xNode, path });
1998
+ return res?.url;
1999
+ })
2000
+ );
2001
+ const uploadedItems = files.map((f, i) => ({
2002
+ name: f.name,
2003
+ datas: uploadedUrls[i] ?? "",
2004
+ mimetype: f.type
2005
+ }));
2006
+ const finalList = [...oldValues, ...uploadedItems];
2007
+ methods?.setValue(name, finalList, { shouldDirty: true });
2008
+ const payloadForBE = sanitizeForBE(finalList);
2009
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
2010
+ } catch (err) {
2011
+ console.error(err);
2012
+ } finally {
2013
+ e.target.value = "";
2014
+ }
2015
+ };
2016
+ const handleRemoveAt = (idx) => {
2017
+ const current = methods?.getValues(name) || [];
2018
+ const next = current.filter((_, i) => i !== idx);
2019
+ setInitialFiles((p) => p.filter((_, i) => i !== idx));
2020
+ methods?.setValue(name, next.length ? next : null, { shouldDirty: true });
2021
+ const payloadForBE = next.length ? sanitizeForBE(next) : null;
2022
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
2023
+ };
2024
+ const handleRemoveAll = () => {
2025
+ setInitialFiles([]);
2026
+ methods?.setValue(name, null, { shouldDirty: true });
2027
+ handleOnchange && handleOnchange(name ?? "", null);
2028
+ };
2029
+ return {
2030
+ inputId,
2031
+ initialFiles,
2032
+ binaryRef,
2033
+ handleFileChange,
2034
+ handleRemoveAt,
2035
+ handleRemoveAll,
2036
+ checkIsImageLink,
2037
+ setInitialFiles
2038
+ };
2039
+ };
2040
+
2041
+ // src/widget/basic/provider-einvoice-field/controller.ts
2042
+ var providerEinvoiceFieldController = (props) => {
2043
+ const { relation, formValues, options: fieldOptions, xNode } = props;
2044
+ const { env } = (0, provider_exports.useEnv)();
2045
+ const { action } = useAppProvider();
2046
+ const { useGetSelection: useGetSelection2 } = (0, provider_exports.useService)();
2047
+ const contextObject = {
2048
+ ...(typeof action?.context === "string" ? (0, utils_exports.evalJSONContext)(action?.context) : action?.context) || {},
2049
+ ...env?.context
2050
+ };
2051
+ const optionsObject = typeof fieldOptions === "string" ? (0, utils_exports.evalJSONContext)(fieldOptions, {
2052
+ ...formValues,
2053
+ ...contextObject,
2054
+ context: contextObject,
2055
+ parent: { ...formValues }
2056
+ }) : fieldOptions;
2057
+ const data = {
2058
+ model: optionsObject?.model,
2059
+ domain: optionsObject?.domain,
2060
+ context: {
2061
+ ...contextObject,
2062
+ ...optionsObject?.context
2063
+ },
2064
+ specification: optionsObject?.specification
2065
+ };
2066
+ const { data: listDataCard } = useGetSelection2({
2067
+ data,
2068
+ queryKey: [`data_${relation}`],
2069
+ enabled: true,
2070
+ service: optionsObject?.service,
2071
+ xNode
2072
+ });
2073
+ return {
2074
+ listDataCard
2075
+ };
2076
+ };
2077
+
2078
+ // src/widget/advance/table/table-head/controller.ts
2079
+ import { useMemo as useMemo10, useRef as useRef4 } from "react";
2080
+ var tableHeadController = (props) => {
2081
+ const {
2082
+ typeTable,
2083
+ rows,
2084
+ tableRef,
2085
+ groupByList,
2086
+ selectedRowKeys,
2087
+ setSelectedRowKeys
2088
+ } = props;
2089
+ const { rowIds: recordIds } = useGetRowIds(tableRef);
2090
+ const selectedRowKeysRef = useRef4(recordIds);
2091
+ const isGroupTable = typeTable === "group";
2092
+ const recordsCheckedGroup = useMemo10(() => {
2093
+ if (!rows || !groupByList) return 0;
2094
+ const groupBy = typeof groupByList === "object" ? groupByList?.contexts?.[0]?.group_by : void 0;
2095
+ return countSum(rows, groupBy);
2096
+ }, [rows, groupByList]);
2097
+ const isAllGroupChecked = useMemo10(() => {
2098
+ if (!isGroupTable || !selectedRowKeys?.length) return false;
2099
+ const selectedLength = selectedRowKeys.filter((id) => id !== -1).length;
2100
+ const allRecordsSelected = recordIds.length === selectedRowKeys.length ? recordIds.length === selectedLength : false;
2101
+ const allGroupsSelected = recordsCheckedGroup === selectedRowKeys.length;
2102
+ return allGroupsSelected || allRecordsSelected;
2103
+ }, [isGroupTable, selectedRowKeys, recordIds, recordsCheckedGroup]);
2104
+ const isAllNormalChecked = useMemo10(() => {
2105
+ if (isGroupTable || !selectedRowKeys?.length || !rows?.length) return false;
2106
+ return selectedRowKeys.length === rows.length && selectedRowKeys.every(
2107
+ (id) => rows.some((record) => record.id === id)
2108
+ );
2109
+ }, [isGroupTable, selectedRowKeys, rows]);
2110
+ const checkedAll = isAllGroupChecked || isAllNormalChecked;
2111
+ const handleCheckBoxAll = (event) => {
2112
+ if (event?.target?.checked && typeTable === "list") {
2113
+ const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
2114
+ setSelectedRowKeys(allRowKeys);
2115
+ } else if (event?.target?.checked && typeTable === "group") {
2116
+ const rowsIDs = document.querySelectorAll("tr[data-row-id]");
2117
+ const ids = Array.from(rowsIDs)?.map(
2118
+ (row) => Number(row?.getAttribute("data-row-id"))
2119
+ );
2120
+ if (ids?.length > 0) {
2121
+ setSelectedRowKeys(ids);
2122
+ } else {
2123
+ const sum = countSum(
2124
+ rows,
2125
+ typeof groupByList === "object" ? groupByList?.contexts?.[0]?.group_by : void 0
2126
+ );
2127
+ const keys = Array.from({ length: sum }, (_) => void 0);
2128
+ setSelectedRowKeys(keys);
2129
+ }
2130
+ if (selectedRowKeysRef) {
2131
+ selectedRowKeysRef.current = [];
2132
+ }
2133
+ } else {
2134
+ setSelectedRowKeys([]);
2135
+ }
2136
+ };
2137
+ return {
2138
+ handleCheckBoxAll,
2139
+ checkedAll,
2140
+ selectedRowKeysRef
2141
+ };
2142
+ };
2143
+
2144
+ // src/widget/advance/table/table-view/controller.ts
2145
+ import { useCallback as useCallback6, useEffect as useEffect13, useMemo as useMemo11, useState as useState14 } from "react";
2146
+ var tableController = ({ data }) => {
2147
+ const [rows, setRows] = useState14([]);
2148
+ const [columnVisibility, setColumnVisibility] = useState14({});
2149
+ const dataModelFields = useMemo11(() => {
2150
+ return data?.fields?.map((field) => ({
2151
+ ...data.dataModel?.[field?.name],
2152
+ ...field,
2153
+ string: field?.string || data.dataModel?.[field?.name]?.string
2154
+ })) ?? [];
2155
+ }, [data?.fields, data?.dataModel]);
2156
+ const mergeFields = useMemo11(
2157
+ () => mergeButtons(dataModelFields),
2158
+ [dataModelFields]
2159
+ );
2160
+ const transformData = useCallback6(
2161
+ (dataList) => {
2162
+ if (!dataList) return [];
2163
+ return dataList.map((item) => {
2164
+ const transformedItem = { ...item };
2165
+ Object.keys(item).forEach((field) => {
2166
+ if (field !== "__domain") {
2167
+ if (item[field] && typeof item[field] === "object" && item[field].display_name) {
2168
+ transformedItem[field] = item[field];
2169
+ } else if (Array.isArray(item[field]) && item[field].length > 0) {
2170
+ if (data.typeTable === "group" && item[field]?.length === 2 && typeof item[field]?.[1] === "string") {
2171
+ transformedItem["string"] = item[field]?.[1];
2172
+ }
2173
+ transformedItem[field] = item[field];
2174
+ }
2175
+ }
2176
+ });
2177
+ return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
2178
+ });
2179
+ },
2180
+ [data?.typeTable]
2181
+ );
2182
+ useEffect13(() => {
2183
+ setRows(transformData(data?.records));
2184
+ }, [data?.records, transformData]);
2185
+ const columns = useMemo11(() => {
2186
+ try {
2187
+ return mergeFields?.filter((item) => {
2188
+ return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? utils_exports.domainHelper.matchDomains(
2189
+ data.context,
2190
+ item?.column_invisible
2191
+ ) : item?.invisible ? utils_exports.domainHelper.matchDomains(data.context, item?.invisible) : false);
2192
+ })?.map((field) => {
2193
+ const overridden = columnVisibility[field?.name];
2194
+ return {
2195
+ name: field?.name,
2196
+ optional: overridden ?? field?.optional,
2197
+ title: field?.type_co === "button" ? "" : field?.string,
2198
+ field: { ...field }
2199
+ };
2200
+ }) ?? [];
2201
+ } catch (error) {
2202
+ console.error("Error in useTable:", error);
2203
+ return [];
2204
+ }
2205
+ }, [mergeFields, data?.context, columnVisibility]);
2206
+ const onToggleColumnOptional = useCallback6((item) => {
2207
+ setColumnVisibility((prev) => ({
2208
+ ...prev,
2209
+ [item?.name]: item?.optional === "show" ? "hide" : "show"
2210
+ }));
2211
+ }, []);
2212
+ return {
2213
+ rows,
2214
+ columns,
2215
+ onToggleColumnOptional,
2216
+ typeTable: data?.typeTable
2217
+ };
2218
+ };
2219
+
2220
+ // src/widget/advance/table/table-group/controller.ts
2221
+ import { useMemo as useMemo12, useState as useState15 } from "react";
2222
+ var tableGroupController = (props) => {
2223
+ const { env } = (0, provider_exports.useEnv)();
2224
+ const { useGetListData: useGetListData2 } = (0, provider_exports.useService)();
2225
+ const {
2226
+ columns,
2227
+ row,
2228
+ model,
2229
+ viewData,
2230
+ level,
2231
+ specification,
2232
+ context,
2233
+ checkedAll,
2234
+ groupByList,
2235
+ setSelectedRowKeys
2236
+ } = props;
2237
+ const [pageGroup, setPageGroup] = useState15(0);
2238
+ const [isShowGroup, setIsShowGroup] = useState15(false);
2239
+ const [colEmptyGroup, setColEmptyGroup] = useState15({
2240
+ fromStart: 1,
2241
+ fromEnd: 1
2242
+ });
2243
+ const domain = row?.__domain;
2244
+ const processedData = useMemo12(() => {
2245
+ const calculateColSpanEmpty = () => {
2246
+ const startIndex = columns.findIndex(
2247
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
2248
+ );
2249
+ const endIndex = columns.findLastIndex(
2250
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
2251
+ );
2252
+ const fromStart = startIndex === -1 ? columns.length : startIndex;
2253
+ const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
2254
+ setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
2255
+ return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
2256
+ };
2257
+ return calculateColSpanEmpty();
2258
+ }, [columns, row]);
2259
+ const shouldFetchData = useMemo12(() => {
2260
+ return !!isShowGroup;
2261
+ }, [isShowGroup]);
2262
+ const enabled = shouldFetchData && !!processedData;
2263
+ const listDataProps = {
2264
+ model,
2265
+ specification,
2266
+ domain,
2267
+ context,
2268
+ offset: pageGroup * 10,
2269
+ fields: groupByList?.fields,
2270
+ groupby: [groupByList?.contexts[level]?.group_by],
2271
+ limit: 10
2272
+ };
2273
+ const queryKey = [
2274
+ `data-${model}-level_${level}-row-${row?.id}`,
2275
+ specification,
2276
+ domain,
2277
+ pageGroup
2278
+ ];
2279
+ const {
2280
+ data: dataGroup,
2281
+ isFetched: isDataGroupFetched,
2282
+ isLoading,
2283
+ isFetching,
2284
+ isPlaceholderData: isDataPlaceHolder
2285
+ } = useGetListData2(listDataProps, queryKey, enabled);
2286
+ const {
2287
+ columns: columnsGroup,
2288
+ rows: rowsGroup,
2289
+ typeTable: typeTableGroup
2290
+ } = tableController({
2291
+ data: {
2292
+ fields: viewData?.views?.list?.fields,
2293
+ records: dataGroup?.records ?? dataGroup?.groups,
2294
+ dataModel: viewData?.models?.[model],
2295
+ context: env.context,
2296
+ typeTable: dataGroup?.groups ? "group" : "list"
2297
+ }
2298
+ });
2299
+ const group_by_field_name = groupByList?.contexts[level - 1]?.group_by;
2300
+ 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(
2301
+ (selectItem) => selectItem?.[0] === row[group_by_field_name]
2302
+ )?.[1] : row[group_by_field_name];
2303
+ const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
2304
+ return {
2305
+ // onExpandChildGroup,
2306
+ colEmptyGroup,
2307
+ isShowGroup,
2308
+ isDataGroupFetched,
2309
+ isDataPlaceHolder,
2310
+ // nameGroupWithCount,
2311
+ columnsGroup,
2312
+ rowsGroup,
2313
+ dataGroup,
2314
+ pageGroup,
2315
+ setPageGroup,
2316
+ typeTableGroup
2317
+ };
2318
+ };
2319
+
2320
+ // src/widget/advance/search/controller.ts
2321
+ import { useState as useState16, useEffect as useEffect14, useCallback as useCallback7 } from "react";
2322
+ var searchController = ({
2323
+ viewData,
2324
+ model,
2325
+ domain,
2326
+ context,
2327
+ fieldsList,
2328
+ validateAndParseDate,
2329
+ moment
2330
+ }) => {
2331
+ const { env } = (0, provider_exports.useEnv)();
2332
+ const [filterBy, setFilterBy] = useState16([]);
2333
+ const [searchBy, setSearchBy] = useState16(null);
2334
+ const [groupBy, setGroupBy] = useState16(null);
2335
+ const [selectedTags, setSelectedTags] = useState16(null);
2336
+ const [searchString, setSearchString] = useState16("");
2337
+ const [searchMap, setSearchMap] = useState16({});
2338
+ const [hoveredIndex, setHoveredIndex] = useState16(0);
2339
+ const [hoveredIndexSearchList, setHoveredIndexSearchList] = useState16(0);
2340
+ const actionContext = typeof context === "string" ? (0, utils_exports.evalJSONContext)(context) : context;
2341
+ const contextSearch = { ...env.context, ...actionContext };
2342
+ const domainAction = domain ? Array.isArray(domain) ? [...domain] : (0, utils_exports.evalJSONDomain)(domain, contextSearch) : [];
2343
+ const resetAllStateSearch = () => {
2344
+ setFilterBy([]);
2345
+ setGroupBy([]);
2346
+ setSearchBy([]);
2347
+ setSelectedTags(null);
2348
+ setSearchString("");
2349
+ setSearchMap({});
2350
+ };
2351
+ const fetchData = async () => {
2352
+ if (viewData) {
2353
+ try {
2354
+ const dataModel = viewData?.models?.[model];
2355
+ const searchViews = viewData?.views?.search;
2356
+ const searchByItems = searchViews?.search_by?.filter(
2357
+ (item) => !utils_exports.domainHelper.matchDomains(contextSearch, item.invisible)
2358
+ )?.map(
2359
+ ({
2360
+ string,
2361
+ name,
2362
+ filter_domain,
2363
+ operator,
2364
+ widget,
2365
+ class: classSearchItem,
2366
+ placeholder
2367
+ }, index) => ({
2368
+ placeholder,
2369
+ class: classSearchItem,
2370
+ dataIndex: index,
2371
+ title: string ?? dataModel?.[name]?.string,
2372
+ name: name ?? dataModel?.[name]?.name,
2373
+ filter_domain,
2374
+ operator,
2375
+ widget,
2376
+ type: dataModel?.[name]?.type
2377
+ })
2378
+ );
2379
+ const filterByItems = searchViews?.filter_by.filter((item) => {
2380
+ return !utils_exports.domainHelper.matchDomains(contextSearch, item?.invisible);
2381
+ })?.map((item) => ({ ...item, active: false }));
2382
+ const groupByItems = searchViews?.group_by.filter(
2383
+ (item) => !utils_exports.domainHelper.matchDomains(contextSearch, item?.invisible)
2384
+ ).map((item) => ({
2385
+ ...item,
2386
+ string: item.string ?? viewData?.models?.[model]?.[item?.name?.split("group_by_")?.[1]]?.string
2387
+ }));
2388
+ setSearchBy(searchByItems);
2389
+ setFilterBy(filterByItems);
2390
+ setGroupBy(groupByItems);
2391
+ } catch (error) {
2392
+ console.error("Error fetching data:", error);
2393
+ }
2394
+ }
2395
+ };
2396
+ useEffect14(() => {
2397
+ fetchData();
2398
+ }, [model, viewData]);
2399
+ const onChangeSearchInput = (search_string) => {
2400
+ setSearchString(search_string);
2401
+ };
2402
+ const removeKeyFromSearchMap = ({
2403
+ key,
2404
+ item
2405
+ }) => {
2406
+ const values = searchMap[key];
2407
+ if (!values) return searchMap;
2408
+ const newSearchMap = { ...searchMap };
2409
+ if (item) {
2410
+ const filtered = values.filter((value) => value.name !== item.name);
2411
+ if (filtered.length > 0) {
2412
+ newSearchMap[key] = filtered;
2413
+ } else {
2414
+ delete newSearchMap[key];
2415
+ }
2416
+ } else {
2417
+ delete newSearchMap[key];
2418
+ }
2419
+ setSearchMap(newSearchMap);
2420
+ };
2421
+ const updateSearchMap = ({ key, item }) => {
2422
+ const newSearchMap = { ...searchMap };
2423
+ const currentValues = searchMap[key] ?? [];
2424
+ newSearchMap[key] = [...currentValues, item];
2425
+ setSearchMap(newSearchMap);
2426
+ };
2427
+ const removeSearchItems = (key, item) => {
2428
+ removeKeyFromSearchMap({ key: String(key), item });
2429
+ };
2430
+ const addSearchItems = (key, newItem) => {
2431
+ updateSearchMap({ key, item: newItem });
2432
+ };
2433
+ const formatDomain = () => {
2434
+ if (domainAction) {
2435
+ const domain2 = [];
2436
+ if (Array.isArray(domainAction) && domainAction.length > 0) {
2437
+ if (Object.keys(searchMap).some((key) => !key.includes(constants_exports.SearchType.GROUP))) {
2438
+ domain2.push("&");
2439
+ }
2440
+ domainAction.forEach((domainItem) => {
2441
+ domain2.push(domainItem);
2442
+ });
2443
+ }
2444
+ Object.keys(searchMap).forEach((key, keyIndex, keys) => {
2445
+ if (!key?.includes(constants_exports.SearchType.GROUP)) {
2446
+ if (keys.length > 1 && keyIndex < keys.length - 1) {
2447
+ domain2.push("&");
2448
+ }
2449
+ const valuesOfKey = searchMap[key];
2450
+ valuesOfKey.forEach((value, index) => {
2451
+ if (index < valuesOfKey.length - 1) {
2452
+ domain2.push("|");
2453
+ }
2454
+ if (value.domain) {
2455
+ domain2.push(...value.domain);
2456
+ return;
2457
+ }
2458
+ let valueDomainItem = value?.value;
2459
+ if (value?.modelType === "date") {
2460
+ valueDomainItem = validateAndParseDate(value?.value);
2461
+ } else if (value?.modelType === "datetime") {
2462
+ if (value?.operator === "<=" || value?.operator === "<") {
2463
+ const parsedDate = validateAndParseDate(value?.value, true);
2464
+ const hasTime = moment(value?.value).format("HH:mm:ss") !== "00:00:00";
2465
+ valueDomainItem = hasTime ? moment(parsedDate).format("YYYY-MM-DD HH:mm:ss") : moment(parsedDate).add(1, "day").subtract(1, "second").format("YYYY-MM-DD HH:mm:ss");
2466
+ } else {
2467
+ valueDomainItem = validateAndParseDate(value?.value, true);
2468
+ }
2469
+ }
2470
+ const operator = value?.modelType === "date" || value?.modelType === "datetime" || value?.modelType === "boolean" || value?.modelType === "integer" ? value?.operator ?? "=" : value.operator ?? "ilike";
2471
+ domain2.push([value.name, operator, valueDomainItem]);
2472
+ });
2473
+ }
2474
+ });
2475
+ return [...domain2];
2476
+ }
2477
+ };
2478
+ const setTagSearch = useCallback7(
2479
+ (updatedMap) => {
2480
+ if (!updatedMap) return;
2481
+ const tagsSearch = Object.entries(updatedMap).map(
2482
+ ([key, objValues]) => {
2483
+ const {
2484
+ title,
2485
+ name,
2486
+ groupIndex,
2487
+ type,
2488
+ widget,
2489
+ modelType,
2490
+ dataIndex,
2491
+ date
2492
+ } = objValues[0];
2493
+ if (!key?.includes(constants_exports.SearchType.GROUP)) {
2494
+ const values = objValues?.map((objValue) => objValue.value);
2495
+ return {
2496
+ title,
2497
+ name: type === constants_exports.SearchType.SEARCH ? `${constants_exports.SearchType.SEARCH}_${String(dataIndex)}` : groupIndex ?? name,
2498
+ values,
2499
+ type,
2500
+ widget,
2501
+ modelType,
2502
+ date
2503
+ };
2504
+ } else {
2505
+ const contexts = [];
2506
+ let groupValues = [];
2507
+ objValues?.forEach((objValue) => {
2508
+ const { context: context2, value, active, groupIndex: groupIndex2, isDefault } = objValue;
2509
+ const indexAppend = groupIndex2 != null ? groupIndex2 : viewData?.views?.search?.filters_by?.length ?? 0;
2510
+ contexts.push(
2511
+ ...Array.isArray(context2?.group_by) ? context2.group_by.map((item) => ({ group_by: item })) : [context2]
2512
+ );
2513
+ groupValues[indexAppend] = {
2514
+ contexts: [
2515
+ ...Array.isArray(context2?.group_by) ? context2.group_by.map((item) => ({
2516
+ group_by: item
2517
+ })) : [context2]
2518
+ ],
2519
+ strings: isDefault ? [value] : [...groupValues[indexAppend]?.strings ?? [], value]
2520
+ };
2521
+ });
2522
+ const fields = [
2523
+ ...new Set(fieldsList?.map((item) => item?.name))
2524
+ ];
2525
+ const groupByTag = {
2526
+ title,
2527
+ values: groupValues?.filter(
2528
+ (item) => item !== void 0
2529
+ ),
2530
+ type,
2531
+ contexts,
2532
+ fields
2533
+ };
2534
+ return groupByTag;
2535
+ }
2536
+ }
2537
+ );
2538
+ setSelectedTags(tagsSearch);
2539
+ setSearchString("");
2540
+ },
2541
+ [searchMap]
2542
+ );
2543
+ const removeSearchItemsByType = (type) => {
2544
+ const newSearchMap = {};
2545
+ Object.entries(searchMap).forEach(([key, values]) => {
2546
+ const isGroup = key.includes(constants_exports.SearchType.GROUP);
2547
+ const isFilter = key.includes(constants_exports.SearchType.FILTER);
2548
+ const isSearch = key.includes(constants_exports.SearchType.SEARCH);
2549
+ if (type === constants_exports.SearchType.GROUP && isGroup) return;
2550
+ if (type === constants_exports.SearchType.FILTER && isFilter) return;
2551
+ if (type === constants_exports.SearchType.SEARCH && isSearch) return;
2552
+ newSearchMap[key] = values;
2553
+ });
2554
+ setSearchMap(newSearchMap);
2555
+ };
2556
+ useEffect14(() => {
2557
+ setTagSearch(searchMap);
2558
+ }, [searchMap]);
2559
+ const handleAddTagSearch = (tag) => {
2560
+ const { domain: domain2, groupIndex, value, type, context: context2, dataIndex } = tag;
2561
+ const domainFormat = new utils_exports.domainHelper.Domain(domain2);
2562
+ if (type === constants_exports.SearchType.FILTER) {
2563
+ addSearchItems(`${constants_exports.SearchType.FILTER}_${groupIndex}`, {
2564
+ ...tag,
2565
+ domain: domain2 ? domainFormat.toList(context2) : null
2566
+ });
2567
+ } else if (type === constants_exports.SearchType.SEARCH) {
2568
+ addSearchItems(`${constants_exports.SearchType.SEARCH}_${String(dataIndex)}`, {
2569
+ ...tag,
2570
+ domain: domain2 ? domainFormat.toList({
2571
+ ...context2,
2572
+ self: value
2573
+ }) : null
2574
+ });
2575
+ } else if (type === constants_exports.SearchType.GROUP) {
2576
+ addSearchItems(`${constants_exports.SearchType.GROUP}`, {
2577
+ ...tag,
2578
+ domain: domain2 ? domainFormat.toList({
2579
+ context: context2,
2580
+ self: value
2581
+ }) : null
2582
+ });
2583
+ }
2584
+ };
2585
+ const onKeyDown = (e) => {
2586
+ if (!searchBy || searchBy.length === 0) return;
2587
+ switch (e.key) {
2588
+ case "Backspace": {
2589
+ if (!searchString && selectedTags && selectedTags.length > 0) {
2590
+ const lastTag = selectedTags[selectedTags.length - 1];
2591
+ if (!lastTag) return;
2592
+ const key = lastTag.type === constants_exports.SearchType.GROUP ? constants_exports.SearchType.GROUP : lastTag.name;
2593
+ removeKeyFromSearchMap({ key: String(key) });
2594
+ }
2595
+ break;
2596
+ }
2597
+ case "ArrowDown": {
2598
+ e.preventDefault();
2599
+ setHoveredIndex((prev) => {
2600
+ const maxIndex = searchBy.length - 1;
2601
+ const next = prev < maxIndex ? prev + 1 : prev;
2602
+ setHoveredIndexSearchList(next);
2603
+ return next;
2604
+ });
2605
+ break;
2606
+ }
2607
+ case "ArrowUp": {
2608
+ e.preventDefault();
2609
+ setHoveredIndex((prev) => {
2610
+ const next = prev > 0 ? prev - 1 : prev;
2611
+ setHoveredIndexSearchList(next);
2612
+ return next;
2613
+ });
2614
+ break;
2615
+ }
2616
+ case "Enter": {
2617
+ e.preventDefault();
2618
+ if (!searchString.trim()) return;
2619
+ const head = searchBy[hoveredIndex];
2620
+ if (!head) return;
2621
+ handleAddTagSearch({
2622
+ title: head.title,
2623
+ name: head.name,
2624
+ value: searchString,
2625
+ type: constants_exports.SearchType.SEARCH,
2626
+ domain: head.filter_domain,
2627
+ operator: head.operator,
2628
+ dataIndex: head.dataIndex,
2629
+ widget: head.widget,
2630
+ modelType: head.type
2631
+ });
2632
+ break;
2633
+ }
2634
+ default:
2635
+ break;
2636
+ }
2637
+ };
2638
+ const handleMouseEnter = (index) => {
2639
+ setHoveredIndexSearchList(index);
2640
+ };
2641
+ const handleMouseLeave = () => {
2642
+ setHoveredIndexSearchList(null);
2643
+ };
2644
+ return {
2645
+ groupBy,
2646
+ searchBy,
2647
+ filterBy,
2648
+ selectedTags,
2649
+ searchString,
2650
+ setFilterBy,
2651
+ setGroupBy,
2652
+ setSearchBy,
2653
+ resetAllStateSearch,
2654
+ setSelectedTags,
2655
+ removeSearchItems,
2656
+ onSearchString: onChangeSearchInput,
2657
+ handleAddTagSearch,
2658
+ domain: formatDomain(),
2659
+ context: contextSearch,
2660
+ onKeyDown,
2661
+ handleMouseEnter,
2662
+ handleMouseLeave,
2663
+ hoveredIndexSearchList,
2664
+ removeSearchItemsByType
2665
+ };
2666
+ };
2667
+
2668
+ // src/index.ts
2669
+ __reExport(index_exports, utils_exports);
2670
+ __reExport(index_exports, constants_exports);
2671
+ __reExport(index_exports, environment_exports);
2672
+ __reExport(index_exports, provider_exports);
2673
+
2674
+ // src/services.ts
2675
+ var services_exports = {};
2676
+ __reExport(services_exports, services_star);
2677
+ import * as services_star from "@fctc/interface-logic/services";
2678
+
2679
+ // src/index.ts
2680
+ __reExport(index_exports, services_exports);
2681
+
2682
+ // src/types.ts
2683
+ var types_exports = {};
2684
+ __reExport(types_exports, types_star);
2685
+ import * as types_star from "@fctc/interface-logic/types";
2686
+
2687
+ // src/index.ts
2688
+ __reExport(index_exports, types_exports);
2689
+ export {
2690
+ AppProvider,
2691
+ STORAGES,
2692
+ binaryFieldController,
2693
+ colorFieldController,
2694
+ copyLinkButtonController,
2695
+ countSum,
2696
+ downLoadBinaryController,
2697
+ downloadFileController,
2698
+ durationController,
2699
+ guessTypeFromUrl,
2700
+ isObjectEmpty,
2701
+ languages,
2702
+ many2manyBinaryController,
2703
+ many2manyFieldController,
2704
+ many2manyTagsController,
2705
+ many2oneButtonController,
2706
+ many2oneFieldController,
2707
+ mergeButtons,
2708
+ priorityFieldController,
2709
+ providerEinvoiceFieldController,
2710
+ searchController,
2711
+ setStorageItemAsync,
2712
+ statusDropdownController,
2713
+ tableController,
2714
+ tableGroupController,
2715
+ tableHeadController,
2716
+ useAddEntity,
2717
+ useAppProvider,
2718
+ useButton,
2719
+ useCallAction,
2720
+ useChangeOrderPreparationState,
2721
+ useChangeStatus,
2722
+ useCheckPayment,
2723
+ useCompany,
2724
+ useConfig,
2725
+ useCreateEntity,
2726
+ useCreatePosConfig,
2727
+ useCreateSession,
2728
+ useDebounce,
2729
+ useDelete,
2730
+ useDeleteComment,
2731
+ useDeleteEntity,
2732
+ useDetail,
2733
+ useDuplicateRecord,
2734
+ useExecuteImport,
2735
+ useExportExcel,
2736
+ useForgotPassword,
2737
+ useForgotPasswordSSO,
2738
+ useGenSerialNumber,
2739
+ useGeneratePaymentQrInfo,
2740
+ useGet2FAMethods,
2741
+ useGetASession,
2742
+ useGetAccessByCode,
2743
+ useGetAction,
2744
+ useGetActionDetail,
2745
+ useGetAll,
2746
+ useGetCalendar,
2747
+ useGetComment,
2748
+ useGetCompanyInfo,
2749
+ useGetConversionRate,
2750
+ useGetCurrency,
2751
+ useGetCurrentCompany,
2752
+ useGetDetail,
2753
+ useGetExternalTabs,
2754
+ useGetFieldExport,
2755
+ useGetFieldOnChange,
2756
+ useGetFileExcel,
2757
+ useGetFormView,
2758
+ useGetGroups,
2759
+ useGetList,
2760
+ useGetListCompany,
2761
+ useGetListData,
2762
+ useGetListMyBankAccount,
2763
+ useGetMenu,
2764
+ useGetOrderLine,
2765
+ useGetPinCode,
2766
+ useGetPrintReport,
2767
+ useGetProGressBar,
2768
+ useGetProfile,
2769
+ useGetProvider,
2770
+ useGetResequence,
2771
+ useGetRowIds,
2772
+ useGetSelection,
2773
+ useGetSpecification,
2774
+ useGetUser,
2775
+ useGetView,
2776
+ useGrantAccess,
2777
+ useIsValidToken,
2778
+ useListData,
2779
+ useLoadAction,
2780
+ useLoadMessage,
2781
+ useLoginCredential,
2782
+ useLoginSocial,
2783
+ useLogout,
2784
+ useMenu,
2785
+ useModel,
2786
+ useOdooDataTransform,
2787
+ useOnChangeForm,
2788
+ useParsePreview,
2789
+ usePrint,
2790
+ useProfile,
2791
+ useReadGroup,
2792
+ useRemoveRow,
2793
+ useRemoveTotpSetup,
2794
+ useRequestSetupTotp,
2795
+ useResetPassword,
2796
+ useResetPasswordSSO,
2797
+ useRunAction,
2798
+ useSave,
2799
+ useSendComment,
2800
+ useSettingsWebRead2fa,
2801
+ useSignInSSO,
2802
+ useStorageState,
2803
+ useSwitchLocale,
2804
+ useUpdatePassword,
2805
+ useUploadFile,
2806
+ useUploadFileExcel,
2807
+ useUploadIdFile,
2808
+ useUploadImage,
2809
+ useUser,
2810
+ useValidateActionToken,
2811
+ useVerify2FA,
2812
+ useVerifyTotp,
2813
+ useViewV2
2814
+ };