1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-02-01 19:14:35 +02:00

[GH-3947]: Added confirmation dialog when deleting a card in calendar/galley view (#3996)

Co-authored-by: Paul Esch-Laurent <paul.esch-laurent@mattermost.com>
Co-authored-by: Rajat Dabade <rajat.dabade@mattermost.com>
This commit is contained in:
Varun Tiwari 2022-10-14 11:52:06 +05:30 committed by GitHub
parent 3479e02657
commit ed3197ca62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 252 additions and 132 deletions

View File

@ -396,7 +396,7 @@
"rhs-boards.no-boards-linked-to-channel": "No boards are linked to {channelName} yet",
"rhs-boards.no-boards-linked-to-channel-description": "Boards is a project management tool that helps define, organize, track and manage work across teams, using a familiar kanban board view.",
"rhs-boards.unlink-board": "Unlink board",
"rhs-boards.unlink-board1": "Unlink board Hello",
"rhs-boards.unlink-board1": "Unlink board",
"rhs-channel-boards-header.title": "Boards",
"share-board.publish": "Publish",
"share-board.share": "Share",

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useMemo} from 'react'
import React, {useCallback, useMemo, useState} from 'react'
import {useIntl} from 'react-intl'
import FullCalendar, {EventChangeArg, EventInput, EventContentArg, DayCellContentArg} from '@fullcalendar/react'
@ -21,6 +21,7 @@ import PropertyValueElement from '../propertyValueElement'
import {Constants, Permission} from '../../constants'
import {useHasCurrentBoardPermissions} from '../../hooks/permissions'
import CardBadges from '../cardBadges'
import ConfirmationDialogBox, {ConfirmationDialogBoxProps} from '../confirmationDialogBox'
import './fullcalendar.scss'
import MenuWrapper from '../../widgets/menuWrapper'
@ -74,6 +75,8 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
const {board, cards, activeView, dateDisplayProperty, readonly} = props
const isSelectable = !readonly
const canAddCards = useHasCurrentBoardPermissions([Permission.ManageBoardCards])
const [showConfirmationDialogBox, setShowConfirmationDialogBox] = useState<boolean>(false)
const [cardItem, setCardItem] = useState<Card>()
const visiblePropertyTemplates = useMemo(() => (
board.cardProperties.filter((template: IPropertyTemplate) => activeView.fields.visiblePropertyIds.includes(template.id))
@ -114,10 +117,35 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
const visibleBadges = activeView.fields.visiblePropertyIds.includes(Constants.badgesColumnId)
const openConfirmationDialogBox = (card: Card) => {
setShowConfirmationDialogBox(true)
setCardItem(card)
}
const handleDeleteCard = useCallback(() => {
if (!cardItem) {
return
}
mutator.deleteBlock(cardItem, 'delete card')
}, [cardItem, board.id])
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {
setShowConfirmationDialogBox(false)
},
}
}, [handleDeleteCard])
const renderEventContent = (eventProps: EventContentArg): JSX.Element|null => {
const {event} = eventProps
const card = cards.find((o) => o.id === event.id) || cards[0]
return (
<>
<div
className='EventContent'
onClick={() => props.showCard(event.id)}
@ -130,7 +158,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
<IconButton icon={<OptionsIcon/>}/>
<CardActionsMenu
cardId={card.id}
onClickDelete={() => mutator.deleteBlock(card, 'delete card')}
onClickDelete={() => openConfirmationDialogBox(card)}
onClickDuplicate={() => {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
mutator.duplicateCard(card.id, board.id)
@ -161,6 +189,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
{visibleBadges &&
<CardBadges card={card}/> }
</div>
</>
)
}
@ -251,6 +280,7 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
selectMirror={true}
select={onNewEvent}
/>
{showConfirmationDialogBox && <ConfirmationDialogBox dialogBox={confirmDialogProps}/>}
</div>
)
}

View File

@ -904,6 +904,77 @@ exports[`src/components/gallery/GalleryCard without block content return Gallery
</div>
</div>
</div>
<div
class="Dialog dialog-back confirmation-dialog-box"
>
<div
class="backdrop"
/>
<div
class="wrapper"
>
<div
class="dialog"
role="dialog"
>
<div
class="toolbar"
>
<div>
<h1
class="dialog-title"
/>
</div>
<div
class="toolbar--right"
>
<button
aria-label="Close dialog"
title="Close dialog"
type="button"
>
<i
class="CompassIcon icon-close CloseIcon"
/>
</button>
</div>
</div>
<div
class="box-area"
title="Confirmation Dialog Box"
>
<h3
class="text-heading5"
>
Confirm card delete!
</h3>
<div
class="sub-text"
/>
<div
class="action-buttons"
>
<button
title="Cancel"
type="button"
>
<span>
Cancel
</span>
</button>
<button
title="Delete"
type="submit"
>
<span>
Delete
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -159,8 +159,6 @@ describe('src/components/gallery/GalleryCard', () => {
const buttonDelete = screen.getByRole('button', {name: 'Delete'})
userEvent.click(buttonDelete)
expect(container).toMatchSnapshot()
expect(mockedMutator.deleteBlock).toBeCalledTimes(1)
expect(mockedMutator.deleteBlock).toBeCalledWith(card, 'delete card')
})
test('return GalleryCard and duplicate card', () => {

View File

@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useMemo} from 'react'
import {FormattedMessage} from 'react-intl'
import React, {useMemo, useState, useCallback} from 'react'
import {useIntl, FormattedMessage} from 'react-intl'
import {Board, IPropertyTemplate} from '../../blocks/board'
import {Card} from '../../blocks/card'
@ -22,6 +22,7 @@ import PropertyValueElement from '../propertyValueElement'
import './galleryCard.scss'
import CardBadges from '../cardBadges'
import CardActionsMenu from '../cardActionsMenu/cardActionsMenu'
import ConfirmationDialogBox, {ConfirmationDialogBoxProps} from '../confirmationDialogBox'
type Props = {
board: Board
@ -37,12 +38,29 @@ type Props = {
}
const GalleryCard = (props: Props) => {
const intl = useIntl()
const {card, board} = props
const [isDragging, isOver, cardRef] = useSortable('card', card, props.isManualSort && !props.readonly, props.onDrop)
const contents = useAppSelector(getCardContents(card.id))
const [showConfirmationDialogBox, setShowConfirmationDialogBox] = useState<boolean>(false)
const visiblePropertyTemplates = props.visiblePropertyTemplates || []
const handleDeleteCard = useCallback(() => {
mutator.deleteBlock(card, 'delete card')
}, [card, board.id])
const confirmDialogProps: ConfirmationDialogBoxProps = useMemo(() => {
return {
heading: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-heading', defaultMessage: 'Confirm card delete!'}),
confirmButtonText: intl.formatMessage({id: 'CardDialog.delete-confirmation-dialog-button-text', defaultMessage: 'Delete'}),
onConfirm: handleDeleteCard,
onClose: () => {
setShowConfirmationDialogBox(false)
},
}
}, [handleDeleteCard])
const image: ContentBlock|undefined = useMemo(() => {
for (let i = 0; i < contents.length; ++i) {
if (Array.isArray(contents[i])) {
@ -60,6 +78,7 @@ const GalleryCard = (props: Props) => {
}
return (
<>
<div
className={className}
onClick={(e: React.MouseEvent) => props.onClick(e, card)}
@ -74,7 +93,7 @@ const GalleryCard = (props: Props) => {
<IconButton icon={<OptionsIcon/>}/>
<CardActionsMenu
cardId={card!.id}
onClickDelete={() => mutator.deleteBlock(card, 'delete card')}
onClickDelete={() => setShowConfirmationDialogBox(true)}
onClickDuplicate={() => {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
mutator.duplicateCard(card.id, board.id)
@ -151,6 +170,8 @@ const GalleryCard = (props: Props) => {
className='gallery-badges'
/>}
</div>
{showConfirmationDialogBox && <ConfirmationDialogBox dialogBox={confirmDialogProps}/>}
</>
)
}