fix: add forms sending
This commit is contained in:
@@ -1,20 +1,103 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import s from './styles.module.scss';
|
import s from './styles.module.scss';
|
||||||
import { Button, Input, PhoneInput } from '@shared/ui';
|
import { Button, Input, PhoneInput } from '@shared/ui';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { isValidPhoneNumber } from 'libphonenumber-js/min';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { sendFormFn } from '@shared/api/api.service';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
type CallbackFormProps = {
|
type CallbackFormProps = {
|
||||||
pageName: string;
|
pageName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function CallbackForm({ pageName }: CallbackFormProps) {
|
const FormSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(3, { message: 'Поле должно содержать не менее 3-х букв' })
|
||||||
|
.regex(/^[A-Za-zА-Яа-яЁё]+(?:[ '-][A-Za-zА-Яа-яЁё]+)*$/, {
|
||||||
|
message: 'Поле содержит некорректные символы',
|
||||||
|
}),
|
||||||
|
phone: z.string().refine(isValidPhoneNumber, 'Некорректный номер телефона'),
|
||||||
|
});
|
||||||
|
|
||||||
|
type TForm = z.infer<typeof FormSchema>;
|
||||||
|
|
||||||
|
const defaultValues = {
|
||||||
|
name: '',
|
||||||
|
phone: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
function CallbackForm({ pageName = 'noname-form' }: CallbackFormProps) {
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
control,
|
||||||
|
reset,
|
||||||
|
clearErrors,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<TForm>({
|
||||||
|
mode: 'onSubmit',
|
||||||
|
reValidateMode: 'onBlur',
|
||||||
|
resolver: zodResolver(FormSchema),
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async (data: TForm) => {
|
||||||
|
const payload = {
|
||||||
|
...data,
|
||||||
|
form: pageName,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sendFormFn(payload);
|
||||||
|
toast.success('Заявка на консультацию принята');
|
||||||
|
reset(defaultValues);
|
||||||
|
} catch (e) {
|
||||||
|
toast.error('Ошибка при отправке заявки...', {
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.Container}>
|
<div className={s.Container}>
|
||||||
<h3 className={s.Title}>Узнать точную стоимость и срок экспертизы</h3>
|
<h3 className={s.Title}>Узнать точную стоимость и срок экспертизы</h3>
|
||||||
<form className={s.Form}>
|
<form className={s.Form} onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Input variant={'ghost'} fullWidth placeholder='Ваше имя' />
|
<Controller
|
||||||
<PhoneInput
|
control={control}
|
||||||
variant={'ghost'}
|
name={'name'}
|
||||||
fullWidth
|
render={({ field }) => (
|
||||||
placeholder='+7 999 123-45-67'
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder='Ваше имя'
|
||||||
|
variant={'ghost'}
|
||||||
|
fullWidth
|
||||||
|
onChange={(e) => {
|
||||||
|
clearErrors('name');
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
error={errors && errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={'phone'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<PhoneInput
|
||||||
|
{...field}
|
||||||
|
placeholder='+7 999 123-45-67'
|
||||||
|
variant={'ghost'}
|
||||||
|
fullWidth
|
||||||
|
onChange={(e) => {
|
||||||
|
clearErrors('phone');
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
error={errors && errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<Button variant={'white'} fullWidth>
|
<Button variant={'white'} fullWidth>
|
||||||
Узнать
|
Узнать
|
||||||
|
|||||||
@@ -1,22 +1,112 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
import s from './styles.module.scss';
|
import s from './styles.module.scss';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { TExpert } from '@/shared/types/expert';
|
import { TExpert } from '@/shared/types/expert';
|
||||||
import { Button, Input, PhoneInput } from '@shared/ui';
|
import { Button, Input, PhoneInput } from '@shared/ui';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { isValidPhoneNumber } from 'libphonenumber-js/min';
|
||||||
|
import { Controller, useForm } from 'react-hook-form';
|
||||||
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
import { sendFormFn } from '@shared/api/api.service';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
type ConsultationProps = TExpert;
|
type ConsultationProps = {
|
||||||
|
pageName?: string;
|
||||||
|
} & TExpert;
|
||||||
|
|
||||||
|
const FormSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(3, { message: 'Поле должно содержать не менее 3-х букв' })
|
||||||
|
.regex(/^[A-Za-zА-Яа-яЁё]+(?:[ '-][A-Za-zА-Яа-яЁё]+)*$/, {
|
||||||
|
message: 'Поле содержит некорректные символы',
|
||||||
|
}),
|
||||||
|
phone: z.string().refine(isValidPhoneNumber, 'Некорректный номер телефона'),
|
||||||
|
});
|
||||||
|
|
||||||
|
type TForm = z.infer<typeof FormSchema>;
|
||||||
|
|
||||||
|
const defaultValues = {
|
||||||
|
name: '',
|
||||||
|
phone: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
function Consultation({
|
||||||
|
pageName = 'noname-form',
|
||||||
|
name,
|
||||||
|
position,
|
||||||
|
photo,
|
||||||
|
}: ConsultationProps) {
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
control,
|
||||||
|
reset,
|
||||||
|
clearErrors,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<TForm>({
|
||||||
|
mode: 'onSubmit',
|
||||||
|
reValidateMode: 'onBlur',
|
||||||
|
resolver: zodResolver(FormSchema),
|
||||||
|
defaultValues,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = async (data: TForm) => {
|
||||||
|
const payload = {
|
||||||
|
...data,
|
||||||
|
form: pageName,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await sendFormFn(payload);
|
||||||
|
toast.success('Заявка на консультацию принята');
|
||||||
|
reset(defaultValues);
|
||||||
|
} catch (e) {
|
||||||
|
toast.error('Ошибка при отправке заявки...', {
|
||||||
|
duration: 3000,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function Consultation({ name, position, photo }: ConsultationProps) {
|
|
||||||
return (
|
return (
|
||||||
<section className={s.Consultation}>
|
<section className={s.Consultation}>
|
||||||
<div className={s.Container}>
|
<div className={s.Container}>
|
||||||
<div className={s.Block}>
|
<div className={s.Block}>
|
||||||
<h3 className={s.Header}>Бесплатная консультация специалиста</h3>
|
<h3 className={s.Header}>Бесплатная консультация специалиста</h3>
|
||||||
<form className={s.Form}>
|
<form className={s.Form} onSubmit={handleSubmit(onSubmit)}>
|
||||||
<Input variant={'ghost'} placeholder={'Имя'} fullWidth />
|
<Controller
|
||||||
<PhoneInput
|
control={control}
|
||||||
variant={'ghost'}
|
name={'name'}
|
||||||
placeholder={'+7 999 123-45-67'}
|
render={({ field }) => (
|
||||||
fullWidth
|
<Input
|
||||||
|
{...field}
|
||||||
|
placeholder='Имя'
|
||||||
|
variant={'ghost'}
|
||||||
|
fullWidth
|
||||||
|
onChange={(e) => {
|
||||||
|
clearErrors('name');
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
error={errors && errors.name?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name={'phone'}
|
||||||
|
render={({ field }) => (
|
||||||
|
<PhoneInput
|
||||||
|
{...field}
|
||||||
|
placeholder={'+7 999 123-45-67'}
|
||||||
|
variant={'ghost'}
|
||||||
|
fullWidth
|
||||||
|
onChange={(e) => {
|
||||||
|
clearErrors('phone');
|
||||||
|
field.onChange(e);
|
||||||
|
}}
|
||||||
|
error={errors && errors.phone?.message}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<Button variant={'white'} fullWidth>
|
<Button variant={'white'} fullWidth>
|
||||||
Записаться
|
Записаться
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ import { CallbackForm } from '@/entities';
|
|||||||
|
|
||||||
type RelatedArticlesProps = {
|
type RelatedArticlesProps = {
|
||||||
related: TRelatedArticles[];
|
related: TRelatedArticles[];
|
||||||
|
pageName?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
function RelatedArticles({ related }: RelatedArticlesProps) {
|
function RelatedArticles({ related, pageName }: RelatedArticlesProps) {
|
||||||
return (
|
return (
|
||||||
<section className={s.Related}>
|
<section className={s.Related}>
|
||||||
<div className={s.Container}>
|
<div className={s.Container}>
|
||||||
@@ -27,7 +28,7 @@ function RelatedArticles({ related }: RelatedArticlesProps) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<CallbackForm pageName='Автотехническая экспертиза' />
|
<CallbackForm pageName={pageName} />
|
||||||
</div>
|
</div>
|
||||||
<div />
|
<div />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Breadcrumbs, PartnersSlider } from '@/widgets';
|
|||||||
import { sidebarData } from './model/sidebar';
|
import { sidebarData } from './model/sidebar';
|
||||||
import { relatedArticlesData } from './model/relatedArticles';
|
import { relatedArticlesData } from './model/relatedArticles';
|
||||||
import { expertData } from './model/expert';
|
import { expertData } from './model/expert';
|
||||||
import { breadcrumbData } from './model/breadcrums';
|
import { breadcrumbData, PAGE_NAME } from './model/breadcrums';
|
||||||
|
|
||||||
function AutoTech() {
|
function AutoTech() {
|
||||||
return (
|
return (
|
||||||
@@ -58,7 +58,7 @@ function AutoTech() {
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<CallbackForm pageName='Автотехническая экспертиза' />
|
<CallbackForm pageName={PAGE_NAME} />
|
||||||
|
|
||||||
<h3 className={s.Header}>Документы, необходимые для экспертизы:</h3>
|
<h3 className={s.Header}>Документы, необходимые для экспертизы:</h3>
|
||||||
<p className={s.Text}>
|
<p className={s.Text}>
|
||||||
@@ -95,8 +95,8 @@ function AutoTech() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<Consultation {...expertData} />
|
<Consultation {...expertData} pageName={PAGE_NAME} />
|
||||||
<RelatedArticles related={relatedArticlesData} />
|
<RelatedArticles related={relatedArticlesData} pageName={PAGE_NAME} />
|
||||||
<section className={s.Partners}>
|
<section className={s.Partners}>
|
||||||
<div className={s.Divider}>
|
<div className={s.Divider}>
|
||||||
<span className={s.Separator} />
|
<span className={s.Separator} />
|
||||||
|
|||||||
Reference in New Issue
Block a user