Files
graff.training/src/components/Main/ModalWithForm.tsx
T

259 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
FormEvent,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import ReactInputMask from 'react-input-mask';
import { ArrowRightIcon } from '../icons/ArrowRightIcon';
import { CloseIcon } from '../icons/CloseIcon';
import { LoaderIcon } from '../icons/LoaderIcon';
import { api } from '../../api/contactsFormInstance';
import { Button } from '../../ui/Button';
import { useModalStore } from '../../store/modalStore';
import { SelectPhoneCode } from './SelectPhoneCode';
import { Country } from 'react-phone-number-input';
import { getExampleNumber } from 'libphonenumber-js';
import examples from 'libphonenumber-js/mobile/examples';
import { ClassNameWrapper } from '../../hocs/ClassNameWrapper';
import { NavLink } from 'react-router-dom';
export function ModalWithForm() {
const { setModal } = useModalStore();
const [name, setName] = useState('');
const [[phoneCode, country], setPhoneCodeAndCountry] = useState<
[string, Country]
>(['+7', 'RU']);
const [phone, setPhone] = useState('');
const [email, setEmail] = useState('');
const [description, setDescription] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [isSend, setIsSend] = useState(false);
const placeholder = useMemo(
() =>
getExampleNumber(country, examples)
?.formatInternational()
.split(' ')
.slice(1)
.join(' '),
[country],
);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
if (textAreaRef.current) {
textAreaRef.current.style.height = 'auto';
textAreaRef.current.style.height =
textAreaRef.current.scrollHeight + 'px';
}
}, [textAreaRef, description]);
function handleSubmit(e: FormEvent<HTMLFormElement>) {
e.preventDefault();
sendMail();
}
async function sendMail() {
setIsLoading(true);
try {
await api
.post('mail', {
json: {
fullname: name,
phone: phoneCode + phone,
email,
request: description,
},
})
.json();
setIsSend(true);
setIsLoading(false);
} catch (error) {
setIsLoading(false);
if (error instanceof Error) {
alert(error.message);
}
}
}
const listener = useCallback(
(e: KeyboardEvent) => {
if (e.key === 'Escape') {
setModal(false);
}
},
[setModal],
);
useEffect(() => {
document.addEventListener('keydown', listener);
return () => document.removeEventListener('keydown', listener);
}, [listener, setModal]);
return (
<div className="fixed flex flex-col gap-4 top-0 right-0 h-full sm:w-[408px] w-full bg-[#14161F] overflow-y-auto sm:p-8 p-6">
{!isSend ? (
<div className="space-y-8">
<div className="flex items-center justify-between">
<p className="font-medium accent">Оставьте заявку</p>
<button
onClick={() => setModal(null)}
className="p-2 transition-colors rounded-full lg:hover:bg-white lg:hover:bg-opacity-10"
>
<CloseIcon />
</button>
</div>
<form onSubmit={handleSubmit}>
<div className="space-y-6">
<hr className="border-[#3D425C]" />
<div>
<label
className="m-text text-[#9299BD] select-none"
htmlFor="name"
>
Имя
</label>
<input
required
id="name"
type="text"
value={name}
onChange={e => setName(e.target.value)}
placeholder="Ваше имя"
className="bg-transparent border-b border-[#3D425C] focus:border-white py-4 rounded-none outline-none transition-all w-full placeholder:h4 placeholder:font-medium placeholder:select-none"
/>
</div>
<div>
<label
className="m-text text-[#9299BD] select-none"
htmlFor="tel"
>
Телефон
</label>
<div className="flex gap-x-3 py-2 border-[#3D425C] relative">
<SelectPhoneCode
currentPhoneCodeAndCountry={[phoneCode, country]}
onClick={setPhoneCodeAndCountry}
/>
<div className="border-l border-[#3D425C]" />
<ReactInputMask
required
type="tel"
id={'tel'}
mask={placeholder?.replace(/\d/g, '9') ?? ''}
maskChar={null}
value={phone}
placeholder={placeholder}
onChange={e => setPhone(e.target.value.replace(/ /g, ''))}
className="w-full transition-all bg-transparent rounded-none outline-none h4 placeholder:h4 placeholder:font-medium placeholder:select-none peer"
/>
<div className="bottom-0 absolute w-full border-b border-[#3D425C] peer-focus:border-white -mb-2" />
</div>
</div>
<div>
<label
className="m-text text-[#9299BD] select-none"
htmlFor="email"
>
Email*
</label>
<input
required
id="email"
type="text"
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="Ваш email"
className="bg-transparent border-b border-[#3D425C] focus:border-white py-4 rounded-none outline-none transition-all w-full placeholder:h4 placeholder:font-medium placeholder:select-none"
/>
</div>
<div>
<label
className="m-text text-[#9299BD] select-none"
htmlFor="description"
>
Задача
</label>
<textarea
ref={textAreaRef}
id="description"
placeholder="Опишите вашу задачу"
value={description}
rows={1}
onChange={e => setDescription(e.target.value)}
className="bg-transparent border-b py-4 focus:border-white max-h-[300px] h-auto rounded-none border-[#3D425C] resize-none outline-none transition-all w-full placeholder:h4 placeholder:font-medium placeholder:select-none placeholder-shown:overflow-hidden"
/>
</div>
</div>
<Button
width="full"
disabled={isLoading}
className="px-6 py-3 mt-12"
onClick={() => `ym(98587267, 'reachGoal', 'submit_form');`}
icon={
isLoading ? (
<LoaderIcon className="relative w-6 h-6 animate-spin" />
) : (
<div className="p-2 bg-white rounded-full">
<ClassNameWrapper
element={<ArrowRightIcon />}
className="text-black"
/>
</div>
)
}
>
Отправить
</Button>
<p className="m-caption mt-6 text-center text-[#52587A]">
Нажимая кнопку отправить, вы даете
<span className="text-gradient">
{' '}
<NavLink to="/privacy-policy" target="_blank">
согласие на обработку персональных данных
</NavLink>
</span>
&nbsp;и принимаете условия&nbsp;
<span className="text-gradient">
<NavLink to="/policy" target="_blank">
политики
</NavLink>
</span>
</p>
</form>
</div>
) : (
<div className="">
<div className="space-y-8">
<h2 className="font-medium h2">Спасибо за отправку заявки!</h2>
<p className="m-text">
Мы ценим ваш интерес к нашей компании и в ближайшее время свяжемся
с вами для уточнения деталей проекта.
</p>
</div>
<Button
width="full"
className="py-5 px-6 absolute top-[50vh]"
icon={<ArrowRightIcon className="w-6 h-6" />}
onClick={() => setModal(false)}
>
На главную
</Button>
</div>
)}
</div>
);
}