import { useState, useMemo } from 'react' import { yupResolver } from '@hookform/resolvers/yup' import type { TFunction } from 'i18next' import { EyeIcon, EyeOffIcon } from 'lucide-react' import { useForm, type SubmitHandler } from 'react-hook-form' import { useTranslation } from 'react-i18next' import * as yup from 'yup' import { Button } from '@/components/ui/button' import { hashPassword } from '@/lib/hash' import { cn, debounce, type WalletFileName } from '@/lib/utils' import { Field, FieldLabel } from '../ui/field' import { InputGroup, InputGroupAddon, InputGroupInput } from '../ui/input-group' import { Spinner } from '../ui/spinner' type PasswordVerificationFormValues = { password: string } const debouncedHashPassword = debounce(hashPassword, 210) type PasswordVerificationI18nKeyPrefix = 'settings.seed_modal.verification' | 'settings.xpubs_modal.verification' const passwordVerificationFormSchema = ( walletFileName: WalletFileName, hashedPassword: string, t: TFunction, i18nKeyPrefix: PasswordVerificationI18nKeyPrefix, ) => { return yup .object({ password: yup .string() .required() .test('verify-password-test', async (value) => { try { const hashed = await debouncedHashPassword(value, walletFileName) if (hashedPassword !== hashed) { const errorMessage = t(`${i18nKeyPrefix}.text_error_password_incorrect`) return new yup.ValidationError(errorMessage, undefined, 'password', undefined, true) } return true } catch (error: unknown) { const reason = (error instanceof Error ? error.message : undefined) || t('global.errors.reason_unknown') const errorMessage = t(`${i18nKeyPrefix}.text_error`, { reason }) throw new yup.ValidationError(errorMessage, undefined, 'password', undefined, true) } }), }) .required() } type PasswordVerificationFormProps = { walletFileName: WalletFileName hashedPassword: string onSubmit: SubmitHandler onCancel?: () => void | Promise className?: string disabled?: boolean i18nKeyPrefix: PasswordVerificationI18nKeyPrefix } export const PasswordVerificationForm = ({ walletFileName, onSubmit, hashedPassword, disabled, className, onCancel, i18nKeyPrefix, }: PasswordVerificationFormProps) => { const { t } = useTranslation() const [showPassword, setShowPassword] = useState(false) const schema = useMemo(() => { return passwordVerificationFormSchema(walletFileName, hashedPassword, t, i18nKeyPrefix) }, [walletFileName, hashedPassword, t, i18nKeyPrefix]) const { register, handleSubmit, formState: { errors, isSubmitting }, } = useForm({ mode: 'onSubmit', reValidateMode: 'onSubmit', resolver: yupResolver(schema), }) const doOnSubmit = handleSubmit(onSubmit) return (
void doOnSubmit(event)} className={cn('flex flex-col gap-4', className)} noValidate>
{t(`${i18nKeyPrefix}.label_password`)} {errors.password?.message &&
{errors.password.message}
}
{onCancel !== undefined && ( )}
) }