@engagebay/engagebay-form-module 1.0.8-beta.6 → 1.0.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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@engagebay/engagebay-form-module",
3
- "version": "1.0.8-beta.6",
4
- "description": "Provide base form components to reacho",
3
+ "version": "1.0.9",
4
+ "description": "Provide base form components to engagebay",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
7
7
  },
8
- "author": "Reacho Dev",
8
+ "author": "Engagebay Developer",
9
9
  "license": "ISC",
10
10
  "dependencies": {
11
11
  "react-phone-input-2": "^2.15.1",
@@ -16,6 +16,7 @@
16
16
  "@heroicons/react": ">=2.1.5",
17
17
  "@reduxjs/toolkit": ">=2.2.7",
18
18
  "@tippyjs/react": ">=4.2.6",
19
+ "@types/lodash": ">=4.17.7",
19
20
  "@types/react-redux": ">=7.1.33",
20
21
  "axios": ">=1.7.2",
21
22
  "clsx": ">=2.1.1",
@@ -31,6 +32,7 @@
31
32
  "@heroicons/react": ">=2.1.5",
32
33
  "@reduxjs/toolkit": ">=2.2.7",
33
34
  "@tippyjs/react": ">=4.2.6",
35
+ "@types/lodash": ">=4.17.7",
34
36
  "@types/react-redux": ">=7.1.33",
35
37
  "axios": ">=1.7.2",
36
38
  "clsx": ">=2.1.1",
package/src/api/index.ts CHANGED
@@ -1,16 +1,10 @@
1
1
  import axios, {AxiosInstance, AxiosRequestConfig} from "axios";
2
2
  import {FormFieldSchema} from "../form/schema/FormFieldSchema";
3
3
 
4
- let baseURL;
5
- try {
6
- baseURL = (window as any).DEFAULT_HOST ||
7
- (window as any).parent.DEFAULT_HOST
8
- } catch (error) {
9
-
10
- }
11
-
12
4
  const BASE_API: AxiosRequestConfig = {
13
- baseURL: baseURL ?? "",
5
+ baseURL:
6
+ (window as any).REACHO_BASE_URL ||
7
+ (window as any).parent.REACHO_BASE_URL,
14
8
  timeout: 30000,
15
9
  headers: {
16
10
  "Content-Type": "application/json",
@@ -28,13 +28,13 @@ import TimeField from "./formfields/TimeField";
28
28
  import Typeahead from "./formfields/Typeahead";
29
29
  import TypeaheadMultiSelect from "./formfields/TypeaheadMultiSelect";
30
30
  import UrlField from "./formfields/UrlField";
31
+ import Typeahead2 from "./formfields/Typeahead2";
31
32
  import {
32
33
  FieldOptionsSchema,
33
34
  FormFieldComponentPropSchema,
34
35
  FormFieldType,
35
36
  OptionMappingConfig,
36
37
  } from "./schema/FormFieldSchema";
37
- import Typeahead2 from "./formfields/Typeahead2";
38
38
 
39
39
  /**
40
40
  * @property {React.FC<FormFieldComponentPropSchema>} component - React component for a form field.
@@ -137,12 +137,12 @@ const formFieldComponents: FormComponentSchema = {
137
137
  [FormFieldType[FormFieldType.TYPEAHEAD]]: {
138
138
  component: Typeahead,
139
139
  },
140
- [FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
141
- component: TypeaheadMultiSelect,
142
- },
143
140
  [FormFieldType[FormFieldType.TYPEAHEAD_2]]: {
144
141
  component: Typeahead2,
145
142
  },
143
+ [FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
144
+ component: TypeaheadMultiSelect,
145
+ },
146
146
  [FormFieldType[FormFieldType.COMBO_SELECT]]: {
147
147
  component: ComboSelect,
148
148
  },
@@ -21,6 +21,7 @@ import FormField from "../FormField";
21
21
  import RenderFormField from "../util/RenderFormField";
22
22
  import { TrashIcon, XMarkIcon } from "@heroicons/react/24/outline";
23
23
  import Tippy from "@tippyjs/react";
24
+ import { set } from "lodash";
24
25
 
25
26
  const defaultBusinessHours = {
26
27
  MONDAY: {
@@ -123,8 +124,9 @@ export const BusinessHoursField: React.FC<FormFieldComponentPropSchema> = (
123
124
  <div className="w-full sm:w-full text-end mr-[2.3em]">
124
125
  <button
125
126
  type="button"
126
- className={`text-end text-primary cursor-pointer font-[13px] font-medium ${getValues(`${mappedName}.sessions`)?.length > 1 ? "mr-9" : ""
127
- }`}
127
+ className={`text-end text-primary cursor-pointer font-[13px] font-medium ${
128
+ getValues(`${mappedName}.sessions`)?.length > 1 ? "mr-9" : ""
129
+ }`}
128
130
  onClick={() => {
129
131
  const lastEndTime =
130
132
  getValues(`${mappedName}.sessions`)?.[
@@ -200,7 +202,7 @@ export const BusinessHoursField: React.FC<FormFieldComponentPropSchema> = (
200
202
  disableDefaultWrapper: true,
201
203
  defaultValue: "08:30",
202
204
  customClassNames: {
203
- fieldClassName: "border-none bg-blue-100",
205
+ fieldClassName: "cursor-pointer bg-blue-100",
204
206
  },
205
207
  },
206
208
  {
@@ -210,7 +212,7 @@ export const BusinessHoursField: React.FC<FormFieldComponentPropSchema> = (
210
212
  disableDefaultWrapper: true,
211
213
  defaultValue: "18:00",
212
214
  customClassNames: {
213
- fieldClassName: "border-none bg-blue-100",
215
+ fieldClassName: "cursor-pointer bg-blue-100",
214
216
  },
215
217
  },
216
218
  ],
@@ -1,46 +1,32 @@
1
1
  import { RegisterOptions } from "react-hook-form";
2
2
  import { useContext, useEffect, useState } from "react";
3
3
  import { FormContext } from "../context/FormContext";
4
- import {
5
- FormFieldComponentPropSchema,
6
- OutputFormatType,
7
- } from "../schema/FormFieldSchema";
4
+ import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
8
5
  import { Checkbox, Field, Input, Label } from "@headlessui/react";
9
6
  import React from "react";
10
7
  import RenderFormField from "../util/RenderFormField";
11
8
  import { handleChange, registerFormField } from "../util";
12
- import { normalizeCheckboxBooleanValue, normalizeMultiSelectValue } from "../util/normalizeCustomFieldValues";
13
9
  const CheckboxField: React.FC<FormFieldComponentPropSchema> = (
14
10
  props: FormFieldComponentPropSchema
15
11
  ) => {
16
12
  const formContext = useContext(FormContext);
17
13
  const [selectedOption, setSelectedOption] = useState<string[]>(
18
- normalizeMultiSelectValue(formContext.getValues(props.fieldConfig.name))
14
+ formContext.getValues(props.fieldConfig.name)
15
+ ? formContext.getValues(props.fieldConfig.name)
16
+ : []
19
17
  );
20
18
  const [isChecked, setIsChecked] = useState<boolean>(
21
- normalizeCheckboxBooleanValue(
22
- formContext.getValues(props.fieldConfig.name) ?? props.fieldConfig.defaultValue
23
- )
19
+ formContext.getValues(props.fieldConfig.name)
20
+ ? formContext.getValues(props.fieldConfig.name)
21
+ : props.fieldConfig.defaultValue
24
22
  );
25
23
  useEffect(() => {
26
- const current = formContext.getValues(props.fieldConfig.name);
27
- if (props.fieldConfig.options) {
28
- setSelectedOption(normalizeMultiSelectValue(current));
29
- } else {
30
- setIsChecked(
31
- normalizeCheckboxBooleanValue(current ?? props.fieldConfig.defaultValue)
32
- );
24
+ if (formContext.getValues(props.fieldConfig.name)) {
25
+ setSelectedOption(formContext.getValues(props.fieldConfig.name));
33
26
  }
34
27
  }, []);
35
28
  let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
36
29
  let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
37
- const getOutputValue = (value: any) => {
38
- if (props.fieldConfig.outputFormat === OutputFormatType.STRING) {
39
- if (Array.isArray(value)) return JSON.stringify(value);
40
- if (typeof value === "boolean") return String(value);
41
- }
42
- return value;
43
- };
44
30
  const handleInput = (option: string) => {
45
31
  let tempData: string[] = selectedOption;
46
32
  if (selectedOption.includes(option)) {
@@ -50,12 +36,7 @@ const CheckboxField: React.FC<FormFieldComponentPropSchema> = (
50
36
  tempData.push(option);
51
37
  setSelectedOption([...tempData]);
52
38
  }
53
- handleChange(
54
- getOutputValue(tempData),
55
- formContext,
56
- props.fieldConfig,
57
- props.onChange
58
- );
39
+ handleChange(tempData, formContext, props.fieldConfig, props.onChange);
59
40
  };
60
41
  function getInput() {
61
42
  return props.fieldConfig.options ? (
@@ -106,7 +87,7 @@ const CheckboxField: React.FC<FormFieldComponentPropSchema> = (
106
87
  checked={isChecked}
107
88
  onChange={(checked) => {
108
89
  handleChange(
109
- getOutputValue(checked),
90
+ checked,
110
91
  formContext,
111
92
  props.fieldConfig,
112
93
  props.onChange
@@ -1,17 +1,14 @@
1
1
  import { RegisterOptions } from "react-hook-form";
2
- import React, { useContext, useEffect } from "react";
2
+ import React, { useContext, useEffect, useRef, useState } from "react";
3
3
  import Datepicker from "react-tailwindcss-datepicker";
4
4
  import { FormContext } from "../context/FormContext";
5
5
  import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
6
6
  import RenderFormField from "../util/RenderFormField";
7
7
  import { handleChange, registerFormField } from "../util";
8
- import { normalizeDateFormat, normalizeDateInputValue } from "../util/normalizeCustomFieldValues";
9
8
  import moment from "moment";
10
9
 
11
-
12
-
13
10
  const DatePicker: React.FC<FormFieldComponentPropSchema> = (
14
- props: FormFieldComponentPropSchema,
11
+ props: FormFieldComponentPropSchema
15
12
  ) => {
16
13
  const formContext = useContext(FormContext);
17
14
  const initialDate = formContext.getValues(props.fieldConfig.name)
@@ -28,17 +25,16 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
28
25
  ) {
29
26
  formContext.setValue(
30
27
  props.fieldConfig.name,
31
- props.fieldConfig.defaultValue,
28
+ props.fieldConfig.defaultValue
32
29
  );
33
30
  }
34
31
  }, [props.fieldConfig.forceUpdate]);
35
32
 
36
33
  let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
37
- //registerOptions.valueAsDate = true;
34
+
38
35
  let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
39
36
 
40
37
  function getInput() {
41
- const displayFormat = normalizeDateFormat(props.fieldConfig.dateDisplayFormat);
42
38
  const rawStart =
43
39
  initialDate?.startDate ||
44
40
  props.fieldConfig.defaultValue ||
@@ -47,9 +43,13 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
47
43
  initialDate?.endDate ||
48
44
  props.fieldConfig.defaultValue ||
49
45
  "";
46
+ const toDate = (v: string | Date | null | undefined): Date | null => {
47
+ if (v == null || v === "") return null;
48
+ return moment(v).isValid() ? moment(v).toDate() : null;
49
+ };
50
50
  const value = {
51
- startDate: normalizeDateInputValue(rawStart, displayFormat),
52
- endDate: normalizeDateInputValue(rawEnd, displayFormat),
51
+ startDate: toDate(rawStart),
52
+ endDate: toDate(rawEnd),
53
53
  };
54
54
  // Calendar opens on selected date's month/year (must be a Date instance)
55
55
  const startFrom = value.startDate instanceof Date ? value.startDate : new Date();
@@ -58,11 +58,10 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
58
58
  value={value}
59
59
  startFrom={startFrom}
60
60
  {...hookProps}
61
- displayFormat={displayFormat}
62
61
  placeholder={
63
62
  props.fieldConfig.placeholder
64
63
  ? props.fieldConfig.placeholder
65
- : displayFormat
64
+ : "YYYY-MM-DD"
66
65
  }
67
66
  asSingle={true}
68
67
  popoverDirection="down"
@@ -80,7 +79,7 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
80
79
  onChange={(dates) => {
81
80
  let date = null;
82
81
  if (dates?.startDate != null)
83
- date = moment(dates?.startDate).format(displayFormat);
82
+ date = moment(dates?.startDate).format("YYYY-MM-DD");
84
83
 
85
84
  handleChange(date, formContext, props.fieldConfig, props.onChange);
86
85
  }}
@@ -9,8 +9,6 @@ import { Description } from "@headlessui/react";
9
9
  import React from "react";
10
10
  import RenderFormField from "../util/RenderFormField";
11
11
  import clsx from "clsx";
12
- import { XMarkIcon } from "@heroicons/react/20/solid";
13
- import { normalizeFileFieldUrls } from "../util/normalizeCustomFieldValues";
14
12
  const FileUploadField: React.FC<FormFieldComponentPropSchema> = (
15
13
  props: FormFieldComponentPropSchema
16
14
  ) => {
@@ -105,7 +103,7 @@ const FileUploadField: React.FC<FormFieldComponentPropSchema> = (
105
103
  <Description>Loading...</Description>
106
104
  ) : (
107
105
  props.fieldConfig.fieldContainer ? <props.fieldConfig.fieldContainer /> :
108
- <div className={"flex flex-col items-center justify-center pt-5 pb-6 px-2"}>
106
+ <div className={"flex flex-col items-center justify-center pt-5 pb-6"}>
109
107
  {file ? (
110
108
  <>
111
109
  {isImageFile(file) ? (
@@ -127,19 +125,19 @@ const FileUploadField: React.FC<FormFieldComponentPropSchema> = (
127
125
  </div>
128
126
  ) : (
129
127
  <div className="flex">
130
- <span className="m-2 max-w-xs truncate">
131
- {normalizeFileFieldUrls(file?.name || file?.toString?.() || '')}
128
+ <span className="m-2">
129
+ {file?.name}
132
130
  </span>{" "}
133
131
  <button
134
132
  onClick={(e) => {
135
133
  e.preventDefault();
136
134
  formContext.setValue(
137
- props.fieldConfig.name,null
135
+ props.fieldConfig.name,cnull
138
136
  );
139
137
  setFile(null);
140
138
  }}
141
- className="btn btn-sm ">
142
- <XMarkIcon className="w-3.5 h-3.5 text-gray-800"/>
139
+ className="btn btn-outline-dark btn-sm ">
140
+ X
143
141
  </button>
144
142
  </div>
145
143
  )}
@@ -13,7 +13,6 @@ import {
13
13
  FieldOptionsSchema,
14
14
  FormFieldComponentPropSchema,
15
15
  FormFieldType,
16
- OutputFormatType,
17
16
  } from "../schema/FormFieldSchema";
18
17
  import { FormContext } from "../context/FormContext";
19
18
  import RenderFormField from "../util/RenderFormField";
@@ -21,7 +20,6 @@ import RenderListOptions, {
21
20
  renderListBoxValue,
22
21
  } from "../util/RenderListOptions";
23
22
  import { handleChange, registerFormField } from "../util";
24
- import { normalizeMultiSelectValue } from "../util/normalizeCustomFieldValues";
25
23
 
26
24
  const MultipleSelectField: React.FC<FormFieldComponentPropSchema> = ({
27
25
  fieldConfig,
@@ -36,11 +34,9 @@ const MultipleSelectField: React.FC<FormFieldComponentPropSchema> = ({
36
34
  fieldConfig.options ? fieldConfig.options : []
37
35
  );
38
36
 
39
- const normalizedSelectedValues = normalizeMultiSelectValue(
40
- formContext.getValues(fieldConfig.name)
41
- );
42
-
43
- const validSelectedValues = normalizedSelectedValues.filter(
37
+ const validSelectedValues = (
38
+ formContext.getValues(fieldConfig.name) || []
39
+ ).filter(
44
40
  (selectedValue: any) =>
45
41
  fieldConfig.options &&
46
42
  fieldConfig.options.some((option) => option.value === selectedValue)
@@ -57,22 +53,14 @@ const MultipleSelectField: React.FC<FormFieldComponentPropSchema> = ({
57
53
  }, [fieldConfig.options]);
58
54
 
59
55
  function getInput() {
60
- const getOutputValue = (val: any) => {
61
- if (fieldConfig.outputFormat === OutputFormatType.STRING) {
62
- const normalized = normalizeMultiSelectValue(val);
63
- return JSON.stringify(normalized);
64
- }
65
- return val;
66
- };
67
-
68
56
  return (
69
57
  <Listbox
70
58
  as={"div"}
71
59
  {...hookProps}
72
60
  value={validSelectedValues}
73
61
  defaultValue={fieldConfig.defaultValue}
74
- onChange={(val: any) =>
75
- handleChange(getOutputValue(val), formContext, fieldConfig, onChange)
62
+ onChange={(val) =>
63
+ handleChange(val, formContext, fieldConfig, onChange)
76
64
  }
77
65
  disabled={fieldConfig.disabled}
78
66
  multiple
@@ -1,9 +1,9 @@
1
1
  import React, {
2
- useCallback,
3
- useContext,
4
- useEffect,
5
- useRef,
6
- useState,
2
+ useCallback,
3
+ useContext,
4
+ useEffect,
5
+ useRef,
6
+ useState,
7
7
  } from "react";
8
8
 
9
9
  import { Listbox, ListboxButton } from "@headlessui/react";
@@ -12,185 +12,199 @@ import { RegisterOptions } from "react-hook-form";
12
12
  import { FormContext } from "../context/FormContext";
13
13
  import { getListOption, getListOptions } from "../FormFieldUtils";
14
14
  import {
15
- FieldOptionsSchema,
16
- FormFieldComponentPropSchema,
17
- FormFieldType,
18
- OutputFormatType,
15
+ FieldOptionsSchema,
16
+ FormFieldComponentPropSchema,
17
+ FormFieldType,
18
+ OutputFormatType,
19
19
  } from "../schema/FormFieldSchema";
20
20
  import { handleChange, registerFormField } from "../util";
21
21
  import RenderFormField from "../util/RenderFormField";
22
22
  import RenderListOptions, {
23
- renderListBoxValue,
23
+ renderListBoxValue,
24
24
  } from "../util/RenderListOptions";
25
25
 
26
26
  const Typeahead: React.FC<FormFieldComponentPropSchema> = (
27
- props: FormFieldComponentPropSchema,
27
+ props: FormFieldComponentPropSchema
28
28
  ) => {
29
- const dynamicSelectRef = useRef<HTMLUListElement>(null);
30
- const formContext = useContext(FormContext);
31
- let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
32
- let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
33
- const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
34
- const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
35
- [],
36
- );
37
- const [loading, setLoading] = useState<boolean>(true);
38
-
39
- useEffect(() => {
40
- if (
41
- !formContext.getValues(props.fieldConfig.name) &&
42
- props.fieldConfig.defaultValue
43
- ) {
44
- formContext.setValue(
29
+ const dynamicSelectRef = useRef<HTMLUListElement>(null);
30
+ const formContext = useContext(FormContext);
31
+ let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
32
+ let hookProps = formContext.register(
45
33
  props.fieldConfig.name,
46
- props.fieldConfig.defaultValue,
47
- );
48
- }
49
- fetchData(undefined);
50
- }, []);
51
-
52
- const fetchData = useCallback(
53
- async (_query: string | undefined) => {
54
- setLoading(true);
55
- try {
56
- if (!props.fieldConfig.fetchUrl) return;
34
+ registerOptions
35
+ );
36
+ const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
37
+ const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
38
+ []
39
+ );
40
+ const [loading, setLoading] = useState<boolean>(true);
57
41
 
58
- let url = props.fieldConfig.fetchUrl;
59
- if (_query) {
60
- url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
42
+ useEffect(() => {
43
+ if (
44
+ !formContext.getValues(props.fieldConfig.name) &&
45
+ props.fieldConfig.defaultValue
46
+ ) {
47
+ formContext.setValue(
48
+ props.fieldConfig.name,
49
+ props.fieldConfig.defaultValue
50
+ );
61
51
  }
52
+ fetchData(undefined);
53
+ }, []);
62
54
 
63
- let response = await (props.fieldConfig.disableHeaderInFetch
64
- ? axios.get(url)
65
- : formContext.axiosInstance?.get(url));
66
- if (response?.data) {
67
- const data: FieldOptionsSchema[] = getListOptions(
68
- response.data,
69
- props.fieldConfig.optionsConfig,
70
- );
71
- setListOptions([...data]);
72
- let value = formContext.getValues(props.fieldConfig.name);
73
- if (value && data.find((i) => i.value !== value)) {
74
- if (selectedValues.find((i) => i.value !== value))
75
- fetchValue(value);
76
- }
77
- if (props.fieldConfig.fetchCallback) {
78
- props.fieldConfig.fetchCallback(response);
79
- }
80
- } else {
81
- console.error(response?.statusText);
82
- }
83
- } catch (err) {
84
- } finally {
85
- setLoading(false);
86
- }
87
- },
88
- [props.fieldConfig.fetchUrl],
89
- );
55
+ const fetchData = useCallback(
56
+ async (_query: string | undefined) => {
57
+ setLoading(true);
58
+ try {
59
+ if (!props.fieldConfig.fetchUrl) return;
60
+
61
+ let url = props.fieldConfig.fetchUrl;
62
+ if (_query) {
63
+ url = url.includes("?")
64
+ ? url + "&q=" + _query
65
+ : url + "?q=" + _query;
66
+ }
67
+
68
+ let response = await (props.fieldConfig.disableHeaderInFetch
69
+ ? axios.get(url)
70
+ : formContext.axiosInstance?.get(url));
71
+ if (response?.data) {
72
+ const data: FieldOptionsSchema[] = getListOptions(
73
+ response.data,
74
+ props.fieldConfig.optionsConfig
75
+ );
76
+ setListOptions([...data]);
77
+ let value = formContext.getValues(props.fieldConfig.name);
78
+ if (
79
+ value &&
80
+ data.find((i) => i.value !== value)
81
+ ) {
82
+ if (selectedValues.find((i) => i.value !== value))
83
+ fetchValue(value);
84
+ }
85
+ if (props.fieldConfig.fetchCallback) {
86
+ props.fieldConfig.fetchCallback(response);
87
+ }
88
+ } else {
89
+ console.error(response?.statusText);
90
+ }
91
+ } catch (err) {
92
+ } finally {
93
+ setLoading(false);
94
+ }
95
+ },
96
+ [props.fieldConfig.fetchUrl]
97
+ );
90
98
 
91
- const fetchValue = async (value: string) => {
92
- try {
93
- if (props.fieldConfig.ignoreFetchValue || !props.fieldConfig.fetchUrl) {
94
- return;
95
- }
99
+ const fetchValue = async (value: string) => {
100
+ try {
101
+ if (
102
+ props.fieldConfig.ignoreFetchValue ||
103
+ !props.fieldConfig.fetchUrl
104
+ ) {
105
+ return;
106
+ }
96
107
 
97
- let url = props.fieldConfig.fetchUrl;
108
+ let url = props.fieldConfig.fetchUrl;
98
109
 
99
- if (value)
100
- url = url.includes("?")
101
- ? url + "&values=" + value
102
- : url + "?values=" + value;
110
+ if (value)
111
+ url = url.includes("?")
112
+ ? url + "&values=" + value
113
+ : url + "?values=" + value;
103
114
 
104
- let response = await (props.fieldConfig.disableHeaderInFetch
105
- ? axios.get(url)
106
- : formContext.axiosInstance?.get(url));
107
- if (response?.data) {
108
- const data: FieldOptionsSchema[] = getListOptions(
109
- response?.data,
110
- props.fieldConfig.optionsConfig,
115
+ let response = await (
116
+ props.fieldConfig.disableHeaderInFetch
117
+ ? axios.get(url)
118
+ : formContext.axiosInstance?.get(url)
119
+ );
120
+ if (response?.data) {
121
+ const data: FieldOptionsSchema[] = getListOptions(
122
+ response?.data,
123
+ props.fieldConfig.optionsConfig
124
+ );
125
+ setSelectedValues([...data]);
126
+ }
127
+ } catch (err) { }
128
+ };
129
+
130
+ const updateListOptions = (data: any) => {
131
+ const resData: FieldOptionsSchema = getListOption(
132
+ data,
133
+ props.fieldConfig.optionsConfig
111
134
  );
112
- setSelectedValues([...data]);
113
- }
114
- } catch (err) {}
115
- };
135
+ setSelectedValues((perv) => [resData]);
136
+ formContext.setValue(props.fieldConfig.name, resData.value);
137
+ };
116
138
 
117
- const updateListOptions = (data: any) => {
118
- const resData: FieldOptionsSchema = getListOption(
119
- data,
120
- props.fieldConfig.optionsConfig,
121
- );
122
- setSelectedValues((perv) => [resData]);
123
- formContext.setValue(props.fieldConfig.name, resData.value);
124
- };
139
+ function getInput() {
140
+ return (
141
+ <Listbox
142
+ as={"div"}
143
+ {...hookProps}
144
+ className={`relative form-listbox flex-1`}
145
+ value={
146
+ formContext.getValues(props.fieldConfig.name)
147
+ ? props.fieldConfig.outputFormat ===
148
+ OutputFormatType.ARRAY
149
+ ? formContext.getValues(props.fieldConfig.name)[0]
150
+ : formContext.getValues(props.fieldConfig.name)
151
+ : undefined
152
+ }
153
+ onChange={(val) => {
154
+ const currentValue = formContext.getValues(
155
+ props.fieldConfig.name
156
+ );
125
157
 
126
- function getInput() {
127
- return (
128
- <Listbox
129
- as={"div"}
130
- {...hookProps}
131
- className={`relative form-listbox flex-1`}
132
- value={
133
- formContext.getValues(props.fieldConfig.name)
134
- ? props.fieldConfig.outputFormat === OutputFormatType.ARRAY
135
- ? formContext.getValues(props.fieldConfig.name)[0]
136
- : formContext.getValues(props.fieldConfig.name)
137
- : undefined
138
- }
139
- onChange={(val) => {
140
- const currentValue = formContext.getValues(props.fieldConfig.name);
158
+ // If the value matches, set it to null, otherwise set it to val
159
+ const newValue = currentValue === val ? null : val;
141
160
 
142
- // If the value matches, set it to null, otherwise set it to val
143
- const newValue = currentValue === val ? null : val;
161
+ const selected = listOptions.find(o => o.value == newValue);
162
+ // selected && setSelectedValues([selected]);
163
+ handleChange(
164
+ newValue,
165
+ formContext,
166
+ props.fieldConfig,
167
+ props.onChange
168
+ );
169
+ }}
170
+ name={props.fieldConfig.name}
171
+ disabled={props.fieldConfig.disabled}>
172
+ <ListboxButton
173
+ className={
174
+ props.fieldConfig.customClassNames?.fieldClassName
175
+ ? "form-listbox-select " +
176
+ props.fieldConfig.customClassNames?.fieldClassName
177
+ : "form-listbox-select"
178
+ }>
179
+ {renderListBoxValue(
180
+ formContext,
181
+ props.fieldConfig,
182
+ [...selectedValues, ...listOptions],
183
+ props.onChange
184
+ )}
185
+ </ListboxButton>
186
+ <RenderListOptions
187
+ formContext={formContext}
188
+ onChange={props.onChange}
189
+ formField={FormFieldType.TYPEAHEAD}
190
+ ref={dynamicSelectRef}
191
+ fieldConfig={props.fieldConfig}
192
+ listOptions={[...selectedValues, ...listOptions]}
193
+ setListOptions={setListOptions}
194
+ loading={loading}
195
+ setLoading={setLoading}
196
+ createCallback={(data) => updateListOptions(data)}
197
+ queryCallback={(query) => fetchData(query)}
198
+ />
199
+ </Listbox>
200
+ );
201
+ }
202
+ if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
203
+ return <></>;
204
+ }
144
205
 
145
- const selected = listOptions.find((o) => o.value == newValue);
146
- selected && setSelectedValues([selected]);
147
- handleChange(
148
- newValue,
149
- formContext,
150
- props.fieldConfig,
151
- props.onChange,
152
- );
153
- }}
154
- name={props.fieldConfig.name}
155
- disabled={props.fieldConfig.disabled}
156
- >
157
- <ListboxButton
158
- className={
159
- props.fieldConfig.customClassNames?.fieldClassName
160
- ? "form-listbox-select " +
161
- props.fieldConfig.customClassNames?.fieldClassName
162
- : "form-listbox-select"
163
- }
164
- >
165
- {renderListBoxValue(
166
- formContext,
167
- props.fieldConfig,
168
- [...selectedValues, ...listOptions],
169
- props.onChange,
170
- )}
171
- </ListboxButton>
172
- <RenderListOptions
173
- formContext={formContext}
174
- onChange={props.onChange}
175
- formField={FormFieldType.TYPEAHEAD}
176
- ref={dynamicSelectRef}
177
- fieldConfig={props.fieldConfig}
178
- listOptions={[...selectedValues, ...listOptions]}
179
- setListOptions={setListOptions}
180
- loading={loading}
181
- setLoading={setLoading}
182
- createCallback={(data) => updateListOptions(data)}
183
- queryCallback={(query) => fetchData(query)}
184
- />
185
- </Listbox>
206
+ return (
207
+ <RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
186
208
  );
187
- }
188
- if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
189
- return <></>;
190
- }
191
-
192
- return (
193
- <RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
194
- );
195
209
  };
196
210
  export default Typeahead;
@@ -199,12 +199,7 @@ const Typeahead2: React.FC<FormFieldComponentPropSchema> = (
199
199
  : result.includes(resData.value)
200
200
  ? [...result.filter((v: string) => v != resData.value), resData.value]
201
201
  : [...result, resData.value];
202
- handleChange(
203
- result,
204
- formContext,
205
- props.fieldConfig,
206
- props.onChange,
207
- );
202
+ formContext.setValue(props.fieldConfig.name, result);
208
203
  };
209
204
 
210
205
  const getInput = () => {
@@ -23,10 +23,9 @@ import RenderListOptions, {
23
23
  } from "../util/RenderListOptions";
24
24
  // import _ from "lodash";
25
25
  import axios from "axios";
26
- import { getAxiosInstance } from "../../api";
27
26
 
28
27
  const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
29
- props: FormFieldComponentPropSchema,
28
+ props: FormFieldComponentPropSchema
30
29
  ) => {
31
30
  const dynamicSelectRef = useRef<HTMLUListElement>(null);
32
31
  const formContext = useContext(FormContext);
@@ -34,7 +33,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
34
33
  let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
35
34
  const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
36
35
  const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
37
- [],
36
+ []
38
37
  );
39
38
  const [loading, setLoading] = useState<boolean>(true);
40
39
 
@@ -45,7 +44,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
45
44
  ) {
46
45
  formContext.setValue(
47
46
  props.fieldConfig.name,
48
- props.fieldConfig.defaultValue,
47
+ props.fieldConfig.defaultValue
49
48
  );
50
49
  }
51
50
  fetchData(undefined);
@@ -61,16 +60,14 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
61
60
  if (_query) {
62
61
  url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
63
62
  }
64
- const axiosInstance = getAxiosInstance(
65
- formContext.axiosInstance,
66
- props.fieldConfig,
67
- );
68
63
 
69
- let response = await axiosInstance.get(url);
64
+ let response = await (props.fieldConfig.disableHeaderInFetch
65
+ ? axios.get(url)
66
+ : formContext.axiosInstance?.get(url));
70
67
  if (response?.data) {
71
68
  const data: FieldOptionsSchema[] = getListOptions(
72
69
  response?.data,
73
- props.fieldConfig.optionsConfig,
70
+ props.fieldConfig.optionsConfig
74
71
  );
75
72
  setListOptions([...data]);
76
73
  let values = formContext.getValues(props.fieldConfig.name) || [];
@@ -80,7 +77,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
80
77
  (data.length === 0 || // If 'data' is empty
81
78
  (!values.every((v: string) => data.some((i) => i.value === v)) && // Ensure none of 'values' match 'data'
82
79
  !values.every((v: string) =>
83
- selectedValues.some((i) => i.value === v),
80
+ selectedValues.some((i) => i.value === v)
84
81
  ))) // Ensure none of 'values' match 'selectedValues'
85
82
  ) {
86
83
  fetchValue(values); // Call 'fetchValue()' if all conditions are met
@@ -97,7 +94,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
97
94
  setLoading(false);
98
95
  }
99
96
  },
100
- [props.fieldConfig.fetchUrl],
97
+ [props.fieldConfig.fetchUrl]
101
98
  );
102
99
 
103
100
  const fetchValue = async (value: string) => {
@@ -108,7 +105,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
108
105
 
109
106
  let url = props.fieldConfig.fetchUrl;
110
107
 
111
- url = url.includes("?")
108
+ url = url = url.includes("?")
112
109
  ? url + "&values=" + value
113
110
  : url + "?values=" + value;
114
111
 
@@ -118,7 +115,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
118
115
  if (response?.data) {
119
116
  const data: FieldOptionsSchema[] = getListOptions(
120
117
  response?.data,
121
- props.fieldConfig.optionsConfig,
118
+ props.fieldConfig.optionsConfig
122
119
  );
123
120
  let values: any[] = formContext.getValues(props.fieldConfig.name) || [];
124
121
  setSelectedValues(
@@ -126,22 +123,22 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
126
123
  ...data,
127
124
  props.fieldConfig.dropdownFieldConfig?.isSuggestionBox && values
128
125
  ? values
129
- .filter(
130
- (value) =>
131
- data.some((d) => d.value !== value) || data.length == 0,
132
- )
133
- .map((val) => ({ label: val, value: val }))
126
+ .filter(
127
+ (value) =>
128
+ data.some((d) => d.value !== value) || data.length == 0
129
+ )
130
+ .map((val) => ({ label: val, value: val }))
134
131
  : [],
135
- ].flat(),
132
+ ].flat()
136
133
  );
137
134
  }
138
- } catch (err) { }
135
+ } catch (err) {}
139
136
  };
140
137
 
141
138
  const updateListOptions = (data: any) => {
142
139
  const resData: FieldOptionsSchema = getListOption(
143
140
  data,
144
- props.fieldConfig.optionsConfig,
141
+ props.fieldConfig.optionsConfig
145
142
  );
146
143
  setSelectedValues((prev) => [...prev, resData]);
147
144
  let result = formContext.getValues(props.fieldConfig.name) || [];
@@ -163,14 +160,14 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
163
160
  className={"relative form-listbox flex-1 overflow-hidden"}
164
161
  onChange={(selectedOptions) => {
165
162
  const chossenOptions = listOptions.filter((op) =>
166
- selectedOptions.includes(op.value),
163
+ selectedOptions.includes(op.value)
167
164
  );
168
165
  // setSelectedValues((prev) => [...prev, ...chossenOptions]);
169
166
  handleChange(
170
167
  selectedOptions,
171
168
  formContext,
172
169
  props.fieldConfig,
173
- props.onChange,
170
+ props.onChange
174
171
  );
175
172
  }}
176
173
  multiple
@@ -179,7 +176,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
179
176
  className={
180
177
  props.fieldConfig.customClassNames?.fieldClassName
181
178
  ? "form-listbox-select " +
182
- props.fieldConfig.customClassNames?.fieldClassName
179
+ props.fieldConfig.customClassNames?.fieldClassName
183
180
  : "form-listbox-select"
184
181
  }
185
182
  >
@@ -187,7 +184,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
187
184
  formContext,
188
185
  props.fieldConfig,
189
186
  [...selectedValues, ...listOptions],
190
- props.onChange,
187
+ props.onChange
191
188
  )}
192
189
  </ListboxButton>
193
190
  <RenderListOptions
@@ -106,12 +106,11 @@ export type FormFieldSchema = {
106
106
  max?: number;
107
107
  min?: number;
108
108
  rows?: number;
109
+ allowedMinQueryLength?: number;
109
110
  defaultValue?: string | string[] | {} | boolean;
110
111
  options?: FieldOptionsSchema[];
111
112
  minDate?: Date | null | undefined;
112
113
  maxDate?: Date | null | undefined;
113
- /** Input display format for date pickers (e.g. 'MMMM D, YYYY'). */
114
- dateDisplayFormat?: string;
115
114
  // ref?:any
116
115
 
117
116
  /**
@@ -130,15 +129,14 @@ export type FormFieldSchema = {
130
129
  decimalAllowed?: boolean;
131
130
  errorMessage?: string;
132
131
  submitOnChange?: boolean;
132
+ isMultiple?: boolean;
133
133
  formFieldPattern?: FormFieldPatternsImpl[];
134
134
  fetchUrl?: string;
135
- fetchSavedDataUrl?: string;
136
135
  postUrl?: string;
136
+ fetchSavedDataUrl?: string;
137
137
  fileAccept?: string;
138
138
  icon?: ReactNode;
139
139
  outputFormat?: OutputFormatType;
140
- isMultiple?: boolean;
141
- allowedMinQueryLength?: number;
142
140
  children?: FormFieldSchema[];
143
141
  defaultOptions?: FieldOptionsSchema[];
144
142
  optionsConfig?: OptionMappingConfig;
@@ -207,7 +205,6 @@ export type FieldOptionsSchema = {
207
205
  isDisabled?: boolean;
208
206
  helpText?: string;
209
207
  groupName?: string;
210
- tooltip?: string;
211
208
  icon?: React.ReactNode;
212
209
  };
213
210
 
@@ -243,7 +240,7 @@ export class FormFieldPatternsImpl implements FormFieldPatterns {
243
240
  static readonly EMAIL = new FormFieldPatternsImpl(
244
241
  "EMAIL",
245
242
  "Please enter a valid email address",
246
- /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i
243
+ /^([A-Za-z0-9\._%+\-]+@[A-Za-z0-9\.\-]+\.[A-Za-z]{2,})$/
247
244
  );
248
245
  // static readonly PASSWORD = new FormFieldPatternsImpl(
249
246
  // "PASSWORD",
@@ -18,7 +18,7 @@ import {
18
18
  FormFieldType,
19
19
  OutputFormatType,
20
20
  } from "../schema/FormFieldSchema";
21
- import { normalizeMultiSelectValue, normalizeMultiSelectValueForStringArrayValues } from "./normalizeCustomFieldValues";
21
+
22
22
  type RenderListOptionsProps = {
23
23
  formContext: FormContextType;
24
24
  fieldConfig: FormFieldSchema;
@@ -127,7 +127,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
127
127
  }, {});
128
128
 
129
129
  const handleQueryCallback = useCallback(() => {
130
- if (filteredList.length < 5 && isTypeahead) {
130
+ if (filteredList.length == 0 && isTypeahead) {
131
131
  queryCallback && queryCallback(query);
132
132
  }
133
133
  }, [filteredList]);
@@ -154,17 +154,12 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
154
154
 
155
155
  const renderOption = (option: FieldOptionsSchema) => {
156
156
  let selected = false;
157
- const formValue = formContext.getValues(fieldConfig.name);
158
- if (formField === FormFieldType.MULTI_SELECT) {
159
- const normalizedValues = normalizeMultiSelectValue(formValue);
160
- const normalizedOptionValue =
161
- typeof option.value === "string"
162
- ? option.value.trim()
163
- : String(option.value).trim();
164
- selected = normalizedValues.includes(normalizedOptionValue);
165
- } else if (Array.isArray(formValue)) {
166
- selected = formValue.includes(option.value);
157
+ if (Array.isArray(formContext.getValues(fieldConfig.name))) {
158
+ selected = formContext
159
+ .getValues(fieldConfig.name)
160
+ .includes(option.value);
167
161
  } else {
162
+ const formValue = formContext.getValues(fieldConfig.name);
168
163
  // const defaultValue = fieldConfig.defaultValue;
169
164
  // selected = formValue ? option.value == formValue : defaultValue == option.value;
170
165
  selected = option.value == formValue;
@@ -194,21 +189,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
194
189
  {option.icon && (
195
190
  <span className="listbox-svg">{option.icon}</span>
196
191
  )}
197
- {option.tooltip ? (
198
- <Tippy
199
- content={
200
- <>
201
- {option.label}
202
- <br />
203
- {option.helpText}
204
- </>
205
- }
206
- >
207
- <div className="truncate">{option.label}</div>
208
- </Tippy>
209
- ) : (
210
- option.label
211
- )}
192
+ {option.label}
212
193
  </span>
213
194
  {isTypeahead &&
214
195
  !fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
@@ -227,30 +208,11 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
227
208
  )
228
209
  )}
229
210
  </div>
230
- {option.helpText &&
231
- (option.tooltip ? (
232
- <Tippy
233
- content={
234
- <>
235
- {option.label}
236
- <br />
237
- {option.helpText}
238
- </>
239
- }
240
- >
241
- <div
242
- className={`mt-0 text-xs text-gray-500 font-normal truncate w-full ${fieldConfig.customClassNames?.optionClassName}`}
243
- >
244
- {option.helpText}
245
- </div>
246
- </Tippy>
247
- ) : (
248
- <div
249
- className={`mt-0 text-xs text-gray-500 font-normal truncate w-full ${fieldConfig.customClassNames?.optionClassName}`}
250
- >
251
- {option.helpText}
252
- </div>
253
- ))}
211
+ {option.helpText && (
212
+ <div className="mt-0 text-xs text-gray-500 font-normal truncate w-full !max-w-[150px]">
213
+ {option.helpText}
214
+ </div>
215
+ )}
254
216
  </>
255
217
  )}
256
218
  </ListboxOption>
@@ -373,7 +335,7 @@ export function renderListBoxValue(
373
335
  listOptions: FieldOptionsSchema[],
374
336
  onChange?: (value: any) => void,
375
337
  ): JSX.Element {
376
- let value = normalizeMultiSelectValueForStringArrayValues(fieldConfig, formContext.getValues(fieldConfig.name));
338
+ let value = formContext.getValues(fieldConfig.name);
377
339
  const renderAsString = () => {
378
340
  // if (!listOptions) {
379
341
  // return value;
@@ -463,10 +425,9 @@ export function renderListBoxValue(
463
425
  )
464
426
  );
465
427
  };
466
- let outputFormat =
467
- fieldConfig.outputFormat != undefined
468
- ? fieldConfig.outputFormat === OutputFormatType.STRING
469
- : false;
428
+ let outputFormat = fieldConfig.outputFormat
429
+ ? fieldConfig.outputFormat === OutputFormatType.ARRAY
430
+ : false;
470
431
  const getPlaceholder = () => (
471
432
  <span className="form-placeholder">
472
433
  {fieldConfig.placeholder || "Select any option"}
@@ -476,7 +437,7 @@ export function renderListBoxValue(
476
437
  if (!value && !listOptions) {
477
438
  return getPlaceholder();
478
439
  }
479
- if (Array.isArray(value)) {
440
+ if (!outputFormat && Array.isArray(value)) {
480
441
  return renderAsArray();
481
442
  }
482
443
  return renderAsString();
@@ -1,149 +0,0 @@
1
- import moment from "moment";
2
- import { FormFieldSchema, OutputFormatType } from "../schema/FormFieldSchema";
3
-
4
- const normalizeStringToken = (value: unknown): string => {
5
- return typeof value === "string" ? value.trim() : String(value).trim();
6
- };
7
-
8
- const normalizeStringArray = (values: unknown[]): string[] => {
9
- return values.map(normalizeStringToken).filter(Boolean);
10
- };
11
-
12
- const parseJsonArrayString = (value: string): string[] | null => {
13
- if (!value.startsWith("[")) return null;
14
- try {
15
- const parsed = JSON.parse(value);
16
- return Array.isArray(parsed) ? normalizeStringArray(parsed) : null;
17
- } catch {
18
- return null;
19
- }
20
- };
21
-
22
- export const normalizeCheckboxBooleanValue = (value: any): boolean => {
23
- if (value === true || value === 1) return true;
24
- if (value === false || value === 0 || value == null || value === "") {
25
- return false;
26
- }
27
-
28
- if (typeof value === "string") {
29
- const s = value.trim().toLowerCase();
30
- if (s === "true" || s === "1" || s === "yes") return true;
31
- if (s === "false" || s === "0" || s === "no" || s === "") return false;
32
- }
33
-
34
- return Boolean(value);
35
- };
36
-
37
- export const normalizeMultiSelectValue = (value: any): string[] => {
38
- if (value == null) return [];
39
-
40
- if (Array.isArray(value)) return normalizeStringArray(value);
41
-
42
- if (typeof value === "string") {
43
- const s = value.trim();
44
- if (!s) return [];
45
-
46
- const jsonArray = parseJsonArrayString(s);
47
- if (jsonArray) return jsonArray;
48
-
49
- return normalizeStringArray(s.split(","));
50
- }
51
-
52
- return normalizeStringArray([value]);
53
- };
54
-
55
- export const normalizeDateFormat = (format?: string): string => {
56
- if (!format) return "YYYY-MM-DD";
57
- return format
58
- .replace(/yyyy/g, "YYYY")
59
- .replace(/yy/g, "YY")
60
- .replace(/dd/g, "DD")
61
- .replace(/d/g, "D")
62
- .replace(/mm/g, "MM");
63
- };
64
-
65
- export const normalizeDateInputValue = (
66
- value: any,
67
- preferredFormat?: string
68
- ): Date | null => {
69
- if (value == null || value === "") return null;
70
-
71
- if (value instanceof Date) {
72
- return Number.isNaN(value.getTime()) ? null : value;
73
- }
74
-
75
- if (typeof value === "number" && Number.isFinite(value)) {
76
- const ms = value < 1_000_000_000_000 ? value * 1000 : value;
77
- const date = new Date(ms);
78
- return Number.isNaN(date.getTime()) ? null : date;
79
- }
80
-
81
- if (typeof value === "string") {
82
- const s = value.trim();
83
- if (!s) return null;
84
-
85
- const numeric = Number(s);
86
- if (Number.isFinite(numeric)) {
87
- const ms = numeric < 1_000_000_000_000 ? numeric * 1000 : numeric;
88
- const date = new Date(ms);
89
- return Number.isNaN(date.getTime()) ? null : date;
90
- }
91
-
92
- const preferred = normalizeDateFormat(preferredFormat);
93
- const formats = Array.from(
94
- new Set([
95
- preferred,
96
- "YYYY-MM-DD",
97
- "DD/MM/YYYY",
98
- "MM/DD/YYYY",
99
- "DD-MM-YYYY",
100
- "MM-DD-YYYY",
101
- ])
102
- );
103
- const parsedWithKnownFormats = moment(s, formats, true);
104
- if (parsedWithKnownFormats.isValid()) {
105
- return parsedWithKnownFormats.toDate();
106
- }
107
-
108
- const date = new Date(s);
109
- return Number.isNaN(date.getTime()) ? null : date;
110
- }
111
-
112
- const date = new Date(value);
113
- return Number.isNaN(date.getTime()) ? null : date;
114
- };
115
-
116
-
117
- export const normalizeMultiSelectValueForStringArrayValues = (fieldConfig: FormFieldSchema, value: any): string[] => {
118
- if (fieldConfig.outputFormat === OutputFormatType.STRING) {
119
- return normalizeMultiSelectValue(value);
120
- }
121
- return value;
122
- };
123
-
124
-
125
- export const normalizeFileFieldUrls = (value: any): string[] => {
126
- if (value == null) return [];
127
-
128
- if (Array.isArray(value)) {
129
- return value.map((v) => String(v).trim()).filter(Boolean);
130
- }
131
-
132
- if (typeof value === 'string') {
133
- const s = value.trim();
134
- if (!s || s === '[]') return [];
135
- if (s.startsWith('[')) {
136
- try {
137
- const parsed = JSON.parse(s);
138
- if (Array.isArray(parsed)) {
139
- return parsed.map((v) => String(v).trim()).filter(Boolean);
140
- }
141
- } catch {
142
- // fall through — treat as single URL
143
- }
144
- }
145
- return [s];
146
- }
147
-
148
- return [];
149
- };