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

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