Skip to content

Commit

Permalink
feat(delete model action): move deletion logic into delete action com…
Browse files Browse the repository at this point in the history
…ponent & improve message
  • Loading branch information
Mohammer5 committed Mar 19, 2024
1 parent 76b51bc commit 0d008f0
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 73 deletions.
24 changes: 3 additions & 21 deletions src/components/sectionList/SectionListWrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { FetchError } from '@dhis2/app-runtime'
import { SharingDialog } from '@dhis2/ui'
import React, { useCallback, useState } from 'react'
import {
BaseListModel,
canEditModel,
useSchemaFromHandle,
useDeleteModelMutation,
} from '../../lib'
import { BaseListModel, canEditModel, useSchemaFromHandle } from '../../lib'
import { Pager, ModelCollection } from '../../types/models'
import { SectionListHeaderBulk } from './bulk'
import { DetailsPanel, DefaultDetailsPanelContent } from './detailsPanel'
Expand Down Expand Up @@ -44,14 +39,6 @@ export const SectionListWrapper = ({
useSelectedModels()
const [detailsId, setDetailsId] = useState<string | undefined>()
const [sharingDialogId, setSharingDialogId] = useState<string | undefined>()
const deleteModelMutation = useDeleteModelMutation(schema)
const deleteModel = useCallback(
async ({ id, displayName }: BaseListModel) => {
await deleteModelMutation.mutateAsync({ id, displayName })
refetch()
},
[deleteModelMutation, refetch]
)

const SectionListMessage = () => {
if (error) {
Expand Down Expand Up @@ -113,15 +100,10 @@ export const SectionListWrapper = ({
modelType={schema.displayName}
onShowDetailsClick={handleDetailsClick}
onOpenSharingClick={setSharingDialogId}
onDeleteClick={() => deleteModel(model)}
onDeleteSuccess={refetch}
/>
),
[
handleDetailsClick,
setSharingDialogId,
deleteModel,
schema.displayName,
]
[handleDetailsClick, setSharingDialogId, schema.displayName, refetch]
)

const isAllSelected = data ? checkAllSelected(data) : false
Expand Down
11 changes: 6 additions & 5 deletions src/components/sectionList/listActions/DefaultListActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ type DefaultListActionProps = {
modelType: string
onShowDetailsClick: (model: BaseListModel) => void
onOpenSharingClick: (id: string) => void
onDeleteClick: () => void
onDeleteSuccess: () => void
}

export const DefaultListActions = ({
model,
modelType,
onShowDetailsClick,
onOpenSharingClick,
onDeleteClick,
onDeleteSuccess,
}: DefaultListActionProps) => {
const deletable = canDeleteModel(model)
const editable = canEditModel(model)
Expand All @@ -25,13 +25,14 @@ export const DefaultListActions = ({
<ListActions>
<ActionEdit modelId={model.id} />
<ActionMore
modelId={model.id}
deletable={editable}
editable={deletable}
modelId={model.id}
modelDisplayName={model.displayName}
modelType={modelType}
onShowDetailsClick={() => onShowDetailsClick(model)}
onOpenSharingClick={() => onOpenSharingClick(model.id)}
onDeleteClick={onDeleteClick}
modelType={modelType}
onDeleteSuccess={onDeleteSuccess}
/>
</ListActions>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.deleteButtonLoadingIcon {
display: inline-block;
margin-right: 8px;
}

.deleteButtonLoadingIcon :global([role="progressbar"]) {
border-color: rgba(110, 122, 138, 0.15) rgba(110, 122, 138, 0.15) white;
}
140 changes: 106 additions & 34 deletions src/components/sectionList/listActions/DeleteAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,159 @@ import i18n from '@dhis2/d2-i18n'
import {
Button,
ButtonStrip,
CircularLoader,
IconDelete16,
MenuItem,
Modal,
ModalActions,
ModalContent,
ModalTitle,
NoticeBox,
} from '@dhis2/ui'
import React, { useState } from 'react'
import { TOOLTIPS } from '../../../lib'
import { TooltipWrapper } from '../../tooltip'
import { useSchemaFromHandle, useDeleteModelMutation } from '../../../lib'
import classes from './DeleteAction.module.css'

export function DeleteAction({
deletable,
disabled,
modelId,
modelDisplayName,
modelType,
onClick,
onCancel,
onDeleteSuccess,
}: {
deletable: boolean
disabled: boolean
modelId: string
modelDisplayName: string
modelType: string
onClick: () => void
onCancel: () => void
onDeleteSuccess: () => void
}) {
const [showConfirmationDialog, setShowConfirmationDialog] = useState(false)
const deleteAndClose = () => {
setShowConfirmationDialog(false)
onDeleteSuccess()
}
const closeAndCancel = () => {
setShowConfirmationDialog(false)
onCancel()
}

return (
<>
<TooltipWrapper
condition={!deletable}
content={TOOLTIPS.noDeleteAccess}
>
<MenuItem
dense
disabled={!deletable}
label={i18n.t('Delete')}
icon={<IconDelete16 />}
onClick={() => setShowConfirmationDialog(true)}
/>
</TooltipWrapper>
<MenuItem
dense
disabled={disabled}
label={i18n.t('Delete')}
icon={<IconDelete16 />}
onClick={() => setShowConfirmationDialog(true)}
/>

{showConfirmationDialog && (
<ConfirmationDialog
modelDisplayName={modelDisplayName}
modelId={modelId}
modelType={modelType}
onConfirm={() => {
setShowConfirmationDialog(false)
onClick()
}}
onCancel={() => {
setShowConfirmationDialog(false)
onCancel()
}}
onDeleteSuccess={deleteAndClose}
onCancel={closeAndCancel}
/>
)}
</>
)
}

function ConfirmationDialog({
modelId,
modelDisplayName,
modelType,
onCancel,
onConfirm,
onDeleteSuccess,
}: {
modelId: string
modelDisplayName: string
modelType: string
onCancel: () => void
onConfirm: () => void
onDeleteSuccess: () => void
}) {
const schema = useSchemaFromHandle()
const deleteModelMutation = useDeleteModelMutation(schema)
const deleteModel = async () => {
await deleteModelMutation.mutateAsync({
id: modelId,
displayName: modelDisplayName,
})
onDeleteSuccess()
}

const deleteAndClose = () =>
deleteModel()
.then(onDeleteSuccess)
// We don't need to do anything on error except for catching it,
// we have all the information on the deleteModelMutation value
.catch(() => null)

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const errorReports = (deleteModelMutation.error as any)?.details?.response
?.errorReports

return (
<Modal>
<ModalTitle>
{i18n.t(
'Are you sure that you want to delete this {{modelType}}?',
{
modelType: modelType,
}
{ modelType }
)}
</ModalTitle>

{!!deleteModelMutation.error && (
<ModalContent>
<NoticeBox
error
title={i18n.t(
'Something went wrong deleting the {{modelType}}',
{ modelType }
)}
>
<div>
{i18n.t(
'Failed to delete {{modelType}} "{{modelDisplayName}}"! {{messages}}',
{ modelDisplayName, modelType }
)}
</div>

{!!errorReports?.length && (
<ul>
{errorReports.map(
// @TODO: I have no idea why TS says "message" isn't being used?
// eslint-disable-next-line react/no-unused-prop-types
({ message }: { message: string }) => (
<li key={message}>{message}</li>
)
)}
</ul>
)}
</NoticeBox>
</ModalContent>
)}

<ModalActions>
<ButtonStrip>
<Button onClick={onCancel}>No</Button>
<Button destructive onClick={onConfirm}>
Yes
<Button
disabled={deleteModelMutation.isLoading}
destructive
onClick={deleteAndClose}
>
{deleteModelMutation.isLoading && (
<span className={classes.deleteButtonLoadingIcon}>
<CircularLoader extrasmall />
</span>
)}

{deleteModelMutation.isError
? i18n.t('Try again')
: i18n.t('Yes')}
</Button>
<Button onClick={onCancel}>{i18n.t('No')}</Button>
</ButtonStrip>
</ModalActions>
</Modal>
Expand Down
35 changes: 22 additions & 13 deletions src/components/sectionList/listActions/SectionListActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,24 @@ export const ActionEdit = ({ modelId }: { modelId: string }) => {
}

type ActionMoreProps = {
modelId: string
deletable: boolean
editable: boolean
modelId: string
modelDisplayName: string
modelType: string
onShowDetailsClick: () => void
onOpenSharingClick: () => void
onDeleteClick: () => void
onDeleteSuccess: () => void
}
export const ActionMore = ({
modelId,
deletable,
editable,
modelId,
modelDisplayName,
modelType,
onOpenSharingClick,
onShowDetailsClick,
onDeleteClick,
onDeleteSuccess,
}: ActionMoreProps) => {
const [open, setOpen] = useState(false)
const ref = useRef(null)
Expand Down Expand Up @@ -108,15 +110,22 @@ export const ActionMore = ({
/>
</TooltipWrapper>

<DeleteAction
modelType={modelType}
deletable={deletable}
onCancel={() => setOpen(false)}
onClick={() => {
onDeleteClick()
setOpen(false)
}}
/>
<TooltipWrapper
condition={!deletable}
content={TOOLTIPS.noDeleteAccess}
>
<DeleteAction
modelDisplayName={modelDisplayName}
modelId={modelId}
modelType={modelType}
disabled={!deletable}
onDeleteSuccess={() => {
onDeleteSuccess()
setOpen(false)
}}
onCancel={() => setOpen(false)}
/>
</TooltipWrapper>
</FlyoutMenu>
</Popover>
)}
Expand Down

0 comments on commit 0d008f0

Please sign in to comment.