PasswordPromptProvider.tsx raw
1 import {
2 AlertDialog,
3 AlertDialogAction,
4 AlertDialogCancel,
5 AlertDialogContent,
6 AlertDialogDescription,
7 AlertDialogFooter,
8 AlertDialogHeader,
9 AlertDialogTitle
10 } from '@/components/ui/alert-dialog'
11 import { Input } from '@/components/ui/input'
12 import { createContext, useCallback, useContext, useRef, useState } from 'react'
13 import { useTranslation } from 'react-i18next'
14
15 type PasswordPromptContextType = {
16 promptPassword: (message: string) => Promise<string | null>
17 }
18
19 const PasswordPromptContext = createContext<PasswordPromptContextType | undefined>(undefined)
20
21 export const usePasswordPrompt = () => {
22 const context = useContext(PasswordPromptContext)
23 if (!context) {
24 throw new Error('usePasswordPrompt must be used within PasswordPromptProvider')
25 }
26 return context
27 }
28
29 export function PasswordPromptProvider({ children }: { children: React.ReactNode }) {
30 const { t } = useTranslation()
31 const [open, setOpen] = useState(false)
32 const [message, setMessage] = useState('')
33 const [password, setPassword] = useState('')
34 const resolverRef = useRef<((value: string | null) => void) | null>(null)
35
36 const promptPassword = useCallback((msg: string): Promise<string | null> => {
37 return new Promise((resolve) => {
38 setMessage(msg)
39 setPassword('')
40 setOpen(true)
41 resolverRef.current = resolve
42 })
43 }, [])
44
45 const handleConfirm = () => {
46 setOpen(false)
47 resolverRef.current?.(password)
48 resolverRef.current = null
49 }
50
51 const handleCancel = () => {
52 setOpen(false)
53 resolverRef.current?.(null)
54 resolverRef.current = null
55 }
56
57 return (
58 <PasswordPromptContext.Provider value={{ promptPassword }}>
59 {children}
60 <AlertDialog open={open} onOpenChange={(o) => !o && handleCancel()}>
61 <AlertDialogContent>
62 <AlertDialogHeader>
63 <AlertDialogTitle>{t('Password Required')}</AlertDialogTitle>
64 <AlertDialogDescription>{message}</AlertDialogDescription>
65 </AlertDialogHeader>
66 <Input
67 type="password"
68 value={password}
69 onChange={(e) => setPassword(e.target.value)}
70 placeholder={t('Enter password')}
71 autoFocus
72 onKeyDown={(e) => {
73 if (e.key === 'Enter') {
74 e.preventDefault()
75 handleConfirm()
76 }
77 }}
78 />
79 <AlertDialogFooter>
80 <AlertDialogCancel onClick={handleCancel}>{t('Cancel')}</AlertDialogCancel>
81 <AlertDialogAction onClick={handleConfirm}>{t('Confirm')}</AlertDialogAction>
82 </AlertDialogFooter>
83 </AlertDialogContent>
84 </AlertDialog>
85 </PasswordPromptContext.Provider>
86 )
87 }
88