From b97b94805663574ea9983ad2dc0fb6c133d76c89 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:17:06 +0330 Subject: [PATCH] Import source: vault/app/login/page Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- vault/app/login/page.tsx | 118 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 vault/app/login/page.tsx diff --git a/vault/app/login/page.tsx b/vault/app/login/page.tsx new file mode 100644 index 0000000..91de876 --- /dev/null +++ b/vault/app/login/page.tsx @@ -0,0 +1,118 @@ +"use client"; + +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; +import { Lock, RefreshCw } from "lucide-react"; +import { toast } from "sonner"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { api } from "@/lib/api-client"; + +export default function LoginPage() { + const router = useRouter(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [captcha, setCaptcha] = useState(""); + const [challenge, setChallenge] = useState(""); + const [submitting, setSubmitting] = useState(false); + + const loadCaptcha = async () => { + const { challenge } = await api.captcha(); + setChallenge(challenge); + setCaptcha(""); + }; + + useEffect(() => { + api.captcha() + .then(({ challenge }) => setChallenge(challenge)) + .catch(() => toast.error("Unable to load captcha")); + }, []); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + setSubmitting(true); + + try { + await api.login(username, password, captcha); + toast.success("Signed in"); + router.push("/snippets"); + router.refresh(); + } catch (error) { + toast.error(error instanceof Error ? error.message : "Unable to sign in"); + await loadCaptcha(); + } finally { + setSubmitting(false); + } + }; + + return ( +
+
+
+
+ +
+
+

Sign in

+

Use a local username and password.

+
+
+ +
+
+ + setUsername(event.target.value)} + className="h-11 bg-muted/50 border-border/50" + required + /> +
+ +
+ + setPassword(event.target.value)} + className="h-11 bg-muted/50 border-border/50" + required + /> +
+ +
+
+ + +
+ setCaptcha(event.target.value)} + className="h-11 bg-muted/50 border-border/50" + required + /> +
+ + +
+ +

+ Need an account?{" "} + + Create one + +

+
+
+ ); +}