Sun Mar 8 09:35:08 AM CST 2026
This commit is contained in:
@@ -1,66 +1,99 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { Card, CardBody } from "@/design-system/base/card";
|
||||||
|
import { Input } from "@/design-system/base/input";
|
||||||
|
import { PrimaryButton } from "@/design-system/base/button";
|
||||||
|
import { VStack } from "@/design-system/layout/stack";
|
||||||
|
|
||||||
export default function LoginPage() {
|
export default function LoginPage() {
|
||||||
const searchParams = useSearchParams();
|
const [username, setUsername] = useState("");
|
||||||
const redirectTo = searchParams.get("redirect");
|
const [password, setPassword] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const session = authClient.useSession().data;
|
const searchParams = useSearchParams();
|
||||||
const router = useRouter();
|
const redirectTo = searchParams.get("redirect");
|
||||||
|
|
||||||
useEffect(() => {
|
const session = authClient.useSession().data;
|
||||||
if (session) {
|
const router = useRouter();
|
||||||
router.push(redirectTo ?? "/profile");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function login() {
|
useEffect(() => {
|
||||||
const username = (document.getElementById("username") as HTMLInputElement).value;
|
if (session) {
|
||||||
const password = (document.getElementById("password") as HTMLInputElement).value;
|
router.push(redirectTo ?? "/profile");
|
||||||
console.log(username, password);
|
}
|
||||||
if (username.includes("@")) {
|
}, [session, router, redirectTo]);
|
||||||
authClient.signIn.email({
|
|
||||||
email: username,
|
const handleLogin = async () => {
|
||||||
password: username
|
if (!username || !password) {
|
||||||
});
|
toast.error("请输入用户名和密码");
|
||||||
} else {
|
return;
|
||||||
authClient.signIn.username({
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
fetchOptions: {
|
|
||||||
onError: (ctx) => {
|
|
||||||
toast.error(ctx.error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
setLoading(true);
|
||||||
<div className="flex justify-center items-center h-screen w-screen">
|
try {
|
||||||
<div className="rounded shadow-lg w-96 flex flex-col py-4">
|
if (username.includes("@")) {
|
||||||
<h1 className="text-6xl m-16 text-center">登录</h1>
|
await authClient.signIn.email({
|
||||||
<input type="text"
|
email: username,
|
||||||
id="username"
|
password: username
|
||||||
placeholder="用户名或邮箱地址"
|
});
|
||||||
className="mx-auto mb-8 pb-2 w-60 border-b-2 outline-none" />
|
} else {
|
||||||
<input type="password"
|
await authClient.signIn.username({
|
||||||
id="password"
|
username: username,
|
||||||
placeholder="密码"
|
password: password,
|
||||||
className="mx-auto mb-8 pb-2 w-60 border-b-2 outline-none" />
|
});
|
||||||
<button
|
}
|
||||||
onClick={login}
|
router.push(redirectTo ?? "/profile");
|
||||||
className="text-xl rounded shadow w-16 mx-auto p-2 my-4">
|
} catch (error) {
|
||||||
确认</button>
|
toast.error("登录失败");
|
||||||
<Link href={"/signup" + (redirectTo ? `?redirect=${redirectTo}` : "")}
|
} finally {
|
||||||
className="text-center text-blue-800"
|
setLoading(false);
|
||||||
>没有账号?去注册</Link>
|
}
|
||||||
</div>
|
};
|
||||||
</div>
|
|
||||||
);
|
return (
|
||||||
|
<div className="flex justify-center items-center min-h-screen">
|
||||||
|
<Card className="w-80">
|
||||||
|
<CardBody>
|
||||||
|
<VStack gap={4} align="center" justify="center">
|
||||||
|
<h1 className="text-3xl font-bold text-center w-full">登录</h1>
|
||||||
|
|
||||||
|
<VStack gap={0} align="center" justify="center" className="w-full">
|
||||||
|
<Input
|
||||||
|
placeholder="用户名或邮箱地址"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder="密码"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</VStack>
|
||||||
|
|
||||||
|
<PrimaryButton
|
||||||
|
onClick={handleLogin}
|
||||||
|
loading={loading}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</PrimaryButton>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href={"/signup" + (redirectTo ? `?redirect=${redirectTo}` : "")}
|
||||||
|
className="text-center text-primary-500 hover:underline"
|
||||||
|
>
|
||||||
|
没有账号?去注册
|
||||||
|
</Link>
|
||||||
|
</VStack>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,67 +1,102 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
import { authClient } from "@/lib/auth-client";
|
import { authClient } from "@/lib/auth-client";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter, useSearchParams } from "next/navigation";
|
import { useRouter, useSearchParams } from "next/navigation";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
import { Card, CardBody } from "@/design-system/base/card";
|
||||||
|
import { Input } from "@/design-system/base/input";
|
||||||
|
import { PrimaryButton } from "@/design-system/base/button";
|
||||||
|
import { VStack } from "@/design-system/layout/stack";
|
||||||
|
|
||||||
export default function SignUpPage() {
|
export default function SignUpPage() {
|
||||||
const searchParams = useSearchParams();
|
const [username, setUsername] = useState("");
|
||||||
const redirectTo = searchParams.get("redirect");
|
const [email, setEmail] = useState("");
|
||||||
|
const [password, setPassword] = useState("");
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const session = authClient.useSession().data;
|
const searchParams = useSearchParams();
|
||||||
const router = useRouter();
|
const redirectTo = searchParams.get("redirect");
|
||||||
|
|
||||||
console.log(JSON.stringify({ re: redirectTo }));
|
const session = authClient.useSession().data;
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (session) {
|
if (session) {
|
||||||
router.push(redirectTo ?? "/profile");
|
router.push(redirectTo ?? "/profile");
|
||||||
}
|
}
|
||||||
});
|
}, [session, router, redirectTo]);
|
||||||
|
|
||||||
function login() {
|
const handleSignUp = async () => {
|
||||||
const username = (document.getElementById("username") as HTMLInputElement).value;
|
if (!username || !email || !password) {
|
||||||
const email = (document.getElementById("email") as HTMLInputElement).value;
|
toast.error("请填写所有字段");
|
||||||
const password = (document.getElementById("password") as HTMLInputElement).value;
|
return;
|
||||||
authClient.signUp.email({
|
|
||||||
email: email,
|
|
||||||
name: username,
|
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
fetchOptions: {
|
|
||||||
onError: (ctx) => {
|
|
||||||
toast.error(ctx.error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
setLoading(true);
|
||||||
<div className="flex justify-center items-center h-screen w-screen">
|
try {
|
||||||
<div className="rounded shadow-lg w-96 flex flex-col py-4">
|
await authClient.signUp.email({
|
||||||
<h1 className="text-6xl m-16 text-center">注册</h1>
|
email: email,
|
||||||
<input type="text"
|
name: username,
|
||||||
id="username"
|
username: username,
|
||||||
placeholder="用户名"
|
password: password,
|
||||||
className="mx-auto mb-8 pb-2 w-60 border-b-2 outline-none" />
|
});
|
||||||
<input type="email"
|
router.push(redirectTo ?? "/profile");
|
||||||
id="email"
|
} catch (error) {
|
||||||
placeholder="邮箱地址"
|
toast.error("注册失败");
|
||||||
className="mx-auto mb-8 pb-2 w-60 border-b-2 outline-none" />
|
} finally {
|
||||||
<input type="password"
|
setLoading(false);
|
||||||
id="password"
|
}
|
||||||
placeholder="密码"
|
};
|
||||||
className="mx-auto mb-8 pb-2 w-60 border-b-2 outline-none" />
|
|
||||||
<button
|
return (
|
||||||
onClick={login}
|
<div className="flex justify-center items-center min-h-screen">
|
||||||
className="text-xl rounded shadow w-16 mx-auto p-2 my-4">
|
<Card className="w-80">
|
||||||
确认</button>
|
<CardBody>
|
||||||
<Link href={"/login" + (redirectTo ? `?redirect=${redirectTo}` : "")}
|
<VStack gap={4} align="center" justify="center">
|
||||||
className="text-center text-blue-800"
|
<h1 className="text-3xl font-bold text-center w-full">注册</h1>
|
||||||
>已有账号?去登录</Link>
|
|
||||||
</div>
|
<VStack gap={0} align="center" justify="center" className="w-full">
|
||||||
</div>
|
<Input
|
||||||
);
|
placeholder="用户名"
|
||||||
|
value={username}
|
||||||
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="email"
|
||||||
|
placeholder="邮箱地址"
|
||||||
|
value={email}
|
||||||
|
onChange={(e) => setEmail(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
type="password"
|
||||||
|
placeholder="密码"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
/>
|
||||||
|
</VStack>
|
||||||
|
|
||||||
|
<PrimaryButton
|
||||||
|
onClick={handleSignUp}
|
||||||
|
loading={loading}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</PrimaryButton>
|
||||||
|
|
||||||
|
<Link
|
||||||
|
href={"/login" + (redirectTo ? `?redirect=${redirectTo}` : "")}
|
||||||
|
className="text-center text-primary-500 hover:underline"
|
||||||
|
>
|
||||||
|
已有账号?去登录
|
||||||
|
</Link>
|
||||||
|
</VStack>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default async function MemorizePage({
|
|||||||
|
|
||||||
if (!folder_id) {
|
if (!folder_id) {
|
||||||
const session = await auth.api.getSession({ headers: await headers() });
|
const session = await auth.api.getSession({ headers: await headers() });
|
||||||
if (!session) redirect("/auth?redirect=/memorize");
|
if (!session) redirect("/login?redirect=/memorize");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FolderSelector
|
<FolderSelector
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ export default async function FoldersPage() {
|
|||||||
const session = await auth.api.getSession(
|
const session = await auth.api.getSession(
|
||||||
{ headers: await headers() }
|
{ headers: await headers() }
|
||||||
);
|
);
|
||||||
if (!session) redirect(`/auth?redirect=/folders`);
|
if (!session) redirect(`/login?redirect=/folders`);
|
||||||
return <FoldersClient userId={session.user.id} />;
|
return <FoldersClient userId={session.user.id} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,13 +139,13 @@ export async function signOutAction() {
|
|||||||
headers: await headers()
|
headers: await headers()
|
||||||
});
|
});
|
||||||
|
|
||||||
redirect("/auth");
|
redirect("/login");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error && e.message.includes('NEXT_REDIRECT')) {
|
if (e instanceof Error && e.message.includes('NEXT_REDIRECT')) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
console.error("Sign out error:", e);
|
console.error("Sign out error:", e);
|
||||||
redirect("/auth");
|
redirect("/login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user