@fctc/widget-logic 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -4724,9 +4724,7 @@ var AppProvider = ({ children }) => {
4724
4724
  return combineContexts([user.context, company.context]);
4725
4725
  }, [user.context, company.context]);
4726
4726
  const menu = useMenu({ context: menuContext });
4727
- const action = useMemo7(() => {
4728
- return menu.state.action;
4729
- }, [menu.state.action]);
4727
+ const action = useMemo7(() => menu.state.action, [menu.state.action]);
4730
4728
  const viewContext = useMemo7(() => {
4731
4729
  return combineContexts([
4732
4730
  menuContext,
@@ -4755,15 +4753,13 @@ var AppProvider = ({ children }) => {
4755
4753
  action,
4756
4754
  view
4757
4755
  },
4758
- children: /* @__PURE__ */ jsx(MainProvider, { children })
4756
+ children
4759
4757
  }
4760
4758
  );
4761
4759
  };
4762
4760
  var useAppProvider = () => {
4763
4761
  const context = useContext(ReactContext);
4764
- if (!context) {
4765
- return AppProviderInitialValue;
4766
- }
4762
+ if (!context) return AppProviderInitialValue;
4767
4763
  return context;
4768
4764
  };
4769
4765
 
@@ -5163,7 +5159,7 @@ var many2oneFieldController = (props) => {
5163
5159
  const queryKey = [`data_${relation}`, domainObject];
5164
5160
  const {
5165
5161
  data: dataOfSelection,
5166
- refetch,
5162
+ // refetch,
5167
5163
  isFetching
5168
5164
  } = useGetSelection({
5169
5165
  data,
@@ -5192,9 +5188,6 @@ var many2oneFieldController = (props) => {
5192
5188
  });
5193
5189
  }
5194
5190
  }, [propValue]);
5195
- const fetchMoreOptions = useCallback6(() => {
5196
- refetch();
5197
- }, [refetch]);
5198
5191
  useEffect10(() => {
5199
5192
  if (actionId) {
5200
5193
  localStorage.setItem("aid", actionId);
@@ -5251,6 +5244,12 @@ var many2oneFieldController = (props) => {
5251
5244
  [methods, name, onChange]
5252
5245
  );
5253
5246
  const allowShowDetail = showDetail && contextObject?.form_view_ref && (!("no_open" in optionsObject) || optionsObject?.no_open === false);
5247
+ const fetchMoreOptions = useCallback6(() => {
5248
+ if (typeof dataOfSelection?.refetch === "function") {
5249
+ ;
5250
+ dataOfSelection.refetch();
5251
+ }
5252
+ }, [dataOfSelection]);
5254
5253
  return {
5255
5254
  allowShowDetail,
5256
5255
  handleClose,
@@ -5266,7 +5265,8 @@ var many2oneFieldController = (props) => {
5266
5265
  setTempSelectedOption,
5267
5266
  setDomainModal,
5268
5267
  dataOfSelection,
5269
- refetch,
5268
+ refetch: dataOfSelection?.refetch ?? (() => {
5269
+ }),
5270
5270
  selectOptions,
5271
5271
  optionsObject,
5272
5272
  contextObject,
@@ -5306,32 +5306,141 @@ var many2oneButtonController = (props) => {
5306
5306
  };
5307
5307
 
5308
5308
  // src/widget/basic/many2many-field/controller.ts
5309
- import { useEffect as useEffect12, useMemo as useMemo10, useState as useState9 } from "react";
5309
+ import { useEffect as useEffect14, useMemo as useMemo12, useState as useState10 } from "react";
5310
5310
  import {
5311
5311
  evalJSONContext as evalJSONContext4,
5312
5312
  formatSortingString as formatSortingString2,
5313
- getEnv as getEnv8,
5314
- selectSearch as selectSearch3,
5313
+ getEnv as getEnv9,
5314
+ selectSearch as selectSearch5,
5315
5315
  setFirstDomain,
5316
5316
  setGroupByDomain,
5317
5317
  setPage,
5318
5318
  setViewDataStore,
5319
- useAppDispatch as useAppDispatch5,
5320
- useAppSelector as useAppSelector5,
5319
+ useAppDispatch as useAppDispatch8,
5320
+ useAppSelector as useAppSelector7,
5321
5321
  useGetFormView,
5322
- useGetListData as useGetListData2,
5322
+ useGetListData as useGetListData3,
5323
5323
  useGetView as useGetView2,
5324
5324
  useModel as useModel2
5325
5325
  } from "@fctc/interface-logic";
5326
5326
 
5327
+ // src/widget/advance/table/table-body/controller.ts
5328
+ import { setSelectedRowKeys, useAppDispatch as useAppDispatch5 } from "@fctc/interface-logic";
5329
+ import { useEffect as useEffect11, useMemo as useMemo9 } from "react";
5330
+ var tableBodyController = (props) => {
5331
+ const {
5332
+ checkedAll,
5333
+ checkboxRef,
5334
+ setIsAutoSelect,
5335
+ selectedRowKeys,
5336
+ row,
5337
+ isAutoSelect,
5338
+ selectedRowKeysRef,
5339
+ onClickRow
5340
+ } = props;
5341
+ const appDispatch = useAppDispatch5();
5342
+ const checked = useMemo9(() => {
5343
+ if (!row?.id) return false;
5344
+ if (selectedRowKeys?.includes(row.id)) {
5345
+ return true;
5346
+ }
5347
+ return checkedAll;
5348
+ }, [row?.id, selectedRowKeys, checkedAll]);
5349
+ const handleCheckBoxSingle = (event) => {
5350
+ event.stopPropagation();
5351
+ if (checkedAll) {
5352
+ checkboxRef.current = "uncheck";
5353
+ setIsAutoSelect(true);
5354
+ return;
5355
+ }
5356
+ const newSelectedRowKeys = selectedRowKeys?.includes(row.id) ? selectedRowKeys?.filter((key) => key !== row.id) : [...selectedRowKeys, row.id];
5357
+ console.log("newSelectedRowKeys", newSelectedRowKeys);
5358
+ appDispatch(setSelectedRowKeys(newSelectedRowKeys));
5359
+ };
5360
+ const handleClickRow = (col, row2) => {
5361
+ onClickRow(col, row2);
5362
+ };
5363
+ useEffect11(() => {
5364
+ if (!row?.id) return;
5365
+ if (isAutoSelect) {
5366
+ if (checkboxRef?.current === "uncheck") {
5367
+ const filtered = selectedRowKeysRef.current.filter(
5368
+ (id) => id !== row.id
5369
+ );
5370
+ selectedRowKeysRef.current = filtered;
5371
+ appDispatch(setSelectedRowKeys(filtered));
5372
+ } else {
5373
+ const unique = Array.from(
5374
+ /* @__PURE__ */ new Set([...selectedRowKeysRef?.current, row?.id])
5375
+ );
5376
+ selectedRowKeysRef.current = unique;
5377
+ appDispatch(setSelectedRowKeys(unique));
5378
+ }
5379
+ }
5380
+ }, [isAutoSelect]);
5381
+ useEffect11(() => {
5382
+ if (!checkedAll) {
5383
+ checkboxRef.current = "enabled";
5384
+ false;
5385
+ }
5386
+ }, [checkedAll]);
5387
+ return {
5388
+ handleCheckBoxSingle,
5389
+ checked,
5390
+ handleClickRow
5391
+ };
5392
+ };
5393
+
5394
+ // src/widget/advance/table/table-head/controller.ts
5395
+ import {
5396
+ selectSearch as selectSearch2,
5397
+ setSelectedRowKeys as setSelectedRowKeys2,
5398
+ useAppDispatch as useAppDispatch6,
5399
+ useAppSelector as useAppSelector4
5400
+ } from "@fctc/interface-logic";
5401
+ var tableHeadController = (props) => {
5402
+ const { typeTable, rows, selectedRowKeysRef } = props;
5403
+ const appDispatch = useAppDispatch6();
5404
+ const { groupByDomain } = useAppSelector4(selectSearch2);
5405
+ const handleCheckBoxAll = (event) => {
5406
+ if (event?.target?.checked && typeTable === "list") {
5407
+ const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
5408
+ appDispatch(setSelectedRowKeys2(allRowKeys));
5409
+ } else if (event?.target?.checked && typeTable === "group") {
5410
+ const rowsIDs = document.querySelectorAll("tr[data-row-id]");
5411
+ const ids = Array.from(rowsIDs)?.map(
5412
+ (row) => Number(row?.getAttribute("data-row-id"))
5413
+ );
5414
+ if (ids?.length > 0) {
5415
+ appDispatch(setSelectedRowKeys2(ids));
5416
+ } else {
5417
+ const sum = countSum(
5418
+ rows,
5419
+ typeof groupByDomain === "object" ? groupByDomain?.contexts?.[0]?.group_by : void 0
5420
+ );
5421
+ const keys = Array.from({ length: sum }, (_) => void 0);
5422
+ appDispatch(setSelectedRowKeys2(keys));
5423
+ }
5424
+ if (selectedRowKeysRef) {
5425
+ selectedRowKeysRef.current = [];
5426
+ }
5427
+ } else {
5428
+ appDispatch(setSelectedRowKeys2([]));
5429
+ }
5430
+ };
5431
+ return {
5432
+ handleCheckBoxAll
5433
+ };
5434
+ };
5435
+
5327
5436
  // src/widget/advance/table/table-view/controller.ts
5328
5437
  import {
5329
5438
  domainHelper,
5330
5439
  selectList as selectList2,
5331
- selectSearch as selectSearch2,
5332
- useAppSelector as useAppSelector4
5440
+ selectSearch as selectSearch3,
5441
+ useAppSelector as useAppSelector5
5333
5442
  } from "@fctc/interface-logic";
5334
- import { useEffect as useEffect11, useMemo as useMemo9, useRef as useRef4, useState as useState8 } from "react";
5443
+ import { useEffect as useEffect12, useMemo as useMemo10, useRef as useRef4, useState as useState8 } from "react";
5335
5444
  var tableController = ({ data }) => {
5336
5445
  const [rows, setRows] = useState8(data.records || []);
5337
5446
  const [columns, setColumns] = useState8([]);
@@ -5362,7 +5471,7 @@ var tableController = ({ data }) => {
5362
5471
  return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
5363
5472
  });
5364
5473
  };
5365
- useEffect11(() => {
5474
+ useEffect12(() => {
5366
5475
  setRows(transformData(data.records || null));
5367
5476
  }, [data.records]);
5368
5477
  const handleGetColumns = () => {
@@ -5383,7 +5492,7 @@ var tableController = ({ data }) => {
5383
5492
  }
5384
5493
  return cols;
5385
5494
  };
5386
- useEffect11(() => {
5495
+ useEffect12(() => {
5387
5496
  const columns2 = handleGetColumns();
5388
5497
  setColumns(columns2);
5389
5498
  }, [data.records]);
@@ -5407,466 +5516,23 @@ var tableController = ({ data }) => {
5407
5516
  };
5408
5517
  };
5409
5518
 
5410
- // src/widget/basic/many2many-field/controller.ts
5411
- var many2manyFieldController = (props) => {
5412
- const {
5413
- relation,
5414
- domain,
5415
- context,
5416
- tab,
5417
- model,
5418
- aid,
5419
- setSelectedRowKeys: setSelectedRowKeys4,
5420
- fields,
5421
- setFields,
5422
- groupByDomain,
5423
- page,
5424
- options,
5425
- sessionStorageUtils
5426
- } = props;
5427
- const appDispatch = useAppDispatch5();
5428
- const actionData = sessionStorageUtils.getActionData();
5429
- const [debouncedPage] = useDebounce(page, 500);
5430
- const [order, setOrder] = useState9();
5431
- const [isLoadedData, setIsLoadedData] = useState9(false);
5432
- const [domainMany2Many, setDomainMany2Many] = useState9(domain);
5433
- const env = getEnv8();
5434
- const { selectedTags } = useAppSelector5(selectSearch3);
5435
- const viewParams = {
5436
- model: relation,
5437
- views: [
5438
- [false, "list"],
5439
- [false, "search"]
5440
- ],
5441
- context
5442
- };
5443
- const { data: viewResponse, isFetched: isViewReponseFetched } = useGetView2(
5444
- viewParams,
5445
- actionData
5446
- );
5447
- const baseModel = useMemo10(
5448
- () => ({
5449
- name: String(relation),
5450
- view: viewResponse || {},
5451
- actContext: context,
5452
- fields: [
5453
- ...Object.values(viewResponse?.views?.list?.fields ?? {}),
5454
- ...tab?.fields ? tab.fields : []
5455
- ]
5456
- }),
5457
- [model, viewResponse]
5458
- );
5459
- const initModel = useModel2();
5460
- const modelInstance = useMemo10(() => {
5461
- if (viewResponse) {
5462
- return initModel.initModel(baseModel);
5463
- }
5464
- return null;
5465
- }, [baseModel, viewResponse]);
5466
- const specification = useMemo10(() => {
5467
- if (modelInstance) {
5468
- return modelInstance.getSpecification();
5469
- }
5470
- return null;
5471
- }, [modelInstance]);
5472
- const default_order = viewResponse && viewResponse?.views?.list?.default_order;
5473
- const optionsObject = tab?.options ? evalJSONContext4(tab?.options) : (options ? evalJSONContext4(options) : {}) || {};
5474
- const fetchData = async () => {
5475
- try {
5476
- setDomainMany2Many(domain);
5477
- appDispatch(setFirstDomain(domain));
5478
- appDispatch(setViewDataStore(viewResponse));
5479
- const modalData = viewResponse?.views?.list?.fields.map((field) => ({
5480
- ...viewResponse?.models?.[String(model)]?.[field?.name],
5481
- ...field
5482
- }));
5483
- if (!fields?.[`${aid}_${relation}_popupmany2many`] && modalData) {
5484
- setFields({
5485
- ...fields,
5486
- [`${aid}_${relation}_popupmany2many`]: modalData
5487
- });
5488
- }
5489
- appDispatch(setPage(0));
5490
- } catch (err) {
5491
- console.log(err);
5492
- }
5493
- };
5494
- const queryKey = [
5495
- `view-${relation}-${aid}`,
5496
- specification,
5497
- domainMany2Many,
5498
- debouncedPage,
5499
- groupByDomain,
5500
- order
5501
- ];
5502
- const data = {
5503
- model: relation,
5504
- specification,
5505
- domain: domainMany2Many,
5506
- offset: debouncedPage * 10,
5507
- limit: 10,
5508
- context,
5509
- fields: groupByDomain?.fields,
5510
- groupby: [groupByDomain?.contexts[0]?.group_by],
5511
- sort: order ? order : default_order ? formatSortingString2(default_order) : ""
5512
- };
5513
- const enabled = isLoadedData && !!specification && !!relation && !!domainMany2Many && !!viewResponse;
5514
- const {
5515
- data: dataResponse,
5516
- isLoading: isDataLoading,
5517
- isFetched: isDataResponseFetched,
5518
- isPlaceholderData
5519
- } = useGetListData2(data, queryKey, enabled);
5520
- useEffect12(() => {
5521
- if (viewResponse) {
5522
- fetchData();
5523
- }
5524
- return () => {
5525
- appDispatch(setGroupByDomain(null));
5526
- setFields((prevFields) => ({
5527
- ...prevFields,
5528
- [`${aid}_${relation}_popupmany2many`]: null
5529
- }));
5530
- appDispatch(setPage(0));
5531
- setSelectedRowKeys4([]);
5532
- setDomainMany2Many(null);
5533
- setIsLoadedData(false);
5534
- };
5535
- }, [viewResponse]);
5536
- const { rows, columns, typeTable } = tableController({
5537
- data: {
5538
- fields: fields?.[`${aid}_${relation}_popupmany2many`] || viewResponse?.views?.list?.fields,
5539
- records: dataResponse?.records ?? dataResponse?.groups,
5540
- dataModel: viewResponse?.models?.[String(relation)],
5541
- context: { ...env.context, ...context },
5542
- typeTable: dataResponse?.groups ? "group" : "list"
5543
- }
5544
- });
5545
- const dataFormView = {
5546
- id: null,
5547
- model: relation,
5548
- context
5549
- };
5550
- const {
5551
- refetch,
5552
- data: dataFormViewResponse,
5553
- isSuccess
5554
- } = useGetFormView({
5555
- data: dataFormView,
5556
- queryKey: [`form-view-action-${relation}`],
5557
- enabled: false
5558
- });
5559
- useEffect12(() => {
5560
- if (isSuccess && dataFormViewResponse) {
5561
- sessionStorage.setItem("actionData", JSON.stringify(dataFormViewResponse));
5562
- window.location.href = `/form/menu?model=${relation}`;
5563
- }
5564
- }, [isSuccess]);
5565
- useEffect12(() => {
5566
- if (domainMany2Many && !isLoadedData) {
5567
- setIsLoadedData(true);
5568
- }
5569
- }, [domainMany2Many]);
5570
- const handleCreateNewOnPage = async () => {
5571
- try {
5572
- refetch();
5573
- } catch (error) {
5574
- console.log(error);
5575
- }
5576
- };
5577
- return {};
5578
- };
5579
-
5580
- // src/widget/basic/many2many-tags-field/controller.ts
5581
- import { useMemo as useMemo11 } from "react";
5582
- import {
5583
- evalJSONContext as evalJSONContext5,
5584
- evalJSONDomain as evalJSONDomain4,
5585
- getEnv as getEnv9,
5586
- useGetSelection as useGetSelection3,
5587
- WIDGETAVATAR,
5588
- WIDGETCOLOR
5589
- } from "@fctc/interface-logic";
5590
- var many2manyTagsController = (props) => {
5591
- const {
5592
- relation,
5593
- domain,
5594
- options: optionsFields,
5595
- widget,
5596
- formValues,
5597
- placeholderNoOption
5598
- } = props;
5599
- const isUser = relation === "res.users" || relation === "res.partner";
5600
- const env = getEnv9();
5601
- const addtionalFields = optionsFields ? evalJSONContext5(optionsFields) : null;
5602
- const domainObject = useMemo11(
5603
- () => evalJSONDomain4(domain, JSON.parse(JSON.stringify(formValues || {}))),
5604
- [domain, formValues]
5605
- );
5606
- const data = {
5607
- model: relation ?? "",
5608
- domain: domainObject,
5609
- specification: {
5610
- id: {},
5611
- name: {},
5612
- display_name: {},
5613
- ...widget && WIDGETAVATAR[widget] ? { image_256: {} } : {},
5614
- ...widget && WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
5615
- },
5616
- enabled: true,
5617
- context: env.context
5618
- };
5619
- const { data: dataOfSelection } = useGetSelection3({
5620
- data,
5621
- queryKey: [`data_${relation}`, domainObject]
5622
- });
5623
- const customNoOptionsMessage = () => placeholderNoOption;
5624
- const tranfer = (data2) => {
5625
- return data2?.map((val) => ({
5626
- id: val.value,
5627
- display_name: val.label
5628
- })) || [];
5629
- };
5630
- const options = dataOfSelection?.records?.map((val) => ({
5631
- value: val.id,
5632
- label: val.name ?? val.display_name,
5633
- ...val
5634
- })) || [];
5635
- return {
5636
- options,
5637
- customNoOptionsMessage,
5638
- tranfer,
5639
- dataOfSelection,
5640
- isUser
5641
- };
5642
- };
5643
-
5644
- // src/widget/basic/status-bar-field/controller.ts
5645
- import { useState as useState10 } from "react";
5519
+ // src/widget/advance/table/table-group/controller.ts
5646
5520
  import {
5647
- evalJSONDomain as evalJSONDomain5,
5648
- selectEnv as selectEnv3,
5521
+ getEnv as getEnv8,
5522
+ selectList as selectList3,
5523
+ selectSearch as selectSearch4,
5524
+ setSelectedRowKeys as setSelectedRowKeys3,
5525
+ useAppDispatch as useAppDispatch7,
5649
5526
  useAppSelector as useAppSelector6,
5650
- useChangeStatus,
5651
- useGetListData as useGetListData3
5527
+ useGetListData as useGetListData2,
5528
+ useOdooDataTransform
5652
5529
  } from "@fctc/interface-logic";
5653
- var durationController = (props) => {
5654
- const {
5655
- relation,
5656
- defaultValue,
5657
- domain,
5658
- formValues,
5659
- name,
5660
- id,
5661
- model,
5662
- onRefetch
5663
- } = props;
5664
- const specification = {
5665
- id: 0,
5666
- name: "",
5667
- fold: ""
5668
- };
5669
- const [disabled, setDisabled] = useState10(false);
5670
- const [modelStatus, setModalStatus] = useState10(false);
5671
- const { context } = useAppSelector6(selectEnv3);
5672
- const queryKey = [`data-status-duration`, specification];
5673
- const listDataProps = {
5674
- model: relation,
5675
- specification,
5676
- domain: evalJSONDomain5(domain, JSON.parse(JSON.stringify(formValues))),
5677
- limit: 10,
5678
- offset: 0,
5679
- fields: "",
5680
- groupby: [],
5681
- context: {
5682
- lang: context.lang
5683
- },
5684
- sort: ""
5685
- };
5686
- const { data: dataResponse } = useGetListData3(listDataProps, queryKey);
5687
- const { mutate: fetchChangeStatus } = useChangeStatus();
5688
- const handleClick = async (stage_id) => {
5689
- setDisabled(true);
5690
- if (stage_id) {
5691
- fetchChangeStatus(
5692
- {
5693
- data: {
5694
- stage_id,
5695
- name,
5696
- id,
5697
- model,
5698
- lang: context.lang
5699
- }
5700
- },
5701
- {
5702
- onSuccess: (res) => {
5703
- if (res) {
5704
- setDisabled(false);
5705
- onRefetch && onRefetch();
5706
- }
5707
- }
5708
- }
5709
- );
5710
- }
5711
- };
5712
- return {
5713
- defaultValue,
5714
- dataResponse,
5715
- handleClick,
5716
- disabled,
5717
- modelStatus,
5718
- setModalStatus
5719
- };
5720
- };
5530
+ import { useEffect as useEffect13, useMemo as useMemo11, useState as useState9 } from "react";
5721
5531
 
5722
- // src/widget/basic/priority-field/controller.ts
5723
- import { evalJSONContext as evalJSONContext6, useSave as useSave2 } from "@fctc/interface-logic";
5724
- var priorityFieldController = (props) => {
5725
- const {
5726
- value,
5727
- isForm,
5728
- name,
5729
- methods,
5730
- onChange,
5731
- model,
5732
- selection,
5733
- id,
5734
- actionData,
5735
- viewData,
5736
- context
5737
- } = props;
5738
- const _context = { ...evalJSONContext6(actionData?.context) };
5739
- const contextObject = { ...context, ..._context };
5740
- const defaultPriority = parseInt(value) + 1;
5741
- const label = viewData?.models?.[model]?.[name ?? ""]?.string ?? name;
5742
- const { mutateAsync: fetchSave } = useSave2();
5743
- const savePriorities = async ({
5744
- value: value2,
5745
- resetPriority
5746
- }) => {
5747
- const priorityValue = value2 <= 0 ? 0 : value2 - 1;
5748
- try {
5749
- fetchSave({
5750
- ids: id ? [id] : [],
5751
- data: { [name ?? ""]: String(priorityValue) },
5752
- model: model ?? "",
5753
- context: contextObject
5754
- });
5755
- if (typeof onChange === "function") {
5756
- onChange(name ?? "", String(priorityValue));
5757
- }
5758
- } catch (error) {
5759
- if (resetPriority) {
5760
- resetPriority();
5761
- }
5762
- }
5763
- };
5764
- return {
5765
- selection,
5766
- isForm,
5767
- methods,
5768
- defaultPriority,
5769
- savePriorities,
5770
- label,
5771
- id,
5772
- onChange
5773
- };
5774
- };
5775
-
5776
- // src/widget/basic/float-time-field/controller.ts
5777
- import { useState as useState11 } from "react";
5778
- import { convertFloatToTime, convertTimeToFloat } from "@fctc/interface-logic";
5779
- var floatTimeFiledController = ({
5780
- onChange: fieldOnChange,
5781
- onBlur,
5782
- value,
5783
- isDirty,
5784
- props
5785
- }) => {
5786
- const { name, defaultValue = 0, onChange } = props;
5787
- const [input, setInput] = useState11(
5788
- convertFloatToTime(value ?? defaultValue)
5789
- );
5790
- const [formattedTime, setFormattedTime] = useState11("");
5791
- const [errors, setErrors] = useState11("");
5792
- const handleInputChange = (e) => {
5793
- const raw = e.target.value.replace(/[^\d:]/g, "");
5794
- setInput(raw);
5795
- const timeRegex = /^(\d{1,2}):?(\d{0,2})$/;
5796
- const match = raw.match(timeRegex);
5797
- if (!match) {
5798
- setErrors("\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7");
5799
- setFormattedTime("");
5800
- return;
5801
- }
5802
- let hours = parseInt(match[1] ?? "0", 10);
5803
- let minutes = parseInt(match[2] ?? "0", 10);
5804
- if (isNaN(hours)) hours = 0;
5805
- if (isNaN(minutes)) minutes = 0;
5806
- if (hours >= 24) {
5807
- hours = 0;
5808
- }
5809
- if (minutes >= 60) {
5810
- minutes = 0;
5811
- }
5812
- const formatted = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
5813
- setErrors("");
5814
- setFormattedTime(formatted);
5815
- fieldOnChange(formatted);
5816
- };
5817
- const handleBlur = () => {
5818
- if (!isDirty) return;
5819
- if (formattedTime) {
5820
- setInput(formattedTime);
5821
- const floatVal = convertTimeToFloat(formattedTime);
5822
- fieldOnChange(floatVal);
5823
- if (onChange) {
5824
- onChange(name ?? "", floatVal);
5825
- }
5826
- } else {
5827
- setInput("00:00");
5828
- fieldOnChange(0);
5829
- if (onChange) {
5830
- onChange(name ?? "", 0);
5831
- }
5832
- setErrors("");
5833
- }
5834
- onBlur();
5835
- };
5836
- const handleKeyDown = (e) => {
5837
- {
5838
- const allowed = [
5839
- "Backspace",
5840
- "Tab",
5841
- "ArrowLeft",
5842
- "ArrowRight",
5843
- "Delete",
5844
- "Home",
5845
- "End",
5846
- ":"
5847
- ];
5848
- const isNumber = /^[0-9]$/.test(e.key);
5849
- if (!isNumber && !allowed.includes(e.key)) {
5850
- e.preventDefault();
5851
- }
5852
- }
5853
- };
5854
- return {
5855
- handleInputChange,
5856
- handleBlur,
5857
- handleKeyDown,
5858
- input,
5859
- errors
5860
- };
5861
- };
5862
-
5863
- // src/widget/basic/float-field/controller.ts
5864
- import { useEffect as useEffect13, useRef as useRef5, useState as useState12 } from "react";
5865
-
5866
- // src/utils/i18n.ts
5867
- import { initReactI18next } from "react-i18next";
5868
- import i18n from "i18next";
5869
- import LanguageDetector from "i18next-browser-languagedetector";
5532
+ // src/utils/i18n.ts
5533
+ import { initReactI18next } from "react-i18next";
5534
+ import i18n from "i18next";
5535
+ import LanguageDetector from "i18next-browser-languagedetector";
5870
5536
 
5871
5537
  // src/locales/vi.json
5872
5538
  var vi_default = {
@@ -6053,8 +5719,6 @@ var vi_default = {
6053
5719
  add_new_attribute: "Th\xEAm thu\u1ED9c t\xEDnh",
6054
5720
  add_attribute_name: "T\xEAn thu\u1ED9c t\xEDnh",
6055
5721
  images_product: "H\xECnh \u1EA3nh",
6056
- selected: "\u0111\u01B0\u1EE3c ch\u1ECDn",
6057
- print: "In",
6058
5722
  generate_code_product: "T\u1EA1o m\xE3 s\u1EA3n ph\u1EA9m",
6059
5723
  order_today: "\u0110\u01A1n h\xE0ng",
6060
5724
  list_best_selling_product: "S\u1EA3n ph\u1EA9m b\xE1n ch\u1EA1y",
@@ -6612,26 +6276,640 @@ var vi_default = {
6612
6276
  "export-all-data-error": "Xu\u1EA5t d\u1EEF li\u1EC7u kh\xF4ng th\xE0nh c\xF4ng, vui l\xF2ng th\u1EED l\u1EA1i sau"
6613
6277
  };
6614
6278
 
6615
- // src/utils/i18n.ts
6616
- i18n.use(LanguageDetector).use(initReactI18next).init({
6617
- resources: {
6618
- vi: { translation: vi_default },
6619
- en: { translation: vi_default }
6620
- },
6621
- fallbackLng: "vi",
6622
- lng: "vi_VN",
6623
- debug: false,
6624
- nonExplicitSupportedLngs: true,
6625
- interpolation: {
6626
- escapeValue: false
6627
- },
6628
- detection: {
6629
- caches: ["cookie"]
6630
- }
6631
- });
6632
- var i18n_default = i18n;
6633
-
6279
+ // src/utils/i18n.ts
6280
+ i18n.use(LanguageDetector).use(initReactI18next).init({
6281
+ resources: {
6282
+ vi: { translation: vi_default },
6283
+ en: { translation: vi_default }
6284
+ },
6285
+ fallbackLng: "vi",
6286
+ lng: "vi_VN",
6287
+ debug: false,
6288
+ nonExplicitSupportedLngs: true,
6289
+ interpolation: {
6290
+ escapeValue: false
6291
+ },
6292
+ detection: {
6293
+ caches: ["cookie"]
6294
+ }
6295
+ });
6296
+ var i18n_default = i18n;
6297
+
6298
+ // src/widget/advance/table/table-group/controller.ts
6299
+ var tableGroupController = (props) => {
6300
+ const env = getEnv8();
6301
+ const {
6302
+ rows,
6303
+ columns,
6304
+ indexRow,
6305
+ row,
6306
+ model,
6307
+ viewData,
6308
+ renderField,
6309
+ level,
6310
+ specification,
6311
+ domain,
6312
+ context,
6313
+ checkedAll,
6314
+ isDisplayCheckbox,
6315
+ isAutoSelect,
6316
+ setIsAutoSelect,
6317
+ selectedRowKeysRef
6318
+ } = props;
6319
+ const [pageGroup, setPageGroup] = useState9(0);
6320
+ const { groupByDomain, selectedTags } = useAppSelector6(selectSearch4);
6321
+ const { selectedRowKeys } = useAppSelector6(selectList3);
6322
+ const appDispatch = useAppDispatch7();
6323
+ const { toDataJS } = useOdooDataTransform();
6324
+ const initVal = toDataJS(row, viewData, model);
6325
+ const [isShowGroup, setIsShowGroup] = useState9(false);
6326
+ const [colEmptyGroup, setColEmptyGroup] = useState9({
6327
+ fromStart: 1,
6328
+ fromEnd: 1
6329
+ });
6330
+ const processedData = useMemo11(() => {
6331
+ const calculateColSpanEmpty = () => {
6332
+ const startIndex = columns.findIndex(
6333
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
6334
+ );
6335
+ const endIndex = columns.findLastIndex(
6336
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
6337
+ );
6338
+ const fromStart = startIndex === -1 ? columns.length : startIndex;
6339
+ const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
6340
+ setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
6341
+ return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
6342
+ };
6343
+ return calculateColSpanEmpty();
6344
+ }, [columns, row]);
6345
+ const shouldFetchData = useMemo11(() => {
6346
+ return !!isShowGroup;
6347
+ }, [isShowGroup]);
6348
+ const enabled = shouldFetchData && !!processedData;
6349
+ const listDataProps = {
6350
+ model,
6351
+ specification,
6352
+ domain,
6353
+ context,
6354
+ offset: pageGroup * 10,
6355
+ fields: groupByDomain?.fields,
6356
+ groupby: [groupByDomain?.contexts[level]?.group_by]
6357
+ };
6358
+ const queryKey = [
6359
+ `data-${model}--${level}-row${indexRow}`,
6360
+ specification,
6361
+ domain,
6362
+ pageGroup
6363
+ ];
6364
+ const {
6365
+ data: dataResponse,
6366
+ isFetched: isQueryFetched,
6367
+ isPlaceholderData,
6368
+ isLoading,
6369
+ isFetching
6370
+ } = useGetListData2(listDataProps, queryKey, enabled);
6371
+ const {
6372
+ columns: columnsGroup,
6373
+ rows: rowsGroup,
6374
+ typeTable: typeTableGroup
6375
+ } = tableController({
6376
+ data: {
6377
+ fields: viewData?.views?.list?.fields,
6378
+ records: dataResponse?.records ?? dataResponse?.groups,
6379
+ dataModel: viewData?.models?.[model],
6380
+ context: env.context,
6381
+ typeTable: dataResponse?.groups ? "group" : "list"
6382
+ }
6383
+ });
6384
+ const leftPadding = level > 1 ? level * 8 + "px" : "0px";
6385
+ useEffect13(() => {
6386
+ if (isShowGroup && selectedTags?.length > 0) {
6387
+ setIsShowGroup(false);
6388
+ }
6389
+ }, [selectedTags]);
6390
+ const group_by_field_name = groupByDomain?.contexts[level - 1]?.group_by;
6391
+ 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(
6392
+ (selectItem) => selectItem?.[0] === row[group_by_field_name]
6393
+ )?.[1] : row[group_by_field_name];
6394
+ 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`]})`;
6395
+ const allIdsNull = selectedRowKeys?.every((item) => item === void 0);
6396
+ const handleExpandChildGroup = () => {
6397
+ if (isLoading || isFetching) return;
6398
+ const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
6399
+ if (allIdsNull || typeTableGroup === "group") {
6400
+ toggleShowGroup();
6401
+ return;
6402
+ }
6403
+ if (isShowGroup && checkedAll) {
6404
+ const ids = rowsGroup?.map((item) => item?.id) || [];
6405
+ const filteredIds = selectedRowKeys.filter(
6406
+ (id) => !ids.includes(id)
6407
+ );
6408
+ appDispatch(setSelectedRowKeys3(filteredIds));
6409
+ } else if (!isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && checkedAll && !allIdsNull && isQueryFetched) {
6410
+ const clonedKeys = [...selectedRowKeys];
6411
+ appDispatch(setSelectedRowKeys3([...clonedKeys, -1]));
6412
+ setTimeout(() => appDispatch(setSelectedRowKeys3(clonedKeys)), 500);
6413
+ } else if (isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && !checkedAll && !allIdsNull) {
6414
+ const filteredKeys = selectedRowKeys.filter((id) => id > -1);
6415
+ appDispatch(setSelectedRowKeys3(filteredKeys));
6416
+ }
6417
+ toggleShowGroup();
6418
+ };
6419
+ useEffect13(() => {
6420
+ if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
6421
+ return;
6422
+ }
6423
+ const clonedKeys = [...selectedRowKeys];
6424
+ setSelectedRowKeys3([...clonedKeys, -1]);
6425
+ setTimeout(() => setSelectedRowKeys3(clonedKeys), 500);
6426
+ }, [isQueryFetched]);
6427
+ return {
6428
+ handleExpandChildGroup,
6429
+ colEmptyGroup,
6430
+ leftPadding,
6431
+ isShowGroup,
6432
+ isQueryFetched,
6433
+ nameGroupWithCount,
6434
+ columns,
6435
+ row,
6436
+ isPlaceholderData,
6437
+ columnsGroup,
6438
+ indexRow,
6439
+ rowsGroup,
6440
+ model,
6441
+ viewData,
6442
+ renderField,
6443
+ level,
6444
+ specification,
6445
+ context,
6446
+ checkedAll,
6447
+ isDisplayCheckbox,
6448
+ isAutoSelect,
6449
+ setIsAutoSelect,
6450
+ selectedRowKeysRef,
6451
+ initVal,
6452
+ dataResponse,
6453
+ pageGroup,
6454
+ setPageGroup
6455
+ };
6456
+ };
6457
+
6458
+ // src/widget/basic/many2many-field/controller.ts
6459
+ var many2manyFieldController = (props) => {
6460
+ const {
6461
+ relation,
6462
+ domain,
6463
+ context,
6464
+ tab,
6465
+ model,
6466
+ aid,
6467
+ setSelectedRowKeys: setSelectedRowKeys4,
6468
+ fields,
6469
+ setFields,
6470
+ groupByDomain,
6471
+ page,
6472
+ options,
6473
+ sessionStorageUtils
6474
+ } = props;
6475
+ const appDispatch = useAppDispatch8();
6476
+ const actionData = sessionStorageUtils.getActionData();
6477
+ const [debouncedPage] = useDebounce(page, 500);
6478
+ const [order, setOrder] = useState10();
6479
+ const [isLoadedData, setIsLoadedData] = useState10(false);
6480
+ const [domainMany2Many, setDomainMany2Many] = useState10(domain);
6481
+ const env = getEnv9();
6482
+ const { selectedTags } = useAppSelector7(selectSearch5);
6483
+ const viewParams = {
6484
+ model: relation,
6485
+ views: [
6486
+ [false, "list"],
6487
+ [false, "search"]
6488
+ ],
6489
+ context
6490
+ };
6491
+ const { data: viewResponse, isFetched: isViewReponseFetched } = useGetView2(
6492
+ viewParams,
6493
+ actionData
6494
+ );
6495
+ const baseModel = useMemo12(
6496
+ () => ({
6497
+ name: String(relation),
6498
+ view: viewResponse || {},
6499
+ actContext: context,
6500
+ fields: [
6501
+ ...Object.values(viewResponse?.views?.list?.fields ?? {}),
6502
+ ...tab?.fields ? tab.fields : []
6503
+ ]
6504
+ }),
6505
+ [model, viewResponse]
6506
+ );
6507
+ const initModel = useModel2();
6508
+ const modelInstance = useMemo12(() => {
6509
+ if (viewResponse) {
6510
+ return initModel.initModel(baseModel);
6511
+ }
6512
+ return null;
6513
+ }, [baseModel, viewResponse]);
6514
+ const specification = useMemo12(() => {
6515
+ if (modelInstance) {
6516
+ return modelInstance.getSpecification();
6517
+ }
6518
+ return null;
6519
+ }, [modelInstance]);
6520
+ const default_order = viewResponse && viewResponse?.views?.list?.default_order;
6521
+ const optionsObject = tab?.options ? evalJSONContext4(tab?.options) : (options ? evalJSONContext4(options) : {}) || {};
6522
+ const fetchData = async () => {
6523
+ try {
6524
+ setDomainMany2Many(domain);
6525
+ appDispatch(setFirstDomain(domain));
6526
+ appDispatch(setViewDataStore(viewResponse));
6527
+ const modalData = viewResponse?.views?.list?.fields.map((field) => ({
6528
+ ...viewResponse?.models?.[String(model)]?.[field?.name],
6529
+ ...field
6530
+ }));
6531
+ if (!fields?.[`${aid}_${relation}_popupmany2many`] && modalData) {
6532
+ setFields({
6533
+ ...fields,
6534
+ [`${aid}_${relation}_popupmany2many`]: modalData
6535
+ });
6536
+ }
6537
+ appDispatch(setPage(0));
6538
+ } catch (err) {
6539
+ console.log(err);
6540
+ }
6541
+ };
6542
+ const queryKey = [
6543
+ `view-${relation}-${aid}`,
6544
+ specification,
6545
+ domainMany2Many,
6546
+ debouncedPage,
6547
+ groupByDomain,
6548
+ order
6549
+ ];
6550
+ const data = {
6551
+ model: relation,
6552
+ specification,
6553
+ domain: domainMany2Many,
6554
+ offset: debouncedPage * 10,
6555
+ limit: 10,
6556
+ context,
6557
+ fields: groupByDomain?.fields,
6558
+ groupby: [groupByDomain?.contexts[0]?.group_by],
6559
+ sort: order ? order : default_order ? formatSortingString2(default_order) : ""
6560
+ };
6561
+ const enabled = isLoadedData && !!specification && !!relation && !!domainMany2Many && !!viewResponse;
6562
+ const {
6563
+ data: dataResponse,
6564
+ isLoading: isDataLoading,
6565
+ isFetched: isDataResponseFetched,
6566
+ isPlaceholderData
6567
+ } = useGetListData3(data, queryKey, enabled);
6568
+ useEffect14(() => {
6569
+ if (viewResponse) {
6570
+ fetchData();
6571
+ }
6572
+ return () => {
6573
+ appDispatch(setGroupByDomain(null));
6574
+ setFields((prevFields) => ({
6575
+ ...prevFields,
6576
+ [`${aid}_${relation}_popupmany2many`]: null
6577
+ }));
6578
+ appDispatch(setPage(0));
6579
+ setSelectedRowKeys4([]);
6580
+ setDomainMany2Many(null);
6581
+ setIsLoadedData(false);
6582
+ };
6583
+ }, [viewResponse]);
6584
+ const { rows, columns, typeTable } = tableController({
6585
+ data: {
6586
+ fields: fields?.[`${aid}_${relation}_popupmany2many`] || viewResponse?.views?.list?.fields,
6587
+ records: dataResponse?.records ?? dataResponse?.groups,
6588
+ dataModel: viewResponse?.models?.[String(relation)],
6589
+ context: { ...env.context, ...context },
6590
+ typeTable: dataResponse?.groups ? "group" : "list"
6591
+ }
6592
+ });
6593
+ const dataFormView = {
6594
+ id: null,
6595
+ model: relation,
6596
+ context
6597
+ };
6598
+ const {
6599
+ refetch,
6600
+ data: dataFormViewResponse,
6601
+ isSuccess
6602
+ } = useGetFormView({
6603
+ data: dataFormView,
6604
+ queryKey: [`form-view-action-${relation}`],
6605
+ enabled: false
6606
+ });
6607
+ useEffect14(() => {
6608
+ if (isSuccess && dataFormViewResponse) {
6609
+ sessionStorage.setItem("actionData", JSON.stringify(dataFormViewResponse));
6610
+ window.location.href = `/form/menu?model=${relation}`;
6611
+ }
6612
+ }, [isSuccess]);
6613
+ useEffect14(() => {
6614
+ if (domainMany2Many && !isLoadedData) {
6615
+ setIsLoadedData(true);
6616
+ }
6617
+ }, [domainMany2Many]);
6618
+ const handleCreateNewOnPage = async () => {
6619
+ try {
6620
+ refetch();
6621
+ } catch (error) {
6622
+ console.log(error);
6623
+ }
6624
+ };
6625
+ return {};
6626
+ };
6627
+
6628
+ // src/widget/basic/many2many-tags-field/controller.ts
6629
+ import { useMemo as useMemo13 } from "react";
6630
+ import {
6631
+ evalJSONContext as evalJSONContext5,
6632
+ evalJSONDomain as evalJSONDomain4,
6633
+ getEnv as getEnv10,
6634
+ useGetSelection as useGetSelection3,
6635
+ WIDGETAVATAR,
6636
+ WIDGETCOLOR
6637
+ } from "@fctc/interface-logic";
6638
+ var many2manyTagsController = (props) => {
6639
+ const {
6640
+ relation,
6641
+ domain,
6642
+ options: optionsFields,
6643
+ widget,
6644
+ formValues,
6645
+ placeholderNoOption
6646
+ } = props;
6647
+ const isUser = relation === "res.users" || relation === "res.partner";
6648
+ const env = getEnv10();
6649
+ const addtionalFields = optionsFields ? evalJSONContext5(optionsFields) : null;
6650
+ const domainObject = useMemo13(
6651
+ () => evalJSONDomain4(domain, JSON.parse(JSON.stringify(formValues || {}))),
6652
+ [domain, formValues]
6653
+ );
6654
+ const data = {
6655
+ model: relation ?? "",
6656
+ domain: domainObject,
6657
+ specification: {
6658
+ id: {},
6659
+ name: {},
6660
+ display_name: {},
6661
+ ...widget && WIDGETAVATAR[widget] ? { image_256: {} } : {},
6662
+ ...widget && WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
6663
+ },
6664
+ enabled: true,
6665
+ context: env.context
6666
+ };
6667
+ const { data: dataOfSelection } = useGetSelection3({
6668
+ data,
6669
+ queryKey: [`data_${relation}`, domainObject]
6670
+ });
6671
+ const customNoOptionsMessage = () => placeholderNoOption;
6672
+ const tranfer = (data2) => {
6673
+ return data2?.map((val) => ({
6674
+ id: val.value,
6675
+ display_name: val.label
6676
+ })) || [];
6677
+ };
6678
+ const options = dataOfSelection?.records?.map((val) => ({
6679
+ value: val.id,
6680
+ label: val.name ?? val.display_name,
6681
+ ...val
6682
+ })) || [];
6683
+ return {
6684
+ options,
6685
+ customNoOptionsMessage,
6686
+ tranfer,
6687
+ dataOfSelection,
6688
+ isUser
6689
+ };
6690
+ };
6691
+
6692
+ // src/widget/basic/status-bar-field/controller.ts
6693
+ import { useState as useState11 } from "react";
6694
+ import {
6695
+ evalJSONDomain as evalJSONDomain5,
6696
+ selectEnv as selectEnv3,
6697
+ useAppSelector as useAppSelector8,
6698
+ useChangeStatus,
6699
+ useGetListData as useGetListData4
6700
+ } from "@fctc/interface-logic";
6701
+ var durationController = (props) => {
6702
+ const {
6703
+ relation,
6704
+ defaultValue,
6705
+ domain,
6706
+ formValues,
6707
+ name,
6708
+ id,
6709
+ model,
6710
+ onRefetch
6711
+ } = props;
6712
+ const specification = {
6713
+ id: 0,
6714
+ name: "",
6715
+ fold: ""
6716
+ };
6717
+ const [disabled, setDisabled] = useState11(false);
6718
+ const [modelStatus, setModalStatus] = useState11(false);
6719
+ const { context } = useAppSelector8(selectEnv3);
6720
+ const queryKey = [`data-status-duration`, specification];
6721
+ const listDataProps = {
6722
+ model: relation,
6723
+ specification,
6724
+ domain: evalJSONDomain5(domain, JSON.parse(JSON.stringify(formValues))),
6725
+ limit: 10,
6726
+ offset: 0,
6727
+ fields: "",
6728
+ groupby: [],
6729
+ context: {
6730
+ lang: context.lang
6731
+ },
6732
+ sort: ""
6733
+ };
6734
+ const { data: dataResponse } = useGetListData4(listDataProps, queryKey);
6735
+ const { mutate: fetchChangeStatus } = useChangeStatus();
6736
+ const handleClick = async (stage_id) => {
6737
+ setDisabled(true);
6738
+ if (stage_id) {
6739
+ fetchChangeStatus(
6740
+ {
6741
+ data: {
6742
+ stage_id,
6743
+ name,
6744
+ id,
6745
+ model,
6746
+ lang: context.lang
6747
+ }
6748
+ },
6749
+ {
6750
+ onSuccess: (res) => {
6751
+ if (res) {
6752
+ setDisabled(false);
6753
+ onRefetch && onRefetch();
6754
+ }
6755
+ }
6756
+ }
6757
+ );
6758
+ }
6759
+ };
6760
+ return {
6761
+ defaultValue,
6762
+ dataResponse,
6763
+ handleClick,
6764
+ disabled,
6765
+ modelStatus,
6766
+ setModalStatus
6767
+ };
6768
+ };
6769
+
6770
+ // src/widget/basic/priority-field/controller.ts
6771
+ import { evalJSONContext as evalJSONContext6, useSave as useSave2 } from "@fctc/interface-logic";
6772
+ var priorityFieldController = (props) => {
6773
+ const {
6774
+ value,
6775
+ isForm,
6776
+ name,
6777
+ methods,
6778
+ onChange,
6779
+ model,
6780
+ selection,
6781
+ id,
6782
+ actionData,
6783
+ viewData,
6784
+ context
6785
+ } = props;
6786
+ const _context = { ...evalJSONContext6(actionData?.context) };
6787
+ const contextObject = { ...context, ..._context };
6788
+ const defaultPriority = parseInt(value) + 1;
6789
+ const label = viewData?.models?.[model]?.[name ?? ""]?.string ?? name;
6790
+ const { mutateAsync: fetchSave } = useSave2();
6791
+ const savePriorities = async ({
6792
+ value: value2,
6793
+ resetPriority
6794
+ }) => {
6795
+ const priorityValue = value2 <= 0 ? 0 : value2 - 1;
6796
+ try {
6797
+ fetchSave({
6798
+ ids: id ? [id] : [],
6799
+ data: { [name ?? ""]: String(priorityValue) },
6800
+ model: model ?? "",
6801
+ context: contextObject
6802
+ });
6803
+ if (typeof onChange === "function") {
6804
+ onChange(name ?? "", String(priorityValue));
6805
+ }
6806
+ } catch (error) {
6807
+ if (resetPriority) {
6808
+ resetPriority();
6809
+ }
6810
+ }
6811
+ };
6812
+ return {
6813
+ selection,
6814
+ isForm,
6815
+ methods,
6816
+ defaultPriority,
6817
+ savePriorities,
6818
+ label,
6819
+ id,
6820
+ onChange
6821
+ };
6822
+ };
6823
+
6824
+ // src/widget/basic/float-time-field/controller.ts
6825
+ import { useState as useState12 } from "react";
6826
+ import { convertFloatToTime, convertTimeToFloat } from "@fctc/interface-logic";
6827
+ var floatTimeFiledController = ({
6828
+ onChange: fieldOnChange,
6829
+ onBlur,
6830
+ value,
6831
+ isDirty,
6832
+ props
6833
+ }) => {
6834
+ const { name, defaultValue = 0, onChange } = props;
6835
+ const [input, setInput] = useState12(
6836
+ convertFloatToTime(value ?? defaultValue)
6837
+ );
6838
+ const [formattedTime, setFormattedTime] = useState12("");
6839
+ const [errors, setErrors] = useState12("");
6840
+ const handleInputChange = (e) => {
6841
+ const raw = e.target.value.replace(/[^\d:]/g, "");
6842
+ setInput(raw);
6843
+ const timeRegex = /^(\d{1,2}):?(\d{0,2})$/;
6844
+ const match = raw.match(timeRegex);
6845
+ if (!match) {
6846
+ setErrors("\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7");
6847
+ setFormattedTime("");
6848
+ return;
6849
+ }
6850
+ let hours = parseInt(match[1] ?? "0", 10);
6851
+ let minutes = parseInt(match[2] ?? "0", 10);
6852
+ if (isNaN(hours)) hours = 0;
6853
+ if (isNaN(minutes)) minutes = 0;
6854
+ if (hours >= 24) {
6855
+ hours = 0;
6856
+ }
6857
+ if (minutes >= 60) {
6858
+ minutes = 0;
6859
+ }
6860
+ const formatted = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
6861
+ setErrors("");
6862
+ setFormattedTime(formatted);
6863
+ fieldOnChange(formatted);
6864
+ };
6865
+ const handleBlur = () => {
6866
+ if (!isDirty) return;
6867
+ if (formattedTime) {
6868
+ setInput(formattedTime);
6869
+ const floatVal = convertTimeToFloat(formattedTime);
6870
+ fieldOnChange(floatVal);
6871
+ if (onChange) {
6872
+ onChange(name ?? "", floatVal);
6873
+ }
6874
+ } else {
6875
+ setInput("00:00");
6876
+ fieldOnChange(0);
6877
+ if (onChange) {
6878
+ onChange(name ?? "", 0);
6879
+ }
6880
+ setErrors("");
6881
+ }
6882
+ onBlur();
6883
+ };
6884
+ const handleKeyDown = (e) => {
6885
+ {
6886
+ const allowed = [
6887
+ "Backspace",
6888
+ "Tab",
6889
+ "ArrowLeft",
6890
+ "ArrowRight",
6891
+ "Delete",
6892
+ "Home",
6893
+ "End",
6894
+ ":"
6895
+ ];
6896
+ const isNumber = /^[0-9]$/.test(e.key);
6897
+ if (!isNumber && !allowed.includes(e.key)) {
6898
+ e.preventDefault();
6899
+ }
6900
+ }
6901
+ };
6902
+ return {
6903
+ handleInputChange,
6904
+ handleBlur,
6905
+ handleKeyDown,
6906
+ input,
6907
+ errors
6908
+ };
6909
+ };
6910
+
6634
6911
  // src/widget/basic/float-field/controller.ts
6912
+ import { useEffect as useEffect15, useRef as useRef5, useState as useState13 } from "react";
6635
6913
  var floatController = ({
6636
6914
  onChange,
6637
6915
  value,
@@ -6639,10 +6917,10 @@ var floatController = ({
6639
6917
  }) => {
6640
6918
  const { name, required, methods, onChange: handleOnchange, string } = props;
6641
6919
  const { setError, clearErrors } = methods;
6642
- const [inputValue, setInputValue] = useState12(
6920
+ const [inputValue, setInputValue] = useState13(
6643
6921
  value !== void 0 && value !== null ? useFormatFloatNumber(value) : ""
6644
6922
  );
6645
- useEffect13(() => {
6923
+ useEffect15(() => {
6646
6924
  if (value !== void 0 && value !== null && value !== parseFloat(inputValue?.replace(/,/g, ""))) {
6647
6925
  setInputValue(useFormatFloatNumber(value));
6648
6926
  clearErrors(name);
@@ -6753,10 +7031,10 @@ var useFormatFloatNumber = (value) => {
6753
7031
  };
6754
7032
 
6755
7033
  // src/widget/basic/download-file-field/controller.ts
6756
- import { useId, useState as useState13 } from "react";
7034
+ import { useId, useState as useState14 } from "react";
6757
7035
  var downloadFileController = () => {
6758
7036
  const inputId = useId();
6759
- const [file, setFile] = useState13(null);
7037
+ const [file, setFile] = useState14(null);
6760
7038
  const handleFileChange = (e) => {
6761
7039
  setFile(e.target.files[0]);
6762
7040
  };
@@ -6920,11 +7198,11 @@ var dateFieldController = (props) => {
6920
7198
  };
6921
7199
 
6922
7200
  // src/widget/basic/copy-link-button/controller.ts
6923
- import { useState as useState14 } from "react";
7201
+ import { useState as useState15 } from "react";
6924
7202
  import { copyTextToClipboard } from "@fctc/interface-logic";
6925
7203
  var copyLinkButtonController = (props) => {
6926
7204
  const { value, defaultValue } = props;
6927
- const [isCopied, setIsCopied] = useState14(false);
7205
+ const [isCopied, setIsCopied] = useState15(false);
6928
7206
  const handleCopyToClipboard = async (value2) => {
6929
7207
  await copyTextToClipboard(value2);
6930
7208
  setIsCopied(true);
@@ -6939,412 +7217,132 @@ var copyLinkButtonController = (props) => {
6939
7217
  };
6940
7218
 
6941
7219
  // src/widget/basic/color-field/color-controller.ts
6942
- import { evalJSONContext as evalJSONContext7, getEnv as getEnv10, useSave as useSave3 } from "@fctc/interface-logic";
7220
+ import { evalJSONContext as evalJSONContext7, getEnv as getEnv11, useSave as useSave3 } from "@fctc/interface-logic";
6943
7221
  var colorFieldController = (props) => {
6944
7222
  const { value, isForm, name, formValues, idForm, model, actionData } = props;
6945
- const env = getEnv10();
6946
- const _context = { ...evalJSONContext7(actionData?.context) || {} };
6947
- const contextObject = { ...env.context, ..._context };
6948
- const idDefault = isForm ? idForm : formValues?.id;
6949
- const { mutate: onSave } = useSave3();
6950
- const savePickColor = async (colorObject) => {
6951
- const { id } = colorObject;
6952
- if (value === id) return;
6953
- try {
6954
- onSave({
6955
- ids: idDefault !== null ? [idDefault] : [],
6956
- model: model ?? "",
6957
- data: { [name ?? ""]: id },
6958
- specification: {
6959
- name: {},
6960
- color: {}
6961
- },
6962
- context: contextObject
6963
- });
6964
- } catch (error) {
6965
- console.log(error);
6966
- }
6967
- };
6968
- return {
6969
- savePickColor
6970
- };
6971
- };
6972
-
6973
- // src/widget/basic/binary-field/controller.ts
6974
- import { useEffect as useEffect14, useId as useId2, useRef as useRef6, useState as useState15 } from "react";
6975
- import { isBase64Image } from "@fctc/interface-logic";
6976
- var binaryFieldController = (props) => {
6977
- const { name, methods, readonly = false, value } = props;
6978
- const inputId = useId2();
6979
- const [selectedImage, setSelectedImage] = useState15(null);
6980
- const [initialImage, setInitialImage] = useState15(value || null);
6981
- const [isInsideTable, setIsInsideTable] = useState15(false);
6982
- const { setValue } = methods;
6983
- const binaryRef = useRef6(null);
6984
- const convertUrlToBase64 = async (url) => {
6985
- try {
6986
- const response = await fetch(url);
6987
- const blob = await response.blob();
6988
- return new Promise((resolve, reject) => {
6989
- const reader = new FileReader();
6990
- reader.onloadend = () => {
6991
- resolve(reader.result);
6992
- };
6993
- reader.onerror = reject;
6994
- reader.readAsDataURL(blob);
6995
- });
6996
- } catch (error) {
6997
- console.error("Error converting URL to Base64:", error);
6998
- throw error;
6999
- }
7000
- };
7001
- const extractBase64Data = (base64Url) => {
7002
- if (base64Url.includes("base64,")) {
7003
- return base64Url.split("base64,")[1];
7004
- }
7005
- return base64Url;
7006
- };
7007
- const handleImageChange = async (e, onChange) => {
7008
- if (readonly) return;
7009
- const file = e?.target?.files?.[0];
7010
- if (file) {
7011
- const imageUrl = URL.createObjectURL(file);
7012
- setSelectedImage(imageUrl);
7013
- setInitialImage(null);
7014
- onChange(file);
7015
- const compressedBase64 = await convertUrlToBase64(imageUrl);
7016
- const base64Data = extractBase64Data(compressedBase64);
7017
- setValue(name, base64Data, {
7018
- shouldDirty: true
7019
- });
7020
- }
7021
- };
7022
- const handleRemoveImage = (onChange) => {
7023
- setSelectedImage(null);
7024
- setInitialImage(null);
7025
- onChange(null);
7026
- };
7027
- const isBlobUrl = (url) => {
7028
- return /^blob:/.test(url);
7029
- };
7030
- const checkIsImageLink = (url) => {
7031
- const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
7032
- return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
7033
- };
7034
- const getImageBase64WithMimeType = (base64) => {
7035
- if (typeof base64 !== "string" || base64.length < 10) return null;
7036
- if (isBase64Image(base64)) return base64;
7037
- let mimeType = null;
7038
- if (base64.startsWith("iVBORw0KGgo")) mimeType = "image/png";
7039
- else if (base64.startsWith("/9j/")) mimeType = "image/jpeg";
7040
- else if (base64.startsWith("R0lGOD")) mimeType = "image/gif";
7041
- else if (base64.startsWith("Qk")) mimeType = "image/bmp";
7042
- else if (base64.startsWith("UklGR")) mimeType = "image/webp";
7043
- return mimeType ? `data:${mimeType};base64,${base64}` : null;
7044
- };
7045
- useEffect14(() => {
7046
- return () => {
7047
- if (selectedImage) {
7048
- URL.revokeObjectURL(selectedImage);
7049
- }
7050
- };
7051
- }, [selectedImage]);
7052
- useEffect14(() => {
7053
- if (binaryRef.current) {
7054
- const isInsideTable2 = !!binaryRef.current.closest("table");
7055
- setIsInsideTable(isInsideTable2);
7056
- }
7057
- }, []);
7058
- return {
7059
- inputId,
7060
- selectedImage,
7061
- initialImage,
7062
- isInsideTable,
7063
- binaryRef,
7064
- handleImageChange,
7065
- handleRemoveImage,
7066
- checkIsImageLink,
7067
- getImageBase64WithMimeType
7068
- };
7069
- };
7070
-
7071
- // src/widget/advance/table/table-body/controller.ts
7072
- import { setSelectedRowKeys, useAppDispatch as useAppDispatch6 } from "@fctc/interface-logic";
7073
- import { useEffect as useEffect15, useMemo as useMemo12 } from "react";
7074
- var tableBodyController = (props) => {
7075
- const {
7076
- checkedAll,
7077
- checkboxRef,
7078
- setIsAutoSelect,
7079
- selectedRowKeys,
7080
- row,
7081
- isAutoSelect,
7082
- selectedRowKeysRef,
7083
- onClickRow
7084
- } = props;
7085
- const appDispatch = useAppDispatch6();
7086
- const checked = useMemo12(() => {
7087
- if (!row?.id) return false;
7088
- if (selectedRowKeys?.includes(row.id)) {
7089
- return true;
7090
- }
7091
- return checkedAll;
7092
- }, [row?.id, selectedRowKeys, checkedAll]);
7093
- const handleCheckBoxSingle = (event) => {
7094
- event.stopPropagation();
7095
- if (checkedAll) {
7096
- checkboxRef.current = "uncheck";
7097
- setIsAutoSelect(true);
7098
- return;
7099
- }
7100
- const newSelectedRowKeys = selectedRowKeys?.includes(row.id) ? selectedRowKeys?.filter((key) => key !== row.id) : [...selectedRowKeys, row.id];
7101
- console.log("newSelectedRowKeys", newSelectedRowKeys);
7102
- appDispatch(setSelectedRowKeys(newSelectedRowKeys));
7103
- };
7104
- const handleClickRow = (col, row2) => {
7105
- onClickRow(col, row2);
7106
- };
7107
- useEffect15(() => {
7108
- if (!row?.id) return;
7109
- if (isAutoSelect) {
7110
- if (checkboxRef?.current === "uncheck") {
7111
- const filtered = selectedRowKeysRef.current.filter(
7112
- (id) => id !== row.id
7113
- );
7114
- selectedRowKeysRef.current = filtered;
7115
- appDispatch(setSelectedRowKeys(filtered));
7116
- } else {
7117
- const unique = Array.from(
7118
- /* @__PURE__ */ new Set([...selectedRowKeysRef?.current, row?.id])
7119
- );
7120
- selectedRowKeysRef.current = unique;
7121
- appDispatch(setSelectedRowKeys(unique));
7122
- }
7123
- }
7124
- }, [isAutoSelect]);
7125
- useEffect15(() => {
7126
- if (!checkedAll) {
7127
- checkboxRef.current = "enabled";
7128
- false;
7129
- }
7130
- }, [checkedAll]);
7131
- return {
7132
- handleCheckBoxSingle,
7133
- checked,
7134
- handleClickRow
7135
- };
7136
- };
7137
-
7138
- // src/widget/advance/table/table-head/controller.ts
7139
- import {
7140
- selectSearch as selectSearch4,
7141
- setSelectedRowKeys as setSelectedRowKeys2,
7142
- useAppDispatch as useAppDispatch7,
7143
- useAppSelector as useAppSelector7
7144
- } from "@fctc/interface-logic";
7145
- var tableHeadController = (props) => {
7146
- const { typeTable, rows, selectedRowKeysRef } = props;
7147
- const appDispatch = useAppDispatch7();
7148
- const { groupByDomain } = useAppSelector7(selectSearch4);
7149
- const handleCheckBoxAll = (event) => {
7150
- if (event?.target?.checked && typeTable === "list") {
7151
- const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
7152
- appDispatch(setSelectedRowKeys2(allRowKeys));
7153
- } else if (event?.target?.checked && typeTable === "group") {
7154
- const rowsIDs = document.querySelectorAll("tr[data-row-id]");
7155
- const ids = Array.from(rowsIDs)?.map(
7156
- (row) => Number(row?.getAttribute("data-row-id"))
7157
- );
7158
- if (ids?.length > 0) {
7159
- appDispatch(setSelectedRowKeys2(ids));
7160
- } else {
7161
- const sum = countSum(
7162
- rows,
7163
- typeof groupByDomain === "object" ? groupByDomain?.contexts?.[0]?.group_by : void 0
7164
- );
7165
- const keys = Array.from({ length: sum }, (_) => void 0);
7166
- appDispatch(setSelectedRowKeys2(keys));
7167
- }
7168
- if (selectedRowKeysRef) {
7169
- selectedRowKeysRef.current = [];
7170
- }
7171
- } else {
7172
- appDispatch(setSelectedRowKeys2([]));
7223
+ const env = getEnv11();
7224
+ const _context = { ...evalJSONContext7(actionData?.context) || {} };
7225
+ const contextObject = { ...env.context, ..._context };
7226
+ const idDefault = isForm ? idForm : formValues?.id;
7227
+ const { mutate: onSave } = useSave3();
7228
+ const savePickColor = async (colorObject) => {
7229
+ const { id } = colorObject;
7230
+ if (value === id) return;
7231
+ try {
7232
+ onSave({
7233
+ ids: idDefault !== null ? [idDefault] : [],
7234
+ model: model ?? "",
7235
+ data: { [name ?? ""]: id },
7236
+ specification: {
7237
+ name: {},
7238
+ color: {}
7239
+ },
7240
+ context: contextObject
7241
+ });
7242
+ } catch (error) {
7243
+ console.log(error);
7173
7244
  }
7174
7245
  };
7175
7246
  return {
7176
- handleCheckBoxAll
7247
+ savePickColor
7177
7248
  };
7178
7249
  };
7179
7250
 
7180
- // src/widget/advance/table/table-group/controller.ts
7181
- import {
7182
- getEnv as getEnv11,
7183
- selectList as selectList3,
7184
- selectSearch as selectSearch5,
7185
- setSelectedRowKeys as setSelectedRowKeys3,
7186
- useAppDispatch as useAppDispatch8,
7187
- useAppSelector as useAppSelector8,
7188
- useGetListData as useGetListData4,
7189
- useOdooDataTransform
7190
- } from "@fctc/interface-logic";
7191
- import { useEffect as useEffect16, useMemo as useMemo13, useState as useState16 } from "react";
7192
- var tableGroupController = (props) => {
7193
- const env = getEnv11();
7194
- const {
7195
- rows,
7196
- columns,
7197
- indexRow,
7198
- row,
7199
- model,
7200
- viewData,
7201
- renderField,
7202
- level,
7203
- specification,
7204
- domain,
7205
- context,
7206
- checkedAll,
7207
- isDisplayCheckbox,
7208
- isAutoSelect,
7209
- setIsAutoSelect,
7210
- selectedRowKeysRef
7211
- } = props;
7212
- const [pageGroup, setPageGroup] = useState16(0);
7213
- const { groupByDomain, selectedTags } = useAppSelector8(selectSearch5);
7214
- const { selectedRowKeys } = useAppSelector8(selectList3);
7215
- const appDispatch = useAppDispatch8();
7216
- const { toDataJS } = useOdooDataTransform();
7217
- const initVal = toDataJS(row, viewData, model);
7218
- const [isShowGroup, setIsShowGroup] = useState16(false);
7219
- const [colEmptyGroup, setColEmptyGroup] = useState16({
7220
- fromStart: 1,
7221
- fromEnd: 1
7222
- });
7223
- const processedData = useMemo13(() => {
7224
- const calculateColSpanEmpty = () => {
7225
- const startIndex = columns.findIndex(
7226
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
7227
- );
7228
- const endIndex = columns.findLastIndex(
7229
- (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
7230
- );
7231
- const fromStart = startIndex === -1 ? columns.length : startIndex;
7232
- const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
7233
- setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
7234
- return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
7235
- };
7236
- return calculateColSpanEmpty();
7237
- }, [columns, row]);
7238
- const shouldFetchData = useMemo13(() => {
7239
- return !!isShowGroup;
7240
- }, [isShowGroup]);
7241
- const enabled = shouldFetchData && !!processedData;
7242
- const listDataProps = {
7243
- model,
7244
- specification,
7245
- domain,
7246
- context,
7247
- offset: pageGroup * 10,
7248
- fields: groupByDomain?.fields,
7249
- groupby: [groupByDomain?.contexts[level]?.group_by]
7250
- };
7251
- const queryKey = [
7252
- `data-${model}--${level}-row${indexRow}`,
7253
- specification,
7254
- domain,
7255
- pageGroup
7256
- ];
7257
- const {
7258
- data: dataResponse,
7259
- isFetched: isQueryFetched,
7260
- isPlaceholderData,
7261
- isLoading,
7262
- isFetching
7263
- } = useGetListData4(listDataProps, queryKey, enabled);
7264
- const {
7265
- columns: columnsGroup,
7266
- rows: rowsGroup,
7267
- typeTable: typeTableGroup
7268
- } = tableController({
7269
- data: {
7270
- fields: viewData?.views?.list?.fields,
7271
- records: dataResponse?.records ?? dataResponse?.groups,
7272
- dataModel: viewData?.models?.[model],
7273
- context: env.context,
7274
- typeTable: dataResponse?.groups ? "group" : "list"
7275
- }
7276
- });
7277
- const leftPadding = level > 1 ? level * 8 + "px" : "0px";
7278
- useEffect16(() => {
7279
- if (isShowGroup && selectedTags?.length > 0) {
7280
- setIsShowGroup(false);
7251
+ // src/widget/basic/binary-field/controller.ts
7252
+ import { useEffect as useEffect16, useId as useId2, useRef as useRef6, useState as useState16 } from "react";
7253
+ import { isBase64Image } from "@fctc/interface-logic";
7254
+ var binaryFieldController = (props) => {
7255
+ const { name, methods, readonly = false, value } = props;
7256
+ const inputId = useId2();
7257
+ const [selectedImage, setSelectedImage] = useState16(null);
7258
+ const [initialImage, setInitialImage] = useState16(value || null);
7259
+ const [isInsideTable, setIsInsideTable] = useState16(false);
7260
+ const { setValue } = methods;
7261
+ const binaryRef = useRef6(null);
7262
+ const convertUrlToBase64 = async (url) => {
7263
+ try {
7264
+ const response = await fetch(url);
7265
+ const blob = await response.blob();
7266
+ return new Promise((resolve, reject) => {
7267
+ const reader = new FileReader();
7268
+ reader.onloadend = () => {
7269
+ resolve(reader.result);
7270
+ };
7271
+ reader.onerror = reject;
7272
+ reader.readAsDataURL(blob);
7273
+ });
7274
+ } catch (error) {
7275
+ console.error("Error converting URL to Base64:", error);
7276
+ throw error;
7281
7277
  }
7282
- }, [selectedTags]);
7283
- const group_by_field_name = groupByDomain?.contexts[level - 1]?.group_by;
7284
- 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(
7285
- (selectItem) => selectItem?.[0] === row[group_by_field_name]
7286
- )?.[1] : row[group_by_field_name];
7287
- 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`]})`;
7288
- const allIdsNull = selectedRowKeys?.every((item) => item === void 0);
7289
- const handleExpandChildGroup = () => {
7290
- if (isLoading || isFetching) return;
7291
- const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
7292
- if (allIdsNull || typeTableGroup === "group") {
7293
- toggleShowGroup();
7294
- return;
7278
+ };
7279
+ const extractBase64Data = (base64Url) => {
7280
+ if (base64Url.includes("base64,")) {
7281
+ return base64Url.split("base64,")[1];
7295
7282
  }
7296
- if (isShowGroup && checkedAll) {
7297
- const ids = rowsGroup?.map((item) => item?.id) || [];
7298
- const filteredIds = selectedRowKeys.filter(
7299
- (id) => !ids.includes(id)
7300
- );
7301
- appDispatch(setSelectedRowKeys3(filteredIds));
7302
- } else if (!isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && checkedAll && !allIdsNull && isQueryFetched) {
7303
- const clonedKeys = [...selectedRowKeys];
7304
- appDispatch(setSelectedRowKeys3([...clonedKeys, -1]));
7305
- setTimeout(() => appDispatch(setSelectedRowKeys3(clonedKeys)), 500);
7306
- } else if (isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && !checkedAll && !allIdsNull) {
7307
- const filteredKeys = selectedRowKeys.filter((id) => id > -1);
7308
- appDispatch(setSelectedRowKeys3(filteredKeys));
7283
+ return base64Url;
7284
+ };
7285
+ const handleImageChange = async (e, onChange) => {
7286
+ if (readonly) return;
7287
+ const file = e?.target?.files?.[0];
7288
+ if (file) {
7289
+ const imageUrl = URL.createObjectURL(file);
7290
+ setSelectedImage(imageUrl);
7291
+ setInitialImage(null);
7292
+ onChange(file);
7293
+ const compressedBase64 = await convertUrlToBase64(imageUrl);
7294
+ const base64Data = extractBase64Data(compressedBase64);
7295
+ setValue(name, base64Data, {
7296
+ shouldDirty: true
7297
+ });
7309
7298
  }
7310
- toggleShowGroup();
7299
+ };
7300
+ const handleRemoveImage = (onChange) => {
7301
+ setSelectedImage(null);
7302
+ setInitialImage(null);
7303
+ onChange(null);
7304
+ };
7305
+ const isBlobUrl = (url) => {
7306
+ return /^blob:/.test(url);
7307
+ };
7308
+ const checkIsImageLink = (url) => {
7309
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
7310
+ return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
7311
+ };
7312
+ const getImageBase64WithMimeType = (base64) => {
7313
+ if (typeof base64 !== "string" || base64.length < 10) return null;
7314
+ if (isBase64Image(base64)) return base64;
7315
+ let mimeType = null;
7316
+ if (base64.startsWith("iVBORw0KGgo")) mimeType = "image/png";
7317
+ else if (base64.startsWith("/9j/")) mimeType = "image/jpeg";
7318
+ else if (base64.startsWith("R0lGOD")) mimeType = "image/gif";
7319
+ else if (base64.startsWith("Qk")) mimeType = "image/bmp";
7320
+ else if (base64.startsWith("UklGR")) mimeType = "image/webp";
7321
+ return mimeType ? `data:${mimeType};base64,${base64}` : null;
7311
7322
  };
7312
7323
  useEffect16(() => {
7313
- if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
7314
- return;
7324
+ return () => {
7325
+ if (selectedImage) {
7326
+ URL.revokeObjectURL(selectedImage);
7327
+ }
7328
+ };
7329
+ }, [selectedImage]);
7330
+ useEffect16(() => {
7331
+ if (binaryRef.current) {
7332
+ const isInsideTable2 = !!binaryRef.current.closest("table");
7333
+ setIsInsideTable(isInsideTable2);
7315
7334
  }
7316
- const clonedKeys = [...selectedRowKeys];
7317
- setSelectedRowKeys3([...clonedKeys, -1]);
7318
- setTimeout(() => setSelectedRowKeys3(clonedKeys), 500);
7319
- }, [isQueryFetched]);
7335
+ }, []);
7320
7336
  return {
7321
- handleExpandChildGroup,
7322
- colEmptyGroup,
7323
- leftPadding,
7324
- isShowGroup,
7325
- isQueryFetched,
7326
- nameGroupWithCount,
7327
- columns,
7328
- row,
7329
- isPlaceholderData,
7330
- columnsGroup,
7331
- indexRow,
7332
- rowsGroup,
7333
- model,
7334
- viewData,
7335
- renderField,
7336
- level,
7337
- specification,
7338
- context,
7339
- checkedAll,
7340
- isDisplayCheckbox,
7341
- isAutoSelect,
7342
- setIsAutoSelect,
7343
- selectedRowKeysRef,
7344
- initVal,
7345
- dataResponse,
7346
- pageGroup,
7347
- setPageGroup
7337
+ inputId,
7338
+ selectedImage,
7339
+ initialImage,
7340
+ isInsideTable,
7341
+ binaryRef,
7342
+ handleImageChange,
7343
+ handleRemoveImage,
7344
+ checkIsImageLink,
7345
+ getImageBase64WithMimeType
7348
7346
  };
7349
7347
  };
7350
7348
  export {