diff --git a/src/app/api/sendform/route.ts b/src/app/api/sendform/route.ts
index 2a8ae60..a083b63 100644
--- a/src/app/api/sendform/route.ts
+++ b/src/app/api/sendform/route.ts
@@ -1,13 +1,8 @@
import nodemailer from 'nodemailer';
+import { TBaseForm } from '@shared/api/api.types';
+import { CORE } from '@shared/config/core';
-type TFormData = {
- name?: string;
- phone: string;
- message?: string;
- form: string;
-};
-
-async function sendMail(data: TFormData) {
+async function sendMail(data: TBaseForm) {
const { name, phone, message, form } = data;
const formattedBody = `
@@ -25,14 +20,14 @@ async function sendMail(data: TFormData) {
const transporter = nodemailer.createTransport({
service: 'yandex',
auth: {
- user: process.env.MAIL_USER,
- pass: process.env.MAIL_PASS,
+ user: CORE.MAIL_USER,
+ pass: CORE.MAIL_PASS,
},
});
return await transporter.sendMail({
- from: process.env.MAIL_FROM,
- to: process.env.MAIL_TO,
+ from: CORE.MAIL_FROM,
+ to: CORE.MAIL_TO,
subject: 'Заявка с сайта FireExams',
html: formattedBody,
});
@@ -42,14 +37,24 @@ export async function POST(request: Request) {
try {
const payload = await request.json();
- if (payload.secure === process.env.MAIL_SECURE_KEY) {
+ if (payload.secure !== CORE.MAIL_SECURE_KEY) {
await Promise.reject('Request failure!');
}
const sendResult = await sendMail({ ...payload });
+ const data = { message: 'Form accepted' };
+ const headers = new Headers({
+ 'Content-Type': 'application/json',
+ });
+ const options = {
+ status: 200,
+ statusText: 'OK',
+ headers: headers,
+ };
+
if (sendResult?.messageId) {
- return new Response('Success!', { status: 200 });
+ return new Response(JSON.stringify(data), options);
} else {
await Promise.reject('Sending request failure!');
}
diff --git a/src/shared/api/api.service.ts b/src/shared/api/api.service.ts
new file mode 100644
index 0000000..2ee7171
--- /dev/null
+++ b/src/shared/api/api.service.ts
@@ -0,0 +1,35 @@
+import { API_ROUTES } from '@shared/config/routes';
+import { TBaseForm } from '@shared/api/api.types';
+import { CORE } from '@shared/config/core';
+
+type TRequest = TBaseForm;
+
+const sendFormFn = async ({ ...props }: TRequest) => {
+ try {
+ const response = await fetch('/api' + API_ROUTES.SEND_FORM, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ ...props,
+ secure: CORE.MAIL_SECURE_KEY,
+ }),
+ });
+
+ if (response.ok) {
+ return response;
+ } else {
+ if (response.status === 400) throw new Error(`400 Bad request`);
+ if (response.status === 401) throw new Error(`401 Unauthorized`);
+ if (response.status === 500) throw new Error('500 Internal server error');
+
+ throw new Error(`${response.status} - Network response failure`);
+ }
+ } catch (e) {
+ console.error(e);
+ }
+};
+
+export { sendFormFn };
diff --git a/src/shared/api/api.types.ts b/src/shared/api/api.types.ts
new file mode 100644
index 0000000..e46571f
--- /dev/null
+++ b/src/shared/api/api.types.ts
@@ -0,0 +1,6 @@
+export type TBaseForm = {
+ form: string;
+ name?: string;
+ phone: string;
+ message?: string;
+};
diff --git a/src/shared/config/core.ts b/src/shared/config/core.ts
new file mode 100644
index 0000000..ddba9d1
--- /dev/null
+++ b/src/shared/config/core.ts
@@ -0,0 +1,7 @@
+export const CORE = {
+ MAIL_USER: process.env.MAIL_USER,
+ MAIL_PASS: process.env.MAIL_PASS,
+ MAIL_FROM: process.env.MAIL_FROM,
+ MAIL_TO: process.env.MAIL_TO,
+ MAIL_SECURE_KEY: process.env.NEXT_PUBLIC_MAIL_SECURE_KEY,
+} as const;
diff --git a/src/shared/config/routes.ts b/src/shared/config/routes.ts
new file mode 100644
index 0000000..cebba69
--- /dev/null
+++ b/src/shared/config/routes.ts
@@ -0,0 +1,4 @@
+export const API_ROUTES = {
+ SEND_FORM: '/sendform',
+ HEARTBEAT: '/heartbeat',
+} as const;
diff --git a/src/shared/ui/phone-input/phone-input.tsx b/src/shared/ui/phone-input/phone-input.tsx
new file mode 100644
index 0000000..f652e58
--- /dev/null
+++ b/src/shared/ui/phone-input/phone-input.tsx
@@ -0,0 +1,10 @@
+//import s from './phone-input.module.scss';
+import { Input } from '@shared/ui';
+
+export default function PhoneInput() {
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/src/widgets/contacts-form/ui.tsx b/src/widgets/contacts-form/ui.tsx
index 24a168f..2021003 100644
--- a/src/widgets/contacts-form/ui.tsx
+++ b/src/widgets/contacts-form/ui.tsx
@@ -9,6 +9,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import bgForm from '@public/images/bg-form.jpg';
+import { sendFormFn } from '@shared/api/api.service';
const FormSchema = z.object({
name: z.string().min(3),
@@ -27,7 +28,6 @@ export default function ContactsForm() {
control,
reset,
formState: { errors },
- clearErrors,
} = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
@@ -36,8 +36,13 @@ export default function ContactsForm() {
});
const onSubmit = async (data: TForm) => {
+ const payload = {
+ ...data,
+ form: 'contacts-form',
+ };
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
reset(defaultValues);
} catch (e) {
diff --git a/src/widgets/footer-form/ui.tsx b/src/widgets/footer-form/ui.tsx
index 2bdb649..dd7739a 100644
--- a/src/widgets/footer-form/ui.tsx
+++ b/src/widgets/footer-form/ui.tsx
@@ -8,6 +8,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import man from '@public/images/footer-man.png';
+import { sendFormFn } from '@shared/api/api.service';
const FormSchema = z.object({
name: z.string().min(3),
@@ -28,7 +29,6 @@ export default function FooterForm() {
control,
reset,
formState: { errors },
- clearErrors,
} = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
@@ -37,8 +37,13 @@ export default function FooterForm() {
});
const onSubmit = async (data: TForm) => {
+ const payload = {
+ ...data,
+ form: 'footer-form',
+ };
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
reset(defaultValues);
} catch (e) {
diff --git a/src/widgets/license-form/ui.tsx b/src/widgets/license-form/ui.tsx
index b3f44f8..fd7f033 100644
--- a/src/widgets/license-form/ui.tsx
+++ b/src/widgets/license-form/ui.tsx
@@ -9,6 +9,7 @@ import bgForm from '@public/images/bg-form.jpg';
import { z } from 'zod';
import { Controller, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
+import { sendFormFn } from '@shared/api/api.service';
const FormSchema = z.object({
name: z.string().min(3),
@@ -27,7 +28,6 @@ export default function LicenseForm() {
control,
reset,
formState: { errors },
- clearErrors,
} = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
@@ -36,8 +36,13 @@ export default function LicenseForm() {
});
const onSubmit = async (data: TForm) => {
+ const payload = {
+ ...data,
+ form: 'license-form',
+ };
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
reset(defaultValues);
} catch (e) {
diff --git a/src/widgets/offer-form/ui.tsx b/src/widgets/offer-form/ui.tsx
index 979c734..d004ee5 100644
--- a/src/widgets/offer-form/ui.tsx
+++ b/src/widgets/offer-form/ui.tsx
@@ -6,6 +6,7 @@ import { Controller, useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import toast from 'react-hot-toast';
+import { sendFormFn } from '@shared/api/api.service';
const FormSchema = z.object({
name: z.string().min(3),
@@ -24,7 +25,6 @@ export default function OfferForm() {
control,
reset,
formState: { errors },
- clearErrors,
} = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
@@ -33,8 +33,13 @@ export default function OfferForm() {
});
const onSubmit = async (data: TForm) => {
+ const payload = {
+ ...data,
+ form: 'offer-form',
+ };
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
reset(defaultValues);
} catch (e) {
diff --git a/src/widgets/offer-request/ui.tsx b/src/widgets/offer-request/ui.tsx
index f89fb5f..a86edfa 100644
--- a/src/widgets/offer-request/ui.tsx
+++ b/src/widgets/offer-request/ui.tsx
@@ -10,6 +10,7 @@ import toast from 'react-hot-toast';
import bgForm from '@public/images/bg-form.jpg';
import { useState } from 'react';
+import { sendFormFn } from '@shared/api/api.service';
const FormSchema = z.object({
name: z.string().min(3),
@@ -28,7 +29,6 @@ export default function OfferRequest() {
control,
reset,
formState: { errors },
- clearErrors,
} = useForm({
mode: 'onSubmit',
reValidateMode: 'onBlur',
@@ -39,8 +39,13 @@ export default function OfferRequest() {
const [inputPhone, setInputPhone] = useState('');
const onSubmitForm = async (data: TForm) => {
+ const payload = {
+ ...data,
+ form: 'offer-request-form',
+ };
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
reset(defaultValues);
} catch (e) {
@@ -51,11 +56,13 @@ export default function OfferRequest() {
};
const onSubmitPhone = async (phone: string) => {
- const data = {
- phone,
+ const payload = {
+ phone: phone,
+ form: 'offer-request-form',
};
+
try {
- console.log('Form', data);
+ await sendFormFn(payload);
toast.success('Заявка на консультацию принята');
setInputPhone('');
} catch (e) {