Files
pitchfast/components/auth-entry.tsx

172 lines
5.8 KiB
TypeScript

"use client";
import { type FormEvent, useState } from "react";
import { useRouter } from "next/navigation";
import {
ArrowRight,
CheckCircle2,
FileSearch,
LockKeyhole,
ShieldCheck,
type LucideIcon,
} from "lucide-react";
import { authClient } from "@/lib/auth-client";
import { Button } from "@/components/ui/button";
const authSignals: Array<{
icon: LucideIcon;
label: string;
value: string;
}> = [
{
icon: FileSearch,
label: "Evidence",
value: "Audit-Aussagen bleiben belegbar.",
},
{
icon: ShieldCheck,
label: "Approval",
value: "Public Audit und Mail bleiben getrennt.",
},
{
icon: CheckCircle2,
label: "Safety",
value: "Versand erfolgt erst nach Finalbestätigung.",
},
];
export function AuthEntry() {
const [error, setError] = useState<string | null>(null);
const [pending, setPending] = useState(false);
const router = useRouter();
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
setError(null);
setPending(true);
const formData = new FormData(event.currentTarget);
const email = String(formData.get("email") ?? "");
const password = String(formData.get("password") ?? "");
const result = await authClient.signIn.email({
email,
password,
});
setPending(false);
if (result.error) {
setError(result.error.message ?? "Authentifizierung fehlgeschlagen.");
return;
}
router.replace("/dashboard");
router.refresh();
}
return (
<main className="dashboard-canvas flex min-h-dvh items-center justify-center px-6 py-10">
<section className="agency-panel grid w-full max-w-5xl overflow-hidden text-card-foreground md:grid-cols-[1.05fr_0.95fr]">
<div className="flex min-h-[520px] flex-col justify-between border-b border-border/75 p-6 md:border-b-0 md:border-r lg:p-8">
<div>
<div className="mb-8 inline-flex items-center gap-3">
<div className="flex size-11 items-center justify-center rounded-md bg-primary font-heading text-sm font-black text-primary-foreground">
WP
</div>
<div>
<p className="font-heading text-sm font-semibold">
WebDev Pipeline
</p>
<p className="text-xs font-medium text-muted-foreground">
Agency Evidence Desk
</p>
</div>
</div>
<p className="agency-kicker">
SaaS Workspace
</p>
<h1 className="mt-4 max-w-xl font-heading text-3xl font-semibold tracking-normal sm:text-4xl">
Lokale Chancen belegen, prüfen und erst dann kontaktieren.
</h1>
<p className="mt-4 max-w-lg text-sm leading-6 text-muted-foreground sm:text-base">
Melde dich an, um Kampagnen, Lead-Qualität, Audit-Evidence und
Outreach-Freigaben in einem geschützten Kunden-Workspace zu steuern.
</p>
</div>
<dl className="grid gap-4 pt-8 sm:grid-cols-3">
{authSignals.map(({ icon: Icon, label, value }) => (
<div className="rounded-md border border-border/75 bg-background/60 p-3" key={label}>
<dt className="inline-flex items-center gap-2 text-sm font-semibold">
<Icon className="size-4 text-primary" />
{label}
</dt>
<dd className="mt-1 text-sm leading-5 text-muted-foreground">
{value}
</dd>
</div>
))}
</dl>
</div>
<div className="flex flex-col justify-center bg-background/45 p-6 lg:p-8">
<div className="mx-auto w-full max-w-sm">
<h2 className="font-heading text-2xl font-semibold tracking-normal">
Workspace Login
</h2>
<p className="mt-2 text-sm leading-6 text-muted-foreground">
Melde dich mit E-Mail und Passwort an.
</p>
<form className="mt-8 grid gap-3" onSubmit={handleSubmit}>
<label className="block space-y-2 text-sm font-medium">
<span>E-Mail</span>
<input
name="email"
type="email"
className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/35"
autoComplete="email"
required
placeholder="admin@firma.de"
/>
</label>
<label className="block space-y-2 text-sm font-medium">
<span>Passwort</span>
<input
name="password"
type="password"
className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm outline-none focus-visible:ring-3 focus-visible:ring-ring/35"
autoComplete="current-password"
required
minLength={8}
placeholder="mindestens 8 Zeichen"
/>
</label>
{error ? (
<p
className="text-sm leading-6 text-destructive"
role="alert"
>
{error}
</p>
) : null}
<Button
className="w-full justify-between"
size="lg"
disabled={pending}
>
<span className="inline-flex items-center gap-2">
<LockKeyhole />
Anmelden
</span>
{pending ? "..." : <ArrowRight />}
</Button>
</form>
</div>
</div>
</section>
</main>
);
}