Skip to content

Commit

Permalink
feat: added confirm dialog to delete or save draft while closing the … (
Browse files Browse the repository at this point in the history
#115)

* feat: added confirm dialog to delete or save draft while closing the composer
  • Loading branch information
dhavaldodiya authored Jul 6, 2022
1 parent a55d8c2 commit af4f7e1
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 60 deletions.
141 changes: 83 additions & 58 deletions src/views/app/detail-panel/edit/edit-view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,13 @@
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Button, Catcher, Container } from '@zextras/carbonio-design-system';
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import {
Button,
Catcher,
Container,
SnackbarManagerContext
} from '@zextras/carbonio-design-system';
import { useDispatch, useSelector } from 'react-redux';
import { throttle, filter, isNil } from 'lodash';
import {
Expand All @@ -13,7 +18,8 @@ import {
useUserAccounts,
replaceHistory,
useAddBoardCallback,
useUpdateCurrentBoard
useUpdateCurrentBoard,
FOLDERS
} from '@zextras/carbonio-shell-ui';
import { useTranslation } from 'react-i18next';
import { useForm } from 'react-hook-form';
Expand All @@ -36,14 +42,15 @@ import DropZoneAttachment from './dropzone-attachment';
import { MAILS_ROUTE, MAIL_APP_ID } from '../../../../constants';

import { addAttachments } from './edit-utils';

import { RouteLeavingGuard } from './parts/nav-guard';
import * as StyledComp from './parts/edit-view-styled-components';
import { EditViewContext } from './parts/edit-view-context';
import ParticipantsRow from './parts/participants-row';
import TextEditorContainer from './parts/text-editor-container';
import EditViewHeader from './parts/edit-view-header';
import WarningBanner from './parts/warning-banner';
import SubjectRow from './parts/subject-row';
import { moveMsgToTrash } from '../../../../ui-actions/message-actions';

let counter = 0;

Expand All @@ -54,6 +61,7 @@ const generateId = () => {

export default function EditView({ mailId, folderId, setHeader, toggleAppBoard }) {
const settings = useUserSettings();
const createSnackbar = useContext(SnackbarManagerContext);
const boardContext = useBoardConfig();
const [editor, setEditor] = useState();

Expand Down Expand Up @@ -82,6 +90,8 @@ export default function EditView({ mailId, folderId, setHeader, toggleAppBoard }
const [actionChanged, setActionChanged] = useState(true);
const [isUploading, setIsUploading] = useState(false);

const [showRouteGuard, setShowRouteGuard] = useState(true);

const activeMailId = useMemo(
() => boardContext?.mailId || mailId,
[mailId, boardContext?.mailId]
Expand Down Expand Up @@ -312,61 +322,76 @@ export default function EditView({ mailId, folderId, setHeader, toggleAppBoard }
</Container>
);
return (
<EditViewContext.Provider
value={{
updateEditorCb,
throttledSaveToDraft,
control,
editorId,
editor,
updateSubjectField,
action,
folderId,
saveDraftCb
}}
>
<Catcher>
<Container onDragOver={(event) => onDragOverEvent(event)}>
<Container
mainAlignment="flex-start"
height="fill"
style={{ position: 'relative', maxHeight: '100%', overflowY: 'auto' }}
background="gray5"
padding={{ top: 'small', bottom: 'medium', horizontal: 'large' }}
>
{dropZoneEnable && (
<DropZoneAttachment
onDragOverEvent={onDragOverEvent}
onDropEvent={onDropEvent}
onDragLeaveEvent={onDragLeaveEvent}
/>
)}
<Container crossAlignment="flex-end" height="fit" background="gray6">
<EditViewHeader
setValue={setValue}
handleSubmit={handleSubmit}
uploadAttachmentsCb={uploadAttachmentsCb}
/>
{isSendingToYourself && <WarningBanner />}

<StyledComp.RowContainer background="gray6" padding={{ all: 'small' }}>
<ParticipantsRow />
<SubjectRow />

{showAttachments && (
<StyledComp.ColContainer occupyFull>
<EditAttachmentsBlock
editor={editor}
throttledSaveToDraft={throttledSaveToDraft}
/>
</StyledComp.ColContainer>
)}
</StyledComp.RowContainer>
<>
<RouteLeavingGuard
when={showRouteGuard && !toggleAppBoard}
onDeleteDraft={() => {
moveMsgToTrash({
ids: [editor.id],
t,
dispatch,
createSnackbar,
folderId: FOLDERS.TRASH
}).click();
}}
/>
<EditViewContext.Provider
value={{
updateEditorCb,
throttledSaveToDraft,
control,
editorId,
editor,
updateSubjectField,
action,
folderId,
saveDraftCb
}}
>
<Catcher>
<Container onDragOver={(event) => onDragOverEvent(event)}>
<Container
mainAlignment="flex-start"
height="fill"
style={{ position: 'relative', maxHeight: '100%', overflowY: 'auto' }}
background="gray5"
padding={{ top: 'small', bottom: 'medium', horizontal: 'large' }}
>
{dropZoneEnable && (
<DropZoneAttachment
onDragOverEvent={onDragOverEvent}
onDropEvent={onDropEvent}
onDragLeaveEvent={onDragLeaveEvent}
/>
)}
<Container crossAlignment="flex-end" height="fit" background="gray6">
<EditViewHeader
setShowRouteGuard={setShowRouteGuard}
setValue={setValue}
handleSubmit={handleSubmit}
uploadAttachmentsCb={uploadAttachmentsCb}
/>
{isSendingToYourself && <WarningBanner />}

<StyledComp.RowContainer background="gray6" padding={{ all: 'small' }}>
<ParticipantsRow />
<SubjectRow />

{showAttachments && (
<StyledComp.ColContainer occupyFull>
<EditAttachmentsBlock
editor={editor}
throttledSaveToDraft={throttledSaveToDraft}
/>
</StyledComp.ColContainer>
)}
</StyledComp.RowContainer>
</Container>
<TextEditorContainer onDragOverEvent={onDragOverEvent} draftSavedAt={draftSavedAt} />
</Container>
<TextEditorContainer onDragOverEvent={onDragOverEvent} draftSavedAt={draftSavedAt} />
</Container>
</Container>
</Catcher>
</EditViewContext.Provider>
</Catcher>
</EditViewContext.Provider>
</>
);
}
22 changes: 20 additions & 2 deletions src/views/app/detail-panel/edit/parts/edit-view-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,17 @@ import { sendMsg } from '../../../../../store/actions/send-msg';
import { ActionsType } from '../../../../../commons/utils';

type PropType = {
setShowRouteGuard: (arg: boolean) => void;
setValue: (arg: unknown) => void;
handleSubmit: (arg: () => void) => void;
uploadAttachmentsCb: () => void;
};
const EditViewHeader: FC<PropType> = ({ setValue, handleSubmit, uploadAttachmentsCb }) => {
const EditViewHeader: FC<PropType> = ({
setShowRouteGuard,
setValue,
handleSubmit,
uploadAttachmentsCb
}) => {
const [t] = useTranslation();
const { control, editor, updateEditorCb, editorId, saveDraftCb, folderId, action } =
useContext(EditViewContext);
Expand Down Expand Up @@ -88,6 +94,7 @@ const EditViewHeader: FC<PropType> = ({ setValue, handleSubmit, uploadAttachment
const sendMailCb = useCallback(() => {
setBtnLabel(t('label.sending', 'Sending'));
setIsDisabled(true);
setShowRouteGuard(false);
if (action === ActionsType.COMPOSE && boardContext?.onConfirm) {
boardContext?.onConfirm(editor);
} else {
Expand Down Expand Up @@ -144,7 +151,18 @@ const EditViewHeader: FC<PropType> = ({ setValue, handleSubmit, uploadAttachment
}
}, 3000);
}
}, [t, action, boardContext, editor, createSnackbar, folderId, closeBoard, dispatch, editorId]);
}, [
t,
action,
boardContext,
editor,
createSnackbar,
folderId,
closeBoard,
dispatch,
editorId,
setShowRouteGuard
]);

const onSave = useCallback(() => {
saveDraftCb(editor);
Expand Down
88 changes: 88 additions & 0 deletions src/views/app/detail-panel/edit/parts/nav-guard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* SPDX-FileCopyrightText: 2021 Zextras <https://www.zextras.com>
*
* SPDX-License-Identifier: AGPL-3.0-only
*/

import React, { useEffect, useState, useMemo } from 'react';
import { Prompt, useHistory } from 'react-router-dom';
import { Modal, Padding, Text } from '@zextras/carbonio-design-system';
import { useTranslation } from 'react-i18next';
import ModalFooter from '../../../../sidebar/commons/modal-footer';

export const RouteLeavingGuard = ({ when, onDeleteDraft }) => {
const history = useHistory();
const lastLocationInitial = useMemo(() => history.location.pathname, [history]);
const [modalVisible, setModalVisible] = useState(false);
const [lastLocation, setLastLocation] = useState(lastLocationInitial);
const [confirmedNavigation, setConfirmedNavigation] = useState(false);
const [t] = useTranslation();

const onDelete = () => {
setModalVisible(false);
onDeleteDraft();
setConfirmedNavigation(true);
};

const onClose = () => {
setModalVisible(false);
};

const onDraft = () => {
setModalVisible(false);
setConfirmedNavigation(true);
};

const handleBlockedNavigation = (nextLocation) => {
if (
!confirmedNavigation &&
nextLocation.pathname !== (lastLocation?.pathname || lastLocationInitial)
) {
setModalVisible(true);
setLastLocation(nextLocation);
return false;
}
return true;
};
useEffect(() => {
if (confirmedNavigation && lastLocation) {
// Navigate to the previous blocked location with your navigate function
history.push(lastLocation.pathname);
}
}, [confirmedNavigation, history, lastLocation]);

return (
<>
<Prompt when={when} message={handleBlockedNavigation} />
{/* Your own alert/dialog/modal component */}
<Modal
open={modalVisible}
title={t('label.before_you_leave', 'Before you leave')}
showCloseIcon
onClose={onClose}
customFooter={
<ModalFooter
typeCancel={'outlined'}
colorCancel={'primary'}
onConfirm={onDraft}
label={t('label.keep_draft', 'Keep Draft')}
secondaryBtnType={'outlined'}
secondaryAction={onDelete}
secondaryLabel={t('label.delete_draft', 'Delete Draft')}
secondaryColor="primary"
showDivider={false}
paddingTop="0"
t={t}
/>
}
>
<Padding vertical="medium">
<Text>
{t('modal.delete_draft.message1', 'Do you want to keep this draft or delete it?')}
</Text>
</Padding>
</Modal>
</>
);
};
export default RouteLeavingGuard;
8 changes: 8 additions & 0 deletions translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
"automatically_delete_duplicates": "Automatically delete duplicate copies of the same message when received",
"back": "Back",
"bcc": "Bcc",
"before_you_leave": "Before you leave",
"behalf_of": "on behalf of",
"by_conversation": "By Conversation",
"by_message": "By Message",
Expand All @@ -251,6 +252,7 @@
"create_tag": "Create Tag",
"decline": "Decline",
"delete": "Delete",
"delete_draft": "Delete Draft",
"delete_permanently": "Delete Permanently",
"delete_tag": "Delete Tag",
"delete_tag_name": "Delete \"{{name}}\" tag",
Expand Down Expand Up @@ -292,6 +294,7 @@
"highlight_tab": "Highlight the Mail tab",
"insert": "Insert",
"invalid_destination": "This node is not a valid destination",
"keep_draft": "Keep Draft",
"keywords": "Keywords",
"loading_results": "Loading Results…",
"mail_folder": "E-mail folder",
Expand Down Expand Up @@ -475,6 +478,11 @@
},
"something_went_wrong": "SOMETHING WENT WRONG"
},
"modal": {
"delete_draft": {
"message1": "Do you want to keep this draft or delete it?"
}
},
"notification": {
"new_message": "New Message",
"no_content": "Message without content"
Expand Down

0 comments on commit af4f7e1

Please sign in to comment.