Skip to content

Commit

Permalink
Merge pull request #13 from JesusMurguia/mattermostGH-4476-No-card-de…
Browse files Browse the repository at this point in the history
…lete-confirmation-status

Gh 4476 no card delete confirmation status
  • Loading branch information
Kuuchuu committed May 9, 2024
2 parents 50970aa + ef31f87 commit a10abae
Show file tree
Hide file tree
Showing 9 changed files with 981 additions and 92 deletions.

Large diffs are not rendered by default.

96 changes: 12 additions & 84 deletions webapp/src/components/calendar/fullCalendar.tsx
@@ -1,7 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import React, {useCallback, useMemo, useState} from 'react'
import React, {useCallback, useMemo} from 'react'
import {useIntl} from 'react-intl'

import FullCalendar, {EventChangeArg, EventInput, EventContentArg, DayCellContentArg} from '@fullcalendar/react'
Expand All @@ -18,18 +18,12 @@ import {BoardView} from '../../blocks/boardView'
import {Card} from '../../blocks/card'
import {DateProperty} from '../../properties/date/date'
import propsRegistry from '../../properties'
import Tooltip from '../../widgets/tooltip'
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'
import CardActionsMenu from '../cardActionsMenu/cardActionsMenu'
import TelemetryClient, {TelemetryActions, TelemetryCategory} from '../../telemetry/telemetryClient'
import CardActionsMenuIcon from '../cardActionsMenu/cardActionsMenuIcon'

import FullCalendarCard from './fullCalendarCard'

const oneDay = 60 * 60 * 24 * 1000

Expand Down Expand Up @@ -76,8 +70,6 @@ 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))
Expand Down Expand Up @@ -127,82 +119,19 @@ 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')
setShowConfirmationDialogBox(false)
}, [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)}
>
{!props.readonly &&
<MenuWrapper
className='optionsMenu'
stopPropagationOnToggle={true}
>
<CardActionsMenuIcon/>
<CardActionsMenu
cardId={card.id}
boardId={card.boardId}
onClickDelete={() => openConfirmationDialogBox(card)}
onClickDuplicate={() => {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.DuplicateCard, {board: board.id, card: card.id})
mutator.duplicateCard(card.id, board.id)
}}
/>
</MenuWrapper>}
<div className='octo-icontitle'>
{ event.extendedProps.icon ? <div className='octo-icon'>{event.extendedProps.icon}</div> : undefined }
<div
className='fc-event-title'
key='__title'
>{event.title || intl.formatMessage({id: 'CalendarCard.untitled', defaultMessage: 'Untitled'})}</div>
</div>
{visiblePropertyTemplates.map((template) => (
<Tooltip
key={template.id}
title={template.name}
>
<PropertyValueElement
board={board}
readOnly={true}
card={card}
propertyTemplate={template}
showEmptyPlaceholder={false}
/>
</Tooltip>
))}
{visibleBadges &&
<CardBadges card={card}/> }
</div>
</>
)
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={visiblePropertyTemplates}
visibleBadges={visibleBadges}
key={card.id}
readonly={props.readonly}
showCard={props.showCard}
/>)
}

const eventChange = useCallback((eventProps: EventChangeArg) => {
Expand Down Expand Up @@ -292,7 +221,6 @@ const CalendarFullView = (props: Props): JSX.Element|null => {
selectMirror={true}
select={onNewEvent}
/>
{showConfirmationDialogBox && <ConfirmationDialogBox dialogBox={confirmDialogProps}/>}
</div>
)
}
Expand Down
186 changes: 186 additions & 0 deletions webapp/src/components/calendar/fullCalendarCard.test.tsx
@@ -0,0 +1,186 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import {render, screen, within} from '@testing-library/react'
import '@testing-library/jest-dom'
import {MemoryRouter} from 'react-router-dom'

import {Provider as ReduxProvider} from 'react-redux'

import userEvent from '@testing-library/user-event'

import {mocked} from 'jest-mock'

import Mutator from '../../mutator'
import {Utils} from '../../utils'

import {TestBlockFactory} from '../../test/testBlockFactory'
import {IPropertyTemplate} from '../../blocks/board'
import {mockStateStore, wrapDNDIntl} from '../../testUtils'

import FullCalendarCard from './fullCalendarCard'

jest.mock('../../mutator')
jest.mock('../../utils')
jest.mock('../../telemetry/telemetryClient')
const mockedUtils = mocked(Utils, true)
const mockedMutator = mocked(Mutator, true)

describe('src/components/calendar/fullCalendarCard', () => {
const board = TestBlockFactory.createBoard()
const card = TestBlockFactory.createCard(board)
const propertyTemplate: IPropertyTemplate = {
id: 'id',
name: 'name',
type: 'text',
options: [
{
color: 'propColorOrange',
id: 'property_value_id_1',
value: 'Q1',
},
{
color: 'propColorBlue',
id: 'property_value_id_2',
value: 'Q2',
},
],
}
const state = {
cards: {
cards: [card],
},
teams: {
current: {id: 'team-id'},
},
boards: {
current: 'board_id_1',
boards: {
board_id_1: {id: 'board_id_1'},
},
myBoardMemberships: {
board_id_1: {userId: 'user_id_1', schemeAdmin: true},
},
},
contents: {},
comments: {
comments: {},
},
users: {
me: {
id: 'user_id_1',
props: {},
},
},
}
const store = mockStateStore([], state)
beforeEach(jest.clearAllMocks)
test('should match snapshot', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={[propertyTemplate]}
visibleBadges={false}
readonly={false}
showCard={jest.fn()}
/>
</ReduxProvider>,
), {wrapper: MemoryRouter})
expect(container).toMatchSnapshot()
})
test('should match snapshot with readonly', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={[propertyTemplate]}
visibleBadges={false}
readonly={true}
showCard={jest.fn()}
/>
</ReduxProvider>,
), {wrapper: MemoryRouter})
expect(container).toMatchSnapshot()
})
test('return FullCalendarCard and click on delete menu ', () => {
const result = render(wrapDNDIntl(
<ReduxProvider store={store}>
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={[propertyTemplate]}
visibleBadges={false}
readonly={false}
showCard={jest.fn()}
/>
</ReduxProvider>,
), {wrapper: MemoryRouter})

const {container} = result

const elementMenuWrapper = screen.getByRole('button', {name: 'menuwrapper'})
expect(elementMenuWrapper).not.toBeNull()
userEvent.click(elementMenuWrapper)
expect(container).toMatchSnapshot()
const elementButtonDelete = within(elementMenuWrapper).getByRole('button', {name: 'Delete'})
expect(elementButtonDelete).not.toBeNull()
userEvent.click(elementButtonDelete)

const confirmDialog = screen.getByTitle('Confirmation Dialog Box')
expect(confirmDialog).toBeDefined()
const confirmButton = within(confirmDialog).getByRole('button', {name: 'Delete'})
expect(confirmButton).toBeDefined()
userEvent.click(confirmButton)

expect(mockedMutator.deleteBlock).toBeCalledWith(card, 'delete card')
})

test('return FullCalendarCard and click on duplicate menu ', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={[propertyTemplate]}
visibleBadges={false}
readonly={false}
showCard={jest.fn()}
/>
</ReduxProvider>,
), {wrapper: MemoryRouter})
const elementMenuWrapper = screen.getByRole('button', {name: 'menuwrapper'})
expect(elementMenuWrapper).not.toBeNull()
userEvent.click(elementMenuWrapper)
expect(container).toMatchSnapshot()
const elementButtonDuplicate = within(elementMenuWrapper).getByRole('button', {name: 'Duplicate'})
expect(elementButtonDuplicate).not.toBeNull()
userEvent.click(elementButtonDuplicate)
expect(mockedMutator.duplicateCard).toBeCalledTimes(1)
})

test('return FullCalendarCard and click on copy link menu ', () => {
const {container} = render(wrapDNDIntl(
<ReduxProvider store={store}>
<FullCalendarCard
card={card}
board={board}
visiblePropertyTemplates={[propertyTemplate]}
visibleBadges={false}
readonly={false}
showCard={jest.fn()}
/>
</ReduxProvider>,
), {wrapper: MemoryRouter})
const elementMenuWrapper = screen.getByRole('button', {name: 'menuwrapper'})
expect(elementMenuWrapper).not.toBeNull()
userEvent.click(elementMenuWrapper)
expect(container).toMatchSnapshot()
const elementButtonCopyLink = within(elementMenuWrapper).getByRole('button', {name: 'Copy link'})
expect(elementButtonCopyLink).not.toBeNull()
userEvent.click(elementButtonCopyLink)
expect(mockedUtils.copyTextToClipboard).toBeCalledTimes(1)
})
})

0 comments on commit a10abae

Please sign in to comment.