amati/apps/frontend/src/routes/forgot-password/index.lazy.tsx
2024-09-13 10:11:52 +07:00

235 lines
7.5 KiB
TypeScript

import { createLazyFileRoute } from "@tanstack/react-router";
import { TbArrowNarrowRight } from "react-icons/tb";
import { IoIosArrowUp } from "react-icons/io";
import { HiOutlineGlobeAlt } from "react-icons/hi";
import { useForm, Control, FieldError } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Button } from "@/shadcn/components/ui/button.tsx";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/shadcn/components/ui/form.tsx";
import { Input } from "@/shadcn/components/ui/input.tsx";
import client from "@/honoClient";
import { useState } from "react";
import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuTrigger } from "@/shadcn/components/ui/dropdown-menu";
// Define validation schema using zod
const formSchema = z.object({
email: z.string().email(),
});
type FormSchema = z.infer<typeof formSchema>;
// Interface for props of CustomFormField
interface CustomFormFieldProps {
name: keyof FormSchema;
label: string;
control: Control<FormSchema>;
type?: string;
placeholder?: string;
error?: FieldError; // Add error prop
}
// Component for form fields with bold labels
const CustomFormField: React.FC<CustomFormFieldProps> = ({
name,
label,
control,
type = "text",
placeholder,
error,
}) => (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem>
<FormLabel className="font-bold">{label}</FormLabel>
<FormControl>
<Input
placeholder={placeholder}
type={type}
{...field}
className={`border ${error ? "border-red-500" : "border-gray-300"}`}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
interface DropdownProps {
onSelect: (selectedOption: string) => void;
defaultOption?: string;
listOption?: string[];
}
const CustomDropdownMenu: React.FC<DropdownProps> = ({
onSelect,
defaultOption = "",
listOption = [],
}) => {
const [selectedOption, setSelectedOption] = useState(defaultOption);
const handleSelect = (option: string) => {
setSelectedOption(option);
onSelect(option);
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="bg-transparent text-gray-800 w-full justify-between text-xs hover:bg-blue-100">
<div className="flex items-center gap-1">
<HiOutlineGlobeAlt className="h-3 w-3" />
{selectedOption || "Select an option"}
</div>
<IoIosArrowUp className="h-3 w-3 ml-auto" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuRadioGroup
value={selectedOption}
onValueChange={handleSelect}
>
{listOption.map((option, index) => (
<DropdownMenuRadioItem key={index} value={option}>
{option}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
);
};
// Define a route for the registration form
export const Route = createLazyFileRoute("/forgot-password/")({
component: () => (
<div>
<ForgotPasswordForm />
</div>
),
});
// Main components of the registration form
export function ForgotPasswordForm() {
// Set up form with react-hook-form and zod
const form = useForm<FormSchema>({
// Integrate schema with form
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
},
});
// Function to handle form submission
const onSubmit = async (values: FormSchema) => {
try {
const response = await client["forgot-password"].$post({
json: values,
});
if (response.ok) {
// Handle successful registration here
alert("Reset instructions sent successfully");
const data = await response.json();
return data;
} else {
throw response;
}
} catch (error) {
// Handle registration error here
console.error("Submission error:", error);
alert("Failed to send reset instructions");
}
};
const handleSelect = (selectedOption: string) => {
console.log('Selected option:', selectedOption);
// Do something with selected option
};
return (
<div className="flex flex-col lg:flex-row min-h-screen w-screen overflow-hidden">
<div className="absolute inset-0 flex z-0 overflow-hidden">
<div className="relative h-[50vw] md:h-screen z-0">
<div className="-translate-y-[calc(50vw+2rem)] md:translate-y-0 w-full md:-translate-x-[calc(10vh-60vw)]">
<span className="absolute scale-[25%] -rotate-12 w-[100vw] h-[100vw] md:w-[100vh] md:h-[100vh] border border-gray-800 flex rounded-xl"></span>
<span className="absolute scale-50 -rotate-12 w-[100vw] h-[100vw] md:w-[100vh] md:h-[100vh] border border-gray-400 flex rounded-xl"></span>
<span className="absolute scale-75 -rotate-12 w-[100vw] h-[100vw] md:w-[100vh] md:h-[100vh] border border-gray-300 flex rounded-xl"></span>
<span className="absolute scale-100 -rotate-12 w-[100vw] h-[100vw] md:w-[100vh] md:h-[100vh] border border-gray-200 flex rounded-xl"></span>
</div>
</div>
</div>
<div className="relative flex flex-col min-h-screen p-7 bg-transparent justify-between z-10">
{/* Top */}
<div className="flex items-center font-bold">Amati</div>
{/* Center */}
<div className="flex flex-col h-full w-full xl:ml-32 2xl:ml-72 bg-transparent justify-center lg:px-28">
<div className="flex flex-col w-full gap-y-1 pb-12 justify-between lg:justify-end">
<h1
className="text-4xl font-bold text-black"
>
Forgot Password
</h1>
<p className="text-sm text-muted-foreground">
No worries, we'll send you reset instructions
</p>
</div>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col gap-12 lg:w-96"
>
<div className="grid grid-cols-1">
<CustomFormField
control={form.control}
name="email"
label="Email"
type="email"
placeholder="eg; user@gmail.com"
error={form.formState.errors.email}
/>
</div>
<div className="flex flex-col justify-between gap-9">
<Button
type="submit"
className="flex items-center justify-between shadow-xl w-full text-white bg-[--primary-color]"
>
<span className="flex">Request Reset</span>
<TbArrowNarrowRight className="h-5 w-5" />
</Button>
<a
href="/login"
className="text-xs text-blue-500 hover:underline font-bold w-fit"
>
Back to login
</a>
</div>
</form>
</Form>
</div>
{/* Bottom */}
<div className="flex items-center justify-center lg:justify-start w-56 h-8 mx-auto lg:mx-0 bg-muted rounded-md">
<CustomDropdownMenu
onSelect={handleSelect}
defaultOption="English (United States)"
listOption={["English (United States)", "Indonesia"]}
/>
</div>
</div>
</div>
);
}