Files
OpenFlare/frontend/components/common/general/password-dialog.tsx
T
ryan 63cd906cfc refactor(repo): consolidate openflare-server to root and move subprojects to internal/apps
- Merge all files inside openflare-server to the repository root directory.
- Relocate agent, relay, and flared subprojects from internal/ to internal/apps/.
- Combine docker-compose files and update build context paths to root.
- Update GitHub workflows and Dockerfiles to refer to new directories and package names.
- Rewrite Go package imports across all files.
- Resolve database renew test race condition and clean up docs.
2026-06-19 14:23:29 +08:00

109 lines
3.0 KiB
TypeScript

"use client"
import * as React from "react"
import {useState} from "react"
import {Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle,} from "@/components/ui/dialog"
import {InputOTP, InputOTPGroup, InputOTPSlot,} from "@/components/ui/input-otp"
import {Button} from "@/components/ui/button"
import {Spinner} from "@/components/ui/spinner"
interface PasswordDialogProps {
isOpen: boolean
onOpenChange: (open: boolean) => void
onConfirm: (password: string) => void
loading?: boolean
title?: string
description?: string
}
/**
* 密码输入对话框
*
* 用于敏感操作前的二次确认
*/
export function PasswordDialog({
isOpen,
onOpenChange,
onConfirm,
loading = false,
title = "请输入密码",
description = "为了您的账户安全,请输入6位认证密码进行验证"
}: PasswordDialogProps) {
const [password, setPassword] = useState("")
const handleConfirm = () => {
if (password.length === 6) {
onConfirm(password)
}
}
/* 当对话框关闭时重置密码*/
React.useEffect(() => {
if (!isOpen) {
setPassword("")
}
}, [isOpen])
return (
<Dialog open={isOpen} onOpenChange={onOpenChange}>
<DialogContent className="w-xs sm:w-md">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>
{description}
</DialogDescription>
</DialogHeader>
<div className="py-2 flex justify-center">
<InputOTP
maxLength={6}
value={password}
onChange={setPassword}
disabled={loading}
onKeyDown={(e) => {
if (e.key === 'Enter' && password.length === 6 && !loading) {
handleConfirm()
}
}}
>
<InputOTPGroup className="gap-2">
<InputOTPSlot index={0} className="w-10 h-10 text-base" />
<InputOTPSlot index={1} className="w-10 h-10 text-base" />
<InputOTPSlot index={2} className="w-10 h-10 text-base" />
<InputOTPSlot index={3} className="w-10 h-10 text-base" />
<InputOTPSlot index={4} className="w-10 h-10 text-base" />
<InputOTPSlot index={5} className="w-10 h-10 text-base" />
</InputOTPGroup>
</InputOTP>
</div>
<div className="flex justify-end gap-2 pt-2">
<Button
variant="ghost"
onClick={() => onOpenChange(false)}
disabled={loading}
className="h-8 text-xs"
>
取消
</Button>
<Button
type="button"
className="bg-primary hover:bg-primary/90 h-8 text-xs"
onClick={handleConfirm}
disabled={password.length !== 6 || loading}
>
{loading ? (
<>
<Spinner className="mr-2 h-4 w-4" />
验证中...
</>
) : (
"确认"
)}
</Button>
</div>
</DialogContent>
</Dialog>
)
}