@fctc/widget-logic 1.8.5 → 1.8.7

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 CHANGED
@@ -5209,48 +5209,63 @@ var statusDropdownController = (props) => {
5209
5209
 
5210
5210
  // src/widget/basic/many2one-field/controller.ts
5211
5211
  var import_react14 = require("react");
5212
- var import_hooks11 = require("@fctc/interface-logic/hooks");
5213
- var import_store7 = require("@fctc/interface-logic/store");
5214
- var import_utils3 = require("@fctc/interface-logic/utils");
5212
+
5213
+ // src/utils.ts
5214
+ var utils_exports = {};
5215
+ __export(utils_exports, {
5216
+ API_APP_URL: () => API_APP_URL,
5217
+ API_PRESCHOOL_URL: () => API_PRESCHOOL_URL,
5218
+ STORAGES: () => STORAGES,
5219
+ combineContexts: () => combineContexts,
5220
+ convertFieldsToArray: () => convertFieldsToArray,
5221
+ countSum: () => countSum,
5222
+ getDateRange: () => getDateRange,
5223
+ languages: () => languages,
5224
+ mergeButtons: () => mergeButtons,
5225
+ setStorageItemAsync: () => setStorageItemAsync,
5226
+ useGetRowIds: () => useGetRowIds,
5227
+ useSelectionState: () => useSelectionState,
5228
+ useStorageState: () => useStorageState
5229
+ });
5230
+ __reExport(utils_exports, require("@fctc/interface-logic/utils"));
5231
+
5232
+ // src/provider.ts
5233
+ var provider_exports = {};
5234
+ __reExport(provider_exports, require("@fctc/interface-logic/provider"));
5235
+
5236
+ // src/widget/basic/many2one-field/controller.ts
5215
5237
  var many2oneFieldController = (props) => {
5216
5238
  const {
5217
- name,
5239
+ sessionStorageUtils,
5218
5240
  methods,
5219
- formValues,
5220
- domain,
5221
5241
  relation,
5222
- onChange,
5242
+ domain,
5243
+ formValues,
5223
5244
  value: propValue,
5245
+ onChange,
5246
+ name,
5224
5247
  context: fieldContext,
5225
5248
  options: fieldOptions,
5226
- showDetail = true,
5227
- actionData
5249
+ showDetail
5228
5250
  } = props;
5229
5251
  const [options, setOptions] = (0, import_react14.useState)([]);
5252
+ const [inputValue, setInputValue] = (0, import_react14.useState)("");
5253
+ const [debouncedInputValue] = useDebounce(inputValue, 1e3);
5230
5254
  const [isShowModalMany2Many, setIsShowModalMany2Many] = (0, import_react14.useState)(false);
5231
5255
  const [tempSelectedOption, setTempSelectedOption] = (0, import_react14.useState)(null);
5232
- const { menuList } = (0, import_store7.useAppSelector)(import_store7.selectNavbar);
5233
- const { context } = (0, import_store7.useAppSelector)(import_store7.selectEnv);
5234
5256
  const [domainModal, setDomainModal] = (0, import_react14.useState)(null);
5257
+ const [domainObject, setDomainObject] = (0, import_react14.useState)(null);
5258
+ const actionData = sessionStorageUtils.getActionData();
5259
+ const { menuList } = (0, store_exports.useAppSelector)(store_exports.selectNavbar);
5260
+ const { context } = (0, store_exports.useAppSelector)(store_exports.selectEnv);
5235
5261
  const initValue = methods?.getValues(name);
5236
- const domainObject = (0, import_react14.useMemo)(
5237
- () => (0, import_utils3.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues)) ?? {}),
5238
- [domain, formValues]
5239
- );
5240
- const optionsObject = (0, import_utils3.evalJSONContext)(fieldOptions) || {};
5262
+ const optionsObject = (0, utils_exports.evalJSONContext)(fieldOptions) || {};
5241
5263
  const contextObject = {
5242
- ...(0, import_utils3.evalJSONContext)(actionData?.context) || {},
5264
+ ...(0, utils_exports.evalJSONContext)(actionData?.context) || {},
5243
5265
  ...fieldContext,
5244
5266
  ...context
5245
5267
  };
