refactor: separation of shared components
This commit is contained in:
105
src/components/ui/PhoneInput/PhoneInput.tsx
Normal file
105
src/components/ui/PhoneInput/PhoneInput.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { IMaskInput } from "react-imask";
|
||||
import {
|
||||
InputBase,
|
||||
type InputBaseProps,
|
||||
type PolymorphicComponentProps,
|
||||
} from "@mantine/core";
|
||||
import CountrySelect from "@/components/ui/PhoneInput/components/CountrySelect";
|
||||
import { Country } from "@/components/ui/PhoneInput/types";
|
||||
import getInitialDataFromValue from "@/components/ui/PhoneInput/utils/getInitialDataFromValue";
|
||||
import getPhoneMask from "@/components/ui/PhoneInput/utils/getPhoneMask";
|
||||
|
||||
type AdditionalProps = {
|
||||
onChange: (value: string | null) => void;
|
||||
setPhoneMask: (mask: string) => void;
|
||||
initialCountryCode?: string;
|
||||
};
|
||||
|
||||
type InputProps = Omit<
|
||||
PolymorphicComponentProps<typeof IMaskInput, InputBaseProps>,
|
||||
"onChange" | "defaultValue" | "value"
|
||||
>;
|
||||
|
||||
export type Props = AdditionalProps & InputProps;
|
||||
|
||||
const PhoneInput = ({
|
||||
initialCountryCode = "RU",
|
||||
onChange: _onChange,
|
||||
setPhoneMask: _setPhoneMask,
|
||||
...props
|
||||
}: Props) => {
|
||||
const [mask, setMask] = useState<string>("");
|
||||
const initialData = useRef(getInitialDataFromValue(initialCountryCode));
|
||||
const [country, setCountry] = useState<Country>(
|
||||
initialData.current.country
|
||||
);
|
||||
const [value, setValue] = useState<string>("");
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [dropdownWidth, setDropdownWidth] = useState<number>(300);
|
||||
|
||||
const onChange = (numberWithoutCode: string) => {
|
||||
setValue(numberWithoutCode);
|
||||
_onChange(`+${country.callingCode} ${numberWithoutCode}`);
|
||||
};
|
||||
|
||||
const setPhoneMask = (phoneMask: string, country: Country) => {
|
||||
setMask(phoneMask);
|
||||
_setPhoneMask(`+${country.callingCode} ${phoneMask}`);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setPhoneMask(initialData.current.format, country);
|
||||
}, [initialData.current.format]);
|
||||
|
||||
const { readOnly, disabled } = props;
|
||||
const leftSectionWidth = 90;
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputRef.current?.offsetWidth) return;
|
||||
setDropdownWidth(inputRef.current?.offsetWidth);
|
||||
}, [inputRef.current?.offsetWidth]);
|
||||
|
||||
return (
|
||||
<InputBase
|
||||
{...props}
|
||||
component={IMaskInput}
|
||||
inputRef={inputRef}
|
||||
leftSection={
|
||||
<CountrySelect
|
||||
disabled={disabled || readOnly}
|
||||
country={country}
|
||||
setCountry={country => {
|
||||
setCountry(country);
|
||||
setPhoneMask(getPhoneMask(country.code), country);
|
||||
setValue("");
|
||||
if (inputRef.current) {
|
||||
inputRef.current.focus();
|
||||
}
|
||||
}}
|
||||
leftSectionWidth={leftSectionWidth}
|
||||
inputWidth={dropdownWidth}
|
||||
/>
|
||||
}
|
||||
leftSectionWidth={leftSectionWidth}
|
||||
styles={{
|
||||
input: {
|
||||
fontSize: 17,
|
||||
paddingLeft: `calc(${leftSectionWidth}px + var(--mantine-spacing-sm))`,
|
||||
},
|
||||
section: {
|
||||
borderRight:
|
||||
"1px solid var(--mantine-color-default-border)",
|
||||
},
|
||||
}}
|
||||
inputMode={"numeric"}
|
||||
mask={mask}
|
||||
value={value}
|
||||
onAccept={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PhoneInput;
|
||||
Reference in New Issue
Block a user