mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 14:06:36 +08:00
117 lines
3.1 KiB
TypeScript
117 lines
3.1 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>
|
|
);
|
|
}
|