Untitled
unknown
plain_text
a year ago
12 kB
17
Indexable
"use client";
import React, { useEffect, useState } from "react";
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions,
} from "@headlessui/react";
import { ChevronDown, Check, CloseCross } from "app/icons";
import { positions } from "app/data";
import type {
AlertType,
FileAttachment,
JoinFormData,
JoinUsModalProps,
PositionType,
} from "app/types";
import { Modal, ModalContent, ModalHeader, ModalBody } from "@nextui-org/react";
import { Alert, FileUpload, Button, Typography } from "app/design-system";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { JoinSchema } from "app/utils/JoinSchema";
const COMPANY_MAIL = process.env.NEXT_PUBLIC_HR_MAIL;
const initialFormData: JoinFormData = {
"full-name": "",
email: "",
phone: "",
position: "",
resume: undefined,
};
export default function JoinUsModal({
isOpen,
onOpenChange,
}: JoinUsModalProps) {
const [filePaths, setFilePaths] = useState<FileAttachment[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [selected, setSelected] = useState<PositionType>(positions[0]);
const [formData, setFormData] = useState<JoinFormData>(initialFormData);
const [alert, setAlert] = useState<AlertType>({
show: false,
type: "",
message: "",
});
const {
register,
handleSubmit,
reset,
formState: { errors },
} = useForm<JoinFormData>({
resolver: zodResolver(JoinSchema),
});
const handleFileUploaded = (paths: FileAttachment) => {
if (Array.isArray(paths)) {
setFilePaths(paths[0]);
}
};
useEffect(() => {
// @ts-ignore
setFormData((prevState) => ({ ...prevState, position: selected?.name }));
}, [selected]);
const handleChange = (event: any) => {
const { name, value } = event.target;
setFormData((prevState) => ({ ...prevState, [name]: value }));
};
const onSubmit = async () => {
setAlert({ show: false, type: "", message: "" });
setLoading(true);
const response = await fetch("/api/send-email", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({
attachments: [filePaths],
from: `${formData.email}`,
to: COMPANY_MAIL,
subject: `${formData.position}`,
text: `name: ${formData["full-name"]} \n
phone: ${formData.phone} \n
position: ${formData.position}`,
}),
});
if (response.ok) {
setAlert({
show: true,
type: "success",
message: "Form submitted successfully!",
});
setLoading(false);
reset();
setFilePaths([]);
} else {
setAlert({
show: true,
type: "error",
message: "Failed to submit the form. Please try again.",
});
setLoading(false);
}
};
const handleToggle = () => {
onOpenChange(!isOpen);
setAlert({ show: false, type: "", message: "" });
};
return (
<Modal
isOpen={isOpen}
hideCloseButton
onOpenChange={onOpenChange}
radius="md"
classNames={{
wrapper: "flex items-center justify-center",
backdrop:
"z-50 backdrop-blur-md bg-white/20 w-screen h-screen fixed inset-0",
base: "my-0 max-w-xs md:max-w-lg space-y-4 duration-300 ease-out data-[closed]:scale-95 data-[closed]:opacity-0 bg-primary-950 p-[24px]",
header: "!mt-0 py-0 px-0 m-0",
body: "px-0 py-0 ",
}}
>
<ModalContent>
<ModalHeader className="flex flex-row justify-between">
<Typography size={"sh3"}>Join Us</Typography>
<CloseCross onClick={handleToggle} />
</ModalHeader>
<ModalBody>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="md:mt-8 grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-6">
<div className="col-span-full space-y-2">
<Typography size="label" className="select-none">
Full Name <span className="text-red-950">*</span>
</Typography>
<div className="mt-2">
<input
{...register("full-name")}
onChange={handleChange}
id="full-name"
name="full-name"
type="text"
placeholder="Ahmed"
autoComplete="full-name"
className="bg-primary-900 focus:border-primary-200 placeholder:text-primary-400 bordered-[4px] h-[48px] border-[1px] border-primary-700 relative w-full rounded-md bordered-[4px] py-1.5 pl-3 pr-10 text-left text-sm text-primary-400 shadow-sm ring-0 focus:ring-transparent ring-inset focus:outline-none sm:text-sm sm:leading-6"
/>
{errors["full-name"] && (
<Typography color="red" size="b4">
{errors["full-name"].message}
</Typography>
)}
</div>
</div>
<div className="col-span-full space-y-2">
<Typography size="label" className="select-none">
Email <span className="text-red-950">*</span>
</Typography>
<div className="mt-2">
<input
{...register("email")}
onChange={handleChange}
id="email"
name="email"
type="email"
placeholder="[email protected]"
autoComplete="email"
className="bg-primary-900 focus:border-primary-200 bordered-[4px] placeholder:text-primary-400 h-[48px] border-[1px] border-primary-700 relative w-full rounded-md bordered-[4px] py-1.5 pl-3 pr-10 text-left text-sm text-primary-400 shadow-sm ring-0 focus:ring-transparent ring-inset focus:outline-none sm:text-sm sm:leading-6"
/>
{errors.email && (
<Typography color="red" size="b4">
{errors.email.message}
</Typography>
)}
</div>
</div>
<div className="col-span-full space-y-2">
<Typography size="label" className="select-none">
Phone Number <span className="text-red-950">*</span>
</Typography>
<div className="mt-2">
<input
{...register("phone")}
onChange={handleChange}
id="phone"
name="phone"
type="tel"
autoComplete="phone"
placeholder="+971 1112345"
className="bg-primary-900 focus:border-primary-200 bordered-[4px] h-[48px] placeholder:text-primary-400 border-[1px] border-primary-700 relative w-full rounded-md bordered-[4px] py-1.5 pl-3 pr-10 text-left text-sm text-primary-400 shadow-sm ring-0 focus:ring-transparent ring-inset focus:outline-none sm:text-sm sm:leading-6"
/>
{errors.phone && (
<Typography color="red" size="b4">
{errors.phone.message}
</Typography>
)}
</div>
</div>
<div className="col-span-full space-y-2 z-20 relative">
<Listbox as="div" value={selected} onChange={setSelected}>
<Typography size="label" className="select-none">
Position <span className="text-red-950">*</span>
</Typography>
<div className="relative mt-2">
<ListboxButton className="bg-primary-900 focus:border-primary-200 bordered-[4px] h-[48px] border-[1px] border-primary-700 relative w-full rounded-md bordered-[4px] py-1.5 pl-3 pr-10 text-left text-sm text-primary-400 shadow-sm ring-0 focus:ring-transparent ring-inset focus:outline-none sm:text-sm sm:leading-6">
<span className="block truncate">
{selected && selected.name}
</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronDown />
</span>
</ListboxButton>
<ListboxOptions
onClick={(e) => e.stopPropagation()}
transition
className="absolute z-20 mt-1 max-h-60 w-full rounded-md bg-primary-900 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none data-[closed]:data-[leave]:opacity-0 data-[leave]:transition data-[leave]:duration-100 data-[leave]:ease-in sm:text-sm"
>
{positions.map((position) => (
<ListboxOption
key={position.id}
value={position}
onClick={(event) => {
event.stopPropagation(); // Prevent event from bubbling up
}}
className="group relative cursor-pointer select-none py-2 pl-3 pr-9 text-primary-400 data-[focus]:bg-primary-600 data-[focus]:text-white"
>
<span className="block truncate font-normal group-data-[selected]:font-semibold">
{position.name}
</span>
<span className="absolute inset-y-0 right-0 flex items-center pr-4 text-primary-50 group-data-[focus]:text-white [.group:not([data-selected])_&]:hidden">
<Check />
</span>
</ListboxOption>
))}
</ListboxOptions>
</div>
</Listbox>
</div>
<div className="col-span-full space-y-2">
<Typography size="label" className="select-none">
Resume <span className="text-red-950">*</span>
</Typography>
<div className="mt-2 flex justify-center rounded-lg border border-dashed border-white/25 px-6 py-10">
<div className="flex justify-center flex-col items-center text-center">
<FileUpload
type="file"
{...register("resume")}
id="resume"
name="resume"
className="sr-only"
accept="application/pdf, application/msword"
onChange={handleChange}
onFileUploaded={handleFileUploaded}
/>
</div>
</div>
{errors.resume && (
<Typography color="red" size="b4">
{errors.resume.message}
</Typography>
)}
</div>
</div>
<div className="mt-[24px]">
<Button disabled={loading} block>
Let’s Talk Now
</Button>
<br />
{alert.show && (
<Alert type={alert.type} message={alert.message} />
)}
</div>
</form>
</ModalBody>
</ModalContent>
</Modal>
);
}
// usage
<JoinUsModal isOpen={isOpen} onOpenChange={onOpenChange} />
Editor is loading...
Leave a Comment