mediahub-fe/components/auth/login-form.tsx

213 lines
7.0 KiB
TypeScript

"use client";
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Link } from "@/i18n/routing";
import { useTranslations } from "next-intl";
import {
Dialog,
DialogContent,
DialogFooter,
DialogTrigger,
} from "@/components/ui/dialog";
import { FormField } from "@/components/auth/form-field";
import { loginSchema, LoginFormData, LoginFormProps } from "@/types/auth";
import { useAuth } from "@/hooks/use-auth";
import { listRole } from "@/service/landing/landing";
import { Role } from "@/types/auth";
export const LoginForm: React.FC<LoginFormProps> = ({
onSuccess,
onError,
className,
}) => {
const t = useTranslations("LandingPage");
const { login } = useAuth();
const [showPassword, setShowPassword] = useState(false);
const [rememberMe, setRememberMe] = useState(true);
const [roles, setRoles] = useState<Role[]>([]);
const [selectedCategory, setSelectedCategory] = useState("5");
const [isDialogOpen, setIsDialogOpen] = useState(false);
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
getValues,
} = useForm<LoginFormData>({
resolver: zodResolver(loginSchema),
mode: "onChange",
});
// Load roles on component mount
React.useEffect(() => {
const loadRoles = async () => {
try {
const response = await listRole();
setRoles(response?.data?.data || []);
} catch (error) {
console.error("Failed to load roles:", error);
}
};
loadRoles();
}, []);
const handlePasswordToggle = () => {
setShowPassword(!showPassword);
};
const handleLogin = async (data: LoginFormData) => {
try {
await login(data);
onSuccess?.(data);
} catch (error: any) {
onError?.(error.message || "Login failed");
}
};
const onSubmit = async (data: LoginFormData) => {
try {
// Pass the form data to the parent component
// The auth page will handle email validation and flow transitions
onSuccess?.(data);
} catch (error: any) {
onError?.(error.message || "Login failed");
}
};
return (
<div className={className}>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
{/* Header */}
<div className="text-left space-y-2">
<h1 className="font-semibold text-3xl text-left">
{t("logInPlease", { defaultValue: "Log In Please" })}
</h1>
<div className="text-default-500 text-base">
{t("acc", { defaultValue: "Acc" })}
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild>
<span className="w-full lg:w-fit px-2 h-8 text-red-500 hover:cursor-pointer hover:underline">
{t("register", { defaultValue: "Register" })}
</span>
</DialogTrigger>
<DialogContent size="sm" className="sm:max-w-[425px]">
<div className="flex flex-col w-full gap-1">
<p className="text-lg font-semibold text-center">
{t("categoryReg", { defaultValue: "Category Reg" })}
</p>
<p className="text-base text-center">
{t("selectOne", { defaultValue: "Select One" })}
</p>
</div>
<div className="space-y-2">
{roles.map((role) => (
<div key={role.id} className="flex items-center space-x-2">
<input
type="radio"
id={`category${role.id}`}
name="category"
value={role.id.toString()}
checked={selectedCategory === role.id.toString()}
onChange={(e) => setSelectedCategory(e.target.value)}
className="text-red-500 focus:ring-red-500"
/>
<Label htmlFor={`category${role.id}`} className="text-sm">
{role.name}
</Label>
</div>
))}
</div>
<div className="border-b-2 border-black"></div>
<DialogFooter>
<Link
href={`/auth/registration?category=${selectedCategory}`}
className="flex justify-center bg-red-500 px-4 py-2 rounded-md border border-black text-white hover:bg-red-600 transition-colors"
>
{t("next", { defaultValue: "Next" })}
</Link>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
</div>
{/* Username Field */}
<FormField
label="Username"
name="username"
type="text"
placeholder="Enter your username"
error={errors.username?.message}
disabled={isSubmitting}
required
inputProps={{
size: "lg",
...register("username"),
}}
/>
{/* Password Field */}
<FormField
label={t("password", { defaultValue: "Password" })}
name="password"
type="password"
placeholder="Enter your password"
error={errors.password?.message}
disabled={isSubmitting}
required
showPasswordToggle
showPassword={showPassword}
onPasswordToggle={handlePasswordToggle}
inputProps={{
size: "lg",
...register("password"),
}}
/>
{/* Remember Me and Forgot Password */}
<div className="flex justify-between items-center">
<div className="flex gap-2 items-center">
<Checkbox
id="rememberMe"
checked={rememberMe}
onCheckedChange={(checked) => setRememberMe(checked as boolean)}
disabled={isSubmitting}
/>
<Label htmlFor="rememberMe" className="text-sm">
{t("rememberMe", { defaultValue: "Remember Me" })}
</Label>
</div>
<Link
href="/auth/forgot-password"
className="text-sm text-default-800 dark:text-default-400 leading-6 font-medium hover:underline"
>
{t("forgotPass", { defaultValue: "Forgot Pass" })}
</Link>
</div>
{/* Submit Button */}
<Button
type="submit"
fullWidth
disabled={isSubmitting}
className="mt-6"
>
{isSubmitting ? (
<div className="flex items-center gap-2">
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
Processing...
</div>
) : (
"Selanjutnya"
)}
</Button>
</form>
</div>
);
};