NAM-APJATEL/src/pages/auth/LoginPage.tsx

136 lines
4.4 KiB
TypeScript

import { useState } from "react";
import { useLogin } from "../../features/auth/api/auth";
import axios from "axios";
import Input from "@/components/forms/Input";
import Alert from "@/components/feedback/Alert";
import Card from "@/components/data_display/Card/Card";
import Button from "@/components/actions/Button";
const LoginPage = () => {
const [errors, setErrors] = useState<Record<string, string>>({});
const { ...login } = useLogin({
onError: (error) => {
setErrors(error)
}
});
const [formData, setFormData] = useState({
username: "",
password: "",
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData((prev) => ({
...prev,
[name]: value,
}));
// Hapus error untuk field yang sedang diubah
if (errors[name]) {
setErrors((prev) => {
const newErrors = { ...prev };
delete newErrors[name];
return newErrors;
});
}
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
await login.mutateAsync(formData);
} catch (error: unknown) {
if (axios.isAxiosError(error) && error.response?.status === 400) {
const apiErrors = error.response.data.status.errors;
setErrors(apiErrors || {});
}
}
};
return (
<div className="min-w-screen flex items-center justify-center bg-base-200 mx-0">
<div className="flex min-h-screen items-center justify-center bg-base-200 mx-0">
<Card className="w-sm bg-base-100 shadow-xl">
<Card.Body>
<h2 className="card-title text-2xl mx-auto mb-2">Login</h2>
{errors.general && (
<Alert
status="error"
soft
icon={
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6 shrink-0 stroke-current" fill="none" viewBox="0 0 24 24" >
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
}
>
<span>{errors.general}</span>
</Alert>
)}
<form onSubmit={handleSubmit}>
<div className="flex flex-col w-full component-preview gap-4 items-center justify-center font-sans">
<div className="form-control w-full">
<label className="label mb-1">
<span className="label-text font-semibold">Username</span>
</label>
<Input
placeholder="Username"
name="username"
onChange={handleChange}
className={`w-full ${errors.username ? "input-error" : ""}`}
/>
{errors.username && (
<label className="label">
<span className="label-text-alt">{errors.username}</span>
</label>
)}
</div>
<div className="form-control w-full">
<label className="label mb-1">
<span className="label-text font-semibold">Password</span>
</label>
<Input
placeholder="Password"
name="password"
type="password"
onChange={handleChange}
className={`w-full ${errors.password ? "input-error" : ""}`}
/>
{errors.password && (
<label className="label">
<span className="label-text-alt">{errors.password}</span>
</label>
)}
</div>
</div>
<div className="form-control mt-6">
<Button
type="submit"
fullWidth
color="primary"
disabled={login.isPending}
>
{login.isPending ? (
<span className="loading loading-spinner loading-sm"></span>
) : (
"Login"
)}
</Button>
</div>
</form>
</Card.Body>
</Card>
</div>
</div>
);
};
export default LoginPage;