5246
- const actionId = (0, import_react14.useMemo)(
5247
- () => menuList?.flatMap(
5248
- (item) => item?.child_id.filter(
5249
- (childItem) => childItem?.is_display && childItem?.action?.res_model === relation
5250
- )
5251
- )?.[0]?.action?.id,
5252
- [menuList, relation]
5253
- );
5268
+ const { useGetSelection: useGetSelection3 } = (0, provider_exports.useService)();
5254
5269
  const data = {
5255
5270
  model: relation,
5256
5271
  domain: domainObject,
@@ -5264,9 +5279,9 @@ var many2oneFieldController = (props) => {
5264
5279
  const queryKey = [`data_${relation}`, domainObject];
5265
5280
  const {
5266
5281
  data: dataOfSelection,
5267
- // refetch,
5282
+ refetch,
5268
5283
  isFetching
5269
- } = (0, import_hooks11.useGetSelection)({
5284
+ } = useGetSelection3({
5270
5285
  data,
5271
5286
  queryKey,
5272
5287
  enabled: false
@@ -5280,8 +5295,16 @@ var many2oneFieldController = (props) => {
5280
5295
  (0, import_react14.useEffect)(() => {
5281
5296
  setOptions(selectOptions);
5282
5297
  setDomainModal(domainObject);
5283
- if (relation === "student.subject") (0, import_store7.setListSubject)(selectOptions);
5298
+ if (relation === "student.subject") (0, store_exports.setListSubject)(selectOptions);
5284
5299
  }, [selectOptions]);
5300
+ (0, import_react14.useEffect)(() => {
5301
+ setDomainObject(
5302
+ (0, utils_exports.evalJSONDomain)(
5303
+ domain,
5304
+ JSON.parse(JSON.stringify({ ...formValues, context: contextObject })) ?? {}
5305
+ )
5306
+ );
5307
+ }, [domain, formValues]);
5285
5308
  (0, import_react14.useEffect)(() => {
5286
5309
  if (!propValue && tempSelectedOption) {
5287
5310
  methods.setValue(name, null);
@@ -5293,11 +5316,24 @@ var many2oneFieldController = (props) => {
5293
5316
  });
5294
5317
  }
5295
5318
  }, [propValue]);
5319
+ const fetchMoreOptions = (0, import_react14.useCallback)(() => {
5320
+ refetch();
5321
+ }, [refetch]);
5296
5322
  (0, import_react14.useEffect)(() => {
5297
- if (actionId) {
5298
- localStorage.setItem("aid", actionId);
5323
+ if (debouncedInputValue) {
5324
+ const filteredDomain = [...domainObject ?? []]?.filter(
5325
+ (d) => !(Array.isArray(d) && d[0] === "name" && d[1] === "ilike")
5326
+ ) || [];
5327
+ const newDomain = [
5328
+ ...filteredDomain,
5329
+ ...debouncedInputValue ? [["name", "ilike", debouncedInputValue]] : []
5330
+ ];
5331
+ setDomainObject(newDomain);
5332
+ setTimeout(() => {
5333
+ fetchMoreOptions();
5334
+ }, 50);
5299
5335
  }
5300
- }, [actionId]);
5336
+ }, [debouncedInputValue]);
5301
5337
  const handleChooseRecord = (0, import_react14.useCallback)(
5302
5338
  (idRecord) => {
5303
5339
  const newOption = options.find(
@@ -5349,52 +5385,42 @@ var many2oneFieldController = (props) => {
5349
5385
  [methods, name, onChange]
5350
5386
  );
5351
5387
  const allowShowDetail = showDetail && contextObject?.form_view_ref && (!("no_open" in optionsObject) || optionsObject?.no_open === false);
5352
- const fetchMoreOptions = (0, import_react14.useCallback)(() => {
5353
- if (typeof dataOfSelection?.refetch === "function") {
5354
- ;
5355
- dataOfSelection.refetch();
5356
- }
5357
- }, [dataOfSelection]);
5358
5388
  return {
5359
- allowShowDetail,
5360
- handleClose,
5389
+ isShowModalMany2Many,
5390
+ isFetching,
5391
+ initValue,
5392
+ menuList,
5361
5393
  handleChooseRecord,
5394
+ handleClose,
5362
5395
  handleSelectChange,
5363
- initValue,
5364
- isFetching,
5365
- isShowModalMany2Many,
5366
- options,
5367
- fetchMoreOptions,
5368
5396
  domainModal,
5369
- tempSelectedOption,
5370
- setTempSelectedOption,
5371
- setDomainModal,
5372
- dataOfSelection,
5373
- refetch: dataOfSelection?.refetch ?? (() => {
5374
- }),
5375
- selectOptions,
5376
- optionsObject,
5397
+ setInputValue,
5398
+ allowShowDetail,
5377
5399
  contextObject,
5378
- actionId,
5379
- setIsShowModalMany2Many
5400
+ tempSelectedOption,
5401
+ options,
5402
+ fetchMoreOptions,
5403
+ domainObject,
5404
+ setIsShowModalMany2Many,
5405
+ setDomainObject
5380
5406
  };
5381
5407
  };
5382
5408
 
5383
5409
  // src/widget/basic/many2one-button-field/controller.ts
5384
5410
  var import_environment6 = require("@fctc/interface-logic/environment");
5385
5411
  var import_hooks12 = require("@fctc/interface-logic/hooks");
5386
- var import_utils4 = require("@fctc/interface-logic/utils");
5412
+ var import_utils5 = require("@fctc/interface-logic/utils");
5387
5413
  var many2oneButtonController = (props) => {
5388
5414
  const { domain, methods, relation } = props;
5389
5415
  const actionDataString = sessionStorage.getItem("actionData");
5390
5416
  const env = (0, import_environment6.getEnv)();
5391
- const domainObject = (0, import_utils4.evalJSONDomain)(domain, methods?.getValues() || {});
5417
+ const domainObject = (0, import_utils5.evalJSONDomain)(domain, methods?.getValues() || {});
5392
5418
  const actionData = actionDataString && actionDataString !== "undefined" ? JSON.parse(actionDataString) : {};
5393
5419
  const { data: dataOfSelection } = (0, import_hooks12.useGetSelection)({
5394
5420
  data: {
5395
5421
  model: relation ?? "",
5396
5422
  domain: domainObject,
5397
- context: { ...env.context, ...(0, import_utils4.evalJSONContext)(actionData?.context) }
5423
+ context: { ...env.context, ...(0, import_utils5.evalJSONContext)(actionData?.context) }
5398
5424
  },
5399
5425
  queryKey: [`data_${relation}`, domainObject]
5400
5426
  });
@@ -5408,204 +5434,473 @@ var many2oneButtonController = (props) => {
5408
5434
  };
5409
5435
 
5410
5436
  // src/widget/basic/many2many-field/controller.ts
5411
- var import_react19 = require("react");
5412
-
5413
- // src/widget/advance/table/table-body/controller.ts
5414
- var import_store8 = require("@fctc/interface-logic/store");
5415
5437
  var import_react15 = require("react");
5416
- var tableBodyController = (props) => {
5438
+ var import_store8 = require("@fctc/interface-logic/store");
5439
+ var import_utils6 = require("@fctc/interface-logic/utils");
5440
+ var many2manyFieldController = (props) => {
5417
5441
  const {
5418
- checkedAll,
5419
- checkboxRef,
5420
- setIsAutoSelect,
5421
- selectedRowKeys,
5422
- row,
5423
- isAutoSelect,
5424
- selectedRowKeysRef,
5425
- onClickRow
5442
+ relation,
5443
+ domain,
5444
+ context,
5445
+ tab,
5446
+ model,
5447
+ aid,
5448
+ setSelectedRowKeys: setSelectedRowKeys4,
5449
+ fields,
5450
+ setFields,
5451
+ groupByDomain,
5452
+ page,
5453
+ options,
5454
+ sessionStorageUtils
5426
5455
  } = props;
5427
5456
  const appDispatch = (0, import_store8.useAppDispatch)();
5428
- const checked = (0, import_react15.useMemo)(() => {
5429
- if (!row?.id) return false;
5430
- if (selectedRowKeys?.includes(row.id)) {
5431
- return true;
5457
+ const actionData = sessionStorageUtils.getActionData();
5458
+ const [debouncedPage] = useDebounce(page, 500);
5459
+ const [order, setOrder] = (0, import_react15.useState)();
5460
+ const [isLoadedData, setIsLoadedData] = (0, import_react15.useState)(false);
5461
+ const [domainMany2Many, setDomainMany2Many] = (0, import_react15.useState)(domain);
5462
+ const { env } = (0, provider_exports.useEnv)();
5463
+ const { useGetView: useGetView2, useGetListData: useGetListData4, useGetFormView } = (0, provider_exports.useService)();
5464
+ const viewParams = {
5465
+ model: relation,
5466
+ views: [
5467
+ [false, "list"],
5468
+ [false, "search"]
5469
+ ],
5470
+ context
5471
+ };
5472
+ const { data: viewResponse } = useGetView2(viewParams, actionData);
5473
+ const baseModel = (0, import_react15.useMemo)(
5474
+ () => ({
5475
+ name: String(relation),
5476
+ view: viewResponse || {},
5477
+ actContext: context,
5478
+ fields: [
5479
+ ...Object.values(viewResponse?.views?.list?.fields ?? {}),
5480
+ ...tab?.fields ? tab.fields : []
5481
+ ]
5482
+ }),
5483
+ [model, viewResponse]
5484
+ );
5485
+ const initModel = (0, hooks_exports.useModel)();
5486
+ const modelInstance = (0, import_react15.useMemo)(() => {
5487
+ if (viewResponse) {
5488
+ return initModel.initModel(baseModel);
5432
5489
  }
5433
- return checkedAll;
5434
- }, [row?.id, selectedRowKeys, checkedAll]);
5435
- const handleCheckBoxSingle = (event) => {
5436
- event.stopPropagation();
5437
- if (checkedAll) {
5438
- checkboxRef.current = "uncheck";
5439
- setIsAutoSelect(true);
5440
- return;
5490
+ return null;
5491
+ }, [baseModel, viewResponse]);
5492
+ const specification = (0, import_react15.useMemo)(() => {
5493
+ if (modelInstance) {
5494
+ return modelInstance.getSpecification();
5495
+ }
5496
+ return null;
5497
+ }, [modelInstance]);
5498
+ const default_order = viewResponse && viewResponse?.views?.list?.default_order;
5499
+ const optionsObject = tab?.options ? (0, import_utils6.evalJSONContext)(tab?.options) : (options ? (0, import_utils6.evalJSONContext)(options) : {}) || {};
5500
+ const fetchData = async () => {
5501
+ try {
5502
+ setDomainMany2Many(domain);
5503
+ appDispatch((0, import_store8.setFirstDomain)(domain));
5504
+ appDispatch((0, import_store8.setViewDataStore)(viewResponse));
5505
+ const modalData = viewResponse?.views?.list?.fields.map((field) => ({
5506
+ ...viewResponse?.models?.[String(model)]?.[field?.name],
5507
+ ...field
5508
+ }));
5509
+ if (!fields?.[`${aid}_${relation}_popupmany2many`] && modalData) {
5510
+ setFields({
5511
+ ...fields,
5512
+ [`${aid}_${relation}_popupmany2many`]: modalData
5513
+ });
5514
+ }
5515
+ appDispatch((0, import_store8.setPage)(0));
5516
+ } catch (err) {
5517
+ console.log(err);
5441
5518
  }
5442
- const newSelectedRowKeys = selectedRowKeys?.includes(row.id) ? selectedRowKeys?.filter((key) => key !== row.id) : [...selectedRowKeys, row.id];
5443
- console.log("newSelectedRowKeys", newSelectedRowKeys);
5444
- appDispatch((0, import_store8.setSelectedRowKeys)(newSelectedRowKeys));
5445
5519
  };
5446
- const handleClickRow = (col, row2) => {
5447
- onClickRow(col, row2);
5520
+ const queryKey = [
5521
+ `view-${relation}-${aid}`,
5522
+ specification,
5523
+ domainMany2Many,
5524
+ debouncedPage,
5525
+ groupByDomain,
5526
+ order
5527
+ ];
5528
+ const data = {
5529
+ model: relation,
5530
+ specification,
5531
+ domain: domainMany2Many,
5532
+ offset: debouncedPage * 10,
5533
+ limit: 10,
5534
+ context,
5535
+ fields: groupByDomain?.fields,
5536
+ groupby: [groupByDomain?.contexts[0]?.group_by],
5537
+ sort: order ? order : default_order ? (0, import_utils6.formatSortingString)(default_order) : ""
5448
5538
  };
5539
+ const enabled = isLoadedData && !!specification && !!relation && !!domainMany2Many && !!viewResponse;
5540
+ const {
5541
+ data: dataResponse,
5542
+ isLoading: isDataLoading,
5543
+ isFetched: isDataResponseFetched,
5544
+ isPlaceholderData
5545
+ } = useGetListData4(data, queryKey, enabled);
5449
5546
  (0, import_react15.useEffect)(() => {
5450
- if (!row?.id) return;
5451
- if (isAutoSelect) {
5452
- if (checkboxRef?.current === "uncheck") {
5453
- const filtered = selectedRowKeysRef.current.filter(
5454
- (id) => id !== row.id
5455
- );
5456
- selectedRowKeysRef.current = filtered;
5457
- appDispatch((0, import_store8.setSelectedRowKeys)(filtered));
5458
- } else {
5459
- const unique = Array.from(
5460
- /* @__PURE__ */ new Set([...selectedRowKeysRef?.current, row?.id])
5461
- );
5462
- selectedRowKeysRef.current = unique;
5463
- appDispatch((0, import_store8.setSelectedRowKeys)(unique));
5464
- }
5547
+ if (viewResponse) {
5548
+ fetchData();
5465
5549
  }
5466
- }, [isAutoSelect]);
5550
+ return () => {
5551
+ appDispatch((0, import_store8.setGroupByDomain)(null));
5552
+ setFields((prevFields) => ({
5553
+ ...prevFields,
5554
+ [`${aid}_${relation}_popupmany2many`]: null
5555
+ }));
5556
+ appDispatch((0, import_store8.setPage)(0));
5557
+ setSelectedRowKeys4([]);
5558
+ setDomainMany2Many(null);
5559
+ setIsLoadedData(false);
5560
+ };
5561
+ }, [viewResponse]);
5562
+ const { rows, columns, typeTable } = tableController({
5563
+ data: {
5564
+ fields: fields?.[`${aid}_${relation}_popupmany2many`] || viewResponse?.views?.list?.fields,
5565
+ records: dataResponse?.records ?? dataResponse?.groups,
5566
+ dataModel: viewResponse?.models?.[String(relation)],
5567
+ context: { ...env.context, ...context },
5568
+ typeTable: dataResponse?.groups ? "group" : "list"
5569
+ }
5570
+ });
5571
+ const dataFormView = {
5572
+ id: null,
5573
+ model: relation,
5574
+ context
5575
+ };
5576
+ const {
5577
+ refetch,
5578
+ data: dataFormViewResponse,
5579
+ isSuccess
5580
+ } = useGetFormView({
5581
+ data: dataFormView,
5582
+ queryKey: [`form-view-action-${relation}`],
5583
+ enabled: false
5584
+ });
5467
5585
  (0, import_react15.useEffect)(() => {
5468
- if (!checkedAll) {
5469
- checkboxRef.current = "enabled";
5470
- false;
5586
+ if (isSuccess && dataFormViewResponse) {
5587
+ sessionStorage.setItem("actionData", JSON.stringify(dataFormViewResponse));
5588
+ window.location.href = `/form/menu?model=${relation}`;
5471
5589
  }
5472
- }, [checkedAll]);
5590
+ }, [isSuccess]);
5591
+ (0, import_react15.useEffect)(() => {
5592
+ if (domainMany2Many && !isLoadedData) {
5593
+ setIsLoadedData(true);
5594
+ }
5595
+ }, [domainMany2Many]);
5596
+ const handleCreateNewOnPage = async () => {
5597
+ try {
5598
+ refetch();
5599
+ } catch (error) {
5600
+ console.log(error);
5601
+ }
5602
+ };
5473
5603
  return {
5474
- handleCheckBoxSingle,
5475
- checked,
5476
- handleClickRow
5604
+ handleCreateNewOnPage,
5605
+ optionsObject,
5606
+ rows,
5607
+ columns,
5608
+ typeTable,
5609
+ isDataLoading,
5610
+ isDataResponseFetched,
5611
+ isPlaceholderData
5477
5612
  };
5478
5613
  };
5479
5614
 
5480
- // src/widget/advance/table/table-head/controller.ts
5481
- var import_store9 = require("@fctc/interface-logic/store");
5482
- var tableHeadController = (props) => {
5483
- const { typeTable, rows, selectedRowKeysRef } = props;
5484
- const appDispatch = (0, import_store9.useAppDispatch)();
5485
- const { groupByDomain } = (0, import_store9.useAppSelector)(import_store9.selectSearch);
5486
- const handleCheckBoxAll = (event) => {
5487
- if (event?.target?.checked && typeTable === "list") {
5488
- const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
5489
- appDispatch((0, import_store9.setSelectedRowKeys)(allRowKeys));
5490
- } else if (event?.target?.checked && typeTable === "group") {
5491
- const rowsIDs = document.querySelectorAll("tr[data-row-id]");
5492
- const ids = Array.from(rowsIDs)?.map(
5493
- (row) => Number(row?.getAttribute("data-row-id"))
5494
- );
5495
- if (ids?.length > 0) {
5496
- appDispatch((0, import_store9.setSelectedRowKeys)(ids));
5497
- } else {
5498
- const sum = countSum(
5499
- rows,
5500
- typeof groupByDomain === "object" ? groupByDomain?.contexts?.[0]?.group_by : void 0
5501
- );
5502
- const keys = Array.from({ length: sum }, (_) => void 0);
5503
- appDispatch((0, import_store9.setSelectedRowKeys)(keys));
5504
- }
5505
- if (selectedRowKeysRef) {
5506
- selectedRowKeysRef.current = [];
5507
- }
5508
- } else {
5509
- appDispatch((0, import_store9.setSelectedRowKeys)([]));
5510
- }
5615
+ // src/widget/basic/many2many-tags-field/controller.ts
5616
+ var import_react16 = require("react");
5617
+ var import_constants4 = require("@fctc/interface-logic/constants");
5618
+ var import_environment7 = require("@fctc/interface-logic/environment");
5619
+ var import_hooks14 = require("@fctc/interface-logic/hooks");
5620
+ var import_utils7 = require("@fctc/interface-logic/utils");
5621
+ var many2manyTagsController = (props) => {
5622
+ const {
5623
+ relation,
5624
+ domain,
5625
+ options: optionsFields,
5626
+ widget,
5627
+ formValues,
5628
+ placeholderNoOption
5629
+ } = props;
5630
+ const isUser = relation === "res.users" || relation === "res.partner";
5631
+ const env = (0, import_environment7.getEnv)();
5632
+ const addtionalFields = optionsFields ? (0, import_utils7.evalJSONContext)(optionsFields) : null;
5633
+ const domainObject = (0, import_react16.useMemo)(
5634
+ () => (0, import_utils7.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues || {}))),
5635
+ [domain, formValues]
5636
+ );
5637
+ const data = {
5638
+ model: relation ?? "",
5639
+ domain: domainObject,
5640
+ specification: {
5641
+ id: {},
5642
+ name: {},
5643
+ display_name: {},
5644
+ ...widget && import_constants4.WIDGETAVATAR[widget] ? { image_256: {} } : {},
5645
+ ...widget && import_constants4.WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
5646
+ },
5647
+ enabled: true,
5648
+ context: env.context
5649
+ };
5650
+ const { data: dataOfSelection } = (0, import_hooks14.useGetSelection)({
5651
+ data,
5652
+ queryKey: [`data_${relation}`, domainObject]
5653
+ });
5654
+ const customNoOptionsMessage = () => placeholderNoOption;
5655
+ const tranfer = (data2) => {
5656
+ return data2?.map((val) => ({
5657
+ id: val.value,
5658
+ display_name: val.label
5659
+ })) || [];
5511
5660
  };
5661
+ const options = dataOfSelection?.records?.map((val) => ({
5662
+ value: val.id,
5663
+ label: val.name ?? val.display_name,
5664
+ ...val
5665
+ })) || [];
5512
5666
  return {
5513
- handleCheckBoxAll
5667
+ options,
5668
+ customNoOptionsMessage,
5669
+ tranfer,
5670
+ dataOfSelection,
5671
+ isUser
5514
5672
  };
5515
5673
  };
5516
5674
 
5517
- // src/widget/advance/table/table-view/controller.ts
5518
- var import_react16 = require("react");
5519
- var import_store10 = require("@fctc/interface-logic/store");
5520
- var import_utils5 = require("@fctc/interface-logic/utils");
5521
- var tableController = ({ data }) => {
5522
- const [rows, setRows] = (0, import_react16.useState)(data.records || []);
5523
- const [columns, setColumns] = (0, import_react16.useState)([]);
5524
- const dataModelFields = data.fields?.map((field) => {
5525
- return {
5526
- ...data.dataModel?.[field?.name],
5527
- ...field,
5528
- string: field?.string || data.dataModel?.[field?.name]?.string
5529
- };
5530
- });
5531
- const mergeFields = mergeButtons(dataModelFields);
5532
- const transformData = (dataList) => {
5533
- if (!dataList) return;
5534
- return dataList?.map((item) => {
5535
- const transformedItem = { ...item };
5536
- Object.keys(item).forEach((field) => {
5537
- if (field !== "__domain") {
5538
- if (item[field] && typeof item[field] === "object" && item[field].display_name) {
5539
- transformedItem[field] = item[field];
5540
- } else if (Array.isArray(item[field]) && item[field].length > 0) {
5541
- if (data.typeTable === "group" && item[field]?.length === 2 && typeof item[field]?.[1] === "string") {
5542
- transformedItem["string"] = item[field]?.[1];
5675
+ // src/widget/basic/status-bar-field/controller.ts
5676
+ var import_react17 = require("react");
5677
+ var import_hooks15 = require("@fctc/interface-logic/hooks");
5678
+ var import_store9 = require("@fctc/interface-logic/store");
5679
+ var import_utils8 = require("@fctc/interface-logic/utils");
5680
+ var durationController = (props) => {
5681
+ const {
5682
+ relation,
5683
+ defaultValue,
5684
+ domain,
5685
+ formValues,
5686
+ name,
5687
+ id,
5688
+ model,
5689
+ onRefetch
5690
+ } = props;
5691
+ const specification = {
5692
+ id: 0,
5693
+ name: "",
5694
+ fold: ""
5695
+ };
5696
+ const [disabled, setDisabled] = (0, import_react17.useState)(false);
5697
+ const [modelStatus, setModalStatus] = (0, import_react17.useState)(false);
5698
+ const { context } = (0, import_store9.useAppSelector)(import_store9.selectEnv);
5699
+ const queryKey = [`data-status-duration`, specification];
5700
+ const listDataProps = {
5701
+ model: relation,
5702
+ specification,
5703
+ domain: (0, import_utils8.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues))),
5704
+ limit: 10,
5705
+ offset: 0,
5706
+ fields: "",
5707
+ groupby: [],
5708
+ context: {
5709
+ lang: context.lang
5710
+ },
5711
+ sort: ""
5712
+ };
5713
+ const { data: dataResponse } = (0, import_hooks15.useGetListData)(listDataProps, queryKey);
5714
+ const { mutate: fetchChangeStatus } = (0, import_hooks15.useChangeStatus)();
5715
+ const handleClick = async (stage_id) => {
5716
+ setDisabled(true);
5717
+ if (stage_id) {
5718
+ fetchChangeStatus(
5719
+ {
5720
+ data: {
5721
+ stage_id,
5722
+ name,
5723
+ id,
5724
+ model,
5725
+ lang: context.lang
5726
+ }
5727
+ },
5728
+ {
5729
+ onSuccess: (res) => {
5730
+ if (res) {
5731
+ setDisabled(false);
5732
+ onRefetch && onRefetch();
5543
5733
  }
5544
- transformedItem[field] = item[field];
5545
5734
  }
5546
5735
  }
5547
- });
5548
- return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
5549
- });
5736
+ );
5737
+ }
5550
5738
  };
5551
- (0, import_react16.useEffect)(() => {
5552
- setRows(transformData(data.records || null));
5553
- }, [data.records]);
5554
- const handleGetColumns = () => {
5555
- let cols = [];
5739
+ return {
5740
+ defaultValue,
5741
+ dataResponse,
5742
+ handleClick,
5743
+ disabled,
5744
+ modelStatus,
5745
+ setModalStatus
5746
+ };
5747
+ };
5748
+
5749
+ // src/widget/basic/priority-field/controller.ts
5750
+ var import_hooks16 = require("@fctc/interface-logic/hooks");
5751
+ var import_utils9 = require("@fctc/interface-logic/utils");
5752
+ var priorityFieldController = (props) => {
5753
+ const {
5754
+ value,
5755
+ isForm,
5756
+ name,
5757
+ methods,
5758
+ onChange,
5759
+ model,
5760
+ selection,
5761
+ id,
5762
+ actionData,
5763
+ viewData,
5764
+ context
5765
+ } = props;
5766
+ const _context = { ...(0, import_utils9.evalJSONContext)(actionData?.context) };
5767
+ const contextObject = { ...context, ..._context };
5768
+ const defaultPriority = parseInt(value) + 1;
5769
+ const label = viewData?.models?.[model]?.[name ?? ""]?.string ?? name;
5770
+ const { mutateAsync: fetchSave } = (0, import_hooks16.useSave)();
5771
+ const savePriorities = async ({
5772
+ value: value2,
5773
+ resetPriority
5774
+ }) => {
5775
+ const priorityValue = value2 <= 0 ? 0 : value2 - 1;
5556
5776
  try {
5557
- cols = mergeFields?.filter((item) => {
5558
- return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? import_utils5.domainHelper.matchDomains(data.context, item?.column_invisible) : item?.invisible ? import_utils5.domainHelper.matchDomains(data.context, item?.invisible) : false);
5559
- })?.map((field) => {
5560
- return {
5561
- name: field?.name,
5562
- optional: field?.optional,
5563
- title: field?.type_co === "button" ? "" : field?.string,
5564
- field: { ...field }
5565
- };
5777
+ fetchSave({
5778
+ ids: id ? [id] : [],
5779
+ data: { [name ?? ""]: String(priorityValue) },
5780
+ model: model ?? "",
5781
+ context: contextObject
5566
5782
  });
5783
+ if (typeof onChange === "function") {
5784
+ onChange(name ?? "", String(priorityValue));
5785
+ }
5567
5786
  } catch (error) {
5568
- console.error("Error in useTable:", error);
5569
- }
5570
- return cols;
5571
- };
5572
- (0, import_react16.useEffect)(() => {
5573
- const columns2 = handleGetColumns();
5574
- setColumns(columns2);
5575
- }, [data.records]);
5576
- const onToggleColumnOptional = (item) => {
5577
- const tempColumn = [...columns]?.map((val) => {
5578
- if (item?.name === val?.name) {
5579
- return {
5580
- ...val,
5581
- optional: item?.optional === "show" ? "hide" : "show"
5582
- };
5787
+ if (resetPriority) {
5788
+ resetPriority();
5583
5789
  }
5584
- return val;
5585
- });
5586
- setColumns(tempColumn);
5790
+ }
5587
5791
  };
5588
5792
  return {
5589
- rows,
5590
- columns,
5591
- onToggleColumnOptional,
5592
- typeTable: data.typeTable
5793
+ selection,
5794
+ isForm,
5795
+ methods,
5796
+ defaultPriority,
5797
+ savePriorities,
5798
+ label,
5799
+ id,
5800
+ onChange
5593
5801
  };
5594
5802
  };
5595
5803
 
5596
- // src/widget/advance/table/table-group/controller.ts
5597
- var import_react17 = require("react");
5598
-
5599
- // src/utils/i18n.ts
5600
- var import_react_i18next2 = require("react-i18next");
5601
- var import_i18next = __toESM(require("i18next"));
5602
- var import_i18next_browser_languagedetector = __toESM(require("i18next-browser-languagedetector"));
5603
-
5604
- // src/locales/vi.json
5605
- var vi_default = {
5606
- login: "\u0110\u0103ng Nh\u1EADp",
5607
- english: "Ti\u1EBFng Anh",
5608
- vietnamese: "Ti\u1EBFng Vi\u1EC7t",
5804
+ // src/widget/basic/float-time-field/controller.ts
5805
+ var import_react18 = require("react");
5806
+ var import_utils10 = require("@fctc/interface-logic/utils");
5807
+ var floatTimeFiledController = ({
5808
+ onChange: fieldOnChange,
5809
+ onBlur,
5810
+ value,
5811
+ isDirty,
5812
+ props
5813
+ }) => {
5814
+ const { name, defaultValue = 0, onChange } = props;
5815
+ const [input, setInput] = (0, import_react18.useState)(
5816
+ (0, import_utils10.convertFloatToTime)(value ?? defaultValue)
5817
+ );
5818
+ const [formattedTime, setFormattedTime] = (0, import_react18.useState)("");
5819
+ const [errors, setErrors] = (0, import_react18.useState)("");
5820
+ const handleInputChange = (e) => {
5821
+ const raw = e.target.value.replace(/[^\d:]/g, "");
5822
+ setInput(raw);
5823
+ const timeRegex = /^(\d{1,2}):?(\d{0,2})$/;
5824
+ const match = raw.match(timeRegex);
5825
+ if (!match) {
5826
+ setErrors("\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7");
5827
+ setFormattedTime("");
5828
+ return;
5829
+ }
5830
+ let hours = parseInt(match[1] ?? "0", 10);
5831
+ let minutes = parseInt(match[2] ?? "0", 10);
5832
+ if (isNaN(hours)) hours = 0;
5833
+ if (isNaN(minutes)) minutes = 0;
5834
+ if (hours >= 24) {
5835
+ hours = 0;
5836
+ }
5837
+ if (minutes >= 60) {
5838
+ minutes = 0;
5839
+ }
5840
+ const formatted = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
5841
+ setErrors("");
5842
+ setFormattedTime(formatted);
5843
+ fieldOnChange(formatted);
5844
+ };
5845
+ const handleBlur = () => {
5846
+ if (!isDirty) return;
5847
+ if (formattedTime) {
5848
+ setInput(formattedTime);
5849
+ const floatVal = (0, import_utils10.convertTimeToFloat)(formattedTime);
5850
+ fieldOnChange(floatVal);
5851
+ if (onChange) {
5852
+ onChange(name ?? "", floatVal);
5853
+ }
5854
+ } else {
5855
+ setInput("00:00");
5856
+ fieldOnChange(0);
5857
+ if (onChange) {
5858
+ onChange(name ?? "", 0);
5859
+ }
5860
+ setErrors("");
5861
+ }
5862
+ onBlur();
5863
+ };
5864
+ const handleKeyDown = (e) => {
5865
+ {
5866
+ const allowed = [
5867
+ "Backspace",
5868
+ "Tab",
5869
+ "ArrowLeft",
5870
+ "ArrowRight",
5871
+ "Delete",
5872
+ "Home",
5873
+ "End",
5874
+ ":"
5875
+ ];
5876
+ const isNumber = /^[0-9]$/.test(e.key);
5877
+ if (!isNumber && !allowed.includes(e.key)) {
5878
+ e.preventDefault();
5879
+ }
5880
+ }
5881
+ };
5882
+ return {
5883
+ handleInputChange,
5884
+ handleBlur,
5885
+ handleKeyDown,
5886
+ input,
5887
+ errors
5888
+ };
5889
+ };
5890
+
5891
+ // src/widget/basic/float-field/controller.ts
5892
+ var import_react19 = require("react");
5893
+
5894
+ // src/utils/i18n.ts
5895
+ var import_react_i18next2 = require("react-i18next");
5896
+ var import_i18next = __toESM(require("i18next"));
5897
+ var import_i18next_browser_languagedetector = __toESM(require("i18next-browser-languagedetector"));
5898
+
5899
+ // src/locales/vi.json
5900
+ var vi_default = {
5901
+ login: "\u0110\u0103ng Nh\u1EADp",
5902
+ english: "Ti\u1EBFng Anh",
5903
+ vietnamese: "Ti\u1EBFng Vi\u1EC7t",
5609
5904
  note_login: "Xin h\xE3y \u0111\u0103ng nh\u1EADp v\xE0o t\xE0i kho\u1EA3n c\u1EE7a b\u1EA1n",
5610
5905
  "note-forgotpassword": "Vui l\xF2ng nh\u1EADp \u0111\u1ECBa ch\u1EC9 email b\u1EA1n mu\u1ED1n th\xF4ng tin \u0111\u1EB7t l\u1EA1i m\u1EADt kh\u1EA9u c\u1EE7a b\u1EA1n \u0111\u01B0\u1EE3c g\u1EEDi t\u1EDBi ",
5611
5906
  placeholder_email: "Nh\u1EADp \u0111\u1ECBa ch\u1EC9 email c\u1EE7a b\u1EA1n",
@@ -6362,1301 +6657,1064 @@ import_i18next.default.use(import_i18next_browser_languagedetector.default).use(
6362
6657
  });
6363
6658
  var i18n_default = import_i18next.default;
6364
6659
 
6365
- // src/widget/advance/table/table-group/controller.ts
6366
- var import_hooks13 = require("@fctc/interface-logic/hooks");
6367
- var import_store11 = require("@fctc/interface-logic/store");
6368
-
6369
- // src/environment.ts
6370
- var environment_exports = {};
6371
- __reExport(environment_exports, require("@fctc/interface-logic/environment"));
6372
-
6373
- // src/widget/advance/table/table-group/controller.ts
6374
- var tableGroupController = (props) => {
6375
- const env = (0, environment_exports.getEnv)();
6376
- const {
6377
- rows,
6378
- columns,
6379
- indexRow,
6380
- row,
6381
- model,
6382
- viewData,
6383
- renderField,
6384
- level,
6385
- specification,
6386
- domain,
6387
- context,
6388
- checkedAll,
6389
- isDisplayCheckbox,
6390
- isAutoSelect,
6391
- setIsAutoSelect,
6392
- selectedRowKeysRef
6393
- } = props;
6394
- const [pageGroup, setPageGroup] = (0, import_react17.useState)(0);
6395
- const { groupByDomain, selectedTags } = (0, import_store11.useAppSelector)(import_store11.selectSearch);
6396
- const { selectedRowKeys } = (0, import_store11.useAppSelector)(import_store11.selectList);
6397
- const appDispatch = (0, import_store11.useAppDispatch)();
6398
- const { toDataJS } = (0, import_hooks13.useOdooDataTransform)();
6399
- const initVal = toDataJS(row, viewData, model);
6400
- const [isShowGroup, setIsShowGroup] = (0, import_react17.useState)(false);
6401
- const [colEmptyGroup, setColEmptyGroup] = (0, import_react17.useState)({
6402
- fromStart: 1,
6403
- fromEnd: 1
6404
- });
6405
- const processedData = (0, import_react17.useMemo)(() => {
6406
- const calculateColSpanEmpty = () => {
6407
- const startIndex = columns.findIndex(
6408
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
6409
- );
6410
- const endIndex = columns.findLastIndex(
6411
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
6412
- );
6413
- const fromStart = startIndex === -1 ? columns.length : startIndex;
6414
- const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
6415
- setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
6416
- return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
6417
- };
6418
- return calculateColSpanEmpty();
6419
- }, [columns, row]);
6420
- const shouldFetchData = (0, import_react17.useMemo)(() => {
6421
- return !!isShowGroup;
6422
- }, [isShowGroup]);
6423
- const enabled = shouldFetchData && !!processedData;
6424
- const listDataProps = {
6425
- model,
6426
- specification,
6427
- domain,
6428
- context,
6429
- offset: pageGroup * 10,
6430
- fields: groupByDomain?.fields,
6431
- groupby: [groupByDomain?.contexts[level]?.group_by]
6432
- };
6433
- const queryKey = [
6434
- `data-${model}--${level}-row${indexRow}`,
6435
- specification,
6436
- domain,
6437
- pageGroup
6438
- ];
6439
- const {
6440
- data: dataResponse,
6441
- isFetched: isQueryFetched,
6442
- isPlaceholderData,
6443
- isLoading,
6444
- isFetching
6445
- } = (0, import_hooks13.useGetListData)(listDataProps, queryKey, enabled);
6446
- const {
6447
- columns: columnsGroup,
6448
- rows: rowsGroup,
6449
- typeTable: typeTableGroup
6450
- } = tableController({
6451
- data: {
6452
- fields: viewData?.views?.list?.fields,
6453
- records: dataResponse?.records ?? dataResponse?.groups,
6454
- dataModel: viewData?.models?.[model],
6455
- context: env.context,
6456
- typeTable: dataResponse?.groups ? "group" : "list"
6457
- }
6458
- });
6459
- const leftPadding = level > 1 ? level * 8 + "px" : "0px";
6460
- (0, import_react17.useEffect)(() => {
6461
- if (isShowGroup && selectedTags?.length > 0) {
6462
- setIsShowGroup(false);
6463
- }
6464
- }, [selectedTags]);
6465
- const group_by_field_name = groupByDomain?.contexts[level - 1]?.group_by;
6466
- 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(
6467
- (selectItem) => selectItem?.[0] === row[group_by_field_name]
6468
- )?.[1] : row[group_by_field_name];
6469
- const nameGroupWithCount = `${typeof nameGroup === "string" ? nameGroup : typeof nameGroup === "boolean" && nameGroup ? i18n_default.t("yes") : i18n_default.t("no")} (${row[`${group_by_field_name?.split(":")?.[0]}_count`]})`;
6470
- const allIdsNull = selectedRowKeys?.every((item) => item === void 0);
6471
- const handleExpandChildGroup = () => {
6472
- if (isLoading || isFetching) return;
6473
- const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
6474
- if (allIdsNull || typeTableGroup === "group") {
6475
- toggleShowGroup();
6476
- return;
6660
+ // src/widget/basic/float-field/controller.ts
6661
+ var floatController = ({
6662
+ onChange,
6663
+ value,
6664
+ props
6665
+ }) => {
6666
+ const { name, required, methods, onChange: handleOnchange, string } = props;
6667
+ const { setError, clearErrors } = methods;
6668
+ const [inputValue, setInputValue] = (0, import_react19.useState)(
6669
+ value !== void 0 && value !== null ? useFormatFloatNumber(value) : ""
6670
+ );
6671
+ (0, import_react19.useEffect)(() => {
6672
+ if (value !== void 0 && value !== null && value !== parseFloat(inputValue?.replace(/,/g, ""))) {
6673
+ setInputValue(useFormatFloatNumber(value));
6674
+ clearErrors(name);
6675
+ } else if (value === null || value === void 0) {
6676
+ setInputValue("");
6477
6677
  }
6478
- if (isShowGroup && checkedAll) {
6479
- const ids = rowsGroup?.map((item) => item?.id) || [];
6480
- const filteredIds = selectedRowKeys.filter(
6481
- (id) => !ids.includes(id)
6482
- );
6483
- appDispatch((0, import_store11.setSelectedRowKeys)(filteredIds));
6484
- } else if (!isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && checkedAll && !allIdsNull && isQueryFetched) {
6485
- const clonedKeys = [...selectedRowKeys];
6486
- appDispatch((0, import_store11.setSelectedRowKeys)([...clonedKeys, -1]));
6487
- setTimeout(() => appDispatch((0, import_store11.setSelectedRowKeys)(clonedKeys)), 500);
6488
- } else if (isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && !checkedAll && !allIdsNull) {
6489
- const filteredKeys = selectedRowKeys.filter((id) => id > -1);
6490
- appDispatch((0, import_store11.setSelectedRowKeys)(filteredKeys));
6678
+ }, [value, name, clearErrors]);
6679
+ const isDirtyRef = (0, import_react19.useRef)(false);
6680
+ const inputRef = (0, import_react19.useRef)(null);
6681
+ const lastCommittedValueRef = (0, import_react19.useRef)(null);
6682
+ const handleInputChange = (e) => {
6683
+ const newValue = e.target.value;
6684
+ const valueWithoutCommas = newValue.replace(/,/g, "");
6685
+ if (/^[0-9]*[.,]?[0-9]*$/.test(valueWithoutCommas) || newValue === "") {
6686
+ const parts = valueWithoutCommas.split(".");
6687
+ let integerPart = parts[0] || "";
6688
+ const decimalPart = parts[1] || "";
6689
+ if (decimalPart.length > 100) return;
6690
+ if (integerPart) {
6691
+ integerPart = Number(integerPart).toLocaleString("en-US");
6692
+ }
6693
+ const formattedValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
6694
+ setInputValue(formattedValue);
6695
+ const parsedValue = parseFloat(valueWithoutCommas.replace(",", "."));
6696
+ if (!isNaN(parsedValue)) {
6697
+ if (parsedValue < 0) {
6698
+ setError(name, {
6699
+ type: "validate",
6700
+ message: i18n_default.t("invalid_number")
6701
+ });
6702
+ } else {
6703
+ onChange(parsedValue);
6704
+ clearErrors(name);
6705
+ isDirtyRef.current = true;
6706
+ }
6707
+ } else {
6708
+ onChange(null);
6709
+ clearErrors(name);
6710
+ }
6491
6711
  }
6492
- toggleShowGroup();
6493
6712
  };
6494
- (0, import_react17.useEffect)(() => {
6495
- if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
6713
+ const handleInputMouseLeave = () => {
6714
+ if (!isDirtyRef.current) {
6715
+ inputRef.current?.blur();
6496
6716
  return;
6497
6717
  }
6498
- const clonedKeys = [...selectedRowKeys];
6499
- (0, import_store11.setSelectedRowKeys)([...clonedKeys, -1]);
6500
- setTimeout(() => (0, import_store11.setSelectedRowKeys)(clonedKeys), 500);
6501
- }, [isQueryFetched]);
6502
- return {
6503
- handleExpandChildGroup,
6504
- colEmptyGroup,
6505
- leftPadding,
6506
- isShowGroup,
6507
- isQueryFetched,
6508
- nameGroupWithCount,
6509
- columns,
6510
- row,
6511
- isPlaceholderData,
6512
- columnsGroup,
6513
- indexRow,
6514
- rowsGroup,
6515
- model,
6516
- viewData,
6517
- renderField,
6518
- level,
6519
- specification,
6520
- context,
6521
- checkedAll,
6522
- isDisplayCheckbox,
6523
- isAutoSelect,
6524
- setIsAutoSelect,
6525
- selectedRowKeysRef,
6526
- initVal,
6527
- dataResponse,
6528
- pageGroup,
6529
- setPageGroup
6530
- };
6531
- };
6532
-
6533
- // src/widget/advance/search/controller.ts
6534
- var import_constants3 = require("@fctc/interface-logic/constants");
6535
- var import_utils6 = require("@fctc/interface-logic/utils");
6536
- var import_react18 = require("react");
6537
- var searchController = ({
6538
- viewData,
6539
- actionData,
6540
- fieldsList,
6541
- contextSearch,
6542
- setSearchMap,
6543
- searchMap
6544
- }) => {
6545
- const [filterBy, setFilterBy] = (0, import_react18.useState)(null);
6546
- const [searchBy, setSearchBy] = (0, import_react18.useState)(null);
6547
- const [groupBy, setGroupBy] = (0, import_react18.useState)(null);
6548
- const [selectedTags, setSelectedTags] = (0, import_react18.useState)(null);
6549
- const [searchString, setSearchString] = (0, import_react18.useState)("");
6550
- const aid = actionData?.id;
6551
- const model = actionData?.res_model;
6552
- const clearSearch = () => {
6553
- setFilterBy([]);
6554
- setGroupBy([]);
6555
- setSearchBy([]);
6556
- setSelectedTags(null);
6557
- setSearchString("");
6558
- setSearchMap({});
6559
- };
6560
- const fetchData = async () => {
6561
- if (viewData) {
6562
- try {
6563
- const dataModel = viewData?.models?.[model];
6564
- const searchViews = viewData?.views?.search;
6565
- const searchByItems = searchViews?.search_by?.filter(
6566
- (item) => !import_utils6.domainHelper.matchDomains(contextSearch, item.invisible)
6567
- )?.map(
6568
- ({ string, name, filter_domain, operator, widget }, index) => ({
6569
- dataIndex: index,
6570
- title: string ?? dataModel[name]?.string,
6571
- name: name ?? dataModel[name]?.name,
6572
- filter_domain,
6573
- operator,
6574
- widget,
6575
- type: dataModel[name]?.type
6576
- })
6577
- );
6578
- const filterByItems = searchViews?.filter_by.filter((item) => {
6579
- return !import_utils6.domainHelper.matchDomains(contextSearch, item?.invisible);
6580
- })?.map((item) => ({ ...item, active: false }));
6581
- const groupByItems = searchViews?.group_by.filter(
6582
- (item) => !import_utils6.domainHelper.matchDomains(contextSearch, item?.invisible)
6583
- ).map((item) => ({
6584
- ...item,
6585
- string: item.string ?? viewData?.models?.[model]?.[item?.name?.split("group_by_")?.[1]]?.string
6586
- }));
6587
- setSearchBy(searchByItems);
6588
- setFilterBy(filterByItems);
6589
- setGroupBy(groupByItems);
6590
- } catch (error) {
6591
- console.error("Error fetching data:", error);
6718
+ const rawValue = inputValue.replace(/,/g, "");
6719
+ const parsedValue = parseFloat(rawValue);
6720
+ if (rawValue === "" || rawValue === ".") {
6721
+ if (required) {
6722
+ setError(name, {
6723
+ type: "required",
6724
+ message: `${string} ${i18n_default.t("must_required")}`
6725
+ });
6592
6726
  }
6593
- }
6594
- };
6595
- (0, import_react18.useEffect)(() => {
6596
- clearSearch();
6597
- fetchData();
6598
- }, [aid, model, viewData]);
6599
- const onChangeSearchInput = (search_string) => {
6600
- setSearchString(search_string);
6601
- };
6602
- const removeKeyFromSearchMap = ({
6603
- key,
6604
- item
6605
- }) => {
6606
- const values = searchMap[key];
6607
- if (!values) return searchMap;
6608
- const newSearchMap = { ...searchMap };
6609
- if (item) {
6610
- const filtered = values.filter((value) => value.name !== item.name);
6611
- if (filtered.length > 0) {
6612
- newSearchMap[key] = filtered;
6727
+ onChange(null);
6728
+ setInputValue("");
6729
+ lastCommittedValueRef.current = null;
6730
+ } else if (!isNaN(parsedValue)) {
6731
+ if (parsedValue < 0) {
6732
+ setError(name, {
6733
+ type: "validate",
6734
+ message: i18n_default.t("invalid_number")
6735
+ });
6736
+ setInputValue("");
6737
+ lastCommittedValueRef.current = null;
6613
6738
  } else {
6614
- delete newSearchMap[key];
6739
+ if (lastCommittedValueRef.current !== parsedValue) {
6740
+ const parts = rawValue.split(".");
6741
+ let integerPart = parts[0];
6742
+ const decimalPart = parts[1] || "";
6743
+ integerPart = Number(integerPart).toLocaleString("en-US");
6744
+ const formattedValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
6745
+ onChange(parsedValue);
6746
+ setInputValue(formattedValue);
6747
+ handleOnchange?.(name ?? "", parsedValue);
6748
+ clearErrors(name);
6749
+ lastCommittedValueRef.current = parsedValue;
6750
+ }
6615
6751
  }
6616
6752
  } else {
6617
- delete newSearchMap[key];
6618
- }
6619
- setSearchMap(newSearchMap);
6620
- };
6621
- const updateSearchMap = ({ key, item }) => {
6622
- const newSearchMap = { ...searchMap };
6623
- const currentValues = searchMap[key] ?? [];
6624
- newSearchMap[key] = [...currentValues, item];
6625
- setSearchMap(newSearchMap);
6626
- };
6627
- const removeSearchItems = (key, item) => {
6628
- removeKeyFromSearchMap({ key: String(key), item });
6629
- };
6630
- const addSearchItems = (key, newItem) => {
6631
- updateSearchMap({ key, item: newItem });
6632
- };
6633
- const setTagSearch = (0, import_react18.useCallback)(
6634
- (updatedMap) => {
6635
- if (!updatedMap) return;
6636
- const tagsSearch = Object.entries(updatedMap).map(
6637
- ([key, objValues]) => {
6638
- const {
6639
- title,
6640
- name,
6641
- groupIndex,
6642
- type,
6643
- widget,
6644
- modelType,
6645
- dataIndex
6646
- } = objValues[0];
6647
- if (!key?.includes(import_constants3.SearchType.GROUP)) {
6648
- const values = objValues?.map((objValue) => objValue.value);
6649
- return {
6650
- title,
6651
- name: type === import_constants3.SearchType.SEARCH ? `${import_constants3.SearchType.SEARCH}_${String(dataIndex)}` : groupIndex ?? name,
6652
- values,
6653
- type,
6654
- widget,
6655
- modelType
6656
- };
6657
- } else {
6658
- const contexts = [];
6659
- let groupValues = [];
6660
- objValues?.forEach((objValue) => {
6661
- const { context, value, active, groupIndex: groupIndex2, isDefault } = objValue;
6662
- const indexAppend = groupIndex2 != null ? groupIndex2 : viewData?.views?.search?.filters_by?.length ?? 0;
6663
- contexts.push(
6664
- ...Array.isArray(context?.group_by) ? context.group_by.map((item) => ({ group_by: item })) : [context]
6665
- );
6666
- groupValues[indexAppend] = {
6667
- contexts: [
6668
- ...Array.isArray(context?.group_by) ? context.group_by.map((item) => ({
6669
- group_by: item
6670
- })) : [context]
6671
- ],
6672
- strings: isDefault ? [value] : [...groupValues[indexAppend]?.strings ?? [], value]
6673
- };
6674
- });
6675
- const fields = [
6676
- ...new Set(fieldsList?.map((item) => item?.name))
6677
- ];
6678
- const groupByTag = {
6679
- title,
6680
- values: groupValues?.filter(
6681
- (item) => item !== void 0
6682
- ),
6683
- type,
6684
- contexts,
6685
- fields
6686
- };
6687
- return groupByTag;
6688
- }
6689
- }
6690
- );
6691
- setSelectedTags(tagsSearch);
6692
- setSearchString("");
6693
- },
6694
- [searchMap]
6695
- );
6696
- (0, import_react18.useEffect)(() => {
6697
- setSelectedTags(null);
6698
- setTagSearch(searchMap);
6699
- }, [searchMap]);
6700
- const handleAddTagSearch = (tag) => {
6701
- const {
6702
- domain,
6703
- groupIndex,
6704
- value,
6705
- type,
6706
- title,
6707
- context,
6708
- active,
6709
- dataIndex
6710
- } = tag;
6711
- const domainFormat = new import_utils6.domainHelper.Domain(domain);
6712
- if (type === import_constants3.SearchType.FILTER) {
6713
- addSearchItems(`${import_constants3.SearchType.FILTER}_${groupIndex}`, {
6714
- ...tag,
6715
- domain: domain ? domainFormat.toList(context) : null
6716
- });
6717
- } else if (type === import_constants3.SearchType.SEARCH) {
6718
- addSearchItems(`${import_constants3.SearchType.SEARCH}_${String(dataIndex)}`, {
6719
- ...tag,
6720
- domain: domain ? domainFormat.toList({
6721
- ...context,
6722
- self: value
6723
- }) : null
6724
- });
6725
- } else if (type === import_constants3.SearchType.GROUP) {
6726
- addSearchItems(`${import_constants3.SearchType.GROUP}`, {
6727
- ...tag,
6728
- domain: domain ? domainFormat.toList({
6729
- context,
6730
- self: value
6731
- }) : null
6753
+ setError(name, {
6754
+ type: "validate",
6755
+ message: i18n_default.t("invalid_number")
6732
6756
  });
6757
+ setInputValue("");
6758
+ lastCommittedValueRef.current = null;
6733
6759
  }
6760
+ isDirtyRef.current = false;
6761
+ inputRef.current?.blur();
6734
6762
  };
6735
6763
  return {
6736
- groupBy,
6737
- searchBy,
6738
- filterBy,
6739
- selectedTags,
6740
- searchString,
6741
- setFilterBy,
6742
- setGroupBy,
6743
- setSearchBy,
6744
- clearSearch,
6745
- setSelectedTags,
6746
- removeSearchItems,
6747
- onSearchString: onChangeSearchInput,
6748
- handleAddTagSearch
6749
- };
6750
- };
6751
-
6752
- // src/widget/basic/many2many-field/controller.ts
6753
- var import_environment8 = require("@fctc/interface-logic/environment");
6754
- var import_store12 = require("@fctc/interface-logic/store");
6755
- var import_utils7 = require("@fctc/interface-logic/utils");
6756
- var many2manyFieldController = (props) => {
6757
- const {
6758
- relation,
6759
- domain,
6760
- context,
6761
- tab,
6762
- model,
6763
- aid,
6764
- setSelectedRowKeys: setSelectedRowKeys4,
6765
- fields,
6766
- setFields,
6767
- groupByDomain,
6768
- page,
6769
- options,
6770
- sessionStorageUtils
6771
- } = props;
6772
- const appDispatch = (0, import_store12.useAppDispatch)();
6773
- const actionData = sessionStorageUtils.getActionData();
6774
- const [debouncedPage] = useDebounce(page, 500);
6775
- const [order, setOrder] = (0, import_react19.useState)();
6776
- const [isLoadedData, setIsLoadedData] = (0, import_react19.useState)(false);
6777
- const [domainMany2Many, setDomainMany2Many] = (0, import_react19.useState)(domain);
6778
- const env = (0, import_environment8.getEnv)();
6779
- const { selectedTags } = (0, import_store12.useAppSelector)(import_store12.selectSearch);
6780
- const viewParams = {
6781
- model: relation,
6782
- views: [
6783
- [false, "list"],
6784
- [false, "search"]
6785
- ],
6786
- context
6787
- };
6788
- const { data: viewResponse, isFetched: isViewReponseFetched } = (0, hooks_exports.useGetView)(
6789
- viewParams,
6790
- actionData
6791
- );
6792
- const baseModel = (0, import_react19.useMemo)(
6793
- () => ({
6794
- name: String(relation),
6795
- view: viewResponse || {},
6796
- actContext: context,
6797
- fields: [
6798
- ...Object.values(viewResponse?.views?.list?.fields ?? {}),
6799
- ...tab?.fields ? tab.fields : []
6800
- ]
6801
- }),
6802
- [model, viewResponse]
6803
- );
6804
- const initModel = (0, hooks_exports.useModel)();
6805
- const modelInstance = (0, import_react19.useMemo)(() => {
6806
- if (viewResponse) {
6807
- return initModel.initModel(baseModel);
6808
- }
6809
- return null;
6810
- }, [baseModel, viewResponse]);
6811
- const specification = (0, import_react19.useMemo)(() => {
6812
- if (modelInstance) {
6813
- return modelInstance.getSpecification();
6814
- }
6815
- return null;
6816
- }, [modelInstance]);
6817
- const default_order = viewResponse && viewResponse?.views?.list?.default_order;
6818
- const optionsObject = tab?.options ? (0, import_utils7.evalJSONContext)(tab?.options) : (options ? (0, import_utils7.evalJSONContext)(options) : {}) || {};
6819
- const fetchData = async () => {
6820
- try {
6821
- setDomainMany2Many(domain);
6822
- appDispatch((0, import_store12.setFirstDomain)(domain));
6823
- appDispatch((0, import_store12.setViewDataStore)(viewResponse));
6824
- const modalData = viewResponse?.views?.list?.fields.map((field) => ({
6825
- ...viewResponse?.models?.[String(model)]?.[field?.name],
6826
- ...field
6827
- }));
6828
- if (!fields?.[`${aid}_${relation}_popupmany2many`] && modalData) {
6829
- setFields({
6830
- ...fields,
6831
- [`${aid}_${relation}_popupmany2many`]: modalData
6832
- });
6833
- }
6834
- appDispatch((0, import_store12.setPage)(0));
6835
- } catch (err) {
6836
- console.log(err);
6837
- }
6838
- };
6839
- const queryKey = [
6840
- `view-${relation}-${aid}`,
6841
- specification,
6842
- domainMany2Many,
6843
- debouncedPage,
6844
- groupByDomain,
6845
- order
6846
- ];
6847
- const data = {
6848
- model: relation,
6849
- specification,
6850
- domain: domainMany2Many,
6851
- offset: debouncedPage * 10,
6852
- limit: 10,
6853
- context,
6854
- fields: groupByDomain?.fields,
6855
- groupby: [groupByDomain?.contexts[0]?.group_by],
6856
- sort: order ? order : default_order ? (0, import_utils7.formatSortingString)(default_order) : ""
6857
- };
6858
- const enabled = isLoadedData && !!specification && !!relation && !!domainMany2Many && !!viewResponse;
6859
- const {
6860
- data: dataResponse,
6861
- isLoading: isDataLoading,
6862
- isFetched: isDataResponseFetched,
6863
- isPlaceholderData
6864
- } = (0, hooks_exports.useGetListData)(data, queryKey, enabled);
6865
- (0, import_react19.useEffect)(() => {
6866
- if (viewResponse) {
6867
- fetchData();
6868
- }
6869
- return () => {
6870
- appDispatch((0, import_store12.setGroupByDomain)(null));
6871
- setFields((prevFields) => ({
6872
- ...prevFields,
6873
- [`${aid}_${relation}_popupmany2many`]: null
6874
- }));
6875
- appDispatch((0, import_store12.setPage)(0));
6876
- setSelectedRowKeys4([]);
6877
- setDomainMany2Many(null);
6878
- setIsLoadedData(false);
6879
- };
6880
- }, [viewResponse]);
6881
- const { rows, columns, typeTable } = tableController({
6882
- data: {
6883
- fields: fields?.[`${aid}_${relation}_popupmany2many`] || viewResponse?.views?.list?.fields,
6884
- records: dataResponse?.records ?? dataResponse?.groups,
6885
- dataModel: viewResponse?.models?.[String(relation)],
6886
- context: { ...env.context, ...context },
6887
- typeTable: dataResponse?.groups ? "group" : "list"
6888
- }
6889
- });
6890
- const dataFormView = {
6891
- id: null,
6892
- model: relation,
6893
- context
6894
- };
6895
- const {
6896
- refetch,
6897
- data: dataFormViewResponse,
6898
- isSuccess
6899
- } = (0, hooks_exports.useGetFormView)({
6900
- data: dataFormView,
6901
- queryKey: [`form-view-action-${relation}`],
6902
- enabled: false
6903
- });
6904
- (0, import_react19.useEffect)(() => {
6905
- if (isSuccess && dataFormViewResponse) {
6906
- sessionStorage.setItem("actionData", JSON.stringify(dataFormViewResponse));
6907
- window.location.href = `/form/menu?model=${relation}`;
6908
- }
6909
- }, [isSuccess]);
6910
- (0, import_react19.useEffect)(() => {
6911
- if (domainMany2Many && !isLoadedData) {
6912
- setIsLoadedData(true);
6913
- }
6914
- }, [domainMany2Many]);
6915
- const handleCreateNewOnPage = async () => {
6916
- try {
6917
- refetch();
6918
- } catch (error) {
6919
- console.log(error);
6920
- }
6921
- };
6922
- return {};
6923
- };
6924
-
6925
- // src/widget/basic/many2many-tags-field/controller.ts
6926
- var import_react20 = require("react");
6927
- var import_constants4 = require("@fctc/interface-logic/constants");
6928
- var import_environment9 = require("@fctc/interface-logic/environment");
6929
- var import_hooks15 = require("@fctc/interface-logic/hooks");
6930
- var import_utils8 = require("@fctc/interface-logic/utils");
6931
- var many2manyTagsController = (props) => {
6932
- const {
6933
- relation,
6934
- domain,
6935
- options: optionsFields,
6936
- widget,
6937
- formValues,
6938
- placeholderNoOption
6939
- } = props;
6940
- const isUser = relation === "res.users" || relation === "res.partner";
6941
- const env = (0, import_environment9.getEnv)();
6942
- const addtionalFields = optionsFields ? (0, import_utils8.evalJSONContext)(optionsFields) : null;
6943
- const domainObject = (0, import_react20.useMemo)(
6944
- () => (0, import_utils8.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues || {}))),
6945
- [domain, formValues]
6946
- );
6947
- const data = {
6948
- model: relation ?? "",
6949
- domain: domainObject,
6950
- specification: {
6951
- id: {},
6952
- name: {},
6953
- display_name: {},
6954
- ...widget && import_constants4.WIDGETAVATAR[widget] ? { image_256: {} } : {},
6955
- ...widget && import_constants4.WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
6956
- },
6957
- enabled: true,
6958
- context: env.context
6959
- };
6960
- const { data: dataOfSelection } = (0, import_hooks15.useGetSelection)({
6961
- data,
6962
- queryKey: [`data_${relation}`, domainObject]
6963
- });
6964
- const customNoOptionsMessage = () => placeholderNoOption;
6965
- const tranfer = (data2) => {
6966
- return data2?.map((val) => ({
6967
- id: val.value,
6968
- display_name: val.label
6969
- })) || [];
6970
- };
6971
- const options = dataOfSelection?.records?.map((val) => ({
6972
- value: val.id,
6973
- label: val.name ?? val.display_name,
6974
- ...val
6975
- })) || [];
6976
- return {
6977
- options,
6978
- customNoOptionsMessage,
6979
- tranfer,
6980
- dataOfSelection,
6981
- isUser
6982
- };
6983
- };
6984
-
6985
- // src/widget/basic/status-bar-field/controller.ts
6986
- var import_react21 = require("react");
6987
- var import_hooks16 = require("@fctc/interface-logic/hooks");
6988
- var import_store13 = require("@fctc/interface-logic/store");
6989
- var import_utils9 = require("@fctc/interface-logic/utils");
6990
- var durationController = (props) => {
6991
- const {
6992
- relation,
6993
- defaultValue,
6994
- domain,
6995
- formValues,
6996
- name,
6997
- id,
6998
- model,
6999
- onRefetch
7000
- } = props;
7001
- const specification = {
7002
- id: 0,
7003
- name: "",
7004
- fold: ""
7005
- };
7006
- const [disabled, setDisabled] = (0, import_react21.useState)(false);
7007
- const [modelStatus, setModalStatus] = (0, import_react21.useState)(false);
7008
- const { context } = (0, import_store13.useAppSelector)(import_store13.selectEnv);
7009
- const queryKey = [`data-status-duration`, specification];
7010
- const listDataProps = {
7011
- model: relation,
7012
- specification,
7013
- domain: (0, import_utils9.evalJSONDomain)(domain, JSON.parse(JSON.stringify(formValues))),
7014
- limit: 10,
7015
- offset: 0,
7016
- fields: "",
7017
- groupby: [],
7018
- context: {
7019
- lang: context.lang
7020
- },
7021
- sort: ""
7022
- };
7023
- const { data: dataResponse } = (0, import_hooks16.useGetListData)(listDataProps, queryKey);
7024
- const { mutate: fetchChangeStatus } = (0, import_hooks16.useChangeStatus)();
7025
- const handleClick = async (stage_id) => {
7026
- setDisabled(true);
7027
- if (stage_id) {
7028
- fetchChangeStatus(
7029
- {
7030
- data: {
7031
- stage_id,
7032
- name,
7033
- id,
7034
- model,
7035
- lang: context.lang
7036
- }
7037
- },
7038
- {
7039
- onSuccess: (res) => {
7040
- if (res) {
7041
- setDisabled(false);
7042
- onRefetch && onRefetch();
7043
- }
7044
- }
7045
- }
7046
- );
7047
- }
6764
+ handleInputMouseLeave,
6765
+ handleInputChange,
6766
+ useFormatFloatNumber,
6767
+ inputRef,
6768
+ inputValue
6769
+ };
6770
+ };
6771
+ var useFormatFloatNumber = (value) => {
6772
+ if (value === void 0 || value === null || value === "") return "";
6773
+ const numValue = typeof value === "string" ? parseFloat(value.replace(/,/g, "")) : value;
6774
+ if (isNaN(numValue)) return "";
6775
+ return numValue.toLocaleString("en-US", {
6776
+ minimumFractionDigits: numValue % 1 === 0 ? 0 : 1,
6777
+ maximumFractionDigits: 20
6778
+ });
6779
+ };
6780
+
6781
+ // src/widget/basic/download-file-field/controller.ts
6782
+ var import_react20 = require("react");
6783
+ var downloadFileController = () => {
6784
+ const inputId = (0, import_react20.useId)();
6785
+ const [file, setFile] = (0, import_react20.useState)(null);
6786
+ const handleFileChange = (e) => {
6787
+ setFile(e.target.files[0]);
6788
+ };
6789
+ const handleFileDownload = () => {
6790
+ const url = URL.createObjectURL(file);
6791
+ const link = document.createElement("a");
6792
+ link.href = url;
6793
+ link.download = file.name;
6794
+ document.body.appendChild(link);
6795
+ link.click();
6796
+ document.body.removeChild(link);
7048
6797
  };
7049
6798
  return {
7050
- defaultValue,
7051
- dataResponse,
7052
- handleClick,
7053
- disabled,
7054
- modelStatus,
7055
- setModalStatus
6799
+ inputId,
6800
+ file,
6801
+ handleFileChange,
6802
+ handleFileDownload
7056
6803
  };
7057
6804
  };
7058
6805
 
7059
- // src/widget/basic/priority-field/controller.ts
7060
- var import_hooks17 = require("@fctc/interface-logic/hooks");
7061
- var import_utils10 = require("@fctc/interface-logic/utils");
7062
- var priorityFieldController = (props) => {
7063
- const {
7064
- value,
7065
- isForm,
7066
- name,
7067
- methods,
7068
- onChange,
7069
- model,
7070
- selection,
7071
- id,
7072
- actionData,
7073
- viewData,
7074
- context
7075
- } = props;
7076
- const _context = { ...(0, import_utils10.evalJSONContext)(actionData?.context) };
7077
- const contextObject = { ...context, ..._context };
7078
- const defaultPriority = parseInt(value) + 1;
7079
- const label = viewData?.models?.[model]?.[name ?? ""]?.string ?? name;
7080
- const { mutateAsync: fetchSave } = (0, import_hooks17.useSave)();
7081
- const savePriorities = async ({
7082
- value: value2,
7083
- resetPriority
7084
- }) => {
7085
- const priorityValue = value2 <= 0 ? 0 : value2 - 1;
6806
+ // src/widget/basic/download-binary-field/controller.ts
6807
+ var downLoadBinaryController = (props) => {
6808
+ const { value, defaultValue, formValues } = props;
6809
+ const handleFileDownload = async (e) => {
6810
+ e.stopPropagation();
6811
+ await downloadFile(value || defaultValue, formValues?.name);
6812
+ };
6813
+ const downloadFile = async (url, filename) => {
7086
6814
  try {
7087
- fetchSave({
7088
- ids: id ? [id] : [],
7089
- data: { [name ?? ""]: String(priorityValue) },
7090
- model: model ?? "",
7091
- context: contextObject
7092
- });
7093
- if (typeof onChange === "function") {
7094
- onChange(name ?? "", String(priorityValue));
6815
+ const response = await fetch(url);
6816
+ if (response) {
6817
+ const blob = await response.blob();
6818
+ const urlBlob = window.URL.createObjectURL(blob);
6819
+ const link = document.createElement("a");
6820
+ link.href = urlBlob;
6821
+ link.download = filename || "downloaded-file";
6822
+ document.body.appendChild(link);
6823
+ link.click();
6824
+ document.body.removeChild(link);
6825
+ window.URL.revokeObjectURL(urlBlob);
7095
6826
  }
7096
6827
  } catch (error) {
7097
- if (resetPriority) {
7098
- resetPriority();
7099
- }
6828
+ console.error("File download failed:", error);
7100
6829
  }
7101
6830
  };
7102
6831
  return {
7103
- selection,
7104
- isForm,
7105
- methods,
7106
- defaultPriority,
7107
- savePriorities,
7108
- label,
7109
- id,
7110
- onChange
6832
+ handleFileDownload
7111
6833
  };
7112
6834
  };
7113
6835
 
7114
- // src/widget/basic/float-time-field/controller.ts
7115
- var import_react22 = require("react");
7116
- var import_utils11 = require("@fctc/interface-logic/utils");
7117
- var floatTimeFiledController = ({
7118
- onChange: fieldOnChange,
7119
- onBlur,
7120
- value,
7121
- isDirty,
7122
- props
7123
- }) => {
7124
- const { name, defaultValue = 0, onChange } = props;
7125
- const [input, setInput] = (0, import_react22.useState)(
7126
- (0, import_utils11.convertFloatToTime)(value ?? defaultValue)
7127
- );
7128
- const [formattedTime, setFormattedTime] = (0, import_react22.useState)("");
7129
- const [errors, setErrors] = (0, import_react22.useState)("");
7130
- const handleInputChange = (e) => {
7131
- const raw = e.target.value.replace(/[^\d:]/g, "");
7132
- setInput(raw);
7133
- const timeRegex = /^(\d{1,2}):?(\d{0,2})$/;
7134
- const match = raw.match(timeRegex);
7135
- if (!match) {
7136
- setErrors("\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7");
7137
- setFormattedTime("");
7138
- return;
7139
- }
7140
- let hours = parseInt(match[1] ?? "0", 10);
7141
- let minutes = parseInt(match[2] ?? "0", 10);
7142
- if (isNaN(hours)) hours = 0;
7143
- if (isNaN(minutes)) minutes = 0;
7144
- if (hours >= 24) {
7145
- hours = 0;
7146
- }
7147
- if (minutes >= 60) {
7148
- minutes = 0;
6836
+ // src/widget/basic/date-field/controller.ts
6837
+ var import_moment = __toESM(require_moment());
6838
+ var DURATIONS = {
6839
+ PAST: "past",
6840
+ NOW: "now",
6841
+ FUTURE: "future"
6842
+ };
6843
+ var dateFieldController = (props) => {
6844
+ const {
6845
+ string,
6846
+ showTime = false,
6847
+ widget,
6848
+ min,
6849
+ max,
6850
+ viewData,
6851
+ formValues,
6852
+ model
6853
+ } = props;
6854
+ const range = (start, end, step = 1) => {
6855
+ const arr = [];
6856
+ for (let i = start; i < end; i += step) {
6857
+ arr.push(i);
7149
6858
  }
7150
- const formatted = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
7151
- setErrors("");
7152
- setFormattedTime(formatted);
7153
- fieldOnChange(formatted);
6859
+ return arr;
7154
6860
  };
7155
- const handleBlur = () => {
7156
- if (!isDirty) return;
7157
- if (formattedTime) {
7158
- setInput(formattedTime);
7159
- const floatVal = (0, import_utils11.convertTimeToFloat)(formattedTime);
7160
- fieldOnChange(floatVal);
7161
- if (onChange) {
7162
- onChange(name ?? "", floatVal);
7163
- }
7164
- } else {
7165
- setInput("00:00");
7166
- fieldOnChange(0);
7167
- if (onChange) {
7168
- onChange(name ?? "", 0);
6861
+ const formatDate = showTime ? "DD/MM/YYYY HH:mm:ss" : "DD/MM/YYYY";
6862
+ const formatDateParse = showTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
6863
+ const fieldForCustom = widget === "datetime_custom" || widget === "date_custom";
6864
+ const minNowValue = fieldForCustom && (min === DURATIONS.NOW ? true : typeof min === "string" && Object.keys(formValues)?.includes(min) && formValues?.[min] ? (0, import_moment.default)(formValues?.[min], formatDateParse).add(7, "hours") : null);
6865
+ const maxNowValue = fieldForCustom && (max === DURATIONS.NOW ? true : typeof max === "string" && Object.keys(formValues)?.includes(max) && formValues?.[max] ? (0, import_moment.default)(formValues?.[max], formatDateParse).add(7, "hours") : null);
6866
+ const years = range(
6867
+ minNowValue ? (/* @__PURE__ */ new Date()).getFullYear() : 1990,
6868
+ (/* @__PURE__ */ new Date()).getFullYear() + 4,
6869
+ 1
6870
+ );
6871
+ const months_vi = [
6872
+ "Th\xE1ng 1",
6873
+ "Th\xE1ng 2",
6874
+ "Th\xE1ng 3",
6875
+ "Th\xE1ng 4",
6876
+ "Th\xE1ng 5",
6877
+ "Th\xE1ng 6",
6878
+ "Th\xE1ng 7",
6879
+ "Th\xE1ng 8",
6880
+ "Th\xE1ng 9",
6881
+ "Th\xE1ng 10",
6882
+ "Th\xE1ng 11",
6883
+ "Th\xE1ng 12"
6884
+ ];
6885
+ const months_en = [
6886
+ "January",
6887
+ "February",
6888
+ "March",
6889
+ "April",
6890
+ "May",
6891
+ "June",
6892
+ "July",
6893
+ "August",
6894
+ "September",
6895
+ "October",
6896
+ "November",
6897
+ "December"
6898
+ ];
6899
+ const customValidateMinMax = (date) => {
6900
+ const selected = (0, import_moment.default)(date, formatDateParse);
6901
+ const now = (0, import_moment.default)();
6902
+ const compareSelected = showTime ? selected : selected.clone().startOf("day");
6903
+ const compareNow = showTime ? now : now.clone().startOf("day");
6904
+ if (minNowValue) {
6905
+ if (compareSelected.isBefore(compareNow) && typeof minNowValue === "boolean" && minNowValue === true) {
6906
+ return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
6907
+ "greater_or_equal_now"
6908
+ )}`;
6909
+ } else if (import_moment.default.isMoment(minNowValue)) {
6910
+ const compareMin = showTime ? minNowValue : minNowValue.clone().startOf("day");
6911
+ if (compareSelected.isBefore(compareMin)) {
6912
+ const fieldRelationDate = viewData?.models?.[model]?.[min ?? ""];
6913
+ return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
6914
+ "greater_or_equal"
6915
+ )} ${fieldRelationDate?.string}`;
6916
+ }
7169
6917
  }
7170
- setErrors("");
7171
- }
7172
- onBlur();
7173
- };
7174
- const handleKeyDown = (e) => {
7175
- {
7176
- const allowed = [
7177
- "Backspace",
7178
- "Tab",
7179
- "ArrowLeft",
7180
- "ArrowRight",
7181
- "Delete",
7182
- "Home",
7183
- "End",
7184
- ":"
7185
- ];
7186
- const isNumber = /^[0-9]$/.test(e.key);
7187
- if (!isNumber && !allowed.includes(e.key)) {
7188
- e.preventDefault();
6918
+ } else if (maxNowValue) {
6919
+ if (compareSelected.isAfter(compareNow) && typeof maxNowValue === "boolean" && maxNowValue === true) {
6920
+ return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
6921
+ "less_or_equal_now"
6922
+ )}`;
6923
+ } else if (import_moment.default.isMoment(maxNowValue)) {
6924
+ const compareMax = showTime ? maxNowValue : maxNowValue.clone().startOf("day");
6925
+ if (compareSelected.isAfter(compareMax)) {
6926
+ const fieldRelationDate = viewData?.models?.[model]?.[max ?? ""];
6927
+ return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
6928
+ "less_or_equal"
6929
+ )} ${fieldRelationDate?.string}`;
6930
+ }
7189
6931
  }
7190
6932
  }
6933
+ return false;
7191
6934
  };
7192
6935
  return {
7193
- handleInputChange,
7194
- handleBlur,
7195
- handleKeyDown,
7196
- input,
7197
- errors
6936
+ formatDate,
6937
+ formatDateParse,
6938
+ range,
6939
+ years,
6940
+ months_vi,
6941
+ months_en,
6942
+ customValidateMinMax,
6943
+ minNowValue,
6944
+ maxNowValue
7198
6945
  };
7199
6946
  };
7200
6947
 
7201
- // src/widget/basic/float-field/controller.ts
7202
- var import_react23 = require("react");
7203
- var floatController = ({
7204
- onChange,
7205
- value,
7206
- props
7207
- }) => {
7208
- const { name, required, methods, onChange: handleOnchange, string } = props;
7209
- const { setError, clearErrors } = methods;
7210
- const [inputValue, setInputValue] = (0, import_react23.useState)(
7211
- value !== void 0 && value !== null ? useFormatFloatNumber(value) : ""
7212
- );
7213
- (0, import_react23.useEffect)(() => {
7214
- if (value !== void 0 && value !== null && value !== parseFloat(inputValue?.replace(/,/g, ""))) {
7215
- setInputValue(useFormatFloatNumber(value));
7216
- clearErrors(name);
7217
- } else if (value === null || value === void 0) {
7218
- setInputValue("");
7219
- }
7220
- }, [value, name, clearErrors]);
7221
- const isDirtyRef = (0, import_react23.useRef)(false);
7222
- const inputRef = (0, import_react23.useRef)(null);
7223
- const lastCommittedValueRef = (0, import_react23.useRef)(null);
7224
- const handleInputChange = (e) => {
7225
- const newValue = e.target.value;
7226
- const valueWithoutCommas = newValue.replace(/,/g, "");
7227
- if (/^[0-9]*[.,]?[0-9]*$/.test(valueWithoutCommas) || newValue === "") {
7228
- const parts = valueWithoutCommas.split(".");
7229
- let integerPart = parts[0] || "";
7230
- const decimalPart = parts[1] || "";
7231
- if (decimalPart.length > 100) return;
7232
- if (integerPart) {
7233
- integerPart = Number(integerPart).toLocaleString("en-US");
7234
- }
7235
- const formattedValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
7236
- setInputValue(formattedValue);
7237
- const parsedValue = parseFloat(valueWithoutCommas.replace(",", "."));
7238
- if (!isNaN(parsedValue)) {
7239
- if (parsedValue < 0) {
7240
- setError(name, {
7241
- type: "validate",
7242
- message: i18n_default.t("invalid_number")
7243
- });
7244
- } else {
7245
- onChange(parsedValue);
7246
- clearErrors(name);
7247
- isDirtyRef.current = true;
7248
- }
7249
- } else {
7250
- onChange(null);
7251
- clearErrors(name);
7252
- }
7253
- }
6948
+ // src/widget/basic/copy-link-button/controller.ts
6949
+ var import_react21 = require("react");
6950
+ var import_utils11 = require("@fctc/interface-logic/utils");
6951
+ var copyLinkButtonController = (props) => {
6952
+ const { value, defaultValue } = props;
6953
+ const [isCopied, setIsCopied] = (0, import_react21.useState)(false);
6954
+ const handleCopyToClipboard = async (value2) => {
6955
+ await (0, import_utils11.copyTextToClipboard)(value2);
6956
+ setIsCopied(true);
6957
+ setTimeout(() => setIsCopied(false), 2e3);
7254
6958
  };
7255
- const handleInputMouseLeave = () => {
7256
- if (!isDirtyRef.current) {
7257
- inputRef.current?.blur();
7258
- return;
7259
- }
7260
- const rawValue = inputValue.replace(/,/g, "");
7261
- const parsedValue = parseFloat(rawValue);
7262
- if (rawValue === "" || rawValue === ".") {
7263
- if (required) {
7264
- setError(name, {
7265
- type: "required",
7266
- message: `${string} ${i18n_default.t("must_required")}`
7267
- });
7268
- }
7269
- onChange(null);
7270
- setInputValue("");
7271
- lastCommittedValueRef.current = null;
7272
- } else if (!isNaN(parsedValue)) {
7273
- if (parsedValue < 0) {
7274
- setError(name, {
7275
- type: "validate",
7276
- message: i18n_default.t("invalid_number")
7277
- });
7278
- setInputValue("");
7279
- lastCommittedValueRef.current = null;
7280
- } else {
7281
- if (lastCommittedValueRef.current !== parsedValue) {
7282
- const parts = rawValue.split(".");
7283
- let integerPart = parts[0];
7284
- const decimalPart = parts[1] || "";
7285
- integerPart = Number(integerPart).toLocaleString("en-US");
7286
- const formattedValue = decimalPart ? `${integerPart}.${decimalPart}` : integerPart;
7287
- onChange(parsedValue);
7288
- setInputValue(formattedValue);
7289
- handleOnchange?.(name ?? "", parsedValue);
7290
- clearErrors(name);
7291
- lastCommittedValueRef.current = parsedValue;
7292
- }
7293
- }
7294
- } else {
7295
- setError(name, {
7296
- type: "validate",
7297
- message: i18n_default.t("invalid_number")
6959
+ const propValue = value || defaultValue;
6960
+ return {
6961
+ isCopied,
6962
+ handleCopyToClipboard,
6963
+ propValue
6964
+ };
6965
+ };
6966
+
6967
+ // src/widget/basic/color-field/color-controller.ts
6968
+ var import_environment8 = require("@fctc/interface-logic/environment");
6969
+ var import_hooks17 = require("@fctc/interface-logic/hooks");
6970
+ var import_utils12 = require("@fctc/interface-logic/utils");
6971
+ var colorFieldController = (props) => {
6972
+ const { value, isForm, name, formValues, idForm, model, actionData } = props;
6973
+ const env = (0, import_environment8.getEnv)();
6974
+ const _context = { ...(0, import_utils12.evalJSONContext)(actionData?.context) || {} };
6975
+ const contextObject = { ...env.context, ..._context };
6976
+ const idDefault = isForm ? idForm : formValues?.id;
6977
+ const { mutate: onSave } = (0, import_hooks17.useSave)();
6978
+ const savePickColor = async (colorObject) => {
6979
+ const { id } = colorObject;
6980
+ if (value === id) return;
6981
+ try {
6982
+ onSave({
6983
+ ids: idDefault !== null ? [idDefault] : [],
6984
+ model: model ?? "",
6985
+ data: { [name ?? ""]: id },
6986
+ specification: {
6987
+ name: {},
6988
+ color: {}
6989
+ },
6990
+ context: contextObject
7298
6991
  });
7299
- setInputValue("");
7300
- lastCommittedValueRef.current = null;
6992
+ } catch (error) {
6993
+ console.log(error);
7301
6994
  }
7302
- isDirtyRef.current = false;
7303
- inputRef.current?.blur();
7304
6995
  };
7305
6996
  return {
7306
- handleInputMouseLeave,
7307
- handleInputChange,
7308
- useFormatFloatNumber,
7309
- inputRef,
7310
- inputValue
6997
+ savePickColor
7311
6998
  };
7312
6999
  };
7313
- var useFormatFloatNumber = (value) => {
7314
- if (value === void 0 || value === null || value === "") return "";
7315
- const numValue = typeof value === "string" ? parseFloat(value.replace(/,/g, "")) : value;
7316
- if (isNaN(numValue)) return "";
7317
- return numValue.toLocaleString("en-US", {
7318
- minimumFractionDigits: numValue % 1 === 0 ? 0 : 1,
7319
- maximumFractionDigits: 20
7320
- });
7321
- };
7322
7000
 
7323
- // src/widget/basic/download-file-field/controller.ts
7324
- var import_react24 = require("react");
7325
- var downloadFileController = () => {
7326
- const inputId = (0, import_react24.useId)();
7327
- const [file, setFile] = (0, import_react24.useState)(null);
7328
- const handleFileChange = (e) => {
7329
- setFile(e.target.files[0]);
7001
+ // src/widget/basic/binary-field/controller.ts
7002
+ var import_react22 = require("react");
7003
+ var import_utils13 = require("@fctc/interface-logic/utils");
7004
+ var binaryFieldController = (props) => {
7005
+ const { name, methods, readonly = false, value } = props;
7006
+ const inputId = (0, import_react22.useId)();
7007
+ const [selectedImage, setSelectedImage] = (0, import_react22.useState)(null);
7008
+ const [initialImage, setInitialImage] = (0, import_react22.useState)(value || null);
7009
+ const [isInsideTable, setIsInsideTable] = (0, import_react22.useState)(false);
7010
+ const { setValue } = methods;
7011
+ const binaryRef = (0, import_react22.useRef)(null);
7012
+ const convertUrlToBase64 = async (url) => {
7013
+ try {
7014
+ const response = await fetch(url);
7015
+ const blob = await response.blob();
7016
+ return new Promise((resolve, reject) => {
7017
+ const reader = new FileReader();
7018
+ reader.onloadend = () => {
7019
+ resolve(reader.result);
7020
+ };
7021
+ reader.onerror = reject;
7022
+ reader.readAsDataURL(blob);
7023
+ });
7024
+ } catch (error) {
7025
+ console.error("Error converting URL to Base64:", error);
7026
+ throw error;
7027
+ }
7330
7028
  };
7331
- const handleFileDownload = () => {
7332
- const url = URL.createObjectURL(file);
7333
- const link = document.createElement("a");
7334
- link.href = url;
7335
- link.download = file.name;
7336
- document.body.appendChild(link);
7337
- link.click();
7338
- document.body.removeChild(link);
7029
+ const extractBase64Data = (base64Url) => {
7030
+ if (base64Url.includes("base64,")) {
7031
+ return base64Url.split("base64,")[1];
7032
+ }
7033
+ return base64Url;
7034
+ };
7035
+ const handleImageChange = async (e, onChange) => {
7036
+ if (readonly) return;
7037
+ const file = e?.target?.files?.[0];
7038
+ if (file) {
7039
+ const imageUrl = URL.createObjectURL(file);
7040
+ setSelectedImage(imageUrl);
7041
+ setInitialImage(null);
7042
+ onChange(file);
7043
+ const compressedBase64 = await convertUrlToBase64(imageUrl);
7044
+ const base64Data = extractBase64Data(compressedBase64);
7045
+ setValue(name, base64Data, {
7046
+ shouldDirty: true
7047
+ });
7048
+ }
7049
+ };
7050
+ const handleRemoveImage = (onChange) => {
7051
+ setSelectedImage(null);
7052
+ setInitialImage(null);
7053
+ onChange(null);
7054
+ };
7055
+ const isBlobUrl = (url) => {
7056
+ return /^blob:/.test(url);
7057
+ };
7058
+ const checkIsImageLink = (url) => {
7059
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
7060
+ return imageExtensions.test(url) || (0, import_utils13.isBase64Image)(url) || isBlobUrl(url);
7061
+ };
7062
+ const getImageBase64WithMimeType = (base64) => {
7063
+ if (typeof base64 !== "string" || base64.length < 10) return null;
7064
+ if ((0, import_utils13.isBase64Image)(base64)) return base64;
7065
+ let mimeType = null;
7066
+ if (base64.startsWith("iVBORw0KGgo")) mimeType = "image/png";
7067
+ else if (base64.startsWith("/9j/")) mimeType = "image/jpeg";
7068
+ else if (base64.startsWith("R0lGOD")) mimeType = "image/gif";
7069
+ else if (base64.startsWith("Qk")) mimeType = "image/bmp";
7070
+ else if (base64.startsWith("UklGR")) mimeType = "image/webp";
7071
+ return mimeType ? `data:${mimeType};base64,${base64}` : null;
7339
7072
  };
7073
+ (0, import_react22.useEffect)(() => {
7074
+ return () => {
7075
+ if (selectedImage) {
7076
+ URL.revokeObjectURL(selectedImage);
7077
+ }
7078
+ };
7079
+ }, [selectedImage]);
7080
+ (0, import_react22.useEffect)(() => {
7081
+ if (binaryRef.current) {
7082
+ const isInsideTable2 = !!binaryRef.current.closest("table");
7083
+ setIsInsideTable(isInsideTable2);
7084
+ }
7085
+ }, []);
7340
7086
  return {
7341
7087
  inputId,
7342
- file,
7343
- handleFileChange,
7344
- handleFileDownload
7088
+ selectedImage,
7089
+ initialImage,
7090
+ isInsideTable,
7091
+ binaryRef,
7092
+ handleImageChange,
7093
+ handleRemoveImage,
7094
+ checkIsImageLink,
7095
+ getImageBase64WithMimeType
7345
7096
  };
7346
7097
  };
7347
7098
 
7348
- // src/widget/basic/download-binary-field/controller.ts
7349
- var downLoadBinaryController = (props) => {
7350
- const { value, defaultValue, formValues } = props;
7351
- const handleFileDownload = async (e) => {
7352
- e.stopPropagation();
7353
- await downloadFile(value || defaultValue, formValues?.name);
7099
+ // src/widget/advance/table/table-body/controller.ts
7100
+ var import_store10 = require("@fctc/interface-logic/store");
7101
+ var import_react23 = require("react");
7102
+ var tableBodyController = (props) => {
7103
+ const {
7104
+ checkedAll,
7105
+ checkboxRef,
7106
+ setIsAutoSelect,
7107
+ selectedRowKeys,
7108
+ row,
7109
+ isAutoSelect,
7110
+ selectedRowKeysRef,
7111
+ onClickRow
7112
+ } = props;
7113
+ const appDispatch = (0, import_store10.useAppDispatch)();
7114
+ const checked = (0, import_react23.useMemo)(() => {
7115
+ if (!row?.id) return false;
7116
+ if (selectedRowKeys?.includes(row.id)) {
7117
+ return true;
7118
+ }
7119
+ return checkedAll;
7120
+ }, [row?.id, selectedRowKeys, checkedAll]);
7121
+ const handleCheckBoxSingle = (event) => {
7122
+ event.stopPropagation();
7123
+ if (checkedAll) {
7124
+ checkboxRef.current = "uncheck";
7125
+ setIsAutoSelect(true);
7126
+ return;
7127
+ }
7128
+ const newSelectedRowKeys = selectedRowKeys?.includes(row.id) ? selectedRowKeys?.filter((key) => key !== row.id) : [...selectedRowKeys, row.id];
7129
+ console.log("newSelectedRowKeys", newSelectedRowKeys);
7130
+ appDispatch((0, import_store10.setSelectedRowKeys)(newSelectedRowKeys));
7354
7131
  };
7355
- const downloadFile = async (url, filename) => {
7356
- try {
7357
- const response = await fetch(url);
7358
- if (response) {
7359
- const blob = await response.blob();
7360
- const urlBlob = window.URL.createObjectURL(blob);
7361
- const link = document.createElement("a");
7362
- link.href = urlBlob;
7363
- link.download = filename || "downloaded-file";
7364
- document.body.appendChild(link);
7365
- link.click();
7366
- document.body.removeChild(link);
7367
- window.URL.revokeObjectURL(urlBlob);
7132
+ const handleClickRow = (col, row2) => {
7133
+ onClickRow(col, row2);
7134
+ };
7135
+ (0, import_react23.useEffect)(() => {
7136
+ if (!row?.id) return;
7137
+ if (isAutoSelect) {
7138
+ if (checkboxRef?.current === "uncheck") {
7139
+ const filtered = selectedRowKeysRef.current.filter(
7140
+ (id) => id !== row.id
7141
+ );
7142
+ selectedRowKeysRef.current = filtered;
7143
+ appDispatch((0, import_store10.setSelectedRowKeys)(filtered));
7144
+ } else {
7145
+ const unique = Array.from(
7146
+ /* @__PURE__ */ new Set([...selectedRowKeysRef?.current, row?.id])
7147
+ );
7148
+ selectedRowKeysRef.current = unique;
7149
+ appDispatch((0, import_store10.setSelectedRowKeys)(unique));
7368
7150
  }
7369
- } catch (error) {
7370
- console.error("File download failed:", error);
7371
7151
  }
7372
- };
7152
+ }, [isAutoSelect]);
7153
+ (0, import_react23.useEffect)(() => {
7154
+ if (!checkedAll) {
7155
+ checkboxRef.current = "enabled";
7156
+ false;
7157
+ }
7158
+ }, [checkedAll]);
7373
7159
  return {
7374
- handleFileDownload
7160
+ handleCheckBoxSingle,
7161
+ checked,
7162
+ handleClickRow
7375
7163
  };
7376
7164
  };
7377
7165
 
7378
- // src/widget/basic/date-field/controller.ts
7379
- var import_moment = __toESM(require_moment());
7380
- var DURATIONS = {
7381
- PAST: "past",
7382
- NOW: "now",
7383
- FUTURE: "future"
7384
- };
7385
- var dateFieldController = (props) => {
7386
- const {
7387
- string,
7388
- showTime = false,
7389
- widget,
7390
- min,
7391
- max,
7392
- viewData,
7393
- formValues,
7394
- model
7395
- } = props;
7396
- const range = (start, end, step = 1) => {
7397
- const arr = [];
7398
- for (let i = start; i < end; i += step) {
7399
- arr.push(i);
7166
+ // src/widget/advance/table/table-head/controller.ts
7167
+ var import_store11 = require("@fctc/interface-logic/store");
7168
+ var tableHeadController = (props) => {
7169
+ const { typeTable, rows, selectedRowKeysRef } = props;
7170
+ const appDispatch = (0, import_store11.useAppDispatch)();
7171
+ const { groupByDomain } = (0, import_store11.useAppSelector)(import_store11.selectSearch);
7172
+ const handleCheckBoxAll = (event) => {
7173
+ if (event?.target?.checked && typeTable === "list") {
7174
+ const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
7175
+ appDispatch((0, import_store11.setSelectedRowKeys)(allRowKeys));
7176
+ } else if (event?.target?.checked && typeTable === "group") {
7177
+ const rowsIDs = document.querySelectorAll("tr[data-row-id]");
7178
+ const ids = Array.from(rowsIDs)?.map(
7179
+ (row) => Number(row?.getAttribute("data-row-id"))
7180
+ );
7181
+ if (ids?.length > 0) {
7182
+ appDispatch((0, import_store11.setSelectedRowKeys)(ids));
7183
+ } else {
7184
+ const sum = countSum(
7185
+ rows,
7186
+ typeof groupByDomain === "object" ? groupByDomain?.contexts?.[0]?.group_by : void 0
7187
+ );
7188
+ const keys = Array.from({ length: sum }, (_) => void 0);
7189
+ appDispatch((0, import_store11.setSelectedRowKeys)(keys));
7190
+ }
7191
+ if (selectedRowKeysRef) {
7192
+ selectedRowKeysRef.current = [];
7193
+ }
7194
+ } else {
7195
+ appDispatch((0, import_store11.setSelectedRowKeys)([]));
7400
7196
  }
7401
- return arr;
7402
7197
  };
7403
- const formatDate = showTime ? "DD/MM/YYYY HH:mm:ss" : "DD/MM/YYYY";
7404
- const formatDateParse = showTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD";
7405
- const fieldForCustom = widget === "datetime_custom" || widget === "date_custom";
7406
- const minNowValue = fieldForCustom && (min === DURATIONS.NOW ? true : typeof min === "string" && Object.keys(formValues)?.includes(min) && formValues?.[min] ? (0, import_moment.default)(formValues?.[min], formatDateParse).add(7, "hours") : null);
7407
- const maxNowValue = fieldForCustom && (max === DURATIONS.NOW ? true : typeof max === "string" && Object.keys(formValues)?.includes(max) && formValues?.[max] ? (0, import_moment.default)(formValues?.[max], formatDateParse).add(7, "hours") : null);
7408
- const years = range(
7409
- minNowValue ? (/* @__PURE__ */ new Date()).getFullYear() : 1990,
7410
- (/* @__PURE__ */ new Date()).getFullYear() + 4,
7411
- 1
7412
- );
7413
- const months_vi = [
7414
- "Th\xE1ng 1",
7415
- "Th\xE1ng 2",
7416
- "Th\xE1ng 3",
7417
- "Th\xE1ng 4",
7418
- "Th\xE1ng 5",
7419
- "Th\xE1ng 6",
7420
- "Th\xE1ng 7",
7421
- "Th\xE1ng 8",
7422
- "Th\xE1ng 9",
7423
- "Th\xE1ng 10",
7424
- "Th\xE1ng 11",
7425
- "Th\xE1ng 12"
7426
- ];
7427
- const months_en = [
7428
- "January",
7429
- "February",
7430
- "March",
7431
- "April",
7432
- "May",
7433
- "June",
7434
- "July",
7435
- "August",
7436
- "September",
7437
- "October",
7438
- "November",
7439
- "December"
7440
- ];
7441
- const customValidateMinMax = (date) => {
7442
- const selected = (0, import_moment.default)(date, formatDateParse);
7443
- const now = (0, import_moment.default)();
7444
- const compareSelected = showTime ? selected : selected.clone().startOf("day");
7445
- const compareNow = showTime ? now : now.clone().startOf("day");
7446
- if (minNowValue) {
7447
- if (compareSelected.isBefore(compareNow) && typeof minNowValue === "boolean" && minNowValue === true) {
7448
- return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
7449
- "greater_or_equal_now"
7450
- )}`;
7451
- } else if (import_moment.default.isMoment(minNowValue)) {
7452
- const compareMin = showTime ? minNowValue : minNowValue.clone().startOf("day");
7453
- if (compareSelected.isBefore(compareMin)) {
7454
- const fieldRelationDate = viewData?.models?.[model]?.[min ?? ""];
7455
- return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
7456
- "greater_or_equal"
7457
- )} ${fieldRelationDate?.string}`;
7458
- }
7459
- }
7460
- } else if (maxNowValue) {
7461
- if (compareSelected.isAfter(compareNow) && typeof maxNowValue === "boolean" && maxNowValue === true) {
7462
- return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
7463
- "less_or_equal_now"
7464
- )}`;
7465
- } else if (import_moment.default.isMoment(maxNowValue)) {
7466
- const compareMax = showTime ? maxNowValue : maxNowValue.clone().startOf("day");
7467
- if (compareSelected.isAfter(compareMax)) {
7468
- const fieldRelationDate = viewData?.models?.[model]?.[max ?? ""];
7469
- return `${i18n_default.t("please_enter")} ${string} ${i18n_default.t(
7470
- "less_or_equal"
7471
- )} ${fieldRelationDate?.string}`;
7198
+ return {
7199
+ handleCheckBoxAll
7200
+ };
7201
+ };
7202
+
7203
+ // src/widget/advance/table/table-view/controller.ts
7204
+ var import_react24 = require("react");
7205
+ var import_store12 = require("@fctc/interface-logic/store");
7206
+ var import_utils14 = require("@fctc/interface-logic/utils");
7207
+ var tableController = ({ data }) => {
7208
+ const [rows, setRows] = (0, import_react24.useState)(data.records || []);
7209
+ const [columns, setColumns] = (0, import_react24.useState)([]);
7210
+ const dataModelFields = data.fields?.map((field) => {
7211
+ return {
7212
+ ...data.dataModel?.[field?.name],
7213
+ ...field,
7214
+ string: field?.string || data.dataModel?.[field?.name]?.string
7215
+ };
7216
+ });
7217
+ const mergeFields = mergeButtons(dataModelFields);
7218
+ const transformData = (dataList) => {
7219
+ if (!dataList) return;
7220
+ return dataList?.map((item) => {
7221
+ const transformedItem = { ...item };
7222
+ Object.keys(item).forEach((field) => {
7223
+ if (field !== "__domain") {
7224
+ if (item[field] && typeof item[field] === "object" && item[field].display_name) {
7225
+ transformedItem[field] = item[field];
7226
+ } else if (Array.isArray(item[field]) && item[field].length > 0) {
7227
+ if (data.typeTable === "group" && item[field]?.length === 2 && typeof item[field]?.[1] === "string") {
7228
+ transformedItem["string"] = item[field]?.[1];
7229
+ }
7230
+ transformedItem[field] = item[field];
7231
+ }
7472
7232
  }
7473
- }
7233
+ });
7234
+ return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
7235
+ });
7236
+ };
7237
+ (0, import_react24.useEffect)(() => {
7238
+ setRows(transformData(data.records || null));
7239
+ }, [data.records]);
7240
+ const handleGetColumns = () => {
7241
+ let cols = [];
7242
+ try {
7243
+ cols = mergeFields?.filter((item) => {
7244
+ return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? import_utils14.domainHelper.matchDomains(data.context, item?.column_invisible) : item?.invisible ? import_utils14.domainHelper.matchDomains(data.context, item?.invisible) : false);
7245
+ })?.map((field) => {
7246
+ return {
7247
+ name: field?.name,
7248
+ optional: field?.optional,
7249
+ title: field?.type_co === "button" ? "" : field?.string,
7250
+ field: { ...field }
7251
+ };
7252
+ });
7253
+ } catch (error) {
7254
+ console.error("Error in useTable:", error);
7474
7255
  }
7475
- return false;
7476
- };
7477
- return {
7478
- formatDate,
7479
- formatDateParse,
7480
- range,
7481
- years,
7482
- months_vi,
7483
- months_en,
7484
- customValidateMinMax,
7485
- minNowValue,
7486
- maxNowValue
7256
+ return cols;
7487
7257
  };
7488
- };
7489
-
7490
- // src/widget/basic/copy-link-button/controller.ts
7491
- var import_react25 = require("react");
7492
- var import_utils12 = require("@fctc/interface-logic/utils");
7493
- var copyLinkButtonController = (props) => {
7494
- const { value, defaultValue } = props;
7495
- const [isCopied, setIsCopied] = (0, import_react25.useState)(false);
7496
- const handleCopyToClipboard = async (value2) => {
7497
- await (0, import_utils12.copyTextToClipboard)(value2);
7498
- setIsCopied(true);
7499
- setTimeout(() => setIsCopied(false), 2e3);
7258
+ (0, import_react24.useEffect)(() => {
7259
+ const columns2 = handleGetColumns();
7260
+ setColumns(columns2);
7261
+ }, [data.records]);
7262
+ const onToggleColumnOptional = (item) => {
7263
+ const tempColumn = [...columns]?.map((val) => {
7264
+ if (item?.name === val?.name) {
7265
+ return {
7266
+ ...val,
7267
+ optional: item?.optional === "show" ? "hide" : "show"
7268
+ };
7269
+ }
7270
+ return val;
7271
+ });
7272
+ setColumns(tempColumn);
7500
7273
  };
7501
- const propValue = value || defaultValue;
7502
7274
  return {
7503
- isCopied,
7504
- handleCopyToClipboard,
7505
- propValue
7275
+ rows,
7276
+ columns,
7277
+ onToggleColumnOptional,
7278
+ typeTable: data.typeTable
7506
7279
  };
7507
7280
  };
7508
7281
 
7509
- // src/widget/basic/color-field/color-controller.ts
7510
- var import_environment10 = require("@fctc/interface-logic/environment");
7282
+ // src/widget/advance/table/table-group/controller.ts
7283
+ var import_react25 = require("react");
7511
7284
  var import_hooks18 = require("@fctc/interface-logic/hooks");
7512
- var import_utils13 = require("@fctc/interface-logic/utils");
7513
- var colorFieldController = (props) => {
7514
- const { value, isForm, name, formValues, idForm, model, actionData } = props;
7515
- const env = (0, import_environment10.getEnv)();
7516
- const _context = { ...(0, import_utils13.evalJSONContext)(actionData?.context) || {} };
7517
- const contextObject = { ...env.context, ..._context };
7518
- const idDefault = isForm ? idForm : formValues?.id;
7519
- const { mutate: onSave } = (0, import_hooks18.useSave)();
7520
- const savePickColor = async (colorObject) => {
7521
- const { id } = colorObject;
7522
- if (value === id) return;
7523
- try {
7524
- onSave({
7525
- ids: idDefault !== null ? [idDefault] : [],
7526
- model: model ?? "",
7527
- data: { [name ?? ""]: id },
7528
- specification: {
7529
- name: {},
7530
- color: {}
7531
- },
7532
- context: contextObject
7533
- });
7534
- } catch (error) {
7535
- console.log(error);
7285
+ var import_store13 = require("@fctc/interface-logic/store");
7286
+
7287
+ // src/environment.ts
7288
+ var environment_exports = {};
7289
+ __reExport(environment_exports, require("@fctc/interface-logic/environment"));
7290
+
7291
+ // src/widget/advance/table/table-group/controller.ts
7292
+ var tableGroupController = (props) => {
7293
+ const env = (0, environment_exports.getEnv)();
7294
+ const {
7295
+ rows,
7296
+ columns,
7297
+ indexRow,
7298
+ row,
7299
+ model,
7300
+ viewData,
7301
+ renderField,
7302
+ level,
7303
+ specification,
7304
+ domain,
7305
+ context,
7306
+ checkedAll,
7307
+ isDisplayCheckbox,
7308
+ isAutoSelect,
7309
+ setIsAutoSelect,
7310
+ selectedRowKeysRef
7311
+ } = props;
7312
+ const [pageGroup, setPageGroup] = (0, import_react25.useState)(0);
7313
+ const { groupByDomain, selectedTags } = (0, import_store13.useAppSelector)(import_store13.selectSearch);
7314
+ const { selectedRowKeys } = (0, import_store13.useAppSelector)(import_store13.selectList);
7315
+ const appDispatch = (0, import_store13.useAppDispatch)();
7316
+ const { toDataJS } = (0, import_hooks18.useOdooDataTransform)();
7317
+ const initVal = toDataJS(row, viewData, model);
7318
+ const [isShowGroup, setIsShowGroup] = (0, import_react25.useState)(false);
7319
+ const [colEmptyGroup, setColEmptyGroup] = (0, import_react25.useState)({
7320
+ fromStart: 1,
7321
+ fromEnd: 1
7322
+ });
7323
+ const processedData = (0, import_react25.useMemo)(() => {
7324
+ const calculateColSpanEmpty = () => {
7325
+ const startIndex = columns.findIndex(
7326
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
7327
+ );
7328
+ const endIndex = columns.findLastIndex(
7329
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
7330
+ );
7331
+ const fromStart = startIndex === -1 ? columns.length : startIndex;
7332
+ const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
7333
+ setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
7334
+ return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
7335
+ };
7336
+ return calculateColSpanEmpty();
7337
+ }, [columns, row]);
7338
+ const shouldFetchData = (0, import_react25.useMemo)(() => {
7339
+ return !!isShowGroup;
7340
+ }, [isShowGroup]);
7341
+ const enabled = shouldFetchData && !!processedData;
7342
+ const listDataProps = {
7343
+ model,
7344
+ specification,
7345
+ domain,
7346
+ context,
7347
+ offset: pageGroup * 10,
7348
+ fields: groupByDomain?.fields,
7349
+ groupby: [groupByDomain?.contexts[level]?.group_by]
7350
+ };
7351
+ const queryKey = [
7352
+ `data-${model}--${level}-row${indexRow}`,
7353
+ specification,
7354
+ domain,
7355
+ pageGroup
7356
+ ];
7357
+ const {
7358
+ data: dataResponse,
7359
+ isFetched: isQueryFetched,
7360
+ isPlaceholderData,
7361
+ isLoading,
7362
+ isFetching
7363
+ } = (0, import_hooks18.useGetListData)(listDataProps, queryKey, enabled);
7364
+ const {
7365
+ columns: columnsGroup,
7366
+ rows: rowsGroup,
7367
+ typeTable: typeTableGroup
7368
+ } = tableController({
7369
+ data: {
7370
+ fields: viewData?.views?.list?.fields,
7371
+ records: dataResponse?.records ?? dataResponse?.groups,
7372
+ dataModel: viewData?.models?.[model],
7373
+ context: env.context,
7374
+ typeTable: dataResponse?.groups ? "group" : "list"
7375
+ }
7376
+ });
7377
+ const leftPadding = level > 1 ? level * 8 + "px" : "0px";
7378
+ (0, import_react25.useEffect)(() => {
7379
+ if (isShowGroup && selectedTags?.length > 0) {
7380
+ setIsShowGroup(false);
7381
+ }
7382
+ }, [selectedTags]);
7383
+ const group_by_field_name = groupByDomain?.contexts[level - 1]?.group_by;
7384
+ 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(
7385
+ (selectItem) => selectItem?.[0] === row[group_by_field_name]
7386
+ )?.[1] : row[group_by_field_name];
7387
+ const nameGroupWithCount = `${typeof nameGroup === "string" ? nameGroup : typeof nameGroup === "boolean" && nameGroup ? i18n_default.t("yes") : i18n_default.t("no")} (${row[`${group_by_field_name?.split(":")?.[0]}_count`]})`;
7388
+ const allIdsNull = selectedRowKeys?.every((item) => item === void 0);
7389
+ const handleExpandChildGroup = () => {
7390
+ if (isLoading || isFetching) return;
7391
+ const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
7392
+ if (allIdsNull || typeTableGroup === "group") {
7393
+ toggleShowGroup();
7394
+ return;
7395
+ }
7396
+ if (isShowGroup && checkedAll) {
7397
+ const ids = rowsGroup?.map((item) => item?.id) || [];
7398
+ const filteredIds = selectedRowKeys.filter(
7399
+ (id) => !ids.includes(id)
7400
+ );
7401
+ appDispatch((0, import_store13.setSelectedRowKeys)(filteredIds));
7402
+ } else if (!isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && checkedAll && !allIdsNull && isQueryFetched) {
7403
+ const clonedKeys = [...selectedRowKeys];
7404
+ appDispatch((0, import_store13.setSelectedRowKeys)([...clonedKeys, -1]));
7405
+ setTimeout(() => appDispatch((0, import_store13.setSelectedRowKeys)(clonedKeys)), 500);
7406
+ } else if (isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && !checkedAll && !allIdsNull) {
7407
+ const filteredKeys = selectedRowKeys.filter((id) => id > -1);
7408
+ appDispatch((0, import_store13.setSelectedRowKeys)(filteredKeys));
7536
7409
  }
7410
+ toggleShowGroup();
7537
7411
  };
7412
+ (0, import_react25.useEffect)(() => {
7413
+ if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
7414
+ return;
7415
+ }
7416
+ const clonedKeys = [...selectedRowKeys];
7417
+ (0, import_store13.setSelectedRowKeys)([...clonedKeys, -1]);
7418
+ setTimeout(() => (0, import_store13.setSelectedRowKeys)(clonedKeys), 500);
7419
+ }, [isQueryFetched]);
7538
7420
  return {
7539
- savePickColor
7421
+ handleExpandChildGroup,
7422
+ colEmptyGroup,
7423
+ leftPadding,
7424
+ isShowGroup,
7425
+ isQueryFetched,
7426
+ nameGroupWithCount,
7427
+ columns,
7428
+ row,
7429
+ isPlaceholderData,
7430
+ columnsGroup,
7431
+ indexRow,
7432
+ rowsGroup,
7433
+ model,
7434
+ viewData,
7435
+ renderField,
7436
+ level,
7437
+ specification,
7438
+ context,
7439
+ checkedAll,
7440
+ isDisplayCheckbox,
7441
+ isAutoSelect,
7442
+ setIsAutoSelect,
7443
+ selectedRowKeysRef,
7444
+ initVal,
7445
+ dataResponse,
7446
+ pageGroup,
7447
+ setPageGroup
7540
7448
  };
7541
7449
  };
7542
7450
 
7543
- // src/widget/basic/binary-field/controller.ts
7451
+ // src/widget/advance/search/controller.ts
7452
+ var import_constants5 = require("@fctc/interface-logic/constants");
7453
+ var import_utils15 = require("@fctc/interface-logic/utils");
7454
+ var import_moment2 = __toESM(require_moment());
7544
7455
  var import_react26 = require("react");
7545
- var import_utils14 = require("@fctc/interface-logic/utils");
7546
- var binaryFieldController = (props) => {
7547
- const { name, methods, readonly = false, value } = props;
7548
- const inputId = (0, import_react26.useId)();
7549
- const [selectedImage, setSelectedImage] = (0, import_react26.useState)(null);
7550
- const [initialImage, setInitialImage] = (0, import_react26.useState)(value || null);
7551
- const [isInsideTable, setIsInsideTable] = (0, import_react26.useState)(false);
7552
- const { setValue } = methods;
7553
- const binaryRef = (0, import_react26.useRef)(null);
7554
- const convertUrlToBase64 = async (url) => {
7555
- try {
7556
- const response = await fetch(url);
7557
- const blob = await response.blob();
7558
- return new Promise((resolve, reject) => {
7559
- const reader = new FileReader();
7560
- reader.onloadend = () => {
7561
- resolve(reader.result);
7562
- };
7563
- reader.onerror = reject;
7564
- reader.readAsDataURL(blob);
7565
- });
7566
- } catch (error) {
7567
- console.error("Error converting URL to Base64:", error);
7568
- throw error;
7456
+ var searchController = ({
7457
+ viewData,
7458
+ actionData,
7459
+ fieldsList,
7460
+ contextSearch,
7461
+ setSearchMap,
7462
+ searchMap
7463
+ }) => {
7464
+ const [filterBy, setFilterBy] = (0, import_react26.useState)(null);
7465
+ const [searchBy, setSearchBy] = (0, import_react26.useState)(null);
7466
+ const [groupBy, setGroupBy] = (0, import_react26.useState)(null);
7467
+ const [selectedTags, setSelectedTags] = (0, import_react26.useState)(null);
7468
+ const [searchString, setSearchString] = (0, import_react26.useState)("");
7469
+ const domainAction = actionData?.domain ? Array.isArray(actionData?.domain) ? [...actionData?.domain] : (0, import_utils15.evalJSONDomain)(actionData?.domain, contextSearch) : [];
7470
+ const aid = actionData?.id;
7471
+ const model = actionData?.res_model;
7472
+ const clearSearch = () => {
7473
+ setFilterBy([]);
7474
+ setGroupBy([]);
7475
+ setSearchBy([]);
7476
+ setSelectedTags(null);
7477
+ setSearchString("");
7478
+ setSearchMap({});
7479
+ };
7480
+ const fetchData = async () => {
7481
+ if (viewData) {
7482
+ try {
7483
+ const dataModel = viewData?.models?.[model];
7484
+ const searchViews = viewData?.views?.search;
7485
+ const searchByItems = searchViews?.search_by?.filter(
7486
+ (item) => !import_utils15.domainHelper.matchDomains(contextSearch, item.invisible)
7487
+ )?.map(
7488
+ ({ string, name, filter_domain, operator, widget }, index) => ({
7489
+ dataIndex: index,
7490
+ title: string ?? dataModel[name]?.string,
7491
+ name: name ?? dataModel[name]?.name,
7492
+ filter_domain,
7493
+ operator,
7494
+ widget,
7495
+ type: dataModel[name]?.type
7496
+ })
7497
+ );
7498
+ const filterByItems = searchViews?.filter_by.filter((item) => {
7499
+ return !import_utils15.domainHelper.matchDomains(contextSearch, item?.invisible);
7500
+ })?.map((item) => ({ ...item, active: false }));
7501
+ const groupByItems = searchViews?.group_by.filter(
7502
+ (item) => !import_utils15.domainHelper.matchDomains(contextSearch, item?.invisible)
7503
+ ).map((item) => ({
7504
+ ...item,
7505
+ string: item.string ?? viewData?.models?.[model]?.[item?.name?.split("group_by_")?.[1]]?.string
7506
+ }));
7507
+ setSearchBy(searchByItems);
7508
+ setFilterBy(filterByItems);
7509
+ setGroupBy(groupByItems);
7510
+ } catch (error) {
7511
+ console.error("Error fetching data:", error);
7512
+ }
7569
7513
  }
7570
7514
  };
7571
- const extractBase64Data = (base64Url) => {
7572
- if (base64Url.includes("base64,")) {
7573
- return base64Url.split("base64,")[1];
7574
- }
7575
- return base64Url;
7515
+ (0, import_react26.useEffect)(() => {
7516
+ clearSearch();
7517
+ fetchData();
7518
+ }, [aid, model, viewData]);
7519
+ const onChangeSearchInput = (search_string) => {
7520
+ setSearchString(search_string);
7576
7521
  };
7577
- const handleImageChange = async (e, onChange) => {
7578
- if (readonly) return;
7579
- const file = e?.target?.files?.[0];
7580
- if (file) {
7581
- const imageUrl = URL.createObjectURL(file);
7582
- setSelectedImage(imageUrl);
7583
- setInitialImage(null);
7584
- onChange(file);
7585
- const compressedBase64 = await convertUrlToBase64(imageUrl);
7586
- const base64Data = extractBase64Data(compressedBase64);
7587
- setValue(name, base64Data, {
7588
- shouldDirty: true
7589
- });
7522
+ const removeKeyFromSearchMap = ({
7523
+ key,
7524
+ item
7525
+ }) => {
7526
+ const values = searchMap[key];
7527
+ if (!values) return searchMap;
7528
+ const newSearchMap = { ...searchMap };
7529
+ if (item) {
7530
+ const filtered = values.filter((value) => value.name !== item.name);
7531
+ if (filtered.length > 0) {
7532
+ newSearchMap[key] = filtered;
7533
+ } else {
7534
+ delete newSearchMap[key];
7535
+ }
7536
+ } else {
7537
+ delete newSearchMap[key];
7590
7538
  }
7539
+ setSearchMap(newSearchMap);
7591
7540
  };
7592
- const handleRemoveImage = (onChange) => {
7593
- setSelectedImage(null);
7594
- setInitialImage(null);
7595
- onChange(null);
7596
- };
7597
- const isBlobUrl = (url) => {
7598
- return /^blob:/.test(url);
7541
+ const updateSearchMap = ({ key, item }) => {
7542
+ const newSearchMap = { ...searchMap };
7543
+ const currentValues = searchMap[key] ?? [];
7544
+ newSearchMap[key] = [...currentValues, item];
7545
+ setSearchMap(newSearchMap);
7599
7546
  };
7600
- const checkIsImageLink = (url) => {
7601
- const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
7602
- return imageExtensions.test(url) || (0, import_utils14.isBase64Image)(url) || isBlobUrl(url);
7547
+ const removeSearchItems = (key, item) => {
7548
+ removeKeyFromSearchMap({ key: String(key), item });
7603
7549
  };
7604
- const getImageBase64WithMimeType = (base64) => {
7605
- if (typeof base64 !== "string" || base64.length < 10) return null;
7606
- if ((0, import_utils14.isBase64Image)(base64)) return base64;
7607
- let mimeType = null;
7608
- if (base64.startsWith("iVBORw0KGgo")) mimeType = "image/png";
7609
- else if (base64.startsWith("/9j/")) mimeType = "image/jpeg";
7610
- else if (base64.startsWith("R0lGOD")) mimeType = "image/gif";
7611
- else if (base64.startsWith("Qk")) mimeType = "image/bmp";
7612
- else if (base64.startsWith("UklGR")) mimeType = "image/webp";
7613
- return mimeType ? `data:${mimeType};base64,${base64}` : null;
7550
+ const addSearchItems = (key, newItem) => {
7551
+ updateSearchMap({ key, item: newItem });
7614
7552
  };
7615
- (0, import_react26.useEffect)(() => {
7616
- return () => {
7617
- if (selectedImage) {
7618
- URL.revokeObjectURL(selectedImage);
7553
+ const formatDomain = () => {
7554
+ if (domainAction) {
7555
+ const domain = [];
7556
+ if (domainAction?.length > 0) {
7557
+ if (Object.keys(searchMap).length > 0) {
7558
+ domain.push("&");
7559
+ }
7560
+ domainAction.forEach((domainItem) => {
7561
+ domain.push(domainItem);
7562
+ });
7619
7563
  }
7620
- };
7621
- }, [selectedImage]);
7564
+ Object.keys(searchMap).forEach((key, keyIndex, keys) => {
7565
+ if (!key?.includes(import_constants5.SearchType.GROUP)) {
7566
+ if (keys.length > 1 && keyIndex < keys.length - 1) {
7567
+ domain.push("&");
7568
+ }
7569
+ const valuesOfKey = searchMap[key];
7570
+ valuesOfKey.forEach((value, index) => {
7571
+ if (index < valuesOfKey.length - 1) {
7572
+ domain.push("|");
7573
+ }
7574
+ if (value.domain) {
7575
+ domain.push(...value.domain);
7576
+ return;
7577
+ }
7578
+ let valueDomainItem = value?.value;
7579
+ if (value?.modelType === "date") {
7580
+ valueDomainItem = (0, import_utils15.validateAndParseDate)(value?.value);
7581
+ } else if (value?.modelType === "datetime") {
7582
+ if (value?.operator === "<=" || value?.operator === "<") {
7583
+ const parsedDate = (0, import_utils15.validateAndParseDate)(value?.value, true);
7584
+ const hasTime = (0, import_moment2.default)(value?.value).format("HH:mm:ss") !== "00:00:00";
7585
+ valueDomainItem = hasTime ? (0, import_moment2.default)(parsedDate).format("YYYY-MM-DD HH:mm:ss") : (0, import_moment2.default)(parsedDate).add(1, "day").subtract(1, "second").format("YYYY-MM-DD HH:mm:ss");
7586
+ } else {
7587
+ valueDomainItem = (0, import_utils15.validateAndParseDate)(value?.value, true);
7588
+ }
7589
+ }
7590
+ const operator = value?.modelType === "date" || value?.modelType === "datetime" || value?.modelType === "boolean" || value?.modelType === "integer" ? value?.operator ?? "=" : value.operator ?? "ilike";
7591
+ domain.push([value.name, operator, valueDomainItem]);
7592
+ });
7593
+ }
7594
+ });
7595
+ return [...domain];
7596
+ }
7597
+ };
7598
+ const setTagSearch = (0, import_react26.useCallback)(
7599
+ (updatedMap) => {
7600
+ if (!updatedMap) return;
7601
+ const tagsSearch = Object.entries(updatedMap).map(
7602
+ ([key, objValues]) => {
7603
+ const {
7604
+ title,
7605
+ name,
7606
+ groupIndex,
7607
+ type,
7608
+ widget,
7609
+ modelType,
7610
+ dataIndex
7611
+ } = objValues[0];
7612
+ if (!key?.includes(import_constants5.SearchType.GROUP)) {
7613
+ const values = objValues?.map((objValue) => objValue.value);
7614
+ return {
7615
+ title,
7616
+ name: type === import_constants5.SearchType.SEARCH ? `${import_constants5.SearchType.SEARCH}_${String(dataIndex)}` : groupIndex ?? name,
7617
+ values,
7618
+ type,
7619
+ widget,
7620
+ modelType
7621
+ };
7622
+ } else {
7623
+ const contexts = [];
7624
+ let groupValues = [];
7625
+ objValues?.forEach((objValue) => {
7626
+ const { context, value, active, groupIndex: groupIndex2, isDefault } = objValue;
7627
+ const indexAppend = groupIndex2 != null ? groupIndex2 : viewData?.views?.search?.filters_by?.length ?? 0;
7628
+ contexts.push(
7629
+ ...Array.isArray(context?.group_by) ? context.group_by.map((item) => ({ group_by: item })) : [context]
7630
+ );
7631
+ groupValues[indexAppend] = {
7632
+ contexts: [
7633
+ ...Array.isArray(context?.group_by) ? context.group_by.map((item) => ({
7634
+ group_by: item
7635
+ })) : [context]
7636
+ ],
7637
+ strings: isDefault ? [value] : [...groupValues[indexAppend]?.strings ?? [], value]
7638
+ };
7639
+ });
7640
+ const fields = [
7641
+ ...new Set(fieldsList?.map((item) => item?.name))
7642
+ ];
7643
+ const groupByTag = {
7644
+ title,
7645
+ values: groupValues?.filter(
7646
+ (item) => item !== void 0
7647
+ ),
7648
+ type,
7649
+ contexts,
7650
+ fields
7651
+ };
7652
+ return groupByTag;
7653
+ }
7654
+ }
7655
+ );
7656
+ setSelectedTags(tagsSearch);
7657
+ setSearchString("");
7658
+ },
7659
+ [searchMap]
7660
+ );
7622
7661
  (0, import_react26.useEffect)(() => {
7623
- if (binaryRef.current) {
7624
- const isInsideTable2 = !!binaryRef.current.closest("table");
7625
- setIsInsideTable(isInsideTable2);
7662
+ setSelectedTags(null);
7663
+ setTagSearch(searchMap);
7664
+ }, [searchMap]);
7665
+ const handleAddTagSearch = (tag) => {
7666
+ const {
7667
+ domain,
7668
+ groupIndex,
7669
+ value,
7670
+ type,
7671
+ title,
7672
+ context,
7673
+ active,
7674
+ dataIndex
7675
+ } = tag;
7676
+ const domainFormat = new import_utils15.domainHelper.Domain(domain);
7677
+ if (type === import_constants5.SearchType.FILTER) {
7678
+ addSearchItems(`${import_constants5.SearchType.FILTER}_${groupIndex}`, {
7679
+ ...tag,
7680
+ domain: domain ? domainFormat.toList(context) : null
7681
+ });
7682
+ } else if (type === import_constants5.SearchType.SEARCH) {
7683
+ addSearchItems(`${import_constants5.SearchType.SEARCH}_${String(dataIndex)}`, {
7684
+ ...tag,
7685
+ domain: domain ? domainFormat.toList({
7686
+ ...context,
7687
+ self: value
7688
+ }) : null
7689
+ });
7690
+ } else if (type === import_constants5.SearchType.GROUP) {
7691
+ addSearchItems(`${import_constants5.SearchType.GROUP}`, {
7692
+ ...tag,
7693
+ domain: domain ? domainFormat.toList({
7694
+ context,
7695
+ self: value
7696
+ }) : null
7697
+ });
7626
7698
  }
7627
- }, []);
7699
+ };
7628
7700
  return {
7629
- inputId,
7630
- selectedImage,
7631
- initialImage,
7632
- isInsideTable,
7633
- binaryRef,
7634
- handleImageChange,
7635
- handleRemoveImage,
7636
- checkIsImageLink,
7637
- getImageBase64WithMimeType
7701
+ groupBy,
7702
+ searchBy,
7703
+ filterBy,
7704
+ selectedTags,
7705
+ searchString,
7706
+ setFilterBy,
7707
+ setGroupBy,
7708
+ setSearchBy,
7709
+ clearSearch,
7710
+ setSelectedTags,
7711
+ removeSearchItems,
7712
+ onSearchString: onChangeSearchInput,
7713
+ handleAddTagSearch,
7714
+ domain: formatDomain()
7638
7715
  };
7639
7716
  };
7640
7717
 
7641
- // src/utils.ts
7642
- var utils_exports = {};
7643
- __export(utils_exports, {
7644
- API_APP_URL: () => API_APP_URL,
7645
- API_PRESCHOOL_URL: () => API_PRESCHOOL_URL,
7646
- STORAGES: () => STORAGES,
7647
- combineContexts: () => combineContexts,
7648
- convertFieldsToArray: () => convertFieldsToArray,
7649
- countSum: () => countSum,
7650
- getDateRange: () => getDateRange,
7651
- languages: () => languages,
7652
- mergeButtons: () => mergeButtons,
7653
- setStorageItemAsync: () => setStorageItemAsync,
7654
- useGetRowIds: () => useGetRowIds,
7655
- useSelectionState: () => useSelectionState,
7656
- useStorageState: () => useStorageState
7657
- });
7658
- __reExport(utils_exports, require("@fctc/interface-logic/utils"));
7659
-
7660
7718
  // src/index.ts
7661
7719
  __reExport(index_exports, utils_exports, module.exports);
7662
7720
  __reExport(index_exports, store_exports, module.exports);
@@ -7668,12 +7726,6 @@ __reExport(constants_exports, require("@fctc/interface-logic/constants"));
7668
7726
  // src/index.ts
7669
7727
  __reExport(index_exports, constants_exports, module.exports);
7670
7728
  __reExport(index_exports, environment_exports, module.exports);
7671
-
7672
- // src/provider.ts
7673
- var provider_exports = {};
7674
- __reExport(provider_exports, require("@fctc/interface-logic/provider"));
7675
-
7676
- // src/index.ts
7677
7729
  __reExport(index_exports, provider_exports, module.exports);
7678
7730
 
7679
7731
  // src/services.ts