DocSpace-client/packages/components/input-phone/index.js

242 lines
6.5 KiB
JavaScript
Raw Normal View History

2022-10-10 07:21:28 +00:00
import { useState, useEffect } from "react";
2022-09-10 09:19:49 +00:00
import { options } from "./options";
2022-09-22 12:20:27 +00:00
import { FixedSizeList as List } from "react-window";
2022-10-03 13:41:15 +00:00
import { StyledBox } from "./styled-input-phone";
import InvalidSvgUrl from "PUBLIC_DIR/images/phoneFlags/invalid.svg?url";
2022-09-29 12:37:33 +00:00
import PropTypes from "prop-types";
2022-09-22 12:20:27 +00:00
import CustomScrollbarsVirtualList from "../scrollbar/custom-scrollbars-virtual-list";
2022-09-10 09:19:49 +00:00
import Box from "@docspace/components/box";
2022-10-03 13:41:15 +00:00
import ComboBox from "@docspace/components/combobox";
2022-10-05 11:36:34 +00:00
import Label from "@docspace/components/label";
2022-10-03 13:41:15 +00:00
import TextInput from "@docspace/components/text-input";
2022-10-04 17:09:54 +00:00
import SearchInput from "@docspace/components/search-input";
2022-10-03 13:41:15 +00:00
import DropDown from "@docspace/components/drop-down";
import DropDownItem from "@docspace/components/drop-down-item";
2022-10-03 09:44:39 +00:00
import Text from "@docspace/components/text";
2023-04-12 10:39:07 +00:00
const PLUS = "+";
const InputPhone = ({
defaultCountry,
onChange,
scaled,
phonePlaceholderText,
searchPlaceholderText,
searchEmptyMessage,
errorMessage,
} = props) => {
const [country, setCountry] = useState(defaultCountry);
2022-10-04 13:59:47 +00:00
const [phoneValue, setPhoneValue] = useState(country.dialCode);
2022-09-14 14:17:00 +00:00
const [searchValue, setSearchValue] = useState("");
2022-09-22 12:20:27 +00:00
const [filteredOptions, setFilteredOptions] = useState([]);
2022-09-14 14:17:00 +00:00
const [isOpen, setIsOpen] = useState(false);
2022-09-22 15:03:03 +00:00
const [isValid, setIsValid] = useState(true);
2022-09-07 17:56:40 +00:00
2022-10-04 13:59:47 +00:00
const onInputChange = (e) => {
2022-10-07 15:29:42 +00:00
const str = e.target.value.replace(/\D/g, "");
2022-10-10 07:21:28 +00:00
const el = options.find(
(option) => option.dialCode && str.startsWith(option.dialCode)
);
2022-09-28 07:08:49 +00:00
2022-10-10 07:21:28 +00:00
const singleСode = ["1", "7"];
const invalidCode = singleСode.find((code) => code === str);
2022-10-10 07:21:28 +00:00
if (e.target.value === "" || !e.target.value.includes(invalidCode)) {
2022-09-29 12:37:33 +00:00
setIsValid(false);
setCountry((prev) => ({ ...prev, icon: InvalidSvgUrl }));
2022-09-29 12:37:33 +00:00
}
2022-10-05 11:36:34 +00:00
setPhoneValue(e.target.value);
2022-09-28 07:08:49 +00:00
if (el) {
2022-09-28 14:18:07 +00:00
setIsValid(true);
setCountry({
locale: el.code,
2022-09-28 07:08:49 +00:00
mask: el.mask,
icon: el.flag,
2022-09-28 14:18:07 +00:00
});
2022-09-14 14:17:00 +00:00
}
onChange && onChange(e);
2022-09-10 09:19:49 +00:00
};
2022-09-28 14:18:07 +00:00
2022-10-04 17:09:54 +00:00
const onCountrySearch = (value) => {
setSearchValue(value);
};
const onClearSearch = () => {
setSearchValue("");
2022-09-28 14:18:07 +00:00
};
2022-09-10 09:19:49 +00:00
2022-09-22 12:20:27 +00:00
const getMask = (locale) => {
2022-09-28 14:18:07 +00:00
return options.find((option) => option.code === locale).mask;
2022-09-22 12:20:27 +00:00
};
2022-09-29 12:37:33 +00:00
const handleClick = () => {
2022-10-05 13:24:17 +00:00
setIsOpen(!isOpen);
2022-09-29 12:37:33 +00:00
};
2022-09-22 12:20:27 +00:00
useEffect(() => {
if (isOpen) {
setFilteredOptions(
options.filter(
(val) =>
2022-10-10 07:21:28 +00:00
val.name.toLowerCase().startsWith(searchValue.toLowerCase()) ||
val.dialCode.startsWith(searchValue.toLowerCase())
2022-09-22 12:20:27 +00:00
)
);
}
}, [isOpen, searchValue]);
2022-10-04 17:09:54 +00:00
const onCountryClick = (e) => {
const data = e.currentTarget.dataset.option;
const country = filteredOptions[data];
setIsOpen(!isOpen);
setCountry({
locale: country.code,
mask: country.mask,
icon: country.flag,
});
2022-10-05 13:24:17 +00:00
setIsValid(true);
2022-10-04 17:09:54 +00:00
setPhoneValue(country.dialCode);
};
2022-09-22 12:20:27 +00:00
const Row = ({ data, index, style }) => {
const country = data[index];
2022-10-07 15:29:42 +00:00
const prefix = "+";
2022-09-22 12:20:27 +00:00
return (
2022-10-03 13:41:15 +00:00
<DropDownItem
2022-09-22 12:20:27 +00:00
key={country.code}
2022-10-03 09:44:39 +00:00
style={style}
2022-09-22 12:20:27 +00:00
icon={country.flag}
fillIcon={false}
2022-10-03 13:41:15 +00:00
className="country-item"
2022-10-04 13:59:47 +00:00
data-option={index}
onClick={onCountryClick}
2022-09-22 12:20:27 +00:00
>
2022-10-03 13:41:15 +00:00
<Text className="country-name">{country.name}</Text>
2022-10-07 15:29:42 +00:00
<Text className="country-prefix">{prefix}</Text>
<Text className="country-dialcode">{country.dialCode}</Text>
2022-10-03 13:41:15 +00:00
</DropDownItem>
2022-09-22 12:20:27 +00:00
);
};
2022-09-15 12:52:39 +00:00
2022-09-07 14:53:27 +00:00
return (
2022-10-05 13:24:17 +00:00
<StyledBox
hasError={!isValid}
displayProp="flex"
alignItems="center"
scaled={scaled}
2022-10-05 13:24:17 +00:00
>
2022-10-03 13:41:15 +00:00
<ComboBox
options={[]}
noBorder={true}
2022-10-06 15:07:49 +00:00
opened={isOpen}
data="country"
toggleAction={handleClick}
displayType="toggle"
2022-10-03 13:41:15 +00:00
className="country-box"
2022-10-06 15:07:49 +00:00
fillIcon={true}
2022-10-03 13:41:15 +00:00
selectedOption={country}
/>
2023-04-12 10:39:07 +00:00
<Label text={PLUS} className="prefix" />
2022-10-03 13:41:15 +00:00
<TextInput
type="tel"
className="input-phone"
placeholder={phonePlaceholderText}
2022-10-03 13:41:15 +00:00
mask={getMask(country.locale)}
withBorder={false}
tabIndex={1}
2022-10-04 13:59:47 +00:00
value={phoneValue}
onChange={onInputChange}
2022-10-03 13:41:15 +00:00
/>
<DropDown
open={isOpen}
clickOutsideAction={handleClick}
isDefaultMode={false}
className="drop-down"
manualWidth="100%"
>
2022-10-04 17:09:54 +00:00
<SearchInput
placeholder={searchPlaceholderText}
2022-10-03 13:41:15 +00:00
value={searchValue}
2022-10-05 13:24:17 +00:00
className="search-country_input"
2022-10-03 13:41:15 +00:00
scale={true}
2022-10-04 17:09:54 +00:00
onClearSearch={onClearSearch}
refreshTimeout={100}
2022-10-04 13:59:47 +00:00
onChange={onCountrySearch}
2022-09-22 15:03:03 +00:00
/>
2022-10-03 13:41:15 +00:00
<Box marginProp="6px 0 0">
{filteredOptions.length ? (
<List
itemData={filteredOptions}
height={108}
itemCount={filteredOptions.length}
itemSize={36}
outerElementType={CustomScrollbarsVirtualList}
width="auto"
>
{Row}
</List>
) : (
2022-10-05 13:24:17 +00:00
<Text
textAlign="center"
className="phone-input_empty-text"
fontSize="14px"
>
{searchEmptyMessage}
2022-10-03 13:41:15 +00:00
</Text>
)}
</Box>
</DropDown>
2022-10-06 15:07:49 +00:00
2022-10-03 09:44:39 +00:00
{!isValid && (
<Text
2022-10-05 13:24:17 +00:00
className="phone-input_error-text"
2022-10-03 09:44:39 +00:00
color="#f21c0e"
fontSize="11px"
lineHeight="14px"
>
{errorMessage}
2022-10-03 09:44:39 +00:00
</Text>
)}
2022-10-03 13:41:15 +00:00
</StyledBox>
2022-09-07 14:53:27 +00:00
);
2022-10-04 13:59:47 +00:00
};
2022-09-29 12:37:33 +00:00
InputPhone.propTypes = {
/** Default selected country */
2022-09-29 12:37:33 +00:00
defaultCountry: PropTypes.object.isRequired,
/** Text displayed on the Input placeholder */
phonePlaceholderText: PropTypes.string,
/** Text displayed on the SearchInput placeholder */
searchPlaceholderText: PropTypes.string,
/** Indicates that the input field has scaled */
2022-10-05 14:19:50 +00:00
scaled: PropTypes.bool,
/** The callback function that is called when the value is changed */
2022-09-29 12:37:33 +00:00
onChange: PropTypes.func,
/** Gets the country mask */
searchEmptyMessage: PropTypes.string,
/** Text displayed in case of the invalid country dial code */
2022-09-29 12:37:33 +00:00
errorMessage: PropTypes.string,
};
InputPhone.defaultProps = {
defaultCountry: {
locale: options[182].code, // default locale RU
dialCode: options[182].dialCode, // default dialCode +7
mask: options[182].mask, // default Russia mask
icon: options[182].flag, // default Russia flag
2022-09-29 12:37:33 +00:00
},
2022-10-04 13:59:47 +00:00
phonePlaceholderText: "",
searchPlaceholderText: "",
2022-10-05 14:19:50 +00:00
scaled: false,
2022-10-04 13:59:47 +00:00
searchEmptyMessage: "",
errorMessage: "",
2022-09-29 12:37:33 +00:00
};
InputPhone.displayName = "InputPhone";
2022-10-05 13:24:17 +00:00
2022-10-10 07:21:28 +00:00
export default InputPhone;