From 8b55dfa939b7563b9fcd7483f25a51b306a1694d Mon Sep 17 00:00:00 2001 From: Shaurya Sharma Date: Fri, 28 Mar 2025 02:55:42 +0530 Subject: [PATCH] Minor fixes and added email and phone input to form --- .../Widgets/BaseComponents/hooks/useInput.js | 13 +- .../src/AppBuilder/Widgets/Form/FormUtils.js | 11 + .../AppBuilder/Widgets/Form/RenderSchema.jsx | 1 + .../src/AppBuilder/Widgets/PhoneInput.jsx | 476 ------------------ .../Widgets/PhoneInput/CountrySelect.jsx | 137 +++++ .../Widgets/PhoneInput/CustomMenuList.jsx | 51 ++ .../Widgets/PhoneInput/CustomOption.jsx | 37 ++ .../PhoneInput/CustomValueContainer.jsx | 28 ++ .../Widgets/PhoneInput/PhoneInput.jsx | 254 ++++++++++ .../AppBuilder/Widgets/PhoneInput/utils.js | 10 + .../src/AppBuilder/_helpers/editorHelpers.js | 2 +- 11 files changed, 532 insertions(+), 488 deletions(-) delete mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/CustomMenuList.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx create mode 100644 frontend/src/AppBuilder/Widgets/PhoneInput/utils.js diff --git a/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js b/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js index b46ab8939e..fff7f091ae 100644 --- a/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js +++ b/frontend/src/AppBuilder/Widgets/BaseComponents/hooks/useInput.js @@ -1,5 +1,6 @@ import { useState, useRef, useEffect } from 'react'; import { useGridStore } from '@/_stores/gridStore'; +//eslint-disable-next-line import/no-unresolved import { getCountryCallingCode } from 'react-phone-number-input'; export const useInput = ({ @@ -29,7 +30,7 @@ export const useInput = ({ const [isFocused, setIsFocused] = useState(false); const [labelWidth, setLabelWidth] = useState(0); const [iconVisibility, setIconVisibility] = useState(false); - const [country, setCountry] = useState(properties.defaultCountry); + const [country, setCountry] = useState(properties.defaultCountry || 'US'); const { isValid, validationError } = validationStatus; const isMandatory = validation?.mandatory ?? false; @@ -96,7 +97,6 @@ export const useInput = ({ }, [validate]); useEffect(() => { - if (isInitialRender.current) return; if (inputType === 'phone') { let code = getCountryCallingCodeSafe(country); setInputValue(`+${code}${properties.value}`); @@ -105,15 +105,6 @@ export const useInput = ({ } }, [properties.value]); - // useEffect(() => { - // if (isInitialRender.current && inputType!=="phone") return; - - // setExposedVariable('setValue', - // async function (value,country){ - - // } - // ) - useEffect(() => { if (inputType !== 'phone') return; setExposedVariable('setValue', async function (value, countryCode = country) { diff --git a/frontend/src/AppBuilder/Widgets/Form/FormUtils.js b/frontend/src/AppBuilder/Widgets/Form/FormUtils.js index f8366e0b29..9769257b58 100644 --- a/frontend/src/AppBuilder/Widgets/Form/FormUtils.js +++ b/frontend/src/AppBuilder/Widgets/Form/FormUtils.js @@ -97,6 +97,8 @@ export function generateUIComponents(JSONSchema, advanced, componentName = '') { if (uiComponentsDraft?.length > 0 && uiComponentsDraft[index * 2 + 1]) { switch (typeResolver(value?.type)) { case 'TextInput': + case 'EmailInput': + case 'PhoneInput': if (value?.styles?.backgroundColor) uiComponentsDraft[index * 2 + 1]['definition']['styles']['backgroundColor'] = value?.styles?.backgroundColor; @@ -127,6 +129,11 @@ export function generateUIComponents(JSONSchema, advanced, componentName = '') { if (value?.value) uiComponentsDraft[index * 2 + 1]['definition']['properties']['value'] = value?.value; if (value?.placeholder) uiComponentsDraft[index * 2 + 1]['definition']['properties']['placeholder'] = value?.placeholder; + + if (value?.defaultCountry && typeResolver(value?.type) === 'PhoneInput') { + uiComponentsDraft[index * 2 + 1]['definition']['properties']['defaultCountry'] = value?.defaultCountry; + } + // prevent label from showing up in text input, because it is already shown in the text component. (Defaults to "Label" if not updated explicitly with an empty string) uiComponentsDraft[index * 2 + 1]['definition']['properties']['label'] = ''; break; @@ -482,6 +489,10 @@ const typeResolver = (type) => { return 'DropDown'; case 'button': return 'Button'; + case 'emailinput': + return 'EmailInput'; + case 'phoneinput': + return 'PhoneInput'; case 'text': return 'Text'; case 'number': diff --git a/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx b/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx index b5bfa9e4c3..89d34b65c7 100644 --- a/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx +++ b/frontend/src/AppBuilder/Widgets/Form/RenderSchema.jsx @@ -26,6 +26,7 @@ const RenderSchema = ({ component, parent, id, onOptionChange, onOptionsChange, return validateWidget({ ...{ widgetValue: value }, ...{ validationObject: component.definition.validation }, + componentType: component?.component, }); }, [component.definition.validation] diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput.jsx deleted file mode 100644 index e55ec4b659..0000000000 --- a/frontend/src/AppBuilder/Widgets/PhoneInput.jsx +++ /dev/null @@ -1,476 +0,0 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; -import Input, { getCountries, getCountryCallingCode } from 'react-phone-number-input/input'; -import en from 'react-phone-number-input/locale/en'; -import flags from 'react-phone-number-input/flags'; -import 'react-phone-number-input/style.css'; -import Select, { components } from 'react-select'; -import cx from 'classnames'; -import SolidIcon from '@/_ui/Icon/SolidIcons'; -import { useInput } from './BaseComponents/hooks/useInput'; -import Loader from '@/ToolJetUI/Loader/Loader'; -import Label from '@/_ui/Label'; -import TickV3 from '@/_ui/Icon/solidIcons/TickV3'; -import Planet from '@/_ui/Icon/bulkIcons/Planet'; -const tinycolor = require('tinycolor2'); - -export const PhoneInput = (props) => { - const { properties, styles, componentName, darkMode, height, setExposedVariable, setExposedVariables, fireEvent } = - props; - const transformedProps = { - ...props, - inputType: 'phone', - }; - const inputLogic = useInput(transformedProps); - const { - inputRef, - labelRef, - visibility, - loading, - disable, - validationStatus, - showValidationError, - isFocused, - labelWidth, - isValid, - validationError, - isMandatory, - handleBlur, - handleFocus, - value, - handlePhoneInputChange, - country, - setCountry, - } = inputLogic; - const { label, placeholder, isCountryChangeEnabled, defaultCountry = 'US' } = properties; - - const { - padding, - textColor, - backgroundColor, - alignment, - width, - direction, - auto, - color, - borderColor, - accentColor, - errTextColor, - boxShadow, - borderRadius, - } = styles; - const _width = (width / 100) * 70; - const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side'; - const isInitialRender = useRef(true); - - const getCountryCallingCodeSafe = (country) => { - try { - return getCountryCallingCode(country); - } catch (error) { - return ''; - } - }; - - const options = useMemo( - () => - getCountries().map((country) => ({ - label: `${en[country]} +${getCountryCallingCodeSafe(country)}`, - value: country, - })), - [] - ); - - const onInputValueChange = (value) => { - setExposedVariables({ - country: country, - countryCode: getCountryCallingCodeSafe(country), - formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`, - }); - handlePhoneInputChange(value); - }; - - const handleKeyUp = (e) => { - if (e.key === 'Enter') { - onInputValueChange(value); - fireEvent('onEnterPressed'); - } - }; - - useEffect(() => { - if (isInitialRender.current) { - setExposedVariables({ - country: country, - countryCode: getCountryCallingCodeSafe(country), - formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`, - value: value, - setCountryCode: (code) => { - let value = getCountryCallingCodeSafe(code); - if (value) { - setCountry(code); - } else { - value = getCountries().find((country) => `+${getCountryCallingCode(country)}` === code); - setCountry(value ? value : ''); - } - }, - }); - isInitialRender.current = false; - } - }, []); - - useEffect(() => { - if (!isInitialRender.current) { - setCountry(defaultCountry); - } - }, [defaultCountry]); - - const disabledState = disable || loading; - - const loaderStyle = { - right: - direction === 'right' && - defaultAlignment === 'side' && - ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) - ? `${labelWidth + 11}px` - : '11px', - top: - defaultAlignment === 'top' - ? ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) && - 'calc(50% + 10px)' - : '', - transform: - defaultAlignment === 'top' && - ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) && - ' translateY(-50%)', - zIndex: 3, - }; - - const computedStyles = { - height: height == 36 ? (padding == 'default' ? '36px' : '40px') : padding == 'default' ? height : height + 4, - borderRadius: `${borderRadius}px`, - color: !['#1B1F24', '#000', '#000000ff'].includes(textColor) - ? textColor - : disabledState - ? 'var(--text-disabled)' - : 'var(--text-primary)', - borderColor: isFocused - ? accentColor != '4368E3' - ? accentColor - : 'var(--primary-accent-strong)' - : borderColor != '#CCD1D5' - ? borderColor - : disabledState - ? '1px solid var(--borders-disabled-on-white)' - : 'var(--borders-default)', - '--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(), - backgroundColor: - backgroundColor != '#fff' - ? backgroundColor - : disabledState - ? darkMode - ? 'var(--surfaces-app-bg-default)' - : 'var(--surfaces-surface-03)' - : 'var(--surfaces-surface-01)', - padding: '8px 10px', - overflow: 'hidden', - textOverflow: 'ellipsis', - borderBottomLeftRadius: '0px', - borderTopLeftRadius: '0px', - borderLeft: 'none', - }; - - const CustomValueContainer = ({ getValue, ...props }) => { - const selectedValue = getValue()[0]; - const FlagIcon = selectedValue ? flags[selectedValue.value] : null; - const countryCode = getCountryCallingCodeSafe(selectedValue.value); - - return ( - - {FlagIcon ? ( -
- <> - {` +${countryCode}`} - -
- ) : ( -
- -
- )} -
- ); - }; - - const CustomOption = (props) => { - const { label, value: optionValue, isSelected } = props; - const optionStyle = { - display: 'flex', - alignItems: 'center', - justifyContent: 'start', - minHeight: '32px', - gap: '6px', - cursor: 'pointer', - fontFamily: 'IBM Plex Sans', - fontSize: '12px', - lineHeight: '18px', - fontWeight: '400', - color: darkMode ? '#fff' : '#1B1F24', - width: '100%', - }; - console.log('darkMode', darkMode); - const FlagIcon = flags[optionValue]; - - return ( - -
-
{FlagIcon ? : null}
- {label} -
- -
-
-
- ); - }; - - const CustomMenuList = (props) => { - const { children, selectProps } = props; - const { onInputChange, inputValue } = selectProps; - - return ( -
e.stopPropagation()} - > -
- - - - { - onInputChange(e.currentTarget.value, { - action: 'input-change', - }); - }} - onMouseDown={(e) => { - e.stopPropagation(); - e.target.focus(); - }} - onTouchEnd={(e) => { - e.stopPropagation(); - e.target.focus(); - }} - /> -
- - - {children?.length > 0 ? children :
No options
} -
-
- ); - }; - - const CountrySelect = ({ value, onChange, options, ...rest }) => { - const [menuIsOpen, setMenuIsOpen] = useState(false); - const dropdownRef = useRef(null); - - useEffect(() => { - const handleClickOutside = (event) => { - if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { - setMenuIsOpen(false); - } - }; - - // Add event listener when dropdown is open - if (menuIsOpen) { - document.addEventListener('mousedown', handleClickOutside); - } - - // Clean up the event listener - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [menuIsOpen]); - - const customStyles = { - container: (provided) => ({ - ...provided, - minWidth: !isCountryChangeEnabled || disabledState ? '77px' : '87px', - width: !isCountryChangeEnabled || disabledState ? '77px' : '87px', - height: '100%', - }), - control: (provided, state) => ({ - ...provided, - minHeight: '0px', - height: '100%', - borderTopLeftRadius: `${borderRadius}px`, - borderBottomLeftRadius: `${borderRadius}px`, - borderTopRightRadius: '0px', - borderBottomRightRadius: '0px', - borderColor: `${ - !isValid && showValidationError ? 'var(--status-error-strong)' : computedStyles?.borderColor - } !important`, - backgroundColor: `${ - isCountryChangeEnabled - ? computedStyles?.backgroundColor - : darkMode - ? 'var(--surfaces-app-bg-default)' - : 'var(--surfaces-surface-03)' - } !important`, - }), - menu: (provided) => ({ - ...provided, - width: '208px', - height: '236px', - borderRadius: '8px', - marginTop: '2px', - }), - menuList: (provided) => ({ - ...provided, - maxHeight: '196px', - overflowY: 'auto', - scrollbarWidth: 'none', - gap: '1px', - padding: '8px', - borderRadius: '0px 0px 8px 8px', - display: 'flex', - flexDirection: 'column', - backgroundColor: 'var(--surfaces-surface-01)', - }), - option: (provided, state) => ({ - ...provided, - backgroundColor: state.isSelected ? '#4368E31A' : 'var(--surfaces-surface-01)', - ...(state.isSelected && { borderRadius: '8px' }), - '&:hover': { - backgroundColor: 'var(--interactive-overlays-fill-hover)', - borderRadius: '8px', - }, - display: 'flex', - cursor: 'pointer', - padding: '1px 14px', - }), - }; - - return ( -
setMenuIsOpen((prev) => !prev)} ref={dropdownRef}> - -
- {loading && } - - {showValidationError && visibility && ( -
- {validationError} -
- )} - - ); -}; diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx new file mode 100644 index 0000000000..240c44d0f6 --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CountrySelect.jsx @@ -0,0 +1,137 @@ +import React, { useEffect, useRef, useState } from 'react'; +import Select from 'react-select'; +import SolidIcon from '@/_ui/Icon/SolidIcons'; +import { CustomMenuList } from './CustomMenuList'; +import { CustomOption } from './CustomOption'; +import { CustomValueContainer } from './CustomValueContainer'; + +export const CountrySelect = ({ value, onChange, options, ...rest }) => { + const { + isCountryChangeEnabled, + disabledState, + borderRadius, + isValid, + showValidationError, + computedStyles, + darkMode, + } = rest; + const [menuIsOpen, setMenuIsOpen] = useState(false); + const dropdownRef = useRef(null); + + useEffect(() => { + const handleClickOutside = (event) => { + if (dropdownRef.current && !dropdownRef.current.contains(event.target)) { + setMenuIsOpen(false); + } + }; + + if (menuIsOpen) { + document.addEventListener('mousedown', handleClickOutside); + } + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [menuIsOpen]); + + const customStyles = { + container: (provided) => ({ + ...provided, + minWidth: !isCountryChangeEnabled || disabledState ? '77px' : '87px', + width: !isCountryChangeEnabled || disabledState ? '77px' : '87px', + height: '100%', + }), + control: (provided) => ({ + ...provided, + minHeight: '0px', + height: '100%', + borderTopLeftRadius: `${borderRadius}px`, + borderBottomLeftRadius: `${borderRadius}px`, + borderTopRightRadius: '0px', + borderBottomRightRadius: '0px', + borderColor: `${ + !isValid && showValidationError ? 'var(--status-error-strong)' : computedStyles?.borderColor + } !important`, + backgroundColor: `${ + isCountryChangeEnabled + ? computedStyles?.backgroundColor + : darkMode + ? 'var(--surfaces-app-bg-default)' + : 'var(--surfaces-surface-03)' + } !important`, + }), + menu: (provided) => ({ + ...provided, + width: '208px', + height: '236px', + borderRadius: '8px', + marginTop: '2px', + }), + menuList: (provided) => ({ + ...provided, + maxHeight: '196px', + overflowY: 'auto', + scrollbarWidth: 'none', + gap: '1px', + padding: '8px', + borderRadius: '0px 0px 8px 8px', + display: 'flex', + flexDirection: 'column', + backgroundColor: 'var(--surfaces-surface-01)', + }), + option: (provided, state) => ({ + ...provided, + backgroundColor: state.isSelected ? '#4368E31A' : 'var(--surfaces-surface-01)', + ...(state.isSelected && { borderRadius: '8px' }), + '&:hover': { + backgroundColor: 'var(--interactive-overlays-fill-hover)', + borderRadius: '8px', + }, + display: 'flex', + cursor: 'pointer', + padding: '1px 14px', + }), + }; + return ( +
{ + if (disabledState || !isCountryChangeEnabled) return; + setMenuIsOpen((prev) => !prev); + }} + ref={dropdownRef} + > + { + onInputChange(e.currentTarget.value, { + action: 'input-change', + }); + }} + onMouseDown={(e) => { + e.stopPropagation(); + e.target.focus(); + }} + onTouchEnd={(e) => { + e.stopPropagation(); + e.target.focus(); + }} + /> +
+ + + {children?.length > 0 ? children :
No options
} +
+ + ); +}; diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx new file mode 100644 index 0000000000..8f3b9d7dac --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomOption.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { components } from 'react-select'; +// eslint-disable-next-line import/no-unresolved +import flags from 'react-phone-number-input/flags'; +import TickV3 from '@/_ui/Icon/solidIcons/TickV3'; + +export const CustomOption = (props) => { + const { label, value: optionValue, isSelected, darkMode } = props; + + const optionStyle = { + display: 'flex', + alignItems: 'center', + justifyContent: 'start', + minHeight: '32px', + gap: '6px', + cursor: 'pointer', + fontFamily: 'IBM Plex Sans', + fontSize: '12px', + lineHeight: '18px', + fontWeight: '400', + color: darkMode ? '#fff' : '#1B1F24', + width: '100%', + }; + const FlagIcon = flags[optionValue]; + + return ( + +
+
{FlagIcon ? : null}
+ {label} +
+ +
+
+
+ ); +}; diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx new file mode 100644 index 0000000000..bf2ad0b5b7 --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/PhoneInput/CustomValueContainer.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { components } from 'react-select'; +// eslint-disable-next-line import/no-unresolved +import flags from 'react-phone-number-input/flags'; +import Planet from '@/_ui/Icon/bulkIcons/Planet'; +import { getCountryCallingCodeSafe } from './utils'; + +export const CustomValueContainer = ({ getValue, ...props }) => { + const selectedValue = getValue()[0]; + const FlagIcon = selectedValue ? flags[selectedValue.value] : null; + const countryCode = getCountryCallingCodeSafe(selectedValue.value); + + return ( + + {FlagIcon ? ( +
+ <> + {` +${countryCode}`} + +
+ ) : ( +
+ +
+ )} +
+ ); +}; diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx b/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx new file mode 100644 index 0000000000..ce7bc39fe8 --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/PhoneInput/PhoneInput.jsx @@ -0,0 +1,254 @@ +import React, { useEffect, useMemo, useRef } from 'react'; +// eslint-disable-next-line import/no-unresolved +import Input, { getCountries, getCountryCallingCode } from 'react-phone-number-input/input'; +import { getCountryCallingCodeSafe } from './utils'; +// eslint-disable-next-line import/no-unresolved +import en from 'react-phone-number-input/locale/en'; +import 'react-phone-number-input/style.css'; +import { useInput } from '../BaseComponents/hooks/useInput'; +import Loader from '@/ToolJetUI/Loader/Loader'; +import Label from '@/_ui/Label'; +import { CountrySelect } from './CountrySelect'; + +const tinycolor = require('tinycolor2'); + +export const PhoneInput = (props) => { + const { properties, styles, componentName, darkMode, setExposedVariables, fireEvent } = props; + const transformedProps = { + ...props, + inputType: 'phone', + }; + const inputLogic = useInput(transformedProps); + const { + inputRef, + labelRef, + visibility, + loading, + disable, + showValidationError, + isFocused, + labelWidth, + isValid, + validationError, + isMandatory, + handleBlur, + handleFocus, + value, + handlePhoneInputChange, + country, + setCountry, + } = inputLogic; + const { label, placeholder, isCountryChangeEnabled, defaultCountry = 'US' } = properties; + + const { + textColor, + backgroundColor, + alignment, + width, + direction, + auto, + color, + borderColor, + accentColor, + errTextColor, + boxShadow, + borderRadius, + } = styles; + const _width = (width / 100) * 70; + const defaultAlignment = alignment === 'side' || alignment === 'top' ? alignment : 'side'; + const isInitialRender = useRef(true); + + const options = useMemo( + () => + getCountries() + .map((country) => ({ + label: `${en[country]} +${getCountryCallingCodeSafe(country)}`, + value: country, + })) + .sort((a, b) => a.label.localeCompare(b.label)), + [] + ); + + const onInputValueChange = (value) => { + setExposedVariables({ + country: country, + countryCode: `+${getCountryCallingCodeSafe(country)}`, + formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`, + }); + handlePhoneInputChange(value); + }; + + const handleKeyUp = (e) => { + if (e.key === 'Enter') { + fireEvent('onEnterPressed'); + } + }; + + useEffect(() => { + if (isInitialRender.current) { + setExposedVariables({ + country: country, + countryCode: `+${getCountryCallingCodeSafe(country)}`, + formattedValue: `+${getCountryCallingCodeSafe(country)} ${inputRef.current?.value}`, + value: value, + setCountryCode: (code) => { + let value = getCountryCallingCodeSafe(code); + if (value) { + setCountry(code); + } else { + value = getCountries().find((country) => `+${getCountryCallingCode(country)}` === code); + setCountry(value ? value : ''); + } + }, + }); + isInitialRender.current = false; + } + }, []); + + useEffect(() => { + if (!isInitialRender.current) { + setCountry(defaultCountry); + } + }, [defaultCountry]); + + const disabledState = disable || loading; + + const loaderStyle = { + right: + direction === 'right' && + defaultAlignment === 'side' && + ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) + ? `${labelWidth + 11}px` + : '11px', + top: + defaultAlignment === 'top' + ? ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) && + 'calc(50% + 10px)' + : '', + transform: + defaultAlignment === 'top' && + ((label?.length > 0 && width > 0) || (auto && width == 0 && label && label?.length != 0)) && + ' translateY(-50%)', + zIndex: 3, + }; + + const computedStyles = { + height: '100%', + borderRadius: `${borderRadius}px`, + color: !['#1B1F24', '#000', '#000000ff'].includes(textColor) + ? textColor + : disabledState + ? 'var(--text-disabled)' + : 'var(--text-primary)', + borderColor: isFocused + ? accentColor != '4368E3' + ? accentColor + : 'var(--primary-accent-strong)' + : borderColor != '#CCD1D5' + ? borderColor + : disabledState + ? '1px solid var(--borders-disabled-on-white)' + : 'var(--borders-default)', + '--tblr-input-border-color-darker': tinycolor(borderColor).darken(24).toString(), + backgroundColor: + backgroundColor != '#fff' + ? backgroundColor + : disabledState + ? darkMode + ? 'var(--surfaces-app-bg-default)' + : 'var(--surfaces-surface-03)' + : 'var(--surfaces-surface-01)', + padding: '8px 10px', + overflow: 'hidden', + textOverflow: 'ellipsis', + borderBottomLeftRadius: '0px', + borderTopLeftRadius: '0px', + borderLeft: 'none', + }; + + return ( + <> +
+
+ {showValidationError && visibility && ( +
+ {validationError} +
+ )} + + ); +}; diff --git a/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js b/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js new file mode 100644 index 0000000000..9a23b45ca5 --- /dev/null +++ b/frontend/src/AppBuilder/Widgets/PhoneInput/utils.js @@ -0,0 +1,10 @@ +// eslint-disable-next-line import/no-unresolved +import { getCountryCallingCode } from 'react-phone-number-input/input'; + +export const getCountryCallingCodeSafe = (country) => { + try { + return getCountryCallingCode(country); + } catch (error) { + return ''; + } +}; diff --git a/frontend/src/AppBuilder/_helpers/editorHelpers.js b/frontend/src/AppBuilder/_helpers/editorHelpers.js index 53906f7d4a..504a09b92c 100644 --- a/frontend/src/AppBuilder/_helpers/editorHelpers.js +++ b/frontend/src/AppBuilder/_helpers/editorHelpers.js @@ -31,7 +31,7 @@ import { Divider } from '@/Editor/Components/Divider'; import { FilePicker } from '@/Editor/Components/FilePicker'; import { PasswordInput } from '@/AppBuilder/Widgets/PasswordInput'; import { EmailInput } from '@/AppBuilder/Widgets/EmailInput'; -import { PhoneInput } from '@/AppBuilder/Widgets/PhoneInput'; +import { PhoneInput } from '@/AppBuilder/Widgets/PhoneInput/PhoneInput'; // import { Calendar } from '@/Editor/Components/Calendar'; // import { Listview } from '@/Editor/Components/Listview'; import { IFrame } from '@/Editor/Components/IFrame';