167 lines
6.1 KiB
TypeScript
167 lines
6.1 KiB
TypeScript
"use client";
|
||
|
||
import { useEffect, useState } from "react";
|
||
import { useRouter, useSearchParams } from "next/navigation";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Label } from "@/components/ui/label";
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||
import { getErrorMessage, postAPI } from "@/lib/api";
|
||
import Link from "next/link";
|
||
import type { LoginResponse } from "@/lib/types";
|
||
|
||
export default function ActivatePage() {
|
||
const [inviteCode, setInviteCode] = useState("");
|
||
const [studentId, setStudentId] = useState("");
|
||
const [email, setEmail] = useState("");
|
||
const [password, setPassword] = useState("");
|
||
const [confirmPassword, setConfirmPassword] = useState("");
|
||
const [error, setError] = useState("");
|
||
const [loading, setLoading] = useState(false);
|
||
const router = useRouter();
|
||
const searchParams = useSearchParams();
|
||
|
||
useEffect(() => {
|
||
const code = searchParams.get("code")?.trim();
|
||
if (code) {
|
||
setInviteCode(code.toUpperCase());
|
||
}
|
||
}, [searchParams]);
|
||
|
||
const handleSubmit = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
setError("");
|
||
|
||
if (password !== confirmPassword) {
|
||
setError("两次密码输入不一致");
|
||
return;
|
||
}
|
||
if (password.length < 8) {
|
||
setError("密码至少8位");
|
||
return;
|
||
}
|
||
|
||
setLoading(true);
|
||
try {
|
||
const res = await postAPI<LoginResponse>("/api/auth/activate", {
|
||
invite_code: inviteCode,
|
||
student_id: studentId,
|
||
email,
|
||
password,
|
||
});
|
||
|
||
if (res.token) {
|
||
localStorage.setItem("auth_token", res.token);
|
||
localStorage.setItem("auth_user", JSON.stringify(res.user));
|
||
router.push("/");
|
||
} else {
|
||
router.push("/login");
|
||
}
|
||
} catch (err: unknown) {
|
||
setError(getErrorMessage(err, "激活失败"));
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="relative min-h-screen overflow-hidden bg-[linear-gradient(180deg,#f7efe2_0%,#f4ebdf_38%,#f9f5ee_100%)] px-4 py-10">
|
||
<div className="absolute inset-x-0 top-0 h-72 bg-[radial-gradient(circle_at_top,rgba(115,25,37,0.18),transparent_60%)]" />
|
||
<div className="relative mx-auto flex min-h-[calc(100vh-5rem)] max-w-6xl items-center justify-center">
|
||
<div className="grid w-full items-center gap-10 lg:grid-cols-[1.05fr_0.95fr]">
|
||
<div className="hidden lg:block">
|
||
<div className="inline-flex items-center rounded-full border border-[#c9ac82] bg-white/55 px-4 py-1.5 text-[11px] uppercase tracking-[0.28em] text-[#84553c]">
|
||
HKU ICB Cohort Access
|
||
</div>
|
||
<h1 className="mt-6 max-w-2xl text-5xl font-semibold leading-tight text-[#4e1d1a]">
|
||
完成账号激活,进入你的班级空间
|
||
</h1>
|
||
<p className="mt-5 max-w-xl text-base leading-8 text-[#775a4a]">
|
||
成员导入后,只需使用激活码与学号确认身份,再补全邮箱和密码即可启用账号。若从邀请链接进入,激活码会自动填入。
|
||
</p>
|
||
</div>
|
||
|
||
<Card className="mx-auto w-full max-w-md bg-[#fffaf3]">
|
||
<CardHeader className="text-center">
|
||
<div className="text-[11px] uppercase tracking-[0.24em] text-[#976746]">Activate Account</div>
|
||
<CardTitle className="text-3xl text-[#4e1d1a]">激活账号</CardTitle>
|
||
<CardDescription className="text-[#7a5e4f]">输入班级激活码与学号,完成账号启用</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<form onSubmit={handleSubmit} className="space-y-4">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="inviteCode">邀请码</Label>
|
||
<Input
|
||
id="inviteCode"
|
||
placeholder="请输入班级邀请码"
|
||
value={inviteCode}
|
||
onChange={(e) => setInviteCode(e.target.value.toUpperCase())}
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="studentId">学号</Label>
|
||
<Input
|
||
id="studentId"
|
||
placeholder="请输入学号"
|
||
value={studentId}
|
||
onChange={(e) => setStudentId(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="email">邮箱</Label>
|
||
<Input
|
||
id="email"
|
||
type="email"
|
||
placeholder="your@email.com"
|
||
value={email}
|
||
onChange={(e) => setEmail(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="password">密码</Label>
|
||
<Input
|
||
id="password"
|
||
type="password"
|
||
placeholder="至少8位"
|
||
value={password}
|
||
onChange={(e) => setPassword(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="confirmPassword">确认密码</Label>
|
||
<Input
|
||
id="confirmPassword"
|
||
type="password"
|
||
placeholder="再次输入密码"
|
||
value={confirmPassword}
|
||
onChange={(e) => setConfirmPassword(e.target.value)}
|
||
required
|
||
/>
|
||
</div>
|
||
{error && (
|
||
<p className="rounded-2xl bg-red-50 p-3 text-sm text-red-600">
|
||
{error}
|
||
</p>
|
||
)}
|
||
<Button type="submit" className="w-full" disabled={loading}>
|
||
{loading ? "激活中..." : "激活账号"}
|
||
</Button>
|
||
</form>
|
||
<div className="mt-5 text-center text-sm text-[#6f5648]">
|
||
已有账号?{" "}
|
||
<Link href="/login" className="text-[#8a4527] hover:underline">
|
||
登录
|
||
</Link>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|