perf(prettier): perf

This commit is contained in:
2026-02-11 13:57:47 +08:00
parent 2696ec8692
commit 03a1e6043d
21 changed files with 354 additions and 285 deletions

View File

@@ -1,50 +1,52 @@
import * as React from "react"
import Link from "next/link"
import * as React from "react";
import Link from "next/link";
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { CaptchaField } from "@/components/auth/captcha-field"
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { CaptchaField } from "@/components/auth/captcha-field";
export function LoginForm(props: {
clientId: string
tenantId: string
callback: string
initialEmail: string
prefillPassword?: string
disabled?: boolean
externalError?: string | null
onClearExternalError?: () => void
captcha: string
onCaptchaChange: (next: string) => void
captchaKey: string
onRefreshCaptcha: () => void
clientId: string;
tenantId: string;
callback: string;
initialEmail: string;
prefillPassword?: string;
disabled?: boolean;
externalError?: string | null;
onClearExternalError?: () => void;
captcha: string;
onCaptchaChange: (next: string) => void;
captchaKey: string;
onRefreshCaptcha: () => void;
}) {
const [email, setEmail] = React.useState(props.initialEmail)
const [password, setPassword] = React.useState("")
const [rememberMe, setRememberMe] = React.useState(Boolean(props.initialEmail))
const [submitting, setSubmitting] = React.useState(false)
const [error, setError] = React.useState<string | null>(null)
const [email, setEmail] = React.useState(props.initialEmail);
const [password, setPassword] = React.useState("");
const [rememberMe, setRememberMe] = React.useState(
Boolean(props.initialEmail),
);
const [submitting, setSubmitting] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
React.useEffect(() => {
setEmail(props.initialEmail)
setRememberMe(Boolean(props.initialEmail))
}, [props.initialEmail])
setEmail(props.initialEmail);
setRememberMe(Boolean(props.initialEmail));
}, [props.initialEmail]);
React.useEffect(() => {
if (props.prefillPassword) {
setPassword(props.prefillPassword)
setPassword(props.prefillPassword);
}
}, [props.prefillPassword])
}, [props.prefillPassword]);
const missingParams = !props.clientId || !props.tenantId || !props.callback
const missingParams = !props.clientId || !props.tenantId || !props.callback;
async function onSubmit(e: React.FormEvent) {
e.preventDefault()
setError(null)
props.onClearExternalError?.()
setSubmitting(true)
e.preventDefault();
setError(null);
props.onClearExternalError?.();
setSubmitting(true);
try {
const res = await fetch("/api/auth/login", {
method: "POST",
@@ -58,22 +60,25 @@ export function LoginForm(props: {
captcha: props.captcha,
rememberMe,
}),
})
const json = (await res.json()) as { redirectTo?: string; message?: string }
});
const json = (await res.json()) as {
redirectTo?: string;
message?: string;
};
if (!res.ok || !json.redirectTo) {
throw new Error(json.message || "登录失败")
throw new Error(json.message || "登录失败");
}
window.location.href = json.redirectTo
window.location.href = json.redirectTo;
} catch (err) {
setError(err instanceof Error ? err.message : "登录失败")
props.onCaptchaChange("")
props.onRefreshCaptcha()
setError(err instanceof Error ? err.message : "登录失败");
props.onCaptchaChange("");
props.onRefreshCaptcha();
} finally {
setSubmitting(false)
setSubmitting(false);
}
}
const disabled = Boolean(props.disabled) || submitting
const disabled = Boolean(props.disabled) || submitting;
return (
<form onSubmit={onSubmit} className="space-y-4">
@@ -146,5 +151,5 @@ export function LoginForm(props: {
{submitting ? "登录中..." : "登录"}
</Button>
</form>
)
);
}

View File

@@ -1,54 +1,60 @@
import * as React from "react"
import * as React from "react";
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { CaptchaField } from "@/components/auth/captcha-field"
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { CaptchaField } from "@/components/auth/captcha-field";
export function RegisterForm(props: {
tenantId: string
disabled?: boolean
captcha: string
onCaptchaChange: (next: string) => void
captchaKey: string
onRefreshCaptcha: () => void
onRegisterSuccessPrefillLogin: (payload: { email: string; password: string }) => void
onLoginAfterRegister: (payload: { email: string; password: string }) => Promise<void>
tenantId: string;
disabled?: boolean;
captcha: string;
onCaptchaChange: (next: string) => void;
captchaKey: string;
onRefreshCaptcha: () => void;
onRegisterSuccessPrefillLogin: (payload: {
email: string;
password: string;
}) => void;
onLoginAfterRegister: (payload: {
email: string;
password: string;
}) => Promise<void>;
}) {
const [email, setEmail] = React.useState("")
const [password, setPassword] = React.useState("")
const [confirmPassword, setConfirmPassword] = React.useState("")
const [submitting, setSubmitting] = React.useState(false)
const [error, setError] = React.useState<string | null>(null)
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const [confirmPassword, setConfirmPassword] = React.useState("");
const [submitting, setSubmitting] = React.useState(false);
const [error, setError] = React.useState<string | null>(null);
const passwordMismatch =
confirmPassword.length > 0 && password !== confirmPassword
confirmPassword.length > 0 && password !== confirmPassword;
const missingTenant = !props.tenantId
const missingTenant = !props.tenantId;
async function onSubmit(e: React.FormEvent) {
e.preventDefault()
setError(null)
e.preventDefault();
setError(null);
const nextEmail = email.trim()
const nextEmail = email.trim();
if (!props.tenantId) {
setError("缺少 tenantId 参数,无法注册")
return
setError("缺少 tenantId 参数,无法注册");
return;
}
if (!nextEmail || !password || !confirmPassword) {
setError("请填写邮箱与密码")
return
setError("请填写邮箱与密码");
return;
}
if (passwordMismatch) {
setError("两次输入的密码不一致")
return
setError("两次输入的密码不一致");
return;
}
if (!props.captcha.trim()) {
setError("请填写验证码")
return
setError("请填写验证码");
return;
}
setSubmitting(true)
setSubmitting(true);
try {
const res = await fetch("/api/auth/register", {
method: "POST",
@@ -58,31 +64,31 @@ export function RegisterForm(props: {
email: nextEmail,
password,
}),
})
});
const json = (await res.json()) as { message?: string; id?: string }
const json = (await res.json()) as { message?: string; id?: string };
if (!res.ok) {
if (res.status === 409) {
throw new Error("该邮箱已注册,请直接登录")
throw new Error("该邮箱已注册,请直接登录");
}
throw new Error(json.message || "注册失败")
throw new Error(json.message || "注册失败");
}
if (!json.id) {
throw new Error("注册失败")
throw new Error("注册失败");
}
props.onRegisterSuccessPrefillLogin({ email: nextEmail, password })
await props.onLoginAfterRegister({ email: nextEmail, password })
props.onRegisterSuccessPrefillLogin({ email: nextEmail, password });
await props.onLoginAfterRegister({ email: nextEmail, password });
} catch (err) {
setError(err instanceof Error ? err.message : "注册失败")
props.onCaptchaChange("")
props.onRefreshCaptcha()
setError(err instanceof Error ? err.message : "注册失败");
props.onCaptchaChange("");
props.onRefreshCaptcha();
} finally {
setSubmitting(false)
setSubmitting(false);
}
}
const disabled = Boolean(props.disabled) || submitting
const disabled = Boolean(props.disabled) || submitting;
return (
<form onSubmit={onSubmit} className="space-y-4">
@@ -151,5 +157,5 @@ export function RegisterForm(props: {
{submitting ? "注册中..." : "注册并登录"}
</Button>
</form>
)
);
}

View File

@@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-base md:text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
@@ -13,7 +13,8 @@ const buttonVariants = cva(
secondary: "bg-secondary text-secondary-foreground hover:opacity-90",
outline: "border border-input bg-background hover:bg-secondary",
ghost: "hover:bg-secondary",
destructive: "bg-destructive text-destructive-foreground hover:opacity-90",
destructive:
"bg-destructive text-destructive-foreground hover:opacity-90",
},
size: {
default: "h-10 px-4 py-2",
@@ -26,27 +27,27 @@ const buttonVariants = cva(
size: "default",
},
},
)
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
extends
React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
);
},
)
Button.displayName = "Button"
export { Button, buttonVariants }
);
Button.displayName = "Button";
export { Button, buttonVariants };

View File

@@ -1,52 +1,86 @@
import * as React from "react"
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("rounded-lg border border-border bg-card text-card-foreground shadow-sm", className)}
{...props}
/>
),
)
Card.displayName = "Card"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border border-border bg-card text-card-foreground shadow-sm",
className,
)}
{...props}
/>
));
Card.displayName = "Card";
const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex flex-col space-y-1.5 p-6", className)} {...props} />
),
)
CardHeader.displayName = "CardHeader"
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
));
CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<HTMLHeadingElement, React.HTMLAttributes<HTMLHeadingElement>>(
({ className, ...props }, ref) => (
<h3 ref={ref} className={cn("text-2xl font-semibold leading-none tracking-tight", className)} {...props} />
),
)
CardTitle.displayName = "CardTitle"
const CardTitle = React.forwardRef<
HTMLHeadingElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
({ className, ...props }, ref) => (
<p ref={ref} className={cn("text-sm text-muted-foreground", className)} {...props} />
),
)
CardDescription.displayName = "CardDescription"
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
),
)
CardContent.displayName = "CardContent"
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
));
CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
({ className, ...props }, ref) => (
<div ref={ref} className={cn("flex items-center p-6 pt-0", className)} {...props} />
),
)
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
));
CardFooter.displayName = "CardFooter";
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardDescription,
CardContent,
};

View File

@@ -1,8 +1,8 @@
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Check } from "lucide-react"
import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check } from "lucide-react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
@@ -20,8 +20,7 @@ const Checkbox = React.forwardRef<
<Check className="h-3.5 w-3.5" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
))
Checkbox.displayName = CheckboxPrimitive.Root.displayName
export { Checkbox }
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
export { Checkbox };

View File

@@ -1,7 +1,7 @@
import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import * as React from "react";
import * as LabelPrimitive from "@radix-ui/react-label";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Label = React.forwardRef<
React.ElementRef<typeof LabelPrimitive.Root>,
@@ -15,8 +15,7 @@ const Label = React.forwardRef<
)}
{...props}
/>
))
Label.displayName = LabelPrimitive.Root.displayName
export { Label }
));
Label.displayName = LabelPrimitive.Root.displayName;
export { Label };

View File

@@ -1,9 +1,9 @@
import * as React from "react"
import * as TabsPrimitive from "@radix-ui/react-tabs"
import * as React from "react";
import * as TabsPrimitive from "@radix-ui/react-tabs";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const Tabs = TabsPrimitive.Root
const Tabs = TabsPrimitive.Root;
const TabsList = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.List>,
@@ -17,8 +17,8 @@ const TabsList = React.forwardRef<
)}
{...props}
/>
))
TabsList.displayName = TabsPrimitive.List.displayName
));
TabsList.displayName = TabsPrimitive.List.displayName;
const TabsTrigger = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Trigger>,
@@ -32,8 +32,8 @@ const TabsTrigger = React.forwardRef<
)}
{...props}
/>
))
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
));
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
const TabsContent = React.forwardRef<
React.ElementRef<typeof TabsPrimitive.Content>,
@@ -41,10 +41,13 @@ const TabsContent = React.forwardRef<
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
ref={ref}
className={cn("mt-4 ring-offset-background focus-visible:outline-none", className)}
className={cn(
"mt-4 ring-offset-background focus-visible:outline-none",
className,
)}
{...props}
/>
))
TabsContent.displayName = TabsPrimitive.Content.displayName
));
TabsContent.displayName = TabsPrimitive.Content.displayName;
export { Tabs, TabsList, TabsTrigger, TabsContent }
export { Tabs, TabsList, TabsTrigger, TabsContent };