@fctc/widget-logic 1.2.1 → 1.2.3

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
@@ -4702,7 +4702,7 @@ var useCompany = (accessToken) => {
4702
4702
  var use_company_default = useCompany;
4703
4703
 
4704
4704
  // src/hooks/core/use-app-provider.tsx
4705
- import { evalJSONContext } from "@fctc/interface-logic";
4705
+ import { evalJSONContext, MainProvider } from "@fctc/interface-logic";
4706
4706
  import { jsx } from "react/jsx-runtime";
4707
4707
  var AppProviderInitialValue = {
4708
4708
  config: {},
@@ -4755,7 +4755,7 @@ var AppProvider = ({ children }) => {
4755
4755
  action,
4756
4756
  view
4757
4757
  },
4758
- children
4758
+ children: /* @__PURE__ */ jsx(MainProvider, { children })
4759
4759
  }
4760
4760
  );
4761
4761
  };
@@ -5163,7 +5163,7 @@ var many2oneFieldController = (props) => {
5163
5163
  const queryKey = [`data_${relation}`, domainObject];
5164
5164
  const {
5165
5165
  data: dataOfSelection,
5166
- refetch,
5166
+ // refetch,
5167
5167
  isFetching
5168
5168
  } = useGetSelection({
5169
5169
  data,
@@ -5192,9 +5192,6 @@ var many2oneFieldController = (props) => {
5192
5192
  });
5193
5193
  }
5194
5194
  }, [propValue]);
5195
- const fetchMoreOptions = useCallback6(() => {
5196
- refetch();
5197
- }, [refetch]);
5198
5195
  useEffect10(() => {
5199
5196
  if (actionId) {
5200
5197
  localStorage.setItem("aid", actionId);
@@ -5251,6 +5248,12 @@ var many2oneFieldController = (props) => {
5251
5248
  [methods, name, onChange]
5252
5249
  );
5253
5250
  const allowShowDetail = showDetail && contextObject?.form_view_ref && (!("no_open" in optionsObject) || optionsObject?.no_open === false);
5251
+ const fetchMoreOptions = useCallback6(() => {
5252
+ if (typeof dataOfSelection?.refetch === "function") {
5253
+ ;
5254
+ dataOfSelection.refetch();
5255
+ }
5256
+ }, [dataOfSelection]);
5254
5257
  return {
5255
5258
  allowShowDetail,
5256
5259
  handleClose,
@@ -5266,7 +5269,8 @@ var many2oneFieldController = (props) => {
5266
5269
  setTempSelectedOption,
5267
5270
  setDomainModal,
5268
5271
  dataOfSelection,
5269
- refetch,
5272
+ refetch: dataOfSelection?.refetch ?? (() => {
5273
+ }),
5270
5274
  selectOptions,
5271
5275
  optionsObject,
5272
5276
  contextObject,
@@ -5306,32 +5310,141 @@ var many2oneButtonController = (props) => {
5306
5310
  };
5307
5311
 
5308
5312
  // src/widget/basic/many2many-field/controller.ts
5309
- import { useEffect as useEffect12, useMemo as useMemo10, useState as useState9 } from "react";
5313
+ import { useEffect as useEffect14, useMemo as useMemo12, useState as useState10 } from "react";
5310
5314
  import {
5311
5315
  evalJSONContext as evalJSONContext4,
5312
5316
  formatSortingString as formatSortingString2,
5313
- getEnv as getEnv8,
5314
- selectSearch as selectSearch3,
5317
+ getEnv as getEnv9,
5318
+ selectSearch as selectSearch5,
5315
5319
  setFirstDomain,
5316
5320
  setGroupByDomain,
5317
5321
  setPage,
5318
5322
  setViewDataStore,
5319
- useAppDispatch as useAppDispatch5,
5320
- useAppSelector as useAppSelector5,
5323
+ useAppDispatch as useAppDispatch8,
5324
+ useAppSelector as useAppSelector7,
5321
5325
  useGetFormView,
5322
- useGetListData as useGetListData2,
5326
+ useGetListData as useGetListData3,
5323
5327
  useGetView as useGetView2,
5324
5328
  useModel as useModel2
5325
5329
  } from "@fctc/interface-logic";
5326
5330
 
5331
+ // src/widget/advance/table/table-body/controller.ts
5332
+ import { setSelectedRowKeys, useAppDispatch as useAppDispatch5 } from "@fctc/interface-logic";
5333
+ import { useEffect as useEffect11, useMemo as useMemo9 } from "react";
5334
+ var tableBodyController = (props) => {
5335
+ const {
5336
+ checkedAll,
5337
+ checkboxRef,
5338
+ setIsAutoSelect,
5339
+ selectedRowKeys,
5340
+ row,
5341
+ isAutoSelect,
5342
+ selectedRowKeysRef,
5343
+ onClickRow
5344
+ } = props;
5345
+ const appDispatch = useAppDispatch5();
5346
+ const checked = useMemo9(() => {
5347
+ if (!row?.id) return false;
5348
+ if (selectedRowKeys?.includes(row.id)) {
5349
+ return true;
5350
+ }
5351
+ return checkedAll;
5352
+ }, [row?.id, selectedRowKeys, checkedAll]);
5353
+ const handleCheckBoxSingle = (event) => {
5354
+ event.stopPropagation();
5355
+ if (checkedAll) {
5356
+ checkboxRef.current = "uncheck";
5357
+ setIsAutoSelect(true);
5358
+ return;
5359
+ }
5360
+ const newSelectedRowKeys = selectedRowKeys?.includes(row.id) ? selectedRowKeys?.filter((key) => key !== row.id) : [...selectedRowKeys, row.id];
5361
+ console.log("newSelectedRowKeys", newSelectedRowKeys);
5362
+ appDispatch(setSelectedRowKeys(newSelectedRowKeys));
5363
+ };
5364
+ const handleClickRow = (col, row2) => {
5365
+ onClickRow(col, row2);
5366
+ };
5367
+ useEffect11(() => {
5368
+ if (!row?.id) return;
5369
+ if (isAutoSelect) {
5370
+ if (checkboxRef?.current === "uncheck") {
5371
+ const filtered = selectedRowKeysRef.current.filter(
5372
+ (id) => id !== row.id
5373
+ );
5374
+ selectedRowKeysRef.current = filtered;
5375
+ appDispatch(setSelectedRowKeys(filtered));
5376
+ } else {
5377
+ const unique = Array.from(
5378
+ /* @__PURE__ */ new Set([...selectedRowKeysRef?.current, row?.id])
5379
+ );
5380
+ selectedRowKeysRef.current = unique;
5381
+ appDispatch(setSelectedRowKeys(unique));
5382
+ }
5383
+ }
5384
+ }, [isAutoSelect]);
5385
+ useEffect11(() => {
5386
+ if (!checkedAll) {
5387
+ checkboxRef.current = "enabled";
5388
+ false;
5389
+ }
5390
+ }, [checkedAll]);
5391
+ return {
5392
+ handleCheckBoxSingle,
5393
+ checked,
5394
+ handleClickRow
5395
+ };
5396
+ };
5397
+
5398
+ // src/widget/advance/table/table-head/controller.ts
5399
+ import {
5400
+ selectSearch as selectSearch2,
5401
+ setSelectedRowKeys as setSelectedRowKeys2,
5402
+ useAppDispatch as useAppDispatch6,
5403
+ useAppSelector as useAppSelector4
5404
+ } from "@fctc/interface-logic";
5405
+ var tableHeadController = (props) => {
5406
+ const { typeTable, rows, selectedRowKeysRef } = props;
5407
+ const appDispatch = useAppDispatch6();
5408
+ const { groupByDomain } = useAppSelector4(selectSearch2);
5409
+ const handleCheckBoxAll = (event) => {
5410
+ if (event?.target?.checked && typeTable === "list") {
5411
+ const allRowKeys = Array.isArray(rows) ? rows.map((record) => record?.id) : [];
5412
+ appDispatch(setSelectedRowKeys2(allRowKeys));
5413
+ } else if (event?.target?.checked && typeTable === "group") {
5414
+ const rowsIDs = document.querySelectorAll("tr[data-row-id]");
5415
+ const ids = Array.from(rowsIDs)?.map(
5416
+ (row) => Number(row?.getAttribute("data-row-id"))
5417
+ );
5418
+ if (ids?.length > 0) {
5419
+ appDispatch(setSelectedRowKeys2(ids));
5420
+ } else {
5421
+ const sum = countSum(
5422
+ rows,
5423
+ typeof groupByDomain === "object" ? groupByDomain?.contexts?.[0]?.group_by : void 0
5424
+ );
5425
+ const keys = Array.from({ length: sum }, (_) => void 0);
5426
+ appDispatch(setSelectedRowKeys2(keys));
5427
+ }
5428
+ if (selectedRowKeysRef) {
5429
+ selectedRowKeysRef.current = [];
5430
+ }
5431
+ } else {
5432
+ appDispatch(setSelectedRowKeys2([]));
5433
+ }
5434
+ };
5435
+ return {
5436
+ handleCheckBoxAll
5437
+ };
5438
+ };
5439
+
5327
5440
  // src/widget/advance/table/table-view/controller.ts
5328
5441
  import {
5329
5442
  domainHelper,
5330
5443
  selectList as selectList2,
5331
- selectSearch as selectSearch2,
5332
- useAppSelector as useAppSelector4
5444
+ selectSearch as selectSearch3,
5445
+ useAppSelector as useAppSelector5
5333
5446
  } from "@fctc/interface-logic";
5334
- import { useEffect as useEffect11, useMemo as useMemo9, useRef as useRef4, useState as useState8 } from "react";
5447
+ import { useEffect as useEffect12, useMemo as useMemo10, useRef as useRef4, useState as useState8 } from "react";
5335
5448
  var tableController = ({ data }) => {
5336
5449
  const [rows, setRows] = useState8(data.records || []);
5337
5450
  const [columns, setColumns] = useState8([]);
@@ -5362,7 +5475,7 @@ var tableController = ({ data }) => {
5362
5475
  return item.display_name ? { ...transformedItem, item: item.display_name } : transformedItem;
5363
5476
  });
5364
5477
  };
5365
- useEffect11(() => {
5478
+ useEffect12(() => {
5366
5479
  setRows(transformData(data.records || null));
5367
5480
  }, [data.records]);
5368
5481
  const handleGetColumns = () => {
@@ -5383,7 +5496,7 @@ var tableController = ({ data }) => {
5383
5496
  }
5384
5497
  return cols;
5385
5498
  };
5386
- useEffect11(() => {
5499
+ useEffect12(() => {
5387
5500
  const columns2 = handleGetColumns();
5388
5501
  setColumns(columns2);
5389
5502
  }, [data.records]);
@@ -5407,466 +5520,23 @@ var tableController = ({ data }) => {
5407
5520
  };
5408
5521
  };
5409
5522
 
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";
5523
+ // src/widget/advance/table/table-group/controller.ts
5646
5524
  import {
5647
- evalJSONDomain as evalJSONDomain5,
5648
- selectEnv as selectEnv3,
5525
+ getEnv as getEnv8,
5526
+ selectList as selectList3,
5527
+ selectSearch as selectSearch4,
5528
+ setSelectedRowKeys as setSelectedRowKeys3,
5529
+ useAppDispatch as useAppDispatch7,
5649
5530
  useAppSelector as useAppSelector6,
5650
- useChangeStatus,
5651
- useGetListData as useGetListData3
5531
+ useGetListData as useGetListData2,
5532
+ useOdooDataTransform
5652
5533
  } 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
- };
5534
+ import { useEffect as useEffect13, useMemo as useMemo11, useState as useState9 } from "react";
5721
5535
 
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";
5536
+ // src/utils/i18n.ts
5537
+ import { initReactI18next } from "react-i18next";
5538
+ import i18n from "i18next";
5539
+ import LanguageDetector from "i18next-browser-languagedetector";
5870
5540
 
5871
5541
  // src/locales/vi.json
5872
5542
  var vi_default = {
@@ -6053,8 +5723,6 @@ var vi_default = {
6053
5723
  add_new_attribute: "Th\xEAm thu\u1ED9c t\xEDnh",
6054
5724
  add_attribute_name: "T\xEAn thu\u1ED9c t\xEDnh",
6055
5725
  images_product: "H\xECnh \u1EA3nh",
6056
- selected: "\u0111\u01B0\u1EE3c ch\u1ECDn",
6057
- print: "In",
6058
5726
  generate_code_product: "T\u1EA1o m\xE3 s\u1EA3n ph\u1EA9m",
6059
5727
  order_today: "\u0110\u01A1n h\xE0ng",
6060
5728
  list_best_selling_product: "S\u1EA3n ph\u1EA9m b\xE1n ch\u1EA1y",
@@ -6612,26 +6280,640 @@ var vi_default = {
6612
6280
  "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
6281
  };
6614
6282
 
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
-
6283
+ // src/utils/i18n.ts
6284
+ i18n.use(LanguageDetector).use(initReactI18next).init({
6285
+ resources: {
6286
+ vi: { translation: vi_default },
6287
+ en: { translation: vi_default }
6288
+ },
6289
+ fallbackLng: "vi",
6290
+ lng: "vi_VN",
6291
+ debug: false,
6292
+ nonExplicitSupportedLngs: true,
6293
+ interpolation: {
6294
+ escapeValue: false
6295
+ },
6296
+ detection: {
6297
+ caches: ["cookie"]
6298
+ }
6299
+ });
6300
+ var i18n_default = i18n;
6301
+
6302
+ // src/widget/advance/table/table-group/controller.ts
6303
+ var tableGroupController = (props) => {
6304
+ const env = getEnv8();
6305
+ const {
6306
+ rows,
6307
+ columns,
6308
+ indexRow,
6309
+ row,
6310
+ model,
6311
+ viewData,
6312
+ renderField,
6313
+ level,
6314
+ specification,
6315
+ domain,
6316
+ context,
6317
+ checkedAll,
6318
+ isDisplayCheckbox,
6319
+ isAutoSelect,
6320
+ setIsAutoSelect,
6321
+ selectedRowKeysRef
6322
+ } = props;
6323
+ const [pageGroup, setPageGroup] = useState9(0);
6324
+ const { groupByDomain, selectedTags } = useAppSelector6(selectSearch4);
6325
+ const { selectedRowKeys } = useAppSelector6(selectList3);
6326
+ const appDispatch = useAppDispatch7();
6327
+ const { toDataJS } = useOdooDataTransform();
6328
+ const initVal = toDataJS(row, viewData, model);
6329
+ const [isShowGroup, setIsShowGroup] = useState9(false);
6330
+ const [colEmptyGroup, setColEmptyGroup] = useState9({
6331
+ fromStart: 1,
6332
+ fromEnd: 1
6333
+ });
6334
+ const processedData = useMemo11(() => {
6335
+ const calculateColSpanEmpty = () => {
6336
+ const startIndex = columns.findIndex(
6337
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
6338
+ );
6339
+ const endIndex = columns.findLastIndex(
6340
+ (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator !== "sum"
6341
+ );
6342
+ const fromStart = startIndex === -1 ? columns.length : startIndex;
6343
+ const fromEnd = endIndex === -1 ? columns.length : columns.length - 1 - endIndex;
6344
+ setColEmptyGroup({ fromStart: fromStart + 1, fromEnd: fromEnd + 1 });
6345
+ return { fromStart: fromStart + 1, fromEnd: fromEnd + 1 };
6346
+ };
6347
+ return calculateColSpanEmpty();
6348
+ }, [columns, row]);
6349
+ const shouldFetchData = useMemo11(() => {
6350
+ return !!isShowGroup;
6351
+ }, [isShowGroup]);
6352
+ const enabled = shouldFetchData && !!processedData;
6353
+ const listDataProps = {
6354
+ model,
6355
+ specification,
6356
+ domain,
6357
+ context,
6358
+ offset: pageGroup * 10,
6359
+ fields: groupByDomain?.fields,
6360
+ groupby: [groupByDomain?.contexts[level]?.group_by]
6361
+ };
6362
+ const queryKey = [
6363
+ `data-${model}--${level}-row${indexRow}`,
6364
+ specification,
6365
+ domain,
6366
+ pageGroup
6367
+ ];
6368
+ const {
6369
+ data: dataResponse,
6370
+ isFetched: isQueryFetched,
6371
+ isPlaceholderData,
6372
+ isLoading,
6373
+ isFetching
6374
+ } = useGetListData2(listDataProps, queryKey, enabled);
6375
+ const {
6376
+ columns: columnsGroup,
6377
+ rows: rowsGroup,
6378
+ typeTable: typeTableGroup
6379
+ } = tableController({
6380
+ data: {
6381
+ fields: viewData?.views?.list?.fields,
6382
+ records: dataResponse?.records ?? dataResponse?.groups,
6383
+ dataModel: viewData?.models?.[model],
6384
+ context: env.context,
6385
+ typeTable: dataResponse?.groups ? "group" : "list"
6386
+ }
6387
+ });
6388
+ const leftPadding = level > 1 ? level * 8 + "px" : "0px";
6389
+ useEffect13(() => {
6390
+ if (isShowGroup && selectedTags?.length > 0) {
6391
+ setIsShowGroup(false);
6392
+ }
6393
+ }, [selectedTags]);
6394
+ const group_by_field_name = groupByDomain?.contexts[level - 1]?.group_by;
6395
+ 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(
6396
+ (selectItem) => selectItem?.[0] === row[group_by_field_name]
6397
+ )?.[1] : row[group_by_field_name];
6398
+ 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`]})`;
6399
+ const allIdsNull = selectedRowKeys?.every((item) => item === void 0);
6400
+ const handleExpandChildGroup = () => {
6401
+ if (isLoading || isFetching) return;
6402
+ const toggleShowGroup = () => setIsShowGroup((prev) => !prev);
6403
+ if (allIdsNull || typeTableGroup === "group") {
6404
+ toggleShowGroup();
6405
+ return;
6406
+ }
6407
+ if (isShowGroup && checkedAll) {
6408
+ const ids = rowsGroup?.map((item) => item?.id) || [];
6409
+ const filteredIds = selectedRowKeys.filter(
6410
+ (id) => !ids.includes(id)
6411
+ );
6412
+ appDispatch(setSelectedRowKeys3(filteredIds));
6413
+ } else if (!isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && checkedAll && !allIdsNull && isQueryFetched) {
6414
+ const clonedKeys = [...selectedRowKeys];
6415
+ appDispatch(setSelectedRowKeys3([...clonedKeys, -1]));
6416
+ setTimeout(() => appDispatch(setSelectedRowKeys3(clonedKeys)), 500);
6417
+ } else if (isShowGroup && selectedRowKeys?.length > 0 && typeTableGroup === "list" && !checkedAll && !allIdsNull) {
6418
+ const filteredKeys = selectedRowKeys.filter((id) => id > -1);
6419
+ appDispatch(setSelectedRowKeys3(filteredKeys));
6420
+ }
6421
+ toggleShowGroup();
6422
+ };
6423
+ useEffect13(() => {
6424
+ if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
6425
+ return;
6426
+ }
6427
+ const clonedKeys = [...selectedRowKeys];
6428
+ setSelectedRowKeys3([...clonedKeys, -1]);
6429
+ setTimeout(() => setSelectedRowKeys3(clonedKeys), 500);
6430
+ }, [isQueryFetched]);
6431
+ return {
6432
+ handleExpandChildGroup,
6433
+ colEmptyGroup,
6434
+ leftPadding,
6435
+ isShowGroup,
6436
+ isQueryFetched,
6437
+ nameGroupWithCount,
6438
+ columns,
6439
+ row,
6440
+ isPlaceholderData,
6441
+ columnsGroup,
6442
+ indexRow,
6443
+ rowsGroup,
6444
+ model,
6445
+ viewData,
6446
+ renderField,
6447
+ level,
6448
+ specification,
6449
+ context,
6450
+ checkedAll,
6451
+ isDisplayCheckbox,
6452
+ isAutoSelect,
6453
+ setIsAutoSelect,
6454
+ selectedRowKeysRef,
6455
+ initVal,
6456
+ dataResponse,
6457
+ pageGroup,
6458
+ setPageGroup
6459
+ };
6460
+ };
6461
+
6462
+ // src/widget/basic/many2many-field/controller.ts
6463
+ var many2manyFieldController = (props) => {
6464
+ const {
6465
+ relation,
6466
+ domain,
6467
+ context,
6468
+ tab,
6469
+ model,
6470
+ aid,
6471
+ setSelectedRowKeys: setSelectedRowKeys4,
6472
+ fields,
6473
+ setFields,
6474
+ groupByDomain,
6475
+ page,
6476
+ options,
6477
+ sessionStorageUtils
6478
+ } = props;
6479
+ const appDispatch = useAppDispatch8();
6480
+ const actionData = sessionStorageUtils.getActionData();
6481
+ const [debouncedPage] = useDebounce(page, 500);
6482
+ const [order, setOrder] = useState10();
6483
+ const [isLoadedData, setIsLoadedData] = useState10(false);
6484
+ const [domainMany2Many, setDomainMany2Many] = useState10(domain);
6485
+ const env = getEnv9();
6486
+ const { selectedTags } = useAppSelector7(selectSearch5);
6487
+ const viewParams = {
6488
+ model: relation,
6489
+ views: [
6490
+ [false, "list"],
6491
+ [false, "search"]
6492
+ ],
6493
+ context
6494
+ };
6495
+ const { data: viewResponse, isFetched: isViewReponseFetched } = useGetView2(
6496
+ viewParams,
6497
+ actionData
6498
+ );
6499
+ const baseModel = useMemo12(
6500
+ () => ({
6501
+ name: String(relation),
6502
+ view: viewResponse || {},
6503
+ actContext: context,
6504
+ fields: [
6505
+ ...Object.values(viewResponse?.views?.list?.fields ?? {}),
6506
+ ...tab?.fields ? tab.fields : []
6507
+ ]
6508
+ }),
6509
+ [model, viewResponse]
6510
+ );
6511
+ const initModel = useModel2();
6512
+ const modelInstance = useMemo12(() => {
6513
+ if (viewResponse) {
6514
+ return initModel.initModel(baseModel);
6515
+ }
6516
+ return null;
6517
+ }, [baseModel, viewResponse]);
6518
+ const specification = useMemo12(() => {
6519
+ if (modelInstance) {
6520
+ return modelInstance.getSpecification();
6521
+ }
6522
+ return null;
6523
+ }, [modelInstance]);
6524
+ const default_order = viewResponse && viewResponse?.views?.list?.default_order;
6525
+ const optionsObject = tab?.options ? evalJSONContext4(tab?.options) : (options ? evalJSONContext4(options) : {}) || {};
6526
+ const fetchData = async () => {
6527
+ try {
6528
+ setDomainMany2Many(domain);
6529
+ appDispatch(setFirstDomain(domain));
6530
+ appDispatch(setViewDataStore(viewResponse));
6531
+ const modalData = viewResponse?.views?.list?.fields.map((field) => ({
6532
+ ...viewResponse?.models?.[String(model)]?.[field?.name],
6533
+ ...field
6534
+ }));
6535
+ if (!fields?.[`${aid}_${relation}_popupmany2many`] && modalData) {
6536
+ setFields({
6537
+ ...fields,
6538
+ [`${aid}_${relation}_popupmany2many`]: modalData
6539
+ });
6540
+ }
6541
+ appDispatch(setPage(0));
6542
+ } catch (err) {
6543
+ console.log(err);
6544
+ }
6545
+ };
6546
+ const queryKey = [
6547
+ `view-${relation}-${aid}`,
6548
+ specification,
6549
+ domainMany2Many,
6550
+ debouncedPage,
6551
+ groupByDomain,
6552
+ order
6553
+ ];
6554
+ const data = {
6555
+ model: relation,
6556
+ specification,
6557
+ domain: domainMany2Many,
6558
+ offset: debouncedPage * 10,
6559
+ limit: 10,
6560
+ context,
6561
+ fields: groupByDomain?.fields,
6562
+ groupby: [groupByDomain?.contexts[0]?.group_by],
6563
+ sort: order ? order : default_order ? formatSortingString2(default_order) : ""
6564
+ };
6565
+ const enabled = isLoadedData && !!specification && !!relation && !!domainMany2Many && !!viewResponse;
6566
+ const {
6567
+ data: dataResponse,
6568
+ isLoading: isDataLoading,
6569
+ isFetched: isDataResponseFetched,
6570
+ isPlaceholderData
6571
+ } = useGetListData3(data, queryKey, enabled);
6572
+ useEffect14(() => {
6573
+ if (viewResponse) {
6574
+ fetchData();
6575
+ }
6576
+ return () => {
6577
+ appDispatch(setGroupByDomain(null));
6578
+ setFields((prevFields) => ({
6579
+ ...prevFields,
6580
+ [`${aid}_${relation}_popupmany2many`]: null
6581
+ }));
6582
+ appDispatch(setPage(0));
6583
+ setSelectedRowKeys4([]);
6584
+ setDomainMany2Many(null);
6585
+ setIsLoadedData(false);
6586
+ };
6587
+ }, [viewResponse]);
6588
+ const { rows, columns, typeTable } = tableController({
6589
+ data: {
6590
+ fields: fields?.[`${aid}_${relation}_popupmany2many`] || viewResponse?.views?.list?.fields,
6591
+ records: dataResponse?.records ?? dataResponse?.groups,
6592
+ dataModel: viewResponse?.models?.[String(relation)],
6593
+ context: { ...env.context, ...context },
6594
+ typeTable: dataResponse?.groups ? "group" : "list"
6595
+ }
6596
+ });
6597
+ const dataFormView = {
6598
+ id: null,
6599
+ model: relation,
6600
+ context
6601
+ };
6602
+ const {
6603
+ refetch,
6604
+ data: dataFormViewResponse,
6605
+ isSuccess
6606
+ } = useGetFormView({
6607
+ data: dataFormView,
6608
+ queryKey: [`form-view-action-${relation}`],
6609
+ enabled: false
6610
+ });
6611
+ useEffect14(() => {
6612
+ if (isSuccess && dataFormViewResponse) {
6613
+ sessionStorage.setItem("actionData", JSON.stringify(dataFormViewResponse));
6614
+ window.location.href = `/form/menu?model=${relation}`;
6615
+ }
6616
+ }, [isSuccess]);
6617
+ useEffect14(() => {
6618
+ if (domainMany2Many && !isLoadedData) {
6619
+ setIsLoadedData(true);
6620
+ }
6621
+ }, [domainMany2Many]);
6622
+ const handleCreateNewOnPage = async () => {
6623
+ try {
6624
+ refetch();
6625
+ } catch (error) {
6626
+ console.log(error);
6627
+ }
6628
+ };
6629
+ return {};
6630
+ };
6631
+
6632
+ // src/widget/basic/many2many-tags-field/controller.ts
6633
+ import { useMemo as useMemo13 } from "react";
6634
+ import {
6635
+ evalJSONContext as evalJSONContext5,
6636
+ evalJSONDomain as evalJSONDomain4,
6637
+ getEnv as getEnv10,
6638
+ useGetSelection as useGetSelection3,
6639
+ WIDGETAVATAR,
6640
+ WIDGETCOLOR
6641
+ } from "@fctc/interface-logic";
6642
+ var many2manyTagsController = (props) => {
6643
+ const {
6644
+ relation,
6645
+ domain,
6646
+ options: optionsFields,
6647
+ widget,
6648
+ formValues,
6649
+ placeholderNoOption
6650
+ } = props;
6651
+ const isUser = relation === "res.users" || relation === "res.partner";
6652
+ const env = getEnv10();
6653
+ const addtionalFields = optionsFields ? evalJSONContext5(optionsFields) : null;
6654
+ const domainObject = useMemo13(
6655
+ () => evalJSONDomain4(domain, JSON.parse(JSON.stringify(formValues || {}))),
6656
+ [domain, formValues]
6657
+ );
6658
+ const data = {
6659
+ model: relation ?? "",
6660
+ domain: domainObject,
6661
+ specification: {
6662
+ id: {},
6663
+ name: {},
6664
+ display_name: {},
6665
+ ...widget && WIDGETAVATAR[widget] ? { image_256: {} } : {},
6666
+ ...widget && WIDGETCOLOR[widget] && addtionalFields?.color_field ? { color: {} } : {}
6667
+ },
6668
+ enabled: true,
6669
+ context: env.context
6670
+ };
6671
+ const { data: dataOfSelection } = useGetSelection3({
6672
+ data,
6673
+ queryKey: [`data_${relation}`, domainObject]
6674
+ });
6675
+ const customNoOptionsMessage = () => placeholderNoOption;
6676
+ const tranfer = (data2) => {
6677
+ return data2?.map((val) => ({
6678
+ id: val.value,
6679
+ display_name: val.label
6680
+ })) || [];
6681
+ };
6682
+ const options = dataOfSelection?.records?.map((val) => ({
6683
+ value: val.id,
6684
+ label: val.name ?? val.display_name,
6685
+ ...val
6686
+ })) || [];
6687
+ return {
6688
+ options,
6689
+ customNoOptionsMessage,
6690
+ tranfer,
6691
+ dataOfSelection,
6692
+ isUser
6693
+ };
6694
+ };
6695
+
6696
+ // src/widget/basic/status-bar-field/controller.ts
6697
+ import { useState as useState11 } from "react";
6698
+ import {
6699
+ evalJSONDomain as evalJSONDomain5,
6700
+ selectEnv as selectEnv3,
6701
+ useAppSelector as useAppSelector8,
6702
+ useChangeStatus,
6703
+ useGetListData as useGetListData4
6704
+ } from "@fctc/interface-logic";
6705
+ var durationController = (props) => {
6706
+ const {
6707
+ relation,
6708
+ defaultValue,
6709
+ domain,
6710
+ formValues,
6711
+ name,
6712
+ id,
6713
+ model,
6714
+ onRefetch
6715
+ } = props;
6716
+ const specification = {
6717
+ id: 0,
6718
+ name: "",
6719
+ fold: ""
6720
+ };
6721
+ const [disabled, setDisabled] = useState11(false);
6722
+ const [modelStatus, setModalStatus] = useState11(false);
6723
+ const { context } = useAppSelector8(selectEnv3);
6724
+ const queryKey = [`data-status-duration`, specification];
6725
+ const listDataProps = {
6726
+ model: relation,
6727
+ specification,
6728
+ domain: evalJSONDomain5(domain, JSON.parse(JSON.stringify(formValues))),
6729
+ limit: 10,
6730
+ offset: 0,
6731
+ fields: "",
6732
+ groupby: [],
6733
+ context: {
6734
+ lang: context.lang
6735
+ },
6736
+ sort: ""
6737
+ };
6738
+ const { data: dataResponse } = useGetListData4(listDataProps, queryKey);
6739
+ const { mutate: fetchChangeStatus } = useChangeStatus();
6740
+ const handleClick = async (stage_id) => {
6741
+ setDisabled(true);
6742
+ if (stage_id) {
6743
+ fetchChangeStatus(
6744
+ {
6745
+ data: {
6746
+ stage_id,
6747
+ name,
6748
+ id,
6749
+ model,
6750
+ lang: context.lang
6751
+ }
6752
+ },
6753
+ {
6754
+ onSuccess: (res) => {
6755
+ if (res) {
6756
+ setDisabled(false);
6757
+ onRefetch && onRefetch();
6758
+ }
6759
+ }
6760
+ }
6761
+ );
6762
+ }
6763
+ };
6764
+ return {
6765
+ defaultValue,
6766
+ dataResponse,
6767
+ handleClick,
6768
+ disabled,
6769
+ modelStatus,
6770
+ setModalStatus
6771
+ };
6772
+ };
6773
+
6774
+ // src/widget/basic/priority-field/controller.ts
6775
+ import { evalJSONContext as evalJSONContext6, useSave as useSave2 } from "@fctc/interface-logic";
6776
+ var priorityFieldController = (props) => {
6777
+ const {
6778
+ value,
6779
+ isForm,
6780
+ name,
6781
+ methods,
6782
+ onChange,
6783
+ model,
6784
+ selection,
6785
+ id,
6786
+ actionData,
6787
+ viewData,
6788
+ context
6789
+ } = props;
6790
+ const _context = { ...evalJSONContext6(actionData?.context) };
6791
+ const contextObject = { ...context, ..._context };
6792
+ const defaultPriority = parseInt(value) + 1;
6793
+ const label = viewData?.models?.[model]?.[name ?? ""]?.string ?? name;
6794
+ const { mutateAsync: fetchSave } = useSave2();
6795
+ const savePriorities = async ({
6796
+ value: value2,
6797
+ resetPriority
6798
+ }) => {
6799
+ const priorityValue = value2 <= 0 ? 0 : value2 - 1;
6800
+ try {
6801
+ fetchSave({
6802
+ ids: id ? [id] : [],
6803
+ data: { [name ?? ""]: String(priorityValue) },
6804
+ model: model ?? "",
6805
+ context: contextObject
6806
+ });
6807
+ if (typeof onChange === "function") {
6808
+ onChange(name ?? "", String(priorityValue));
6809
+ }
6810
+ } catch (error) {
6811
+ if (resetPriority) {
6812
+ resetPriority();
6813
+ }
6814
+ }
6815
+ };
6816
+ return {
6817
+ selection,
6818
+ isForm,
6819
+ methods,
6820
+ defaultPriority,
6821
+ savePriorities,
6822
+ label,
6823
+ id,
6824
+ onChange
6825
+ };
6826
+ };
6827
+
6828
+ // src/widget/basic/float-time-field/controller.ts
6829
+ import { useState as useState12 } from "react";
6830
+ import { convertFloatToTime, convertTimeToFloat } from "@fctc/interface-logic";
6831
+ var floatTimeFiledController = ({
6832
+ onChange: fieldOnChange,
6833
+ onBlur,
6834
+ value,
6835
+ isDirty,
6836
+ props
6837
+ }) => {
6838
+ const { name, defaultValue = 0, onChange } = props;
6839
+ const [input, setInput] = useState12(
6840
+ convertFloatToTime(value ?? defaultValue)
6841
+ );
6842
+ const [formattedTime, setFormattedTime] = useState12("");
6843
+ const [errors, setErrors] = useState12("");
6844
+ const handleInputChange = (e) => {
6845
+ const raw = e.target.value.replace(/[^\d:]/g, "");
6846
+ setInput(raw);
6847
+ const timeRegex = /^(\d{1,2}):?(\d{0,2})$/;
6848
+ const match = raw.match(timeRegex);
6849
+ if (!match) {
6850
+ setErrors("\u0110\u1ECBnh d\u1EA1ng kh\xF4ng h\u1EE3p l\u1EC7");
6851
+ setFormattedTime("");
6852
+ return;
6853
+ }
6854
+ let hours = parseInt(match[1] ?? "0", 10);
6855
+ let minutes = parseInt(match[2] ?? "0", 10);
6856
+ if (isNaN(hours)) hours = 0;
6857
+ if (isNaN(minutes)) minutes = 0;
6858
+ if (hours >= 24) {
6859
+ hours = 0;
6860
+ }
6861
+ if (minutes >= 60) {
6862
+ minutes = 0;
6863
+ }
6864
+ const formatted = `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
6865
+ setErrors("");
6866
+ setFormattedTime(formatted);
6867
+ fieldOnChange(formatted);
6868
+ };
6869
+ const handleBlur = () => {
6870
+ if (!isDirty) return;
6871
+ if (formattedTime) {
6872
+ setInput(formattedTime);
6873
+ const floatVal = convertTimeToFloat(formattedTime);
6874
+ fieldOnChange(floatVal);
6875
+ if (onChange) {
6876
+ onChange(name ?? "", floatVal);
6877
+ }
6878
+ } else {
6879
+ setInput("00:00");
6880
+ fieldOnChange(0);
6881
+ if (onChange) {
6882
+ onChange(name ?? "", 0);
6883
+ }
6884
+ setErrors("");
6885
+ }
6886
+ onBlur();
6887
+ };
6888
+ const handleKeyDown = (e) => {
6889
+ {
6890
+ const allowed = [
6891
+ "Backspace",
6892
+ "Tab",
6893
+ "ArrowLeft",
6894
+ "ArrowRight",
6895
+ "Delete",
6896
+ "Home",
6897
+ "End",
6898
+ ":"
6899
+ ];
6900
+ const isNumber = /^[0-9]$/.test(e.key);
6901
+ if (!isNumber && !allowed.includes(e.key)) {
6902
+ e.preventDefault();
6903
+ }
6904
+ }
6905
+ };
6906
+ return {
6907
+ handleInputChange,
6908
+ handleBlur,
6909
+ handleKeyDown,
6910
+ input,
6911
+ errors
6912
+ };
6913
+ };
6914
+
6634
6915
  // src/widget/basic/float-field/controller.ts
6916
+ import { useEffect as useEffect15, useRef as useRef5, useState as useState13 } from "react";
6635
6917
  var floatController = ({
6636
6918
  onChange,
6637
6919
  value,
@@ -6639,10 +6921,10 @@ var floatController = ({
6639
6921
  }) => {
6640
6922
  const { name, required, methods, onChange: handleOnchange, string } = props;
6641
6923
  const { setError, clearErrors } = methods;
6642
- const [inputValue, setInputValue] = useState12(
6924
+ const [inputValue, setInputValue] = useState13(
6643
6925
  value !== void 0 && value !== null ? useFormatFloatNumber(value) : ""
6644
6926
  );
6645
- useEffect13(() => {
6927
+ useEffect15(() => {
6646
6928
  if (value !== void 0 && value !== null && value !== parseFloat(inputValue?.replace(/,/g, ""))) {
6647
6929
  setInputValue(useFormatFloatNumber(value));
6648
6930
  clearErrors(name);
@@ -6753,10 +7035,10 @@ var useFormatFloatNumber = (value) => {
6753
7035
  };
6754
7036
 
6755
7037
  // src/widget/basic/download-file-field/controller.ts
6756
- import { useId, useState as useState13 } from "react";
7038
+ import { useId, useState as useState14 } from "react";
6757
7039
  var downloadFileController = () => {
6758
7040
  const inputId = useId();
6759
- const [file, setFile] = useState13(null);
7041
+ const [file, setFile] = useState14(null);
6760
7042
  const handleFileChange = (e) => {
6761
7043
  setFile(e.target.files[0]);
6762
7044
  };
@@ -6920,11 +7202,11 @@ var dateFieldController = (props) => {
6920
7202
  };
6921
7203
 
6922
7204
  // src/widget/basic/copy-link-button/controller.ts
6923
- import { useState as useState14 } from "react";
7205
+ import { useState as useState15 } from "react";
6924
7206
  import { copyTextToClipboard } from "@fctc/interface-logic";
6925
7207
  var copyLinkButtonController = (props) => {
6926
7208
  const { value, defaultValue } = props;
6927
- const [isCopied, setIsCopied] = useState14(false);
7209
+ const [isCopied, setIsCopied] = useState15(false);
6928
7210
  const handleCopyToClipboard = async (value2) => {
6929
7211
  await copyTextToClipboard(value2);
6930
7212
  setIsCopied(true);
@@ -6939,412 +7221,132 @@ var copyLinkButtonController = (props) => {
6939
7221
  };
6940
7222
 
6941
7223
  // src/widget/basic/color-field/color-controller.ts
6942
- import { evalJSONContext as evalJSONContext7, getEnv as getEnv10, useSave as useSave3 } from "@fctc/interface-logic";
7224
+ import { evalJSONContext as evalJSONContext7, getEnv as getEnv11, useSave as useSave3 } from "@fctc/interface-logic";
6943
7225
  var colorFieldController = (props) => {
6944
7226
  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([]));
7227
+ const env = getEnv11();
7228
+ const _context = { ...evalJSONContext7(actionData?.context) || {} };
7229
+ const contextObject = { ...env.context, ..._context };
7230
+ const idDefault = isForm ? idForm : formValues?.id;
7231
+ const { mutate: onSave } = useSave3();
7232
+ const savePickColor = async (colorObject) => {
7233
+ const { id } = colorObject;
7234
+ if (value === id) return;
7235
+ try {
7236
+ onSave({
7237
+ ids: idDefault !== null ? [idDefault] : [],
7238
+ model: model ?? "",
7239
+ data: { [name ?? ""]: id },
7240
+ specification: {
7241
+ name: {},
7242
+ color: {}
7243
+ },
7244
+ context: contextObject
7245
+ });
7246
+ } catch (error) {
7247
+ console.log(error);
7173
7248
  }
7174
7249
  };
7175
7250
  return {
7176
- handleCheckBoxAll
7251
+ savePickColor
7177
7252
  };
7178
7253
  };
7179
7254
 
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);
7255
+ // src/widget/basic/binary-field/controller.ts
7256
+ import { useEffect as useEffect16, useId as useId2, useRef as useRef6, useState as useState16 } from "react";
7257
+ import { isBase64Image } from "@fctc/interface-logic";
7258
+ var binaryFieldController = (props) => {
7259
+ const { name, methods, readonly = false, value } = props;
7260
+ const inputId = useId2();
7261
+ const [selectedImage, setSelectedImage] = useState16(null);
7262
+ const [initialImage, setInitialImage] = useState16(value || null);
7263
+ const [isInsideTable, setIsInsideTable] = useState16(false);
7264
+ const { setValue } = methods;
7265
+ const binaryRef = useRef6(null);
7266
+ const convertUrlToBase64 = async (url) => {
7267
+ try {
7268
+ const response = await fetch(url);
7269
+ const blob = await response.blob();
7270
+ return new Promise((resolve, reject) => {
7271
+ const reader = new FileReader();
7272
+ reader.onloadend = () => {
7273
+ resolve(reader.result);
7274
+ };
7275
+ reader.onerror = reject;
7276
+ reader.readAsDataURL(blob);
7277
+ });
7278
+ } catch (error) {
7279
+ console.error("Error converting URL to Base64:", error);
7280
+ throw error;
7281
7281
  }
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;
7282
+ };
7283
+ const extractBase64Data = (base64Url) => {
7284
+ if (base64Url.includes("base64,")) {
7285
+ return base64Url.split("base64,")[1];
7295
7286
  }
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));
7287
+ return base64Url;
7288
+ };
7289
+ const handleImageChange = async (e, onChange) => {
7290
+ if (readonly) return;
7291
+ const file = e?.target?.files?.[0];
7292
+ if (file) {
7293
+ const imageUrl = URL.createObjectURL(file);
7294
+ setSelectedImage(imageUrl);
7295
+ setInitialImage(null);
7296
+ onChange(file);
7297
+ const compressedBase64 = await convertUrlToBase64(imageUrl);
7298
+ const base64Data = extractBase64Data(compressedBase64);
7299
+ setValue(name, base64Data, {
7300
+ shouldDirty: true
7301
+ });
7309
7302
  }
7310
- toggleShowGroup();
7303
+ };
7304
+ const handleRemoveImage = (onChange) => {
7305
+ setSelectedImage(null);
7306
+ setInitialImage(null);
7307
+ onChange(null);
7308
+ };
7309
+ const isBlobUrl = (url) => {
7310
+ return /^blob:/.test(url);
7311
+ };
7312
+ const checkIsImageLink = (url) => {
7313
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
7314
+ return imageExtensions.test(url) || isBase64Image(url) || isBlobUrl(url);
7315
+ };
7316
+ const getImageBase64WithMimeType = (base64) => {
7317
+ if (typeof base64 !== "string" || base64.length < 10) return null;
7318
+ if (isBase64Image(base64)) return base64;
7319
+ let mimeType = null;
7320
+ if (base64.startsWith("iVBORw0KGgo")) mimeType = "image/png";
7321
+ else if (base64.startsWith("/9j/")) mimeType = "image/jpeg";
7322
+ else if (base64.startsWith("R0lGOD")) mimeType = "image/gif";
7323
+ else if (base64.startsWith("Qk")) mimeType = "image/bmp";
7324
+ else if (base64.startsWith("UklGR")) mimeType = "image/webp";
7325
+ return mimeType ? `data:${mimeType};base64,${base64}` : null;
7311
7326
  };
7312
7327
  useEffect16(() => {
7313
- if (!isQueryFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
7314
- return;
7328
+ return () => {
7329
+ if (selectedImage) {
7330
+ URL.revokeObjectURL(selectedImage);
7331
+ }
7332
+ };
7333
+ }, [selectedImage]);
7334
+ useEffect16(() => {
7335
+ if (binaryRef.current) {
7336
+ const isInsideTable2 = !!binaryRef.current.closest("table");
7337
+ setIsInsideTable(isInsideTable2);
7315
7338
  }
7316
- const clonedKeys = [...selectedRowKeys];
7317
- setSelectedRowKeys3([...clonedKeys, -1]);
7318
- setTimeout(() => setSelectedRowKeys3(clonedKeys), 500);
7319
- }, [isQueryFetched]);
7339
+ }, []);
7320
7340
  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
7341
+ inputId,
7342
+ selectedImage,
7343
+ initialImage,
7344
+ isInsideTable,
7345
+ binaryRef,
7346
+ handleImageChange,
7347
+ handleRemoveImage,
7348
+ checkIsImageLink,
7349
+ getImageBase64WithMimeType
7348
7350
  };
7349
7351
  };
7350
7352
  export {