Add send appeal form
This commit is contained in:
parent
9dda476c16
commit
9c3657190a
@ -118,5 +118,19 @@
|
||||
"serverError": "Error on the server side",
|
||||
"noPassword": "Weak password, please avoid obvious passwords",
|
||||
"errorOccured": "An unexpected error occurred"
|
||||
},
|
||||
"contacts": {
|
||||
"serverError": "Error on the server side",
|
||||
"addressTitle": "Address",
|
||||
"address": "Bishkek, Turusbekov str. 109/1, office 108",
|
||||
"phoneTitle": "Phone",
|
||||
"title": "We're in touch",
|
||||
"name": "Name",
|
||||
"surname": "Last name",
|
||||
"phone": "Phone number",
|
||||
"message": "Message",
|
||||
"checkbox": "I agree to the processing of my personal data",
|
||||
"send": "Send a message",
|
||||
"successMessage": "Your message has been sent"
|
||||
}
|
||||
}
|
||||
|
@ -118,5 +118,19 @@
|
||||
"serverError": "Сервер тараптагы ката",
|
||||
"noPassword": "Начар сырсөз, ачык сырсөздөрдү колдонбоңуз",
|
||||
"errorOccured": "Күтүлбөгөн ката кетти"
|
||||
},
|
||||
"contacts": {
|
||||
"serverError": "Сервер тараптагы ката",
|
||||
"addressTitle": "Дарек",
|
||||
"address": "Бишкек ш., Турусбеков көч. 109/1, офис 108",
|
||||
"phoneTitle": "Телефон",
|
||||
"title": "Биз байланыштабыз",
|
||||
"name": "Аты-жөнү",
|
||||
"familia": "фамилиясы",
|
||||
"phone": "Телефон номери",
|
||||
"message": "Кабар",
|
||||
"checkbox": "Мен жеке маалыматтарымды иштетүүгө макулмун",
|
||||
"send": "Билдирүү жөнөтүү",
|
||||
"successMessage": "Сиздин билдирүү жөнөтүлдү"
|
||||
}
|
||||
}
|
||||
|
@ -109,5 +109,19 @@
|
||||
"serverError": "Ошибка на стороне сервера",
|
||||
"noPassword": "Слабый пароль, прошу избегайте очевидных паролей",
|
||||
"errorOccured": "Произошла непредвиденная ошибка"
|
||||
},
|
||||
"contacts": {
|
||||
"serverError": "Ошибка на стороне сервера",
|
||||
"addressTitle": "Адрес",
|
||||
"address": "г. Бишкек, ул. Турусбекова 109/1, офис 108",
|
||||
"phoneTitle": "Телефон",
|
||||
"title": "Мы на связи",
|
||||
"name": "Имя",
|
||||
"surname": "Фамилия",
|
||||
"phone": "Номер телефона",
|
||||
"message": "Сообщение",
|
||||
"checkbox": "Я согласен (-на) на обработку моих личных данных",
|
||||
"send": "Отправить сообщение",
|
||||
"successMessage": "Ваше сообщение отправлено"
|
||||
}
|
||||
}
|
||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -18,6 +18,7 @@
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.52.2",
|
||||
"react-toastify": "^10.0.5",
|
||||
"sass": "^1.77.8",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"zod": "^3.23.8",
|
||||
@ -4224,6 +4225,19 @@
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/react-toastify": {
|
||||
"version": "10.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz",
|
||||
"integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18",
|
||||
"react-dom": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.52.2",
|
||||
"react-toastify": "^10.0.5",
|
||||
"sass": "^1.77.8",
|
||||
"tailwind-merge": "^2.5.2",
|
||||
"zod": "^3.23.8",
|
||||
|
@ -1,8 +1,58 @@
|
||||
"use client";
|
||||
import { apiInstance } from "@/shared/config/apiConfig";
|
||||
import { Container, Title } from "@/shared/ui";
|
||||
|
||||
// import ContactForm from "@/widgets/forms/ContactForm";
|
||||
import Loader from "@/shared/ui/Loader/Loader";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { AxiosError } from "axios";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { toast } from "react-toastify";
|
||||
import { z } from "zod";
|
||||
|
||||
export default function Contacts() {
|
||||
const t = useTranslations("contacts");
|
||||
const [error, setError] = useState<string>("");
|
||||
const [loader, setLoader] = useState<boolean>(false);
|
||||
|
||||
const appealFormScheme = z.object({
|
||||
first_name: z.string(),
|
||||
last_name: z.string(),
|
||||
email: z.string(),
|
||||
phone_number: z.string(),
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
type FormFields = z.infer<typeof appealFormScheme>;
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors, isSubmitting },
|
||||
} = useForm<FormFields>({
|
||||
resolver: zodResolver(appealFormScheme),
|
||||
});
|
||||
|
||||
const onSubmit = async (data: FormFields) => {
|
||||
try {
|
||||
setError("");
|
||||
setLoader(true);
|
||||
|
||||
const response = await apiInstance.post("/appeal_response/", data);
|
||||
console.log(response);
|
||||
toast.success(t("successMessage"));
|
||||
} catch (error) {
|
||||
if (error instanceof AxiosError) {
|
||||
if (
|
||||
[500, 501, 502, 503, 504].includes(error.response?.status as number)
|
||||
) {
|
||||
toast.error(t("serverError"));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
setLoader(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<section className="bg-[#FAFCFF]">
|
||||
<Container className="py-[100px] ">
|
||||
@ -12,13 +62,11 @@ export default function Contacts() {
|
||||
></iframe>
|
||||
<section className="flex items-center justify-between mb-[152px] mt-[64px]">
|
||||
<div className="max-w-[384px] max-h-[106px] flex flex-col items-center px-7">
|
||||
<Title text="Адрес" className="font-extrabold mb-2" />
|
||||
<p className="text-grey-text">
|
||||
г. Бишкек, ул. Турусбекова 109/1, офис 108
|
||||
</p>
|
||||
<Title text={t("addressTitle")} className="font-extrabold mb-2" />
|
||||
<p className="text-grey-text">{t("address")}</p>
|
||||
</div>
|
||||
<div className="max-w-[384px] max-h-[106px] flex flex-col items-center px-7">
|
||||
<Title text="Телефон" className="font-extrabold mb-2" />
|
||||
<Title text={t("phoneTitle")} className="font-extrabold mb-2" />
|
||||
<p className="text-grey-text">(0312) 39 40 38</p>
|
||||
</div>
|
||||
<div className="max-w-[384px] max-h-[106px] flex flex-col items-center px-7">
|
||||
@ -26,36 +74,38 @@ export default function Contacts() {
|
||||
<p className="text-grey-text">kyrgyzstan@transparency.org</p>
|
||||
</div>
|
||||
</section>
|
||||
{/* <ContactForm /> */}
|
||||
<form className="w-[480px] my-0 mx-auto">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-[480px] my-0 mx-auto"
|
||||
>
|
||||
<div className="flex items-center flex-col mt-[96px] mb-[96px]">
|
||||
<h1 className="text-gray-900 text-[36px]">Мы на связи</h1>
|
||||
<h1 className="text-gray-900 text-[36px]">{t("title")}</h1>
|
||||
<div className="flex flex-col items-center gap-6 mt-[64px]">
|
||||
<div className="flex gap-8 w-full">
|
||||
<div className="w-[224px] flex flex-col">
|
||||
<label htmlFor="firstName" className="mb-[6px]">
|
||||
Имя
|
||||
{t("name")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="firstName"
|
||||
className="w-full h-[48px] bg-white py-3 px-4 rounded-md shadow-sm border border-gray"
|
||||
placeholder="Имя"
|
||||
placeholder={t("name")}
|
||||
id="firstName"
|
||||
required
|
||||
{...register("first_name", { required: true })}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-[224px] flex flex-col">
|
||||
<label htmlFor="lastName" className="mb-[6px]">
|
||||
Фамилия
|
||||
{t("surname")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="lastName"
|
||||
className="w-full h-[48px] bg-white py-3 px-4 rounded-md shadow-sm border border-gray"
|
||||
placeholder="Фамилия"
|
||||
placeholder={t("surname")}
|
||||
id="lastName"
|
||||
required
|
||||
{...register("last_name", { required: true })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -65,36 +115,36 @@ export default function Contacts() {
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
placeholder="user@gmail.com"
|
||||
className="w-full h-[48px] bg-white py-3 px-4 rounded-md shadow-sm border border-gray"
|
||||
id="email"
|
||||
{...register("email", { required: true })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<label htmlFor="phoneNumber" className="mb-[6px]">
|
||||
Номер телефона
|
||||
{t("phone")}
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="phoneNumber"
|
||||
className="w-full h-[48px] bg-white py-3 px-4 rounded-md shadow-sm border border-gray"
|
||||
placeholder="+996"
|
||||
id="phoneNumber"
|
||||
required
|
||||
{...register("phone_number", { required: true })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<label htmlFor="message" className="mb-[6px]">
|
||||
Сообщение
|
||||
{t("message")}
|
||||
</label>
|
||||
<textarea
|
||||
className="h-[120px] resize-none w-full bg-white py-3 px-4 rounded-md shadow-sm border border-gray"
|
||||
id="message"
|
||||
name="message"
|
||||
required
|
||||
{...register("message", { required: true })}
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
@ -110,16 +160,24 @@ export default function Contacts() {
|
||||
htmlFor="consentCheckbox"
|
||||
className="text-[#667085] ml-[10px]"
|
||||
>
|
||||
Я согласен (-на) на обработку моих личных данных
|
||||
{t("checkbox")}
|
||||
</label>
|
||||
</div>
|
||||
{errors.root && (
|
||||
<p className="text-sm leading-5 text-red-500">
|
||||
{errors.root.message}
|
||||
</p>
|
||||
)}
|
||||
{error ? (
|
||||
<p className="text-red-500 leading-5 text-sm">{error}</p>
|
||||
) : null}
|
||||
|
||||
<div className="w-full">
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue text-white w-full h-[48px] rounded-md "
|
||||
>
|
||||
Отправить сообщение
|
||||
{loader ? <Loader /> : t("send")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -5,6 +5,8 @@ import { NextIntlClientProvider, useMessages } from "next-intl";
|
||||
import Footer from "../../widgets/Footer/Footer";
|
||||
import Navbar from "@/widgets/Navbar/Navbar";
|
||||
import { Providers } from "./Providers";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { ToastContainer } from "react-toastify";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
@ -29,6 +31,7 @@ export default function RootLayout({
|
||||
<Providers>
|
||||
<Navbar />
|
||||
<div>{children}</div>
|
||||
<ToastContainer />
|
||||
<Footer />
|
||||
</Providers>
|
||||
</NextIntlClientProvider>
|
||||
|
Loading…
Reference in New Issue
Block a user