refactored Authentication

This commit is contained in:
2026-02-17 16:51:47 +00:00
parent 13e8866875
commit d32d0f5c03
45 changed files with 1322 additions and 66 deletions
@@ -0,0 +1,103 @@
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { Link } from 'react-router';
import { Card } from '@/components/Card';
import { useNavigate } from 'react-router';
import { useState } from 'react';
import { toast } from 'sonner';
import { useForm } from 'hooks/useForm';
import { useAuth } from 'hooks/useAuth';
export function Login() {
const navigate = useNavigate();
const [isSubmitting, setIsSubmitting] = useState(false);
const { state, formRef, update, isValid } = useForm<LoginFormState>({}, validateForm);
const { signin } = useAuth();
const handleSubmit = async (ev: React.FormEvent) => {
ev.preventDefault();
if (!isValid || isSubmitting) return;
setIsSubmitting(true);
try {
await signin({ email: state.email!, password: state.password! });
window.location.href = '/';
} catch (ex) {
const error = ex as { message?: string };
toast.error(error.message || 'Login failed. Please try again.');
update({ ...state, password: '' });
} finally {
setIsSubmitting(false);
}
};
return (
<Card className="md:py-12 md:px-24 flex flex-col gap-6">
<div className="text-center">
<div className="text-duck-dark text-2xl font-bold">Welcome Back</div>
<div className="text-duck-dark/60">Sign in to your account</div>
</div>
<form ref={formRef} onSubmit={handleSubmit} className="grid gap-4">
<Label className="grid gap-2">
<span className="text-duck-dark/70">Email</span>
<Input
className="h-11 bg-white/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40"
type="email"
name="email"
placeholder="you@example.com"
autoComplete="email"
/>
</Label>
<Label className="grid gap-2">
<span className="text-duck-dark/70">Password</span>
<Input
className="h-11 bg-white/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40"
type="password"
name="password"
placeholder="Your password"
autoComplete="current-password"
/>
</Label>
<div className="pt-2">
<Button
type="submit"
disabled={!isValid || isSubmitting}
className="w-full h-11 bg-duck-yellow hover:bg-duck-yellow/90 text-duck-teal font-bold text-lg transition-all duration-200 hover:scale-105 cursor-pointer disabled:opacity-50 disabled:hover:scale-100"
>
{isSubmitting ? 'Signing in...' : 'Sign In'}
</Button>
</div>
<div className="text-center text-sm text-duck-dark/60 grid gap-1">
{/* <p> */}
{/* Don't have an account?{' '} */}
{/* <Link to="/auth/register" className="text-duck-forest underline hover:text-duck-forest/80"> */}
{/* Register */}
{/* </Link> */}
{/* </p> */}
<p>
<Link to="/auth/forgot-password" className="text-duck-forest underline hover:text-duck-forest/80">
Forgot password?
</Link>
</p>
</div>
</form>
</Card>
);
}
type LoginFormState = {
email?: string;
password?: string;
};
const validateForm = (state: Partial<LoginFormState>) => {
const { email, password } = state;
if (!email || !password) return false;
return true;
};