fix captcha show

This commit is contained in:
songtianlun 2025-06-14 21:34:28 +08:00
parent fe4fbf0ea1
commit f779a277a8
2 changed files with 113 additions and 77 deletions

View File

@ -58,7 +58,12 @@ function SignInContent() {
const handleEmailSignInClick = (e: React.FormEvent) => {
e.preventDefault()
if (!email) return
if (!email.trim()) return
// 清除之前的消息
setMessage("")
// 显示验证码弹窗
setShowCaptcha(true)
}
@ -68,7 +73,7 @@ function SignInContent() {
try {
const result = await signIn("nodemailer", {
email,
email: email.trim(),
redirect: false,
})
@ -78,6 +83,7 @@ function SignInContent() {
setMessage("登录链接已发送到您的邮箱,请查收")
}
} catch (error) {
console.error("Email sign in error:", error)
setMessage("登录失败,请重试")
} finally {
setIsLoading(false)
@ -86,14 +92,24 @@ function SignInContent() {
const handleCaptchaCancel = () => {
setMessage("")
setIsLoading(false)
}
const handleCaptchaOpenChange = (open: boolean) => {
setShowCaptcha(open)
if (!open) {
setIsLoading(false)
}
}
const handleGoogleSignIn = async () => {
setIsLoading(true)
setMessage("")
try {
const callbackUrl = searchParams.get("callbackUrl") || "/"
await signIn("google", { callbackUrl })
} catch (error) {
console.error("Google sign in error:", error)
setMessage("Google登录失败请重试")
setIsLoading(false)
}
@ -145,12 +161,13 @@ function SignInContent() {
onChange={(e) => setEmail(e.target.value)}
required
className="bg-background border-input"
disabled={isLoading}
/>
</div>
<Button
type="submit"
className="w-full"
disabled={isLoading || !email}
disabled={isLoading || !email.trim()}
>
<Mail className="mr-2 h-4 w-4" />
{isLoading ? "发送中..." : "发送登录链接"}
@ -169,7 +186,7 @@ function SignInContent() {
{/* 验证码弹窗 */}
<CaptchaDialog
open={showCaptcha}
onOpenChange={setShowCaptcha}
onOpenChange={handleCaptchaOpenChange}
onVerify={handleCaptchaVerify}
onCancel={handleCaptchaCancel}
/>

View File

@ -8,12 +8,15 @@ import {
DialogFooter,
DialogHeader,
DialogTitle,
DialogPortal,
DialogOverlay,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Alert, AlertDescription } from "@/components/ui/alert"
import { Shield, RefreshCw, AlertCircle } from "lucide-react"
import * as DialogPrimitive from "@radix-ui/react-dialog"
interface CaptchaDialogProps {
open: boolean
@ -76,88 +79,104 @@ export function CaptchaDialog({
}
}
// 防止第一次打开时的遮罩层问题
const handleOpenChange = (newOpen: boolean) => {
if (!newOpen) {
setUserAnswer("")
setError("")
onCancel()
}
onOpenChange(newOpen)
}
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-foreground">
<Shield className="h-5 w-5 text-blue-500 dark:text-blue-400" />
</DialogTitle>
<DialogDescription>
使
</DialogDescription>
</DialogHeader>
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogPortal>
<DialogOverlay className="fixed inset-0 z-[100] bg-black/80" />
<DialogPrimitive.Content
className="fixed left-[50%] top-[50%] z-[101] grid w-full max-w-md translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg focus:outline-none"
onPointerDownOutside={(e) => e.preventDefault()}
>
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-foreground">
<Shield className="h-5 w-5 text-blue-500 dark:text-blue-400" />
</DialogTitle>
<DialogDescription>
使
</DialogDescription>
</DialogHeader>
<div className="space-y-4">
<Alert className="border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/50">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
<strong></strong>
</AlertDescription>
</Alert>
<div className="space-y-4">
<Alert className="border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-950/50">
<AlertCircle className="h-4 w-4" />
<AlertDescription>
<strong></strong>
</AlertDescription>
</Alert>
<div className="space-y-3">
<div className="flex items-center justify-center p-6 bg-muted/50 rounded-lg border">
<div className="text-center">
<div className="text-2xl font-bold text-foreground mb-2">
{num1} + {num2} = ?
</div>
<div className="flex items-center justify-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={generateCaptcha}
className="text-muted-foreground hover:text-foreground"
>
<RefreshCw className="h-4 w-4 mr-1" />
</Button>
<div className="space-y-3">
<div className="flex items-center justify-center p-6 bg-muted/50 rounded-lg border">
<div className="text-center">
<div className="text-2xl font-bold text-foreground mb-2">
{num1} + {num2} = ?
</div>
<div className="flex items-center justify-center gap-2">
<Button
variant="ghost"
size="sm"
onClick={generateCaptcha}
className="text-muted-foreground hover:text-foreground"
>
<RefreshCw className="h-4 w-4 mr-1" />
</Button>
</div>
</div>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="captcha-answer" className="text-foreground">
</Label>
<Input
id="captcha-answer"
type="number"
placeholder="输入计算结果"
value={userAnswer}
onChange={(e) => setUserAnswer(e.target.value)}
onKeyPress={handleKeyPress}
className="text-center text-lg font-medium"
autoFocus
/>
</div>
<div className="space-y-2">
<Label htmlFor="captcha-answer" className="text-foreground">
</Label>
<Input
id="captcha-answer"
type="number"
placeholder="输入计算结果"
value={userAnswer}
onChange={(e) => setUserAnswer(e.target.value)}
onKeyDown={handleKeyPress}
className="text-center text-lg font-medium"
autoFocus
/>
</div>
{error && (
<Alert className="border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-950 dark:text-red-200">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
{error && (
<Alert className="border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-950 dark:text-red-200">
<AlertCircle className="h-4 w-4" />
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
</div>
</div>
</div>
<DialogFooter className="flex justify-between">
<Button
variant="outline"
onClick={handleCancel}
>
</Button>
<Button
onClick={handleVerify}
disabled={!userAnswer.trim()}
className="bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700"
>
</Button>
</DialogFooter>
</DialogContent>
<DialogFooter className="flex justify-between">
<Button
variant="outline"
onClick={handleCancel}
>
</Button>
<Button
onClick={handleVerify}
disabled={!userAnswer.trim()}
className="bg-blue-600 hover:bg-blue-700 dark:bg-blue-600 dark:hover:bg-blue-700"
>
</Button>
</DialogFooter>
</DialogPrimitive.Content>
</DialogPortal>
</Dialog>
)
}