import { c } from 'ttag' ; import { useEventManager , useHandler , useMailSettings , useNotifications } from '@proton/components' ; import { Abortable } from '@proton/components/hooks/useHandler' ; import { useDispatch } from 'react-redux' ; import SendingMessageNotification , { createSendingMessageNotificationManager , SendingMessageNotificationManager , } from '../../components/notifications/SendingMessageNotification' ; import { useSendMessage } from './useSendMessage' ; import { useSendVerifications } from './useSendVerifications' ; import { useOnCompose } from '../../containers/ComposeProvider' ; import { MapSendInfo } from '../../models/crypto' ; import { SAVE_DRAFT_ERROR_CODES , SEND_EMAIL_ERROR_CODES , MESSAGE_ALREADY_SENT_INTERNAL_ERROR } from '../../constants' ; import { PromiseHandlers } from '../usePromise' ; import { MessageState , MessageStateWithData } from '../../logic/messages/messagesTypes' ; import { endSending , startSending } from '../../logic/messages/draft/messagesDraftActions' ; import { useGetMessage } from '../message/useMessage' ; export interface UseSendHandlerParameters { getModelMessage : ( ) => MessageState ; ensureMessageContent : ( ) => void ; mapSendInfo : MapSendInfo ; promiseUpload : Promise < void > ; pendingSave : PromiseHandlers < void > ; pendingAutoSave : PromiseHandlers < void > ; autoSave : ( ( message : MessageState ) => Promise < void > ) & Abortable ; saveNow : ( message : MessageState ) => Promise < void > ; onClose : ( ) => void ; onMessageAlreadySent : ( ) => void ; handleNoRecipients ? : ( ) => void ; handleNoSubjects ? : ( ) => void ; handleNoAttachments ? : ( keyword : string ) => void ; } export const useSendHandler = ( { getModelMessage , ensureMessageContent , mapSendInfo , promiseUpload , pendingSave , pendingAutoSave , autoSave , saveNow , onClose , onMessageAlreadySent , handleNoRecipients , handleNoSubjects , handleNoAttachments , } ) => { const { createNotification , hideNotification } = useNotifications ( ) ; const { call } = useEventManager ( ) ; const dispatch = useDispatch ( ) ; const getMessage = useGetMessage ( ) ; const { preliminaryVerifications , extendedVerifications } = useSendVerifications ( handleNoRecipients , handleNoSubjects , handleNoAttachments ) ; const sendMessage = useSendMessage ( ) ; const [ mailSettings ] = useMailSettings ( ) ; const onCompose = useOnCompose ( ) ; const handleSendAfterUploads = useHandler ( async ( notifManager ) => { let verificationResults ; let inputMessage ; let mapSendPrefs ; let alreadySaved ; try { await pendingSave . promise ; verificationResults = await extendedVerifications ( getModelMessage ( ) as MessageStateWithData , mapSendInfo ) ; mapSendPrefs = verificationResults . mapSendPrefs ; inputMessage = verificationResults . cleanMessage ; alreadySaved = ! ! inputMessage . data . ID && ! pendingAutoSave . isPending && ! verificationResults . hasChanged ; autoSave . abort ?. ( ) ; if ( ! alreadySaved ) { await saveNow ( inputMessage ) ; await call ( ) ; } inputMessage = { ... getModelMessage ( ) , data : ( getMessage ( inputMessage . localID ) as MessageStateWithData ) . data , } ; } catch { hideNotification ( notifManager . ID ) ; onCompose ( { existingDraft : getModelMessage ( ) , fromUndo : true } ) ; return ; } try { await sendMessage ( { inputMessage , mapSendPrefs , onCompose , alreadySaved , sendingMessageNotificationManager : notifManager , useSilentApi : true , } ) ; } catch ( error ) { hideNotification ( notifManager . ID ) ; if ( [ SAVE_DRAFT_ERROR_CODES . MESSAGE_ALREADY_SENT , SEND_EMAIL_ERROR_CODES . MESSAGE_ALREADY_SENT ] . includes ( error . data ?. Code ) ) { onMessageAlreadySent ( ) ; throw error ; } if ( error . data ?. Error ) { createNotification ( { text : error . data ?. Error , type : 'error' , } ) ; throw error ; } createNotification ( { text : c ( 'Error' ) . t `Error while sending the message. Message is not sent.` , type : 'error' , } ) ; console . error ( 'Error while sending the message.' , error ) ; throw error ; } } ) ; const handleSend = useHandler ( async ( ) => { const { localID , draftFlags } = getModelMessage ( ) ; const { scheduledAt } = draftFlags || { } ; const notifManager = createSendingMessageNotificationManager ( ) ; if ( ! scheduledAt ) { try { await preliminaryVerifications ( getModelMessage ( ) as MessageStateWithData ) ; } catch ( error ) { if ( error ?. message === MESSAGE_ALREADY_SENT_INTERNAL_ERROR ) { onMessageAlreadySent ( ) ; } throw error ; } } notifManager . ID = createNotification ( { text : ( < SendingMessageNotification scheduledAt = { scheduledAt } manager = { notifManager } viewMode = { mailSettings ?. ViewMode || 0 } message = { getModelMessage ( ) . data } / > ) , expiration : - 1 , disableAutoClose : true , } ) ; ensureMessageContent ( ) ; try { dispatch ( startSending ( localID ) ) ; onClose ( ) ; try { await promiseUpload ; } catch ( error ) { hideNotification ( notifManager . ID ) ; createNotification ( { text : c ( 'Error' ) . t `Error while uploading attachments. Message is not sent.` , type : 'error' , } ) ; console . error ( 'Error while uploading attachments.' , error ) ; onCompose ( { existingDraft : getModelMessage ( ) , fromUndo : true } ) ; throw error ; } await handleSendAfterUploads ( notifManager ) ; } finally { const asyncFinally = async ( ) => { await call ( ) ; dispatch ( endSending ( localID ) ) ; } ; void asyncFinally ( ) ; } } ) ; return handleSend ; } ;