TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import Link from "next/link";4import { useRouter } from "next/navigation";5import { authClient } from "@/lib/auth-client";6import { AuthCard } from "@/components/auth/auth-card";7import { PasswordInput } from "@/components/auth/password-input";8import { Button } from "@/components/ui/button";9import { Input } from "@/components/ui/input";10import { Field, FieldError, Label } from "@/components/ui/label";11import { Alert } from "@/components/ui/alert";1213export function LoginForm({ next, verified, reset }: { next?: string; verified?: boolean; reset?: boolean }) {14 const router = useRouter();15 const [email, setEmail] = React.useState("");16 const [password, setPassword] = React.useState("");17 const [remember, setRemember] = React.useState(true);18 const [error, setError] = React.useState<string | null>(null);19 const [loading, setLoading] = React.useState(false);2021 async function onSubmit(e: React.FormEvent) {22 e.preventDefault();23 setError(null);24 setLoading(true);25 const { error } = await authClient.signIn.email({ email: email.trim(), password, rememberMe: remember, callbackURL: next && next.startsWith("/") ? next : "/dashboard" });26 setLoading(false);27 if (error) {28 setError(error.status === 429 ? "Too many attempts. Wait a minute and try again." : error.message ?? "Invalid email or password.");29 return;30 }31 router.push(next && next.startsWith("/") ? next : "/dashboard");32 router.refresh();33 }3435 return (36 <AuthCard37 title="Welcome back"38 description="Log in to your Fetcha account. Fetcha is a private platform: accounts are created by invitation."39 footer={40 <>41 Invitation only — ask your administrator.{" "}42 <Link href={`/signup${next ? `?next=${encodeURIComponent(next)}` : ""}`} className="font-medium text-fg underline-offset-4 hover:underline">43 Invited? Create your account44 </Link>45 </>46 }47 >48 <form onSubmit={onSubmit} className="grid gap-4" noValidate>49 {verified ? <Alert variant="success">Your email is verified. Log in to continue.</Alert> : null}50 {reset ? <Alert variant="success">Your password was updated. Log in with the new one.</Alert> : null}51 {error ? <Alert variant="danger">{error}</Alert> : null}52 <Field>53 <Label htmlFor="email">Email</Label>54 <Input id="email" name="email" type="email" autoComplete="email" required value={email} onChange={(e) => setEmail(e.target.value)} placeholder="you@company.com" autoFocus />55 </Field>56 <Field>57 <div className="flex items-center justify-between">58 <Label htmlFor="password">Password</Label>59 <Link href="/forgot-password" className="text-[12.5px] text-fg-muted underline-offset-4 hover:text-fg hover:underline">Forgot password?</Link>60 </div>61 <PasswordInput id="password" name="password" autoComplete="current-password" required value={password} onChange={(e) => setPassword(e.target.value)} />62 <FieldError />63 </Field>64 <label className="flex items-center gap-2 text-[13px] text-fg-muted">65 <input type="checkbox" checked={remember} onChange={(e) => setRemember(e.target.checked)} className="size-4 rounded border-border accent-[var(--accent)]" />66 Remember this device67 </label>68 <Button type="submit" size="lg" loading={loading} className="mt-1 w-full">69 Log in70 </Button>71 </form>72 </AuthCard>73 );74}75