import * as React from 'react'; import { useCallback, useState } from 'react'; import { Dispatch } from 'redux'; import { _ } from '@joplin/lib/locale'; import NoteLockSession from '@joplin/lib/services/noteLock/NoteLockSession'; import Button, { ButtonLevel } from '../../Button/Button'; import LabelledPasswordInput from '../../PasswordInput/LabelledPasswordInput'; interface Props { noteTitle: string; hasNoteLockKey: boolean; dispatch: Dispatch; undecryptable?: boolean; migrationRunning?: boolean; lockedInShare?: boolean; } export default function NoteLockPanel(props: Props) { const [password, setPassword] = useState(''); const [unlocking, setUnlocking] = useState(false); const [errorMessage, setErrorMessage] = useState(''); const onPasswordChange = useCallback((event: React.ChangeEvent) => { setPassword(event.target.value); }, []); const unlock = useCallback(async () => { if (!password || unlocking) return; setUnlocking(true); try { await NoteLockSession.instance().unlock(password); // No success handling: the unlock event swaps this panel out for the note. } catch (error) { // WebCrypto reports a wrong password as a generic OperationError. setErrorMessage(error.name === 'OperationError' ? _('Invalid password') : error.message); setUnlocking(false); } }, [password, unlocking]); const onSubmit = useCallback((event: React.FormEvent) => { event.preventDefault(); void unlock(); }, [unlock]); const onSetUpClick = useCallback(() => { props.dispatch({ type: 'NAV_GO', routeName: 'Config', props: { defaultSection: 'noteLock' }, }); }, [props.dispatch]); const renderAction = () => { if (props.migrationRunning) { return

{_('This note cannot be read while a note lock key migration is in progress.')}

; } if (props.undecryptable) { return

{_('This note could not be unlocked. If it was locked prior to a password reset, the content is no longer recoverable.')}

; } if (!props.hasNoteLockKey) { return ( <>

{_('Reading this note requires the note lock password, which has not been set up on this device yet.')}