mirror of
https://github.com/snowykami/neo-blog.git
synced 2025-09-26 19:16:24 +00:00
feat: 更新用户界面,添加注销功能和绑定第三方账号选项,优化表单布局
This commit is contained in:
@ -8,33 +8,49 @@ import { useTranslations } from "next-intl";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import React from "react";
|
||||
import { SectionDivider } from '@/components/common/section-divider';
|
||||
import { LogOut } from "lucide-react";
|
||||
import { userLogout } from "@/api/user";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function CurrentLogged() {
|
||||
const t = useTranslations("Login");
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
const redirectBack = searchParams.get("redirect_back") || "/"
|
||||
const { user } = useAuth();
|
||||
const { user, logout } = useAuth();
|
||||
|
||||
const handleLoggedContinue = () => {
|
||||
router.push(redirectBack);
|
||||
}
|
||||
|
||||
const handleLogOut = () => {
|
||||
userLogout().then(() => {
|
||||
logout();
|
||||
toast.success(t("logout_success"));
|
||||
})
|
||||
}
|
||||
|
||||
if (!user) return null;
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<SectionDivider className="mb-4">{t("currently_logged_in")}</SectionDivider>
|
||||
<div onClick={handleLoggedContinue} className="cursor-pointer">
|
||||
<div className="flex gap-2 justify-center items-center">
|
||||
<Avatar className="h-10 w-10 rounded-full">
|
||||
<AvatarImage src={getGravatarFromUser({ user })} alt={user.username} />
|
||||
<AvatarFallback className="rounded-full">{getFallbackAvatarFromUsername(user.nickname || user.username)}</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex justify-evenly items-center">
|
||||
<div className="flex gap-4 items-center cursor-pointer">
|
||||
<div onClick={handleLoggedContinue} className="flex gap-2 justify-center items-center ">
|
||||
<Avatar className="h-10 w-10 rounded-full">
|
||||
<AvatarImage src={getGravatarFromUser({ user })} alt={user.username} />
|
||||
<AvatarFallback className="rounded-full">{getFallbackAvatarFromUsername(user.nickname || user.username)}</AvatarFallback>
|
||||
</Avatar>
|
||||
</div>
|
||||
<div className="grid place-items-center text-sm leading-tight text-center">
|
||||
<span className="text-primary font-medium">{formatDisplayName(user)}</span>
|
||||
<span className="text-muted-foreground truncate text-xs">
|
||||
{user.email}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid place-items-center text-sm leading-tight text-center">
|
||||
<span className="text-primary font-medium">{formatDisplayName(user)}</span>
|
||||
<span className="text-muted-foreground truncate text-xs">
|
||||
{user.email}
|
||||
</span>
|
||||
<div>
|
||||
<LogOut onClick={handleLogOut} className="text-muted-foreground cursor-pointer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -25,6 +25,7 @@ import { useAuth } from "@/contexts/auth-context"
|
||||
import { registerPath, resetPasswordPath } from "@/hooks/use-route"
|
||||
import { CurrentLogged } from "@/components/auth/common/current-logged"
|
||||
import { SectionDivider } from "@/components/common/section-divider"
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
|
||||
|
||||
export function LoginForm({
|
||||
className,
|
||||
@ -103,9 +104,9 @@ export function LoginForm({
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<CurrentLogged />
|
||||
<SectionDivider className="my-4">{t("with_oidc")}</SectionDivider>
|
||||
<SectionDivider className="mb-6">{user ? t("bind_oidc") : t("with_oidc")}</SectionDivider>
|
||||
<form>
|
||||
<div className="grid gap-6">
|
||||
<div className="grid gap-4">
|
||||
{/* OIDC 登录选项 */}
|
||||
{oidcConfigs.length > 0 && (
|
||||
<div className="flex flex-col gap-4">
|
||||
@ -130,10 +131,10 @@ export function LoginForm({
|
||||
)}
|
||||
{/* 分隔线 */}
|
||||
{oidcConfigs.length > 0 && (
|
||||
<SectionDivider className="my-0"> {t("or_continue_with_local_account")}</SectionDivider>
|
||||
<SectionDivider className="my-2"> {t("or_continue_with_local_account")}</SectionDivider>
|
||||
)}
|
||||
{/* 邮箱密码登录 */}
|
||||
<div className="grid gap-6">
|
||||
<div className="grid gap-4">
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="email">{t("email_or_username")}</Label>
|
||||
<Input
|
||||
@ -181,7 +182,7 @@ export function LoginForm({
|
||||
{/* 注册链接 */}
|
||||
<div className="text-center text-sm">
|
||||
{t("no_account")}{" "}
|
||||
<Link href={registerPath+"?redirect_back="+encodeURIComponent(redirectBack)} className="underline underline-offset-4">
|
||||
<Link href={registerPath + "?redirect_back=" + encodeURIComponent(redirectBack)} className="underline underline-offset-4">
|
||||
{t("register")}
|
||||
</Link>
|
||||
</div>
|
||||
@ -211,20 +212,10 @@ function LoginWithOidc({
|
||||
asChild
|
||||
>
|
||||
<Link href={loginUrl}>
|
||||
<Image
|
||||
src={icon}
|
||||
alt={`${displayName} icon`}
|
||||
width={16}
|
||||
height={16}
|
||||
style={{
|
||||
width: '16px',
|
||||
height: '16px',
|
||||
marginRight: '8px'
|
||||
}}
|
||||
onError={(e) => {
|
||||
e.currentTarget.style.display = 'none';
|
||||
}}
|
||||
/>
|
||||
<Avatar className="h-6 w-6 rounded-full">
|
||||
<AvatarImage src={icon} alt={displayName} />
|
||||
<AvatarFallback className="rounded-full"></AvatarFallback>
|
||||
</Avatar>
|
||||
{displayName}
|
||||
</Link>
|
||||
</Button>
|
||||
|
@ -109,10 +109,10 @@ export function RegisterForm({
|
||||
<CardContent>
|
||||
<CurrentLogged />
|
||||
<form>
|
||||
<div className="grid gap-6">
|
||||
<SectionDivider className="mt-4">{t("register_a_new_account")}</SectionDivider>
|
||||
<div className="grid gap-4">
|
||||
<SectionDivider className="mt-0">{t("register_a_new_account")}</SectionDivider>
|
||||
|
||||
<div className="grid gap-6">
|
||||
<div className="grid gap-4">
|
||||
|
||||
{/* 用户名 */}
|
||||
<div className="grid gap-3">
|
||||
@ -152,17 +152,21 @@ export function RegisterForm({
|
||||
value={email}
|
||||
onChange={e => setEmail(e.target.value)}
|
||||
/>
|
||||
<Button onClick={handleSendVerifyCode} disabled={!email} variant="outline" className="border-2" type="button">
|
||||
{commonT("send_verify_code")}
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/* 邮箱验证码 */}
|
||||
<div className="grid gap-3">
|
||||
<Label htmlFor="email">{commonT("verify_code")}</Label>
|
||||
<InputOTPControlled
|
||||
onChange={value => setVerifyCode(value)}
|
||||
/>
|
||||
<div className="flex justify-between">
|
||||
<InputOTPControlled
|
||||
onChange={value => setVerifyCode(value)}
|
||||
/>
|
||||
<Button onClick={handleSendVerifyCode} disabled={!email} variant="outline" className="border-2" type="button">
|
||||
{commonT("send_verify_code")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{captchaProps &&
|
||||
<div className="flex justify-center items-center w-full">
|
||||
|
Reference in New Issue
Block a user