refactor: Deduplicate delete modal (#1734)

This commit is contained in:
Philip Molares 2022-02-14 00:44:17 +01:00 committed by GitHub
parent 6a6f6105b9
commit 5f228b1bf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 36 deletions

View file

@ -11,36 +11,58 @@ import { DeletionModal } from '../../../common/modals/deletion-modal'
import { useApplicationState } from '../../../../hooks/common/use-application-state' import { useApplicationState } from '../../../../hooks/common/use-application-state'
import type { ModalVisibilityProps } from '../../../common/modals/common-modal' import type { ModalVisibilityProps } from '../../../common/modals/common-modal'
export interface DeleteHistoryNoteModalProps {
modalTitleI18nKey?: string
modalQuestionI18nKey?: string
modalWarningI18nKey?: string
modalButtonI18nKey?: string
}
export interface DeleteNoteModalProps extends ModalVisibilityProps { export interface DeleteNoteModalProps extends ModalVisibilityProps {
optionalNoteTitle?: string
onConfirm: () => void onConfirm: () => void
} }
/** /**
* A modal that asks the user if they really want to delete the current note. * A modal that asks the user if they really want to delete the current note.
* *
* @param optionalNoteTitle optional note title
* @param show Defines if the modal should be shown * @param show Defines if the modal should be shown
* @param onHide A callback that fires if the modal should be hidden without confirmation * @param onHide A callback that fires if the modal should be hidden without confirmation
* @param onConfirm A callback that fires if the user confirmed the request * @param onConfirm A callback that fires if the user confirmed the request
* @param modalTitleI18nKey optional i18nKey for the title
* @param modalQuestionI18nKey optional i18nKey for the question
* @param modalWarningI18nKey optional i18nKey for the warning
* @param modalButtonI18nKey optional i18nKey for the button
*/ */
export const DeleteNoteModal: React.FC<DeleteNoteModalProps> = ({ show, onHide, onConfirm }) => { export const DeleteNoteModal: React.FC<DeleteNoteModalProps & DeleteHistoryNoteModalProps> = ({
optionalNoteTitle,
show,
onHide,
onConfirm,
modalTitleI18nKey,
modalQuestionI18nKey,
modalWarningI18nKey,
modalButtonI18nKey
}) => {
const noteTitle = useApplicationState((state) => state.noteDetails.noteTitle) const noteTitle = useApplicationState((state) => state.noteDetails.noteTitle)
return ( return (
<DeletionModal <DeletionModal
{...cypressId('sidebar.deleteNote.modal')} {...cypressId('sidebar.deleteNote.modal')}
onConfirm={onConfirm} onConfirm={onConfirm}
deletionButtonI18nKey={'editor.modal.deleteNote.button'} deletionButtonI18nKey={modalButtonI18nKey ?? 'editor.modal.deleteNote.button'}
show={show} show={show}
onHide={onHide} onHide={onHide}
title={'editor.modal.deleteNote.title'}> title={modalTitleI18nKey ?? 'editor.modal.deleteNote.title'}>
<h5> <h5>
<Trans i18nKey={'editor.modal.deleteNote.question'} /> <Trans i18nKey={modalQuestionI18nKey ?? 'editor.modal.deleteNote.question'} />
</h5> </h5>
<ul> <ul>
<li {...cypressId('sidebar.deleteNote.modal.noteTitle')}>&nbsp;{noteTitle}</li> <li {...cypressId('sidebar.deleteNote.modal.noteTitle')}>{optionalNoteTitle ?? noteTitle}</li>
</ul> </ul>
<h6> <h6>
<Trans i18nKey={'editor.modal.deleteNote.warning'} /> <Trans i18nKey={modalWarningI18nKey ?? 'editor.modal.deleteNote.warning'} />
</h6> </h6>
</DeletionModal> </DeletionModal>
) )

View file

@ -17,11 +17,7 @@ export const DeleteNoteItem: React.FC<DeleteNoteItemProps> = ({ noteTitle, onCon
<DropdownItemWithDeletionModal <DropdownItemWithDeletionModal
onConfirm={onConfirm} onConfirm={onConfirm}
itemI18nKey={'landing.history.menu.deleteNote'} itemI18nKey={'landing.history.menu.deleteNote'}
modalButtonI18nKey={'editor.modal.deleteNote.button'}
modalIcon={'trash'} modalIcon={'trash'}
modalTitleI18nKey={'editor.modal.deleteNote.title'}
modalQuestionI18nKey={'editor.modal.deleteNote.question'}
modalWarningI18nKey={'editor.modal.deleteNote.warning'}
noteTitle={noteTitle} noteTitle={noteTitle}
/> />
) )

View file

@ -4,26 +4,38 @@
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import React, { Fragment, useState } from 'react' import React, { Fragment, useCallback, useState } from 'react'
import { Dropdown } from 'react-bootstrap' import { Dropdown } from 'react-bootstrap'
import { Trans, useTranslation } from 'react-i18next' import { Trans, useTranslation } from 'react-i18next'
import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon' import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon'
import type { IconName } from '../../common/fork-awesome/types' import type { IconName } from '../../common/fork-awesome/types'
import { DeletionModal } from '../../common/modals/deletion-modal' import type { DeleteHistoryNoteModalProps } from '../../editor-page/sidebar/delete-note-sidebar-entry/delete-note-modal'
import { DeleteNoteModal } from '../../editor-page/sidebar/delete-note-sidebar-entry/delete-note-modal'
export interface DropdownItemWithDeletionModalProps { export interface DropdownItemWithDeletionModalProps {
onConfirm: () => void onConfirm: () => void
itemI18nKey: string itemI18nKey: string
modalButtonI18nKey: string
modalIcon: IconName modalIcon: IconName
modalTitleI18nKey: string
modalQuestionI18nKey: string
modalWarningI18nKey: string
noteTitle: string noteTitle: string
className?: string className?: string
} }
export const DropdownItemWithDeletionModal: React.FC<DropdownItemWithDeletionModalProps> = ({ /**
* Renders a dropdown item and the corresponding deletion modal
*
* @param onConfirm A callback that fires if the user confirmed the request
* @param noteTitle The note title to be displayed
* @param modalTitleI18nKey The i18nKey for title to be shown in the modal
* @param modalButtonI18nKey The i18nKey for button to be shown in the modal
* @param itemI18nKey The i18nKey for the dropdown item
* @param modalIcon The icon for the dropdown item
* @param modalQuestionI18nKey The i18nKey for question to be shown in the modal
* @param modalWarningI18nKey The i18nKey for warning to be shown in the modal
* @param className Additional classes given to the dropdown item
*/
export const DropdownItemWithDeletionModal: React.FC<
DropdownItemWithDeletionModalProps & DeleteHistoryNoteModalProps
> = ({
onConfirm, onConfirm,
noteTitle, noteTitle,
modalTitleI18nKey, modalTitleI18nKey,
@ -36,6 +48,11 @@ export const DropdownItemWithDeletionModal: React.FC<DropdownItemWithDeletionMod
}) => { }) => {
useTranslation() useTranslation()
const [showDialog, setShowDialog] = useState(false) const [showDialog, setShowDialog] = useState(false)
const handleConfirm = useCallback(() => {
setShowDialog(false)
onConfirm()
}, [onConfirm])
const onHide = useCallback(() => setShowDialog(false), [])
return ( return (
<Fragment> <Fragment>
@ -43,25 +60,16 @@ export const DropdownItemWithDeletionModal: React.FC<DropdownItemWithDeletionMod
<ForkAwesomeIcon icon={modalIcon} fixedWidth={true} className='mx-2' /> <ForkAwesomeIcon icon={modalIcon} fixedWidth={true} className='mx-2' />
<Trans i18nKey={itemI18nKey} /> <Trans i18nKey={itemI18nKey} />
</Dropdown.Item> </Dropdown.Item>
<DeletionModal <DeleteNoteModal
onConfirm={() => { optionalNoteTitle={noteTitle}
setShowDialog(false) onConfirm={handleConfirm}
onConfirm()
}}
deletionButtonI18nKey={modalButtonI18nKey}
show={showDialog} show={showDialog}
onHide={() => setShowDialog(false)} onHide={onHide}
title={modalTitleI18nKey}> modalTitleI18nKey={modalTitleI18nKey}
<h5> modalButtonI18nKey={modalButtonI18nKey}
<Trans i18nKey={modalQuestionI18nKey} /> modalQuestionI18nKey={modalQuestionI18nKey}
</h5> modalWarningI18nKey={modalWarningI18nKey}
<ul> />
<li>{noteTitle}</li>
</ul>
<h6>
<Trans i18nKey={modalWarningI18nKey} />
</h6>
</DeletionModal>
</Fragment> </Fragment>
) )
} }

View file

@ -72,7 +72,7 @@ export const HistoryCard: React.FC<HistoryEntryProps & HistoryEventHandlers> = (
<div className={'d-flex flex-column'}> <div className={'d-flex flex-column'}>
<EntryMenu <EntryMenu
id={entry.identifier} id={entry.identifier}
title={entry.title} title={entryTitle}
origin={entry.origin} origin={entry.origin}
isDark={false} isDark={false}
onRemove={onRemove} onRemove={onRemove}