Yaltopia-FIFA/components/auth/login-form.tsx
Kirubel-Kibru-Yaltopia 89440985f1
Some checks failed
Deploy to Cloudflare Workers / deploy (push) Has been cancelled
x
2026-05-24 21:46:10 +03:00

158 lines
4.7 KiB
TypeScript

"use client";
import { useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { createClient } from "@/lib/supabase/client";
import { formatAuthNetworkError } from "@/lib/supabase/env";
import type { PortalRole } from "@/lib/auth/roles";
import { PORTAL_ROUTES } from "@/lib/auth/roles";
import {
ensureUserProfile,
isPortalRoleSchemaError,
resolvePortalRole,
} from "@/lib/auth/resolve-portal-role";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { PasswordInput } from "@/components/ui/password-input";
import { Label } from "@/components/ui/label";
export function LoginForm({ expectedRole }: { expectedRole: PortalRole }) {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setLoading(true);
setError(null);
try {
const supabase = createClient();
const { data: authData, error: authError } =
await supabase.auth.signInWithPassword({ email, password });
if (authError) {
setError(authError.message);
return;
}
const userId = authData.user?.id;
if (!userId) {
setError("Sign in failed");
return;
}
const {
data: { user },
} = await supabase.auth.getUser();
if (!user) {
setError("Sign in failed");
return;
}
const { role, profileError } = await resolvePortalRole(supabase, user);
if (role !== expectedRole) {
await supabase.auth.signOut();
setError(
expectedRole === "manager"
? "This account is not a Team Manager. Use the League Master sign-in URL if you are an admin."
: "This account is not a League Master. Use the manager sign-in page."
);
return;
}
if (profileError && isPortalRoleSchemaError(profileError)) {
setError(
"Database is missing portal_role. Run: npm run db:push — then try again."
);
return;
}
if (profileError) {
await ensureUserProfile(supabase, user, expectedRole);
}
router.push(PORTAL_ROUTES[expectedRole]);
router.refresh();
} catch (err) {
setError(formatAuthNetworkError(err));
} finally {
setLoading(false);
}
}
return (
<form onSubmit={handleSubmit} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
autoComplete="email"
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<PasswordInput
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
autoComplete="current-password"
/>
</div>
{error && (
<p className="whitespace-pre-line text-sm text-red-400">{error}</p>
)}
<Button type="submit" className="w-full" disabled={loading}>
{loading ? "Signing in…" : "Sign in"}
</Button>
<p className="text-center text-sm">
<Link
href={
expectedRole === "league_master"
? "/forgot-password/master"
: "/forgot-password/manager"
}
className="text-muted-foreground underline-offset-4 hover:text-foreground hover:underline"
>
Forgot password?
</Link>
</p>
</form>
);
}
export function LoginPageShell({
title,
subtitle,
children,
footer,
}: {
title: string;
subtitle: string;
children: React.ReactNode;
footer?: React.ReactNode;
}) {
return (
<div className="retro-grid flex min-h-screen flex-col items-center justify-center px-4">
<div className="retro-card w-full max-w-md p-8">
<p className="font-display text-[10px] font-bold uppercase tracking-[0.2em] text-neon">
Yaltopia FIFA
</p>
<h1 className="font-display mt-1 text-2xl font-black uppercase tracking-tight">
{title}
</h1>
<p className="mt-1 text-sm text-muted-foreground">{subtitle}</p>
<div className="mt-6">{children}</div>
{footer && <div className="mt-6">{footer}</div>}
</div>
</div>
);
}