@fctc/widget-logic 5.2.7 → 5.2.9

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/hooks.js CHANGED
@@ -745,11 +745,14 @@ var useGetSpecification = ({
745
745
  viewData,
746
746
  fields
747
747
  }) => {
748
- const baseModel = {
749
- name: String(model),
750
- view: viewData,
751
- fields
752
- };
748
+ const baseModel = (0, import_react10.useMemo)(
749
+ () => ({
750
+ name: String(model),
751
+ view: viewData,
752
+ fields
753
+ }),
754
+ [model, viewData, fields]
755
+ );
753
756
  const initModel = (0, import_hooks2.useModel)();
754
757
  const modelInstance = (0, import_react10.useMemo)(() => {
755
758
  if (viewData) {
package/dist/hooks.mjs CHANGED
@@ -726,11 +726,14 @@ var useGetSpecification = ({
726
726
  viewData,
727
727
  fields
728
728
  }) => {
729
- const baseModel = {
730
- name: String(model),
731
- view: viewData,
732
- fields
733
- };
729
+ const baseModel = useMemo5(
730
+ () => ({
731
+ name: String(model),
732
+ view: viewData,
733
+ fields
734
+ }),
735
+ [model, viewData, fields]
736
+ );
734
737
  const initModel = useModel();
735
738
  const modelInstance = useMemo5(() => {
736
739
  if (viewData) {
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ export { useAddEntity, useButton, useChangeOrderPreparationState, useChangeStatu
2
2
  export { ActionResultType, AppProvider, CompanyTuple, ContextProfile, CurrentCompany, RecordMenu, UseMenuReturn, ViewResponse, useAppProvider, useCallAction, useCallActionType, useClickOutside, useCompany, useCompanyType, useConfig, useConfigType, useDebounce, useDetail, useGetAction, useGetRowIds, useGetSpecification, useListData, useListDataType, useMenu, useMenuType, useProfile, useUser, useUserType, useViewV2, useViewV2Type } from './hooks.mjs';
3
3
  export * from '@fctc/interface-logic/configs';
4
4
  export { CheckIcon, ChevronBottomIcon, CloseIcon, EyeIcon, FilterIcon, GroupByIcon, LoadingIcon, SearchIcon } from './icons.mjs';
5
- export { ISelctionStateProps, ITableHeadProps, ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController } from './widget.mjs';
5
+ export { ISelctionStateProps, ITableHeadProps, ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyBinaryController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController } from './widget.mjs';
6
6
  export * from '@fctc/interface-logic/types';
7
7
  export { IInputFieldProps, ValuePropsType } from './types.mjs';
8
8
  export { STORAGES, combineContexts, convertFieldsToArray, countSum, getDateRange, languages, mergeButtons, setStorageItemAsync, useStorageState } from './utils.mjs';
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { useAddEntity, useButton, useChangeOrderPreparationState, useChangeStatu
2
2
  export { ActionResultType, AppProvider, CompanyTuple, ContextProfile, CurrentCompany, RecordMenu, UseMenuReturn, ViewResponse, useAppProvider, useCallAction, useCallActionType, useClickOutside, useCompany, useCompanyType, useConfig, useConfigType, useDebounce, useDetail, useGetAction, useGetRowIds, useGetSpecification, useListData, useListDataType, useMenu, useMenuType, useProfile, useUser, useUserType, useViewV2, useViewV2Type } from './hooks.js';
3
3
  export * from '@fctc/interface-logic/configs';
4
4
  export { CheckIcon, ChevronBottomIcon, CloseIcon, EyeIcon, FilterIcon, GroupByIcon, LoadingIcon, SearchIcon } from './icons.js';
5
- export { ISelctionStateProps, ITableHeadProps, ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController } from './widget.js';
5
+ export { ISelctionStateProps, ITableHeadProps, ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyBinaryController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController } from './widget.js';
6
6
  export * from '@fctc/interface-logic/types';
7
7
  export { IInputFieldProps, ValuePropsType } from './types.js';
8
8
  export { STORAGES, combineContexts, convertFieldsToArray, countSum, getDateRange, languages, mergeButtons, setStorageItemAsync, useStorageState } from './utils.js';
package/dist/index.js CHANGED
@@ -4057,6 +4057,7 @@ __export(index_exports, {
4057
4057
  durationController: () => durationController,
4058
4058
  getDateRange: () => getDateRange,
4059
4059
  languages: () => languages,
4060
+ many2manyBinaryController: () => many2manyBinaryController,
4060
4061
  many2manyFieldController: () => many2manyFieldController,
4061
4062
  many2manyTagsController: () => many2manyTagsController,
4062
4063
  many2oneButtonController: () => many2oneButtonController,
@@ -4257,6 +4258,7 @@ var languages = [
4257
4258
  { id: "vi_VN", name: "VIE" },
4258
4259
  { id: "en_US", name: "ENG" }
4259
4260
  ];
4261
+ var isBlobUrl = (url) => url.startsWith("blob:");
4260
4262
 
4261
4263
  // src/utils/function.ts
4262
4264
  var import_react2 = require("react");
@@ -4817,11 +4819,14 @@ var useGetSpecification = ({
4817
4819
  viewData,
4818
4820
  fields
4819
4821
  }) => {
4820
- const baseModel = {
4821
- name: String(model),
4822
- view: viewData,
4823
- fields
4824
- };
4822
+ const baseModel = (0, import_react10.useMemo)(
4823
+ () => ({
4824
+ name: String(model),
4825
+ view: viewData,
4826
+ fields
4827
+ }),
4828
+ [model, viewData, fields]
4829
+ );
4825
4830
  const initModel = (0, import_hooks2.useModel)();
4826
4831
  const modelInstance = (0, import_react10.useMemo)(() => {
4827
4832
  if (viewData) {
@@ -6339,8 +6344,82 @@ var binaryFieldController = (props) => {
6339
6344
  };
6340
6345
  };
6341
6346
 
6342
- // src/widget/advance/table/table-head/controller.ts
6347
+ // src/widget/basic/many2many-binary-field/controller.tsx
6343
6348
  var import_react23 = require("react");
6349
+ var many2manyBinaryController = (props) => {
6350
+ const {
6351
+ name,
6352
+ methods,
6353
+ value,
6354
+ onChange: handleOnchange,
6355
+ service,
6356
+ xNode,
6357
+ path
6358
+ } = props;
6359
+ const inputId = (0, import_react23.useId)();
6360
+ const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
6361
+ const { mutateAsync } = useUploadFile2();
6362
+ const binaryRef = (0, import_react23.useRef)(null);
6363
+ const [initialFiles, setInitialFiles] = (0, import_react23.useState)(
6364
+ Array.isArray(value) ? value : value ? [value] : []
6365
+ );
6366
+ const checkIsImageLink = (url) => {
6367
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
6368
+ return imageExtensions.test(url) || (0, utils_exports.isBase64Image)(url) || isBlobUrl(url);
6369
+ };
6370
+ const sanitizeForBE = (list) => list.filter((x) => x?.datas && !isBlobUrl(x.datas)).map((x) => ({ name: x.name, datas: x.datas, mimetype: x.mimetype }));
6371
+ const handleFileChange = async (files, e, oldValues) => {
6372
+ try {
6373
+ const uploadedUrls = await Promise.all(
6374
+ files.map(async (f) => {
6375
+ const formData = new FormData();
6376
+ formData.append("file", f);
6377
+ const res = await mutateAsync({ formData, service, xNode, path });
6378
+ return res?.url;
6379
+ })
6380
+ );
6381
+ const uploadedItems = files.map((f, i) => ({
6382
+ name: f.name,
6383
+ datas: uploadedUrls[i] ?? "",
6384
+ mimetype: f.type
6385
+ }));
6386
+ const finalList = [...oldValues, ...uploadedItems];
6387
+ methods?.setValue(name, finalList, { shouldDirty: true });
6388
+ const payloadForBE = sanitizeForBE(finalList);
6389
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
6390
+ } catch (err) {
6391
+ console.error(err);
6392
+ } finally {
6393
+ e.target.value = "";
6394
+ }
6395
+ };
6396
+ const handleRemoveAt = (idx) => {
6397
+ const current = methods?.getValues(name) || [];
6398
+ const next = current.filter((_, i) => i !== idx);
6399
+ setInitialFiles((p) => p.filter((_, i) => i !== idx));
6400
+ methods?.setValue(name, next.length ? next : null, { shouldDirty: true });
6401
+ const payloadForBE = next.length ? sanitizeForBE(next) : null;
6402
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
6403
+ };
6404
+ const handleRemoveAll = () => {
6405
+ setInitialFiles([]);
6406
+ methods?.setValue(name, null, { shouldDirty: true });
6407
+ handleOnchange && handleOnchange(name ?? "", null);
6408
+ };
6409
+ return {
6410
+ inputId,
6411
+ initialFiles,
6412
+ binaryRef,
6413
+ handleFileChange,
6414
+ handleRemoveAt,
6415
+ handleRemoveAll,
6416
+ checkIsImageLink,
6417
+ setInitialFiles
6418
+ };
6419
+ };
6420
+
6421
+ // src/widget/advance/table/table-head/controller.ts
6422
+ var import_react24 = require("react");
6344
6423
  var tableHeadController = (props) => {
6345
6424
  const {
6346
6425
  typeTable,
@@ -6351,21 +6430,21 @@ var tableHeadController = (props) => {
6351
6430
  setSelectedRowKeys
6352
6431
  } = props;
6353
6432
  const { rowIds: recordIds } = useGetRowIds(tableRef);
6354
- const selectedRowKeysRef = (0, import_react23.useRef)(recordIds);
6433
+ const selectedRowKeysRef = (0, import_react24.useRef)(recordIds);
6355
6434
  const isGroupTable = typeTable === "group";
6356
- const recordsCheckedGroup = (0, import_react23.useMemo)(() => {
6435
+ const recordsCheckedGroup = (0, import_react24.useMemo)(() => {
6357
6436
  if (!rows || !groupByList) return 0;
6358
6437
  const groupBy = typeof groupByList === "object" ? groupByList?.contexts?.[0]?.group_by : void 0;
6359
6438
  return countSum(rows, groupBy);
6360
6439
  }, [rows, groupByList]);
6361
- const isAllGroupChecked = (0, import_react23.useMemo)(() => {
6440
+ const isAllGroupChecked = (0, import_react24.useMemo)(() => {
6362
6441
  if (!isGroupTable || !selectedRowKeys?.length) return false;
6363
6442
  const selectedLength = selectedRowKeys.filter((id) => id !== -1).length;
6364
6443
  const allRecordsSelected = recordIds.length === selectedRowKeys.length ? recordIds.length === selectedLength : false;
6365
6444
  const allGroupsSelected = recordsCheckedGroup === selectedRowKeys.length;
6366
6445
  return allGroupsSelected || allRecordsSelected;
6367
6446
  }, [isGroupTable, selectedRowKeys, recordIds, recordsCheckedGroup]);
6368
- const isAllNormalChecked = (0, import_react23.useMemo)(() => {
6447
+ const isAllNormalChecked = (0, import_react24.useMemo)(() => {
6369
6448
  if (isGroupTable || !selectedRowKeys?.length || !rows?.length) return false;
6370
6449
  return selectedRowKeys.length === rows.length && selectedRowKeys.every(
6371
6450
  (id) => rows.some((record) => record.id === id)
@@ -6406,23 +6485,23 @@ var tableHeadController = (props) => {
6406
6485
  };
6407
6486
 
6408
6487
  // src/widget/advance/table/table-view/controller.ts
6409
- var import_react24 = require("react");
6410
- var import_utils17 = require("@fctc/interface-logic/utils");
6488
+ var import_react25 = require("react");
6489
+ var import_utils18 = require("@fctc/interface-logic/utils");
6411
6490
  var tableController = ({ data }) => {
6412
- const [rows, setRows] = (0, import_react24.useState)([]);
6413
- const [columnVisibility, setColumnVisibility] = (0, import_react24.useState)({});
6414
- const dataModelFields = (0, import_react24.useMemo)(() => {
6491
+ const [rows, setRows] = (0, import_react25.useState)([]);
6492
+ const [columnVisibility, setColumnVisibility] = (0, import_react25.useState)({});
6493
+ const dataModelFields = (0, import_react25.useMemo)(() => {
6415
6494
  return data?.fields?.map((field) => ({
6416
6495
  ...data.dataModel?.[field?.name],
6417
6496
  ...field,
6418
6497
  string: field?.string || data.dataModel?.[field?.name]?.string
6419
6498
  })) ?? [];
6420
6499
  }, [data?.fields, data?.dataModel]);
6421
- const mergeFields = (0, import_react24.useMemo)(
6500
+ const mergeFields = (0, import_react25.useMemo)(
6422
6501
  () => mergeButtons(dataModelFields),
6423
6502
  [dataModelFields]
6424
6503
  );
6425
- const transformData = (0, import_react24.useCallback)(
6504
+ const transformData = (0, import_react25.useCallback)(
6426
6505
  (dataList) => {
6427
6506
  if (!dataList) return [];
6428
6507
  return dataList.map((item) => {
@@ -6444,16 +6523,16 @@ var tableController = ({ data }) => {
6444
6523
  },
6445
6524
  [data?.typeTable]
6446
6525
  );
6447
- (0, import_react24.useEffect)(() => {
6526
+ (0, import_react25.useEffect)(() => {
6448
6527
  setRows(transformData(data?.records));
6449
6528
  }, [data?.records, transformData]);
6450
- const columns = (0, import_react24.useMemo)(() => {
6529
+ const columns = (0, import_react25.useMemo)(() => {
6451
6530
  try {
6452
6531
  return mergeFields?.filter((item) => {
6453
- return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? import_utils17.domainHelper.matchDomains(
6532
+ return item?.widget !== "details_Receive_money" && !(item?.column_invisible ? import_utils18.domainHelper.matchDomains(
6454
6533
  data.context,
6455
6534
  item?.column_invisible
6456
- ) : item?.invisible ? import_utils17.domainHelper.matchDomains(data.context, item?.invisible) : false);
6535
+ ) : item?.invisible ? import_utils18.domainHelper.matchDomains(data.context, item?.invisible) : false);
6457
6536
  })?.map((field) => {
6458
6537
  const overridden = columnVisibility[field?.name];
6459
6538
  return {
@@ -6468,7 +6547,7 @@ var tableController = ({ data }) => {
6468
6547
  return [];
6469
6548
  }
6470
6549
  }, [mergeFields, data?.context, columnVisibility]);
6471
- const onToggleColumnOptional = (0, import_react24.useCallback)((item) => {
6550
+ const onToggleColumnOptional = (0, import_react25.useCallback)((item) => {
6472
6551
  setColumnVisibility((prev) => ({
6473
6552
  ...prev,
6474
6553
  [item?.name]: item?.optional === "show" ? "hide" : "show"
@@ -6483,7 +6562,7 @@ var tableController = ({ data }) => {
6483
6562
  };
6484
6563
 
6485
6564
  // src/widget/advance/table/table-group/controller.ts
6486
- var import_react25 = require("react");
6565
+ var import_react26 = require("react");
6487
6566
  var import_store = require("@fctc/interface-logic/store");
6488
6567
  var tableGroupController = (props) => {
6489
6568
  const { env } = (0, provider_exports.useEnv)();
@@ -6500,15 +6579,15 @@ var tableGroupController = (props) => {
6500
6579
  groupByList,
6501
6580
  setSelectedRowKeys
6502
6581
  } = props;
6503
- const [pageGroup, setPageGroup] = (0, import_react25.useState)(0);
6582
+ const [pageGroup, setPageGroup] = (0, import_react26.useState)(0);
6504
6583
  const { selectedRowKeys } = (0, import_store.useAppSelector)(import_store.selectList);
6505
- const [isShowGroup, setIsShowGroup] = (0, import_react25.useState)(false);
6506
- const [colEmptyGroup, setColEmptyGroup] = (0, import_react25.useState)({
6584
+ const [isShowGroup, setIsShowGroup] = (0, import_react26.useState)(false);
6585
+ const [colEmptyGroup, setColEmptyGroup] = (0, import_react26.useState)({
6507
6586
  fromStart: 1,
6508
6587
  fromEnd: 1
6509
6588
  });
6510
6589
  const domain = row?.__domain;
6511
- const processedData = (0, import_react25.useMemo)(() => {
6590
+ const processedData = (0, import_react26.useMemo)(() => {
6512
6591
  const calculateColSpanEmpty = () => {
6513
6592
  const startIndex = columns.findIndex(
6514
6593
  (col) => col.field.type === "monetary" && typeof row[col.key] === "number" || col.field.aggregator === "sum"
@@ -6523,7 +6602,7 @@ var tableGroupController = (props) => {
6523
6602
  };
6524
6603
  return calculateColSpanEmpty();
6525
6604
  }, [columns, row]);
6526
- const shouldFetchData = (0, import_react25.useMemo)(() => {
6605
+ const shouldFetchData = (0, import_react26.useMemo)(() => {
6527
6606
  return !!isShowGroup;
6528
6607
  }, [isShowGroup]);
6529
6608
  const enabled = shouldFetchData && !!processedData;
@@ -6592,7 +6671,7 @@ var tableGroupController = (props) => {
6592
6671
  }
6593
6672
  toggleShowGroup();
6594
6673
  };
6595
- (0, import_react25.useEffect)(() => {
6674
+ (0, import_react26.useEffect)(() => {
6596
6675
  if (!isDataGroupFetched || !rowsGroup || !checkedAll || allIdsNull || typeTableGroup === "group") {
6597
6676
  return;
6598
6677
  }
@@ -6618,7 +6697,7 @@ var tableGroupController = (props) => {
6618
6697
 
6619
6698
  // src/widget/advance/search/controller.ts
6620
6699
  var import_moment2 = __toESM(require_moment());
6621
- var import_react26 = require("react");
6700
+ var import_react27 = require("react");
6622
6701
 
6623
6702
  // src/constants.ts
6624
6703
  var constants_exports = {};
@@ -6633,14 +6712,14 @@ var searchController = ({
6633
6712
  fieldsList
6634
6713
  }) => {
6635
6714
  const { env } = (0, provider_exports.useEnv)();
6636
- const [filterBy, setFilterBy] = (0, import_react26.useState)(null);
6637
- const [searchBy, setSearchBy] = (0, import_react26.useState)(null);
6638
- const [groupBy, setGroupBy] = (0, import_react26.useState)(null);
6639
- const [selectedTags, setSelectedTags] = (0, import_react26.useState)(null);
6640
- const [searchString, setSearchString] = (0, import_react26.useState)("");
6641
- const [searchMap, setSearchMap] = (0, import_react26.useState)({});
6642
- const [hoveredIndex, setHoveredIndex] = (0, import_react26.useState)(0);
6643
- const [hoveredIndexSearchList, setHoveredIndexSearchList] = (0, import_react26.useState)(0);
6715
+ const [filterBy, setFilterBy] = (0, import_react27.useState)(null);
6716
+ const [searchBy, setSearchBy] = (0, import_react27.useState)(null);
6717
+ const [groupBy, setGroupBy] = (0, import_react27.useState)(null);
6718
+ const [selectedTags, setSelectedTags] = (0, import_react27.useState)(null);
6719
+ const [searchString, setSearchString] = (0, import_react27.useState)("");
6720
+ const [searchMap, setSearchMap] = (0, import_react27.useState)({});
6721
+ const [hoveredIndex, setHoveredIndex] = (0, import_react27.useState)(0);
6722
+ const [hoveredIndexSearchList, setHoveredIndexSearchList] = (0, import_react27.useState)(0);
6644
6723
  const actionContext = typeof context === "string" ? (0, utils_exports.evalJSONContext)(context) : context;
6645
6724
  const contextSearch = { ...env.context, ...actionContext };
6646
6725
  const domainAction = domain ? Array.isArray(domain) ? [...domain] : (0, utils_exports.evalJSONDomain)(domain, contextSearch) : [];
@@ -6687,7 +6766,7 @@ var searchController = ({
6687
6766
  }
6688
6767
  }
6689
6768
  };
6690
- (0, import_react26.useEffect)(() => {
6769
+ (0, import_react27.useEffect)(() => {
6691
6770
  fetchData();
6692
6771
  }, [model, viewData]);
6693
6772
  const onChangeSearchInput = (search_string) => {
@@ -6769,7 +6848,7 @@ var searchController = ({
6769
6848
  return [...domain2];
6770
6849
  }
6771
6850
  };
6772
- const setTagSearch = (0, import_react26.useCallback)(
6851
+ const setTagSearch = (0, import_react27.useCallback)(
6773
6852
  (updatedMap) => {
6774
6853
  if (!updatedMap) return;
6775
6854
  const tagsSearch = Object.entries(updatedMap).map(
@@ -6832,7 +6911,7 @@ var searchController = ({
6832
6911
  },
6833
6912
  [searchMap]
6834
6913
  );
6835
- (0, import_react26.useEffect)(() => {
6914
+ (0, import_react27.useEffect)(() => {
6836
6915
  setTagSearch(searchMap);
6837
6916
  }, [searchMap]);
6838
6917
  const handleAddTagSearch = (tag) => {
@@ -6999,6 +7078,7 @@ __reExport(index_exports, types_exports, module.exports);
6999
7078
  durationController,
7000
7079
  getDateRange,
7001
7080
  languages,
7081
+ many2manyBinaryController,
7002
7082
  many2manyFieldController,
7003
7083
  many2manyTagsController,
7004
7084
  many2oneButtonController,
package/dist/index.mjs CHANGED
@@ -4061,6 +4061,7 @@ __export(index_exports, {
4061
4061
  durationController: () => durationController,
4062
4062
  getDateRange: () => getDateRange,
4063
4063
  languages: () => languages,
4064
+ many2manyBinaryController: () => many2manyBinaryController,
4064
4065
  many2manyFieldController: () => many2manyFieldController,
4065
4066
  many2manyTagsController: () => many2manyTagsController,
4066
4067
  many2oneButtonController: () => many2oneButtonController,
@@ -4346,6 +4347,7 @@ var languages = [
4346
4347
  { id: "vi_VN", name: "VIE" },
4347
4348
  { id: "en_US", name: "ENG" }
4348
4349
  ];
4350
+ var isBlobUrl = (url) => url.startsWith("blob:");
4349
4351
 
4350
4352
  // src/utils/function.ts
4351
4353
  import { useCallback as useCallback2, useEffect, useReducer } from "react";
@@ -4907,11 +4909,14 @@ var useGetSpecification = ({
4907
4909
  viewData,
4908
4910
  fields
4909
4911
  }) => {
4910
- const baseModel = {
4911
- name: String(model),
4912
- view: viewData,
4913
- fields
4914
- };
4912
+ const baseModel = useMemo5(
4913
+ () => ({
4914
+ name: String(model),
4915
+ view: viewData,
4916
+ fields
4917
+ }),
4918
+ [model, viewData, fields]
4919
+ );
4915
4920
  const initModel = useModel();
4916
4921
  const modelInstance = useMemo5(() => {
4917
4922
  if (viewData) {
@@ -6434,8 +6439,82 @@ var binaryFieldController = (props) => {
6434
6439
  };
6435
6440
  };
6436
6441
 
6442
+ // src/widget/basic/many2many-binary-field/controller.tsx
6443
+ import { useId as useId2, useRef as useRef4, useState as useState13 } from "react";
6444
+ var many2manyBinaryController = (props) => {
6445
+ const {
6446
+ name,
6447
+ methods,
6448
+ value,
6449
+ onChange: handleOnchange,
6450
+ service,
6451
+ xNode,
6452
+ path
6453
+ } = props;
6454
+ const inputId = useId2();
6455
+ const { useUploadFile: useUploadFile2 } = (0, provider_exports.useService)();
6456
+ const { mutateAsync } = useUploadFile2();
6457
+ const binaryRef = useRef4(null);
6458
+ const [initialFiles, setInitialFiles] = useState13(
6459
+ Array.isArray(value) ? value : value ? [value] : []
6460
+ );
6461
+ const checkIsImageLink = (url) => {
6462
+ const imageExtensions = /\.(jpg|jpeg|png|gif|bmp|webp|svg|tiff|ico)$/i;
6463
+ return imageExtensions.test(url) || (0, utils_exports.isBase64Image)(url) || isBlobUrl(url);
6464
+ };
6465
+ const sanitizeForBE = (list) => list.filter((x) => x?.datas && !isBlobUrl(x.datas)).map((x) => ({ name: x.name, datas: x.datas, mimetype: x.mimetype }));
6466
+ const handleFileChange = async (files, e, oldValues) => {
6467
+ try {
6468
+ const uploadedUrls = await Promise.all(
6469
+ files.map(async (f) => {
6470
+ const formData = new FormData();
6471
+ formData.append("file", f);
6472
+ const res = await mutateAsync({ formData, service, xNode, path });
6473
+ return res?.url;
6474
+ })
6475
+ );
6476
+ const uploadedItems = files.map((f, i) => ({
6477
+ name: f.name,
6478
+ datas: uploadedUrls[i] ?? "",
6479
+ mimetype: f.type
6480
+ }));
6481
+ const finalList = [...oldValues, ...uploadedItems];
6482
+ methods?.setValue(name, finalList, { shouldDirty: true });
6483
+ const payloadForBE = sanitizeForBE(finalList);
6484
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
6485
+ } catch (err) {
6486
+ console.error(err);
6487
+ } finally {
6488
+ e.target.value = "";
6489
+ }
6490
+ };
6491
+ const handleRemoveAt = (idx) => {
6492
+ const current = methods?.getValues(name) || [];
6493
+ const next = current.filter((_, i) => i !== idx);
6494
+ setInitialFiles((p) => p.filter((_, i) => i !== idx));
6495
+ methods?.setValue(name, next.length ? next : null, { shouldDirty: true });
6496
+ const payloadForBE = next.length ? sanitizeForBE(next) : null;
6497
+ handleOnchange && handleOnchange(name ?? "", payloadForBE);
6498
+ };
6499
+ const handleRemoveAll = () => {
6500
+ setInitialFiles([]);
6501
+ methods?.setValue(name, null, { shouldDirty: true });
6502
+ handleOnchange && handleOnchange(name ?? "", null);
6503
+ };
6504
+ return {
6505
+ inputId,
6506
+ initialFiles,
6507
+ binaryRef,
6508
+ handleFileChange,
6509
+ handleRemoveAt,
6510
+ handleRemoveAll,
6511
+ checkIsImageLink,
6512
+ setInitialFiles
6513
+ };
6514
+ };
6515
+
6437
6516
  // src/widget/advance/table/table-head/controller.ts
6438
- import { useMemo as useMemo10, useRef as useRef4 } from "react";
6517
+ import { useMemo as useMemo10, useRef as useRef5 } from "react";
6439
6518
  var tableHeadController = (props) => {
6440
6519
  const {
6441
6520
  typeTable,
@@ -6446,7 +6525,7 @@ var tableHeadController = (props) => {
6446
6525
  setSelectedRowKeys
6447
6526
  } = props;
6448
6527
  const { rowIds: recordIds } = useGetRowIds(tableRef);
6449
- const selectedRowKeysRef = useRef4(recordIds);
6528
+ const selectedRowKeysRef = useRef5(recordIds);
6450
6529
  const isGroupTable = typeTable === "group";
6451
6530
  const recordsCheckedGroup = useMemo10(() => {
6452
6531
  if (!rows || !groupByList) return 0;
@@ -6501,11 +6580,11 @@ var tableHeadController = (props) => {
6501
6580
  };
6502
6581
 
6503
6582
  // src/widget/advance/table/table-view/controller.ts
6504
- import { useCallback as useCallback6, useEffect as useEffect14, useMemo as useMemo11, useState as useState13 } from "react";
6583
+ import { useCallback as useCallback6, useEffect as useEffect14, useMemo as useMemo11, useState as useState14 } from "react";
6505
6584
  import { domainHelper } from "@fctc/interface-logic/utils";
6506
6585
  var tableController = ({ data }) => {
6507
- const [rows, setRows] = useState13([]);
6508
- const [columnVisibility, setColumnVisibility] = useState13({});
6586
+ const [rows, setRows] = useState14([]);
6587
+ const [columnVisibility, setColumnVisibility] = useState14({});
6509
6588
  const dataModelFields = useMemo11(() => {
6510
6589
  return data?.fields?.map((field) => ({
6511
6590
  ...data.dataModel?.[field?.name],
@@ -6578,7 +6657,7 @@ var tableController = ({ data }) => {
6578
6657
  };
6579
6658
 
6580
6659
  // src/widget/advance/table/table-group/controller.ts
6581
- import { useEffect as useEffect15, useMemo as useMemo12, useState as useState14 } from "react";
6660
+ import { useEffect as useEffect15, useMemo as useMemo12, useState as useState15 } from "react";
6582
6661
  import { useAppSelector, selectList } from "@fctc/interface-logic/store";
6583
6662
  var tableGroupController = (props) => {
6584
6663
  const { env } = (0, provider_exports.useEnv)();
@@ -6595,10 +6674,10 @@ var tableGroupController = (props) => {
6595
6674
  groupByList,
6596
6675
  setSelectedRowKeys
6597
6676
  } = props;
6598
- const [pageGroup, setPageGroup] = useState14(0);
6677
+ const [pageGroup, setPageGroup] = useState15(0);
6599
6678
  const { selectedRowKeys } = useAppSelector(selectList);
6600
- const [isShowGroup, setIsShowGroup] = useState14(false);
6601
- const [colEmptyGroup, setColEmptyGroup] = useState14({
6679
+ const [isShowGroup, setIsShowGroup] = useState15(false);
6680
+ const [colEmptyGroup, setColEmptyGroup] = useState15({
6602
6681
  fromStart: 1,
6603
6682
  fromEnd: 1
6604
6683
  });
@@ -6713,7 +6792,7 @@ var tableGroupController = (props) => {
6713
6792
 
6714
6793
  // src/widget/advance/search/controller.ts
6715
6794
  var import_moment2 = __toESM(require_moment());
6716
- import { useCallback as useCallback7, useEffect as useEffect16, useState as useState15 } from "react";
6795
+ import { useCallback as useCallback7, useEffect as useEffect16, useState as useState16 } from "react";
6717
6796
 
6718
6797
  // src/constants.ts
6719
6798
  var constants_exports = {};
@@ -6729,14 +6808,14 @@ var searchController = ({
6729
6808
  fieldsList
6730
6809
  }) => {
6731
6810
  const { env } = (0, provider_exports.useEnv)();
6732
- const [filterBy, setFilterBy] = useState15(null);
6733
- const [searchBy, setSearchBy] = useState15(null);
6734
- const [groupBy, setGroupBy] = useState15(null);
6735
- const [selectedTags, setSelectedTags] = useState15(null);
6736
- const [searchString, setSearchString] = useState15("");
6737
- const [searchMap, setSearchMap] = useState15({});
6738
- const [hoveredIndex, setHoveredIndex] = useState15(0);
6739
- const [hoveredIndexSearchList, setHoveredIndexSearchList] = useState15(0);
6811
+ const [filterBy, setFilterBy] = useState16(null);
6812
+ const [searchBy, setSearchBy] = useState16(null);
6813
+ const [groupBy, setGroupBy] = useState16(null);
6814
+ const [selectedTags, setSelectedTags] = useState16(null);
6815
+ const [searchString, setSearchString] = useState16("");
6816
+ const [searchMap, setSearchMap] = useState16({});
6817
+ const [hoveredIndex, setHoveredIndex] = useState16(0);
6818
+ const [hoveredIndexSearchList, setHoveredIndexSearchList] = useState16(0);
6740
6819
  const actionContext = typeof context === "string" ? (0, utils_exports.evalJSONContext)(context) : context;
6741
6820
  const contextSearch = { ...env.context, ...actionContext };
6742
6821
  const domainAction = domain ? Array.isArray(domain) ? [...domain] : (0, utils_exports.evalJSONDomain)(domain, contextSearch) : [];
@@ -7098,6 +7177,7 @@ export {
7098
7177
  durationController,
7099
7178
  getDateRange,
7100
7179
  languages,
7180
+ many2manyBinaryController,
7101
7181
  many2manyFieldController,
7102
7182
  many2manyTagsController,
7103
7183
  many2oneButtonController,
package/dist/widget.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react from 'react';
2
+ import { ChangeEvent } from 'react';
2
3
  import { IInputFieldProps } from './types.mjs';
3
4
  import moment from 'moment';
4
5
  import '@fctc/interface-logic/types';
@@ -232,6 +233,26 @@ declare const binaryFieldController: (props: IBinaryFieldProps) => {
232
233
  url: any;
233
234
  };
234
235
 
236
+ type UploadDeps = {
237
+ service?: any;
238
+ xNode?: any;
239
+ path?: any;
240
+ };
241
+
242
+ declare const many2manyBinaryController: (props: IInputFieldProps & UploadDeps & {
243
+ rootField?: any;
244
+ index?: number;
245
+ }) => {
246
+ inputId: string;
247
+ initialFiles: any[];
248
+ binaryRef: react.RefObject<HTMLDivElement>;
249
+ handleFileChange: (files: any, e: ChangeEvent<HTMLInputElement>, oldValues: any) => Promise<void>;
250
+ handleRemoveAt: (idx: number) => void;
251
+ handleRemoveAll: () => void;
252
+ checkIsImageLink: (url: string) => boolean;
253
+ setInitialFiles: react.Dispatch<react.SetStateAction<any[]>>;
254
+ };
255
+
235
256
  declare const tableHeadController: (props: any) => {
236
257
  handleCheckBoxAll: (event: React.ChangeEvent<HTMLInputElement>) => void;
237
258
  checkedAll: any;
@@ -319,4 +340,4 @@ declare const searchController: ({ viewData, model, domain, context, fieldsList,
319
340
  hoveredIndexSearchList: number | null;
320
341
  };
321
342
 
322
- export { type ISelctionStateProps, type ITableHeadProps, type ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController };
343
+ export { type ISelctionStateProps, type ITableHeadProps, type ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyBinaryController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController };
package/dist/widget.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as react from 'react';
2
+ import { ChangeEvent } from 'react';
2
3
  import { IInputFieldProps } from './types.js';
3
4
  import moment from 'moment';
4
5
  import '@fctc/interface-logic/types';
@@ -232,6 +233,26 @@ declare const binaryFieldController: (props: IBinaryFieldProps) => {
232
233
  url: any;
233
234
  };
234
235
 
236
+ type UploadDeps = {
237
+ service?: any;
238
+ xNode?: any;
239
+ path?: any;
240
+ };
241
+
242
+ declare const many2manyBinaryController: (props: IInputFieldProps & UploadDeps & {
243
+ rootField?: any;
244
+ index?: number;
245
+ }) => {
246
+ inputId: string;
247
+ initialFiles: any[];
248
+ binaryRef: react.RefObject<HTMLDivElement>;
249
+ handleFileChange: (files: any, e: ChangeEvent<HTMLInputElement>, oldValues: any) => Promise<void>;
250
+ handleRemoveAt: (idx: number) => void;
251
+ handleRemoveAll: () => void;
252
+ checkIsImageLink: (url: string) => boolean;
253
+ setInitialFiles: react.Dispatch<react.SetStateAction<any[]>>;
254
+ };
255
+
235
256
  declare const tableHeadController: (props: any) => {
236
257
  handleCheckBoxAll: (event: React.ChangeEvent<HTMLInputElement>) => void;
237
258
  checkedAll: any;
@@ -319,4 +340,4 @@ declare const searchController: ({ viewData, model, domain, context, fieldsList,
319
340
  hoveredIndexSearchList: number | null;
320
341
  };
321
342
 
322
- export { type ISelctionStateProps, type ITableHeadProps, type ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController };
343
+ export { type ISelctionStateProps, type ITableHeadProps, type ITableProps, binaryFieldController, colorFieldController, copyLinkButtonController, dateFieldController, downLoadBinaryController, downloadFileController, durationController, many2manyBinaryController, many2manyFieldController, many2manyTagsController, many2oneButtonController, many2oneFieldController, priorityFieldController, searchController, statusDropdownController, tableController, tableGroupController, tableHeadController };