291 lines
9.8 KiB
TypeScript
291 lines
9.8 KiB
TypeScript
|
|
"use client";
|
||
|
|
import { getCookiesDecrypt } from "@/lib/utils";
|
||
|
|
import React, { useEffect, useState } from "react";
|
||
|
|
import { useForm } from "react-hook-form";
|
||
|
|
import { getInfoProfile, getSubjects } from "@/service/auth";
|
||
|
|
import { close, error, loading, successCallback } from "@/config/swal";
|
||
|
|
import { sendMessage } from "@/service/landing/landing";
|
||
|
|
import { useTranslations } from "next-intl";
|
||
|
|
import { z } from "zod";
|
||
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||
|
|
import { useRouter } from "@/i18n/routing";
|
||
|
|
import { Reveal } from "@/components/landing-page/Reveal";
|
||
|
|
|
||
|
|
interface IFormInput {
|
||
|
|
name: string;
|
||
|
|
email: string;
|
||
|
|
phone?: string | undefined;
|
||
|
|
subjects: string;
|
||
|
|
othersubject?: string | undefined;
|
||
|
|
message: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
const ContactForm = () => {
|
||
|
|
const router = useRouter();
|
||
|
|
const userId = getCookiesDecrypt("uie");
|
||
|
|
const [subjects, setSubjects] = useState<any[]>([]);
|
||
|
|
const [isOtherActive, setIsOtherActive] = useState(false);
|
||
|
|
const t = useTranslations("LandingPage");
|
||
|
|
|
||
|
|
const validationSchema = z.object({
|
||
|
|
name: z.string().min(1, "Nama tidak boleh kosong"),
|
||
|
|
email: z.string().email("Email tidak valid"),
|
||
|
|
phone: z.string().optional(),
|
||
|
|
subjects: z.string().min(1, "Subjek tidak boleh kosong"),
|
||
|
|
othersubject: z.string().optional(),
|
||
|
|
message: z.string().min(1, "Pesan tidak boleh kosong"),
|
||
|
|
});
|
||
|
|
|
||
|
|
type IFormInput = z.infer<typeof validationSchema>;
|
||
|
|
|
||
|
|
const {
|
||
|
|
register,
|
||
|
|
handleSubmit,
|
||
|
|
formState: { errors },
|
||
|
|
setValue,
|
||
|
|
reset,
|
||
|
|
} = useForm<IFormInput>({
|
||
|
|
resolver: zodResolver(validationSchema),
|
||
|
|
});
|
||
|
|
|
||
|
|
// Init state
|
||
|
|
useEffect(() => {
|
||
|
|
async function initState() {
|
||
|
|
const response = await getInfoProfile();
|
||
|
|
const responseSubject = await getSubjects();
|
||
|
|
const profile = response?.data?.data;
|
||
|
|
|
||
|
|
setSubjects(responseSubject?.data?.data || []);
|
||
|
|
if (profile) {
|
||
|
|
setValue("name", profile?.fullname || "");
|
||
|
|
setValue("email", profile?.email || "");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
initState();
|
||
|
|
}, [setValue]);
|
||
|
|
|
||
|
|
async function save(data: IFormInput) {
|
||
|
|
loading();
|
||
|
|
|
||
|
|
const finalData = {
|
||
|
|
name: data.name,
|
||
|
|
email: data.email,
|
||
|
|
phone: data.phone,
|
||
|
|
title: isOtherActive ? data.othersubject : data.subjects,
|
||
|
|
message: data.message,
|
||
|
|
};
|
||
|
|
|
||
|
|
const response = await sendMessage(finalData);
|
||
|
|
if (response?.error) {
|
||
|
|
error(response?.message);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
close();
|
||
|
|
successCallback("Terima kasih, pesan Anda telah terkirim");
|
||
|
|
reset();
|
||
|
|
}
|
||
|
|
|
||
|
|
async function onSubmit(data: IFormInput) {
|
||
|
|
if (userId == undefined) {
|
||
|
|
router.push("/auth");
|
||
|
|
} else {
|
||
|
|
save(data);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const handleSubjects = (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||
|
|
if (e.target.value === "Lainnya") {
|
||
|
|
setIsOtherActive(true);
|
||
|
|
} else {
|
||
|
|
setIsOtherActive(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<form
|
||
|
|
method="POST"
|
||
|
|
onSubmit={handleSubmit(onSubmit)}
|
||
|
|
className="max-w-2xl mx-auto bg-white dark:bg-black p-6"
|
||
|
|
>
|
||
|
|
<Reveal>
|
||
|
|
{/* Header */}
|
||
|
|
<div className="flex items-center justify-center mb-6">
|
||
|
|
<div>
|
||
|
|
<svg
|
||
|
|
xmlns="http://www.w3.org/2000/svg"
|
||
|
|
width="24"
|
||
|
|
height="24"
|
||
|
|
viewBox="0 0 24 24"
|
||
|
|
>
|
||
|
|
<g fill="none" stroke="currentColor" strokeWidth="1.5">
|
||
|
|
<path d="M4 10c0-3.771 0-5.657 1.172-6.828S8.229 2 12 2h1.5c3.771 0 5.657 0 6.828 1.172S21.5 6.229 21.5 10v4c0 3.771 0 5.657-1.172 6.828S17.271 22 13.5 22H12c-3.771 0-5.657 0-6.828-1.172S4 17.771 4 14z" />
|
||
|
|
<path
|
||
|
|
strokeLinejoin="round"
|
||
|
|
d="M9.8 11.974c-.427-.744-.633-1.351-.757-1.967c-.184-.91.237-1.8.933-2.368c.295-.24.632-.158.806.155l.393.705c.311.558.467.838.436 1.134c-.03.296-.24.537-.66 1.02zm0 0a10.36 10.36 0 0 0 3.726 3.726m0 0c.744.427 1.351.633 1.967.757c.91.184 1.8-.237 2.368-.933c.24-.295.158-.632-.155-.806l-.704-.393c-.56-.311-.839-.467-1.135-.436c-.296.03-.537.24-1.02.66z"
|
||
|
|
/>
|
||
|
|
<path
|
||
|
|
strokeLinecap="round"
|
||
|
|
strokeLinejoin="round"
|
||
|
|
d="M5 6H2.5M5 12H2.5M5 18H2.5"
|
||
|
|
/>
|
||
|
|
</g>
|
||
|
|
</svg>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<h2 className="ml-4 text-2xl font-bold">
|
||
|
|
{t("contactUs", { defaultValue: "Contact Us" })}
|
||
|
|
</h2>
|
||
|
|
</div>
|
||
|
|
{/* <h3 className="text-lg font-semibold text-gray-800 dark:text-white mb-1">
|
||
|
|
{t("writeMessage", { defaultValue: "Write Message" })}
|
||
|
|
</h3>
|
||
|
|
<p className="text-sm text-gray-600 dark:text-white mb-6">
|
||
|
|
{t("leaveMessage", { defaultValue: "Leave Message" })}
|
||
|
|
</p> */}
|
||
|
|
|
||
|
|
{/* Form */}
|
||
|
|
<div>
|
||
|
|
{/* Name */}
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
{t("name", { defaultValue: "Name" })}
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
placeholder={t("enterName", { defaultValue: "Enter Name" })}
|
||
|
|
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||
|
|
errors.name
|
||
|
|
? "border-red-500 focus:ring-red-500"
|
||
|
|
: "border-gray-300 focus:ring-blue-500"
|
||
|
|
}`}
|
||
|
|
{...register("name")}
|
||
|
|
/>
|
||
|
|
{errors.name && (
|
||
|
|
<p className="text-red-500 text-sm">{errors.name.message}</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Email */}
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
Email
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
type="email"
|
||
|
|
placeholder="name@mail.com"
|
||
|
|
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||
|
|
errors.email
|
||
|
|
? "border-red-500 focus:ring-red-500"
|
||
|
|
: "border-gray-300 focus:ring-blue-500"
|
||
|
|
}`}
|
||
|
|
{...register("email")}
|
||
|
|
/>
|
||
|
|
{errors.email && (
|
||
|
|
<p className="text-red-500 text-sm">{errors.email.message}</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Phone */}
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
{t("number", { defaultValue: "Number" })} (Optional)
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
placeholder={t("enterNumber", { defaultValue: "Enter Number" })}
|
||
|
|
className="w-full p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||
|
|
{...register("phone")}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Subjects */}
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
{t("subject", { defaultValue: "Subject" })}
|
||
|
|
</label>
|
||
|
|
<select
|
||
|
|
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||
|
|
errors.subjects
|
||
|
|
? "border-red-500 focus:ring-red-500"
|
||
|
|
: "border-gray-300 focus:ring-blue-500"
|
||
|
|
}`}
|
||
|
|
{...register("subjects", { onChange: (e) => handleSubjects(e) })}
|
||
|
|
defaultValue=""
|
||
|
|
>
|
||
|
|
<option value="" disabled>
|
||
|
|
{t("selectSubject", { defaultValue: "Select Subject" })}
|
||
|
|
</option>
|
||
|
|
{subjects?.map((list: any) => (
|
||
|
|
<option key={list.id} value={list.title}>
|
||
|
|
{list.title}
|
||
|
|
</option>
|
||
|
|
))}
|
||
|
|
<option value="Lainnya">Lainnya</option>
|
||
|
|
</select>
|
||
|
|
{errors.subjects && (
|
||
|
|
<p className="text-red-500 text-sm">{errors.subjects.message}</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Other Subject */}
|
||
|
|
{isOtherActive && (
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
Subjek Lainnya
|
||
|
|
</label>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
placeholder="Masukkan subjek lainnya"
|
||
|
|
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||
|
|
errors.othersubject
|
||
|
|
? "border-red-500 focus:ring-red-500"
|
||
|
|
: "border-gray-300 focus:ring-blue-500"
|
||
|
|
}`}
|
||
|
|
{...register("othersubject")}
|
||
|
|
/>
|
||
|
|
{errors.othersubject && (
|
||
|
|
<p className="text-red-500 text-sm">
|
||
|
|
{errors.othersubject.message}
|
||
|
|
</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{/* Message */}
|
||
|
|
<div className="mb-4">
|
||
|
|
<label className="block text-sm font-medium text-gray-700 dark:text-white mb-1">
|
||
|
|
{t("messages", { defaultValue: "Messages" })}
|
||
|
|
</label>
|
||
|
|
<textarea
|
||
|
|
placeholder={t("writeYourMessage", {
|
||
|
|
defaultValue: "Write Your Message",
|
||
|
|
})}
|
||
|
|
rows={4}
|
||
|
|
className={`w-full p-2 border rounded-md focus:outline-none focus:ring-2 ${
|
||
|
|
errors.message
|
||
|
|
? "border-red-500 focus:ring-red-500"
|
||
|
|
: "border-gray-300 focus:ring-blue-500"
|
||
|
|
}`}
|
||
|
|
{...register("message")}
|
||
|
|
></textarea>
|
||
|
|
{errors.message && (
|
||
|
|
<p className="text-red-500 text-sm">{errors.message.message}</p>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<button
|
||
|
|
type="submit"
|
||
|
|
className="w-fit bg-blue-500 flex justify-self-end text-white p-2 px-8 rounded-md hover:bg-blue-600 transition"
|
||
|
|
>
|
||
|
|
{t("send", { defaultValue: "Send" })}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</Reveal>
|
||
|
|
</form>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
export default ContactForm;
|