import { useHandler } from '@proton/components' ; import { Abortable } from '@proton/components/hooks/useHandler' ; import { useRef } from 'react' ; import { isDecryptionError , isNetworkError } from '../../helpers/errors' ; import { useDeleteDraft , useSaveDraft } from '../message/useSaveDraft' ; import { usePromise } from '../usePromise' ; import { MessageState , MessageStateWithData } from '../../logic/messages/messagesTypes' ; interface AutoSaveArgs { onMessageAlreadySent ? : ( ) => void ; } export const useAutoSave = ( { onMessageAlreadySent } ) => { const pendingAutoSave = usePromise < void > ( ) ; const pendingSave = usePromise < void > ( ) ; const pauseDebouncer = useRef < boolean > ( false ) ; const lastCall = useRef < MessageState > ( ) ; const saveDraft = useSaveDraft ( { onMessageAlreadySent } ) ; const deleteDraftSource = useDeleteDraft ( ) ; let pause ; let restart ; const actualSave = useHandler ( async ( message ) => { pause ( ) ; try { await pendingSave . promise ; } catch { } try { lastCall . current = undefined ; pendingSave . renew ( ) ; await saveDraft ( message as MessageStateWithData ) ; } catch ( error ) { if ( isNetworkError ( error ) || isDecryptionError ( error ) ) { console . error ( error ) ; } else { throw error ; } } finally { pendingSave . resolver ( ) ; restart ( ) ; } } ) ; const debouncedHandler = useHandler ( ( message ) => { pendingAutoSave . resolver ( ) ; return actualSave ( message ) ; } , { debounce : 2000 } ) ; pause = useHandler ( ( ) => { pauseDebouncer . current = true ; } ) ; restart = useHandler ( ( ) => { pauseDebouncer . current = false ; if ( lastCall . current !== undefined ) { void debouncedHandler ( lastCall . current as MessageState ) ; } } ) ; const pausableHandler = useHandler ( ( message ) => { if ( ! pendingAutoSave . isPending ) { pendingAutoSave . renew ( ) ; } lastCall . current = message ; if ( ! pauseDebouncer . current ) { return debouncedHandler ( message ) ; } } ) ; const abort = useHandler ( ( ) => { debouncedHandler . abort ?. ( ) ; pendingAutoSave . resolver ( ) ; pauseDebouncer . current = false ; } ) ; pausableHandler . abort = abort ; const saveNow = ( message ) => { abort ( ) ; return actualSave ( message ) ; } ; const deleteDraft = useHandler ( async ( message ) => { abort ( ) ; try { await pendingSave . promise ; } catch { } try { pendingSave . renew ( ) ; await deleteDraftSource ( message ) ; } finally { pendingSave . resolver ( ) ; restart ( ) ; } } ) ; return { autoSave : pausableHandler as ( ( message : MessageState ) => Promise < void > ) & Abortable , saveNow , deleteDraft , pendingSave , pendingAutoSave , pause , restart , } ; } ;