src/applications/mhv-secure-messaging/components/ComposeForm/ComposeForm.jsx
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import PropTypes from 'prop-types';
import { validateNameSymbols } from 'platform/forms-system/src/js/web-component-patterns/fullNamePattern';
import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { focusElement } from '@department-of-veterans-affairs/platform-utilities/ui';
import {
DowntimeNotification,
externalServices,
} from '@department-of-veterans-affairs/platform-monitoring/DowntimeNotification';
import { renderMHVDowntime } from '@department-of-veterans-affairs/mhv/exports';
import FileInput from './FileInput';
import CategoryInput from './CategoryInput';
import AttachmentsList from '../AttachmentsList';
import { saveDraft } from '../../actions/draftDetails';
import DraftSavedInfo from './DraftSavedInfo';
import useDebounce from '../../hooks/use-debounce';
import {
messageSignatureFormatter,
setCaretToPos,
navigateToFolderByFolderId,
resetUserSession,
dateFormat,
scrollToTop,
} from '../../util/helpers';
import { sendMessage } from '../../actions/messages';
import { focusOnErrorField } from '../../util/formHelpers';
import RouteLeavingGuard from '../shared/RouteLeavingGuard';
import {
draftAutoSaveTimeout,
DefaultFolders,
ErrorMessages,
Recipients,
ParentComponent,
RecipientStatus,
BlockedTriageAlertStyles,
FormLabels,
downtimeNotificationParams,
Alerts,
} from '../../util/constants';
import EmergencyNote from '../EmergencyNote';
import ComposeFormActionButtons from './ComposeFormActionButtons';
import EditPreferences from './EditPreferences';
import BlockedTriageGroupAlert from '../shared/BlockedTriageGroupAlert';
import ViewOnlyDraftSection from './ViewOnlyDraftSection';
import { RadioCategories } from '../../util/inputContants';
import { getCategories } from '../../actions/categories';
import ElectronicSignature from './ElectronicSignature';
import RecipientsSelect from './RecipientsSelect';
const ComposeForm = props => {
const { pageTitle, headerRef, draft, recipients, signature } = props;
const {
noAssociations,
allTriageGroupsBlocked,
allowedRecipients,
} = recipients;
const dispatch = useDispatch();
const history = useHistory();
const [recipientsList, setRecipientsList] = useState(allowedRecipients);
const [selectedRecipientId, setSelectedRecipientId] = useState(null);
const [isSignatureRequired, setIsSignatureRequired] = useState(null);
const [checkboxMarked, setCheckboxMarked] = useState(false);
useEffect(
() => {
if (selectedRecipientId) {
setIsSignatureRequired(
allowedRecipients.some(
r => +r.id === +selectedRecipientId && r.signatureRequired,
) || false,
);
}
},
[selectedRecipientId, allowedRecipients],
);
const [category, setCategory] = useState(null);
const [categoryError, setCategoryError] = useState('');
const [bodyError, setBodyError] = useState(null);
const [recipientError, setRecipientError] = useState('');
const [subjectError, setSubjectError] = useState('');
const [signatureError, setSignatureError] = useState('');
const [checkboxError, setCheckboxError] = useState('');
const [subject, setSubject] = useState('');
const [messageBody, setMessageBody] = useState('');
const [electronicSignature, setElectronicSignature] = useState('');
const [attachments, setAttachments] = useState([]);
const [formPopulated, setFormPopulated] = useState(false);
const [fieldsString, setFieldsString] = useState('');
const [sendMessageFlag, setSendMessageFlag] = useState(false);
const [messageInvalid, setMessageInvalid] = useState(false);
const [navigationError, setNavigationError] = useState(null);
const [saveError, setSaveError] = useState(null);
const [lastFocusableElement, setLastFocusableElement] = useState(null);
const [modalVisible, updateModalVisible] = useState(false);
const [attachFileSuccess, setAttachFileSuccess] = useState(false);
const [deleteButtonClicked, setDeleteButtonClicked] = useState(false);
const [savedDraft, setSavedDraft] = useState(false);
const [currentRecipient, setCurrentRecipient] = useState(null);
const { isSaving } = useSelector(state => state.sm.threadDetails);
const categories = useSelector(state => state.sm.categories?.categories);
const alertStatus = useSelector(state => state.sm.alerts?.alertFocusOut);
const currentFolder = useSelector(state => state.sm.folders?.folder);
const debouncedSubject = useDebounce(subject, draftAutoSaveTimeout);
const debouncedMessageBody = useDebounce(messageBody, draftAutoSaveTimeout);
const debouncedCategory = useDebounce(category, draftAutoSaveTimeout);
const debouncedRecipient = useDebounce(
selectedRecipientId,
draftAutoSaveTimeout,
);
const alertsList = useSelector(state => state.sm.alerts.alertList);
const attachmentScanError = useMemo(
() =>
alertsList.filter(
alert =>
alert.content === Alerts.Message.ATTACHMENT_SCAN_FAIL &&
alert.isActive,
).length > 0,
[alertsList],
);
const localStorageValues = useMemo(() => {
return {
atExpires: localStorage.atExpires,
hasSession: localStorage.hasSession,
sessionExpiration: localStorage.sessionExpiration,
userFirstName: localStorage.userFirstName,
};
}, []);
const { signOutMessage, timeoutId } = resetUserSession(localStorageValues);
const noTimeout = () => {
clearTimeout(timeoutId);
};
useEffect(
() => {
if (!categories) {
dispatch(getCategories());
}
},
[categories, dispatch],
);
const formattedSignature = useMemo(
() => {
return messageSignatureFormatter(signature);
},
[signature],
);
const setUnsavedNavigationError = useCallback(
typeOfError => {
if (typeOfError === null) {
setNavigationError(null);
}
if (
typeOfError ===
ErrorMessages.Navigation.UNABLE_TO_SAVE_DRAFT_ATTACHMENT_ERROR
) {
setNavigationError({
...ErrorMessages.ComposeForm.UNABLE_TO_SAVE_DRAFT_ATTACHMENT,
p1: '',
});
}
if (typeOfError === ErrorMessages.Navigation.UNABLE_TO_SAVE_ERROR) {
setNavigationError({
...ErrorMessages.ComposeForm.UNABLE_TO_SAVE,
});
}
if (typeOfError === ErrorMessages.Navigation.CONT_SAVING_DRAFT_ERROR) {
setNavigationError({
...ErrorMessages.ComposeForm.CONT_SAVING_DRAFT,
});
}
if (
typeOfError === ErrorMessages.Navigation.CONT_SAVING_DRAFT_CHANGES_ERROR
) {
setNavigationError({
...ErrorMessages.ComposeForm.CONT_SAVING_DRAFT_CHANGES,
});
}
if (
typeOfError ===
ErrorMessages.Navigation.UNABLE_TO_SAVE_DRAFT_SIGNATURE_ERROR
) {
setNavigationError({
...ErrorMessages.ComposeForm.UNABLE_TO_SAVE_DRAFT_SIGNATURE,
});
}
},
[setNavigationError],
);
useEffect(
() => {
if (allowedRecipients?.length > 0) {
setRecipientsList([...allowedRecipients]);
}
if (!draft) {
setCategory(null);
setSubject('');
setMessageBody('');
}
},
[recipients, draft, allowedRecipients],
);
useEffect(
() => {
if (draft) {
const tempRecipient = {
recipientId: draft.recipientId,
name: draft.triageGroupName,
type: Recipients.CARE_TEAM,
status: RecipientStatus.ALLOWED,
};
setCurrentRecipient(tempRecipient);
}
// The Blocked Triage Group alert should stay visible until the draft is sent or user navigates away
},
[draft],
);
useEffect(
() => {
const today = dateFormat(new Date(), 'YYYY-MM-DD');
if (sendMessageFlag && isSaving !== true) {
scrollToTop();
const messageData = {
category,
body: `${messageBody} ${
electronicSignature
? `\n\n${electronicSignature}\nSigned electronically on ${today}.`
: ``
}`,
subject,
};
messageData[`${'draft_id'}`] = draft?.messageId;
messageData[`${'recipient_id'}`] = selectedRecipientId;
let sendData;
if (attachments.length > 0) {
sendData = new FormData();
sendData.append('message', JSON.stringify(messageData));
attachments.map(upload => sendData.append('uploads[]', upload));
} else {
sendData = JSON.stringify(messageData);
}
dispatch(sendMessage(sendData, attachments.length > 0))
.then(() => {
setTimeout(() => {
navigateToFolderByFolderId(
currentFolder?.folderId || DefaultFolders.INBOX.id,
history,
);
}, 1000);
// Timeout neccessary for UCD requested 1 second delay
})
.catch(() => setSendMessageFlag(false), scrollToTop());
}
},
[sendMessageFlag, isSaving, scrollToTop],
);
useEffect(
() => {
if (messageInvalid) {
focusOnErrorField();
}
},
[messageInvalid],
);
useEffect(
() => {
if (alertStatus) {
focusElement(lastFocusableElement);
}
},
[alertStatus, lastFocusableElement],
);
const recipientExists = useCallback(
recipientId => {
return recipientsList.findIndex(item => +item.id === +recipientId) > -1;
},
[recipientsList],
);
// Populates form fields with recipients and categories
const populateForm = () => {
if (recipientExists(draft.recipientId)) {
setSelectedRecipientId(draft.recipientId);
} else {
const newRecipient = {
id: draft?.recipientId,
name: draft?.recipientName,
};
setRecipientsList(prevRecipientsList => [
...prevRecipientsList,
newRecipient,
]);
setSelectedRecipientId(newRecipient.id);
}
setCategory(draft.category);
setSubject(draft.subject);
setMessageBody(draft.body);
if (draft.attachments) {
setAttachments(draft.attachments);
}
setFormPopulated(true);
setFieldsString(
JSON.stringify({
rec: draft.recipientId,
cat: draft.category,
sub: draft.subject,
bod: draft.body,
}),
);
};
if (draft && !formPopulated) populateForm();
const checkMessageValidity = useCallback(
() => {
let messageValid = true;
let signatureValid = true;
let checkboxValid = true;
if (
selectedRecipientId === '0' ||
selectedRecipientId === '' ||
!selectedRecipientId
) {
setRecipientError(ErrorMessages.ComposeForm.RECIPIENT_REQUIRED);
messageValid = false;
}
if (!subject || subject === '') {
setSubjectError(ErrorMessages.ComposeForm.SUBJECT_REQUIRED);
messageValid = false;
}
if (messageBody === '' || messageBody.match(/^[\s]+$/)) {
setBodyError(ErrorMessages.ComposeForm.BODY_REQUIRED);
messageValid = false;
}
if (!category || category === '') {
setCategoryError(ErrorMessages.ComposeForm.CATEGORY_REQUIRED);
messageValid = false;
}
if (isSignatureRequired && !electronicSignature) {
setSignatureError(ErrorMessages.ComposeForm.SIGNATURE_REQUIRED);
signatureValid = false;
}
if (isSignatureRequired && !checkboxMarked) {
setCheckboxError(ErrorMessages.ComposeForm.CHECKBOX_REQUIRED);
checkboxValid = false;
}
setMessageInvalid(!messageValid);
return { messageValid, signatureValid, checkboxValid };
},
[
selectedRecipientId,
subject,
messageBody,
category,
isSignatureRequired,
electronicSignature,
checkboxMarked,
setMessageInvalid,
],
);
const saveDraftHandler = useCallback(
async (type, e) => {
const {
messageValid,
signatureValid,
checkboxValid,
} = checkMessageValidity();
const validSignatureNotRequired = messageValid && !isSignatureRequired;
if (type === 'manual') {
setSavedDraft(true);
if (validSignatureNotRequired) {
setNavigationError(null);
setLastFocusableElement(e?.target);
} else focusOnErrorField();
setUnsavedNavigationError(
ErrorMessages.Navigation.UNABLE_TO_SAVE_ERROR,
);
const getErrorType = () => {
const hasAttachments = attachments.length > 0;
const hasValidSignature =
isSignatureRequired && electronicSignature !== '';
const verifyAllFieldsAreValid =
(messageValid &&
signatureValid &&
checkboxValid &&
isSignatureRequired) ||
(!isSignatureRequired && messageValid && validSignatureNotRequired);
let errorType = null;
if (hasAttachments && hasValidSignature && verifyAllFieldsAreValid) {
errorType =
ErrorMessages.ComposeForm
.UNABLE_TO_SAVE_DRAFT_SIGNATURE_OR_ATTACHMENTS;
} else if (hasAttachments && verifyAllFieldsAreValid) {
errorType =
ErrorMessages.ComposeForm.UNABLE_TO_SAVE_DRAFT_ATTACHMENT;
} else if (!validSignatureNotRequired && verifyAllFieldsAreValid) {
errorType =
ErrorMessages.ComposeForm.UNABLE_TO_SAVE_DRAFT_SIGNATURE;
}
if (errorType) {
setSaveError(errorType);
if (
errorType.title !==
ErrorMessages.ComposeForm.UNABLE_TO_SAVE_DRAFT_SIGNATURE.title
) {
setNavigationError({
...errorType,
confirmButtonText: 'Continue editing',
cancelButtonText: 'Delete draft',
});
}
}
};
getErrorType();
}
const draftId = draft && draft.messageId;
const newFieldsString = JSON.stringify({
rec: parseInt(debouncedRecipient || selectedRecipientId, 10),
cat: debouncedCategory || category,
sub: debouncedSubject || subject,
bod: debouncedMessageBody || messageBody,
});
if (type === 'auto' && newFieldsString === fieldsString) {
return;
}
setFieldsString(newFieldsString);
const formData = {
recipientId: selectedRecipientId,
category,
subject,
body: messageBody,
};
if (
(messageValid && !isSignatureRequired) ||
(isSignatureRequired &&
messageValid &&
saveError !== null &&
savedDraft)
) {
dispatch(saveDraft(formData, type, draftId));
setSavedDraft(true);
}
},
[
checkMessageValidity,
isSignatureRequired,
savedDraft,
saveError,
draft,
debouncedRecipient,
selectedRecipientId,
debouncedCategory,
category,
debouncedSubject,
subject,
debouncedMessageBody,
messageBody,
fieldsString,
setUnsavedNavigationError,
attachments.length,
electronicSignature,
dispatch,
],
);
const sendMessageHandler = useCallback(
async e => {
const {
messageValid,
signatureValid,
checkboxValid,
} = checkMessageValidity();
// TODO add GA event
await setMessageInvalid(false);
await setSendMessageFlag(false);
const validSignatureNotRequired = messageValid && !isSignatureRequired;
const isSignatureValid =
isSignatureRequired && messageValid && signatureValid && checkboxValid;
if (validSignatureNotRequired || isSignatureValid) {
setSendMessageFlag(true);
setNavigationError(null);
setLastFocusableElement(e.target);
} else {
setSendMessageFlag(false);
focusOnErrorField();
}
},
[checkMessageValidity, isSignatureRequired],
);
// Navigation error effect
useEffect(
() => {
const isBlankForm = () =>
messageBody === '' &&
subject === '' &&
Number(selectedRecipientId) === 0 &&
category === null &&
attachments.length === 0;
const isEditedSaved = () =>
messageBody === draft?.body &&
Number(selectedRecipientId) === draft?.recipientId &&
category === draft?.category &&
subject === draft?.subject;
const isEditedForm = () =>
(messageBody !== draft?.body ||
selectedRecipientId !== draft?.recipientId ||
category !== draft?.category ||
subject !== draft?.subject) &&
!isBlankForm() &&
!isEditedSaved();
const isFormFilled = () =>
messageBody !== '' &&
subject !== '' &&
selectedRecipientId !== null &&
category !== null;
let error = null;
const unsavedFilledDraft =
isFormFilled() && !isEditedSaved() && !savedDraft;
const partiallySavedDraftWithSignRequired =
!draft &&
unsavedFilledDraft &&
!attachments.length &&
isSignatureRequired;
const partiallySavedDraft =
(!isFormFilled() && (!isBlankForm() || attachments.length > 0)) ||
partiallySavedDraftWithSignRequired;
const savedDraftWithEdits =
(savedDraft && !isEditedSaved() && isEditedForm()) ||
(!!draft && unsavedFilledDraft);
const savedDraftWithNoEdits =
(savedDraft && !isEditedForm()) || (!!draft && !isEditedForm());
if (isBlankForm()) {
error = null;
} else if (partiallySavedDraft) {
error = ErrorMessages.Navigation.UNABLE_TO_SAVE_ERROR;
} else if (
attachments.length > 0 &&
(unsavedFilledDraft ||
savedDraftWithEdits ||
savedDraftWithNoEdits ||
partiallySavedDraft)
) {
error = ErrorMessages.Navigation.UNABLE_TO_SAVE_DRAFT_ATTACHMENT_ERROR;
} else if (
!draft &&
unsavedFilledDraft &&
!attachments.length &&
!isSignatureRequired
) {
error = ErrorMessages.Navigation.CONT_SAVING_DRAFT_ERROR;
} else if (
!isSignatureRequired &&
savedDraftWithEdits &&
!attachments.length
) {
error = ErrorMessages.Navigation.CONT_SAVING_DRAFT_CHANGES_ERROR;
} else if (
isSignatureRequired &&
savedDraftWithEdits &&
!attachments.length
) {
error = ErrorMessages.Navigation.UNABLE_TO_SAVE_DRAFT_SIGNATURE_ERROR;
}
setUnsavedNavigationError(error);
},
[
attachments,
category,
checkMessageValidity,
deleteButtonClicked,
draft?.category,
draft?.messageBody,
draft?.recipientId,
draft?.subject,
formPopulated,
isSignatureRequired,
messageBody,
selectedRecipientId,
subject,
savedDraft,
setUnsavedNavigationError,
draft?.body,
draft,
modalVisible,
],
);
useEffect(
() => {
if (
debouncedRecipient &&
debouncedCategory &&
debouncedSubject &&
debouncedMessageBody &&
!modalVisible
) {
saveDraftHandler('auto');
setUnsavedNavigationError();
}
},
[
debouncedCategory,
debouncedMessageBody,
debouncedSubject,
debouncedRecipient,
saveDraftHandler,
modalVisible,
setUnsavedNavigationError,
],
);
const recipientHandler = useCallback(
recipient => {
setSelectedRecipientId(recipient?.id ? recipient.id.toString() : '0');
if (recipient.id !== '0') {
if (recipient.id) setRecipientError('');
setUnsavedNavigationError();
}
},
[setRecipientError, setUnsavedNavigationError],
);
const subjectHandler = e => {
setSubject(e.target.value);
if (e.target.value) setSubjectError('');
setUnsavedNavigationError();
};
const messageBodyHandler = e => {
setMessageBody(e.target.value);
if (e.target.value) setBodyError('');
setUnsavedNavigationError();
};
const electronicSignatureHandler = e => {
setElectronicSignature(e.target.value);
let validationError = null;
const addError = err => {
validationError = err;
};
validateNameSymbols({ addError }, e.target.value);
if (validationError !== null) {
setSignatureError(validationError);
} else {
setSignatureError('');
}
setUnsavedNavigationError();
};
const electronicCheckboxHandler = e => {
setCheckboxMarked(e.detail.checked);
};
const beforeUnloadHandler = useCallback(
e => {
if (
selectedRecipientId?.toString() !==
(draft ? draft?.recipientId.toString() : '0') ||
category !== (draft ? draft?.category : null) ||
subject !== (draft ? draft?.subject : '') ||
messageBody !== (draft ? draft?.body : '') ||
attachments.length
) {
e.preventDefault();
window.onbeforeunload = () => signOutMessage;
e.returnValue = true;
} else {
window.removeEventListener('beforeunload', beforeUnloadHandler);
window.onbeforeunload = null;
e.returnValue = false;
noTimeout();
}
},
[
draft,
selectedRecipientId,
category,
subject,
messageBody,
attachments,
timeoutId,
],
);
useEffect(
() => {
window.addEventListener('beforeunload', beforeUnloadHandler);
return () => {
window.removeEventListener('beforeunload', beforeUnloadHandler);
window.onbeforeunload = null;
noTimeout();
};
},
[beforeUnloadHandler],
);
if (sendMessageFlag === true) {
return (
<va-loading-indicator
message="Sending message..."
setFocus
data-testid="sending-indicator"
/>
);
}
return (
<>
<h1 className="page-title vads-u-margin-top--0" ref={headerRef}>
{pageTitle}
</h1>
<DowntimeNotification
appTitle={downtimeNotificationParams.appTitle}
dependencies={[externalServices.mhvPlatform, externalServices.mhvSm]}
render={renderMHVDowntime}
/>
{noAssociations || allTriageGroupsBlocked ? (
<BlockedTriageGroupAlert
alertStyle={BlockedTriageAlertStyles.ALERT}
parentComponent={ParentComponent.COMPOSE_FORM}
currentRecipient={currentRecipient}
/>
) : (
<EmergencyNote dropDownFlag />
)}
<form className="compose-form" id="sm-compose-form">
<RouteLeavingGuard
when={!!navigationError || !!saveError}
navigate={path => {
history.push(path);
}}
shouldBlockNavigation={() => {
return !!navigationError;
}}
// if save button is clicked, set saveErrors instead of NavigationErrors
title={
saveError && savedDraft ? saveError?.title : navigationError?.title
}
p1={saveError && savedDraft ? saveError?.p1 : navigationError?.p1}
p2={saveError && savedDraft ? saveError?.p2 : navigationError?.p2}
confirmButtonText={
saveError && savedDraft
? saveError?.confirmButtonText
: navigationError?.confirmButtonText
}
cancelButtonText={
saveError && savedDraft
? saveError?.cancelButtonText
: navigationError?.cancelButtonText
}
saveDraftHandler={saveDraftHandler}
savedDraft={savedDraft}
saveError={saveError}
setSetErrorModal={setSavedDraft}
setIsModalVisible={updateModalVisible}
/>
<div>
{!noAssociations &&
!allTriageGroupsBlocked && (
<div
className="
vads-u-border-top--1px
vads-u-padding-top--3
vads-u-margin-top--3
vads-u-margin-bottom--neg2"
>
<BlockedTriageGroupAlert
alertStyle={BlockedTriageAlertStyles.ALERT}
parentComponent={ParentComponent.COMPOSE_FORM}
currentRecipient={currentRecipient}
/>
</div>
)}
{recipientsList &&
!noAssociations &&
!allTriageGroupsBlocked && (
<RecipientsSelect
recipientsList={recipientsList}
onValueChange={recipientHandler}
error={recipientError}
defaultValue={+selectedRecipientId}
isSignatureRequired={isSignatureRequired}
setCheckboxMarked={setCheckboxMarked}
setElectronicSignature={setElectronicSignature}
/>
)}
<div className="compose-form-div">
{noAssociations || allTriageGroupsBlocked ? (
<ViewOnlyDraftSection
title={FormLabels.CATEGORY}
body={`${RadioCategories[(draft?.category)].label}: ${
RadioCategories[(draft?.category)].description
}`}
/>
) : (
<CategoryInput
categories={categories}
category={category}
categoryError={categoryError}
setCategory={setCategory}
setCategoryError={setCategoryError}
setUnsavedNavigationError={setUnsavedNavigationError}
setNavigationError={setNavigationError}
/>
)}
</div>
<div className="compose-form-div">
{noAssociations || allTriageGroupsBlocked ? (
<ViewOnlyDraftSection title={FormLabels.SUBJECT} body={subject} />
) : (
<va-text-input
label={FormLabels.SUBJECT}
required
type="text"
id="message-subject"
name="message-subject"
class="message-subject"
data-testid="message-subject-field"
onInput={subjectHandler}
value={subject}
error={subjectError}
data-dd-privacy="mask"
data-dd-action-name="Subject (Required) Input Field"
maxlength="50"
uswds
charcount
/>
)}
</div>
<div className="compose-form-div vads-u-margin-bottom--0">
{noAssociations || allTriageGroupsBlocked ? (
<ViewOnlyDraftSection
title={FormLabels.MESSAGE}
body={messageBody || formattedSignature}
/>
) : (
<va-textarea
label={FormLabels.MESSAGE}
required
id="compose-message-body"
name="compose-message-body"
class="message-body"
data-testid="message-body-field"
onInput={messageBodyHandler}
value={messageBody || formattedSignature} // populate with the signature, unless there is a saved draft
error={bodyError}
onFocus={e => {
setCaretToPos(
e.target.shadowRoot.querySelector('textarea'),
0,
);
}}
data-dd-privacy="mask"
data-dd-action-name="Message (Required) Textbox"
/>
)}
</div>
{recipientsList &&
(!noAssociations &&
!allTriageGroupsBlocked && (
<section className="attachments-section">
<AttachmentsList
compose
attachments={attachments}
setAttachments={setAttachments}
attachFileSuccess={attachFileSuccess}
setAttachFileSuccess={setAttachFileSuccess}
setNavigationError={setNavigationError}
editingEnabled
attachmentScanError={attachmentScanError}
/>
<FileInput
attachments={attachments}
setAttachments={setAttachments}
setAttachFileSuccess={setAttachFileSuccess}
attachmentScanError={attachmentScanError}
/>
</section>
))}
{isSignatureRequired && (
<ElectronicSignature
nameError={signatureError}
checkboxError={checkboxError}
onInput={electronicSignatureHandler}
onCheckboxCheck={electronicCheckboxHandler}
checked={checkboxMarked}
electronicSignature={electronicSignature}
/>
)}
<DraftSavedInfo />
<ComposeFormActionButtons
cannotReply={noAssociations || allTriageGroupsBlocked}
draftId={draft?.messageId}
draftsCount={1}
formPopulated={formPopulated}
navigationError={navigationError}
onSaveDraft={(type, e) => saveDraftHandler(type, e)}
onSend={sendMessageHandler}
setDeleteButtonClicked={setDeleteButtonClicked}
setNavigationError={setNavigationError}
setUnsavedNavigationError={setUnsavedNavigationError}
savedComposeDraft={!!draft}
/>
<EditPreferences />
</div>
</form>
</>
);
};
ComposeForm.propTypes = {
draft: PropTypes.object,
recipients: PropTypes.object,
signature: PropTypes.object,
};
export default ComposeForm;