Files
evanpage/frontend/app/init/page.tsx
root 694b02e848 frontend: rebuild bookmark page with drag-and-drop, search, and theme system
- bookmark management with dnd-kit reordering, bulk edit, search,
  category filter/rename, and meta auto-fetch
- migrate /bookmarks → /dashboard/bookmarks under (main) layout
- homepage redesign with category grid, /-key search, dock tooltips
- theme toggle + use-theme, sonner toasts, alert-dialog/skeleton,
  visual refresh of auth pages

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-02 22:53:17 +00:00

152 lines
4.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
export default function InitPage() {
const router = useRouter();
const [loading, setLoading] = useState(true);
const [initialized, setInitialized] = useState(true);
const [form, setForm] = useState({
username: "",
email: "",
password: "",
confirmPassword: "",
});
const [error, setError] = useState("");
useEffect(() => {
fetch("/api/proxy/admin/users", {
headers: { "X-User-Role": "admin" },
})
.then((res) => {
if (res.ok) {
setInitialized(true);
} else {
setInitialized(false);
}
})
.catch(() => setInitialized(false))
.finally(() => setLoading(false));
}, []);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setError("");
if (form.password !== form.confirmPassword) {
setError("两次输入的密码不一致");
return;
}
const res = await fetch("/api/proxy/auth/init", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
username: form.username,
email: form.email,
password: form.password,
}),
});
if (!res.ok) {
const data = await res.json();
setError(data.error || "初始化失败");
return;
}
router.push("/login");
}
if (loading) {
return (
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-background via-background to-muted/40 text-sm text-muted-foreground">
...
</div>
);
}
if (initialized) {
return (
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-background via-background to-muted/40 p-4">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-center"></CardTitle>
</CardHeader>
<CardContent>
<p className="text-center text-sm text-muted-foreground">
</p>
</CardContent>
</Card>
</div>
);
}
return (
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-background via-background to-muted/40 p-4">
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle className="text-center"></CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<p className="text-sm text-muted-foreground">
</p>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<Label htmlFor="username"></Label>
<Input
id="username"
value={form.username}
onChange={(e) => setForm({ ...form, username: e.target.value })}
required
/>
</div>
<div>
<Label htmlFor="email"></Label>
<Input
id="email"
type="email"
value={form.email}
onChange={(e) => setForm({ ...form, email: e.target.value })}
required
/>
</div>
<div>
<Label htmlFor="password"></Label>
<Input
id="password"
type="password"
value={form.password}
onChange={(e) => setForm({ ...form, password: e.target.value })}
required
/>
</div>
<div>
<Label htmlFor="confirmPassword"></Label>
<Input
id="confirmPassword"
type="password"
value={form.confirmPassword}
onChange={(e) =>
setForm({ ...form, confirmPassword: e.target.value })
}
required
/>
</div>
{error && <p className="text-sm text-destructive">{error}</p>}
<Button type="submit" className="w-full">
</Button>
</form>
</CardContent>
</Card>
</div>
);
}