Skip to content

Commit

Permalink
Display a confirmation dialog before deleting an announcement
Browse files Browse the repository at this point in the history
  • Loading branch information
K-Phoen committed Mar 11, 2023
1 parent 8435880 commit 528302a
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 36 deletions.
5 changes: 5 additions & 0 deletions .changeset/chilly-planes-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@k-phoen/backstage-plugin-announcements': patch
---

Display a confirmation dialog before deleting an announcement
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, ReactNode } from 'react';
import React, { ReactNode } from 'react';
import { useAsyncRetry } from 'react-use';
import { usePermission } from '@backstage/plugin-permission-react';
import {
Expand Down Expand Up @@ -41,6 +41,8 @@ import {
announcementViewRouteRef,
} from '../../routes';
import { Announcement, announcementsApiRef } from '../../api';
import { DeleteAnnouncementDialog } from './DeleteAnnouncementDialog';
import { useDeleteAnnouncementDialogState } from './useDeleteAnnouncementDialogState';

const useStyles = makeStyles(theme => ({
cardHeader: {
Expand All @@ -50,18 +52,15 @@ const useStyles = makeStyles(theme => ({

const AnnouncementCard = ({
announcement,
onChange,
onDelete,
}: {
announcement: Announcement;
onChange?: () => void;
onDelete: () => void;
}) => {
const classes = useStyles();
const announcementsApi = useApi(announcementsApiRef);
const alertApi = useApi(alertApiRef);
const viewAnnouncementLink = useRouteRef(announcementViewRouteRef);
const editAnnouncementLink = useRouteRef(announcementEditRouteRef);
const entityLink = useRouteRef(entityRouteRef);
const [deleting, setDeleting] = useState(false);

const publisherRef = parseEntityRef(announcement.publisher);
const title = (
Expand All @@ -86,26 +85,6 @@ const AnnouncementCard = ({
const { loading: loadingUpdatePermission, allowed: canUpdate } =
usePermission({ permission: announcementUpdatePermission });

const handleDelete = async () => {
setDeleting(true);

try {
await announcementsApi.deleteAnnouncementByID(announcement.id);

alertApi.post({ message: 'Announcement deleted.', severity: 'success' });
} catch (err) {
alertApi.post({ message: (err as Error).message, severity: 'error' });
}

if (onChange) {
onChange();
}
};

if (deleting) {
return <Progress />;
}

return (
<Card>
<CardMedia>
Expand All @@ -122,7 +101,7 @@ const AnnouncementCard = ({
</LinkButton>
)}
{!loadingDeletePermission && canDelete && (
<Button onClick={handleDelete} color="default">
<Button onClick={onDelete} color="default">
<DeleteIcon />
</Button>
)}
Expand All @@ -133,29 +112,62 @@ const AnnouncementCard = ({

const AnnouncementsGrid = () => {
const announcementsApi = useApi(announcementsApiRef);
const alertApi = useApi(alertApiRef);

const {
value: announcements,
loading,
error,
retry: refresh,
} = useAsyncRetry(async () => announcementsApi.announcements({}));
const {
isOpen: isDeleteDialogOpen,
open: openDeleteDialog,
close: closeDeleteDialog,
announcement: announcementToDelete,
} = useDeleteAnnouncementDialogState();

if (loading) {
return <Progress />;
} else if (error) {
return <Alert severity="error">{error.message}</Alert>;
}

const onCancelDelete = () => {
closeDeleteDialog();
};
const onConfirmDelete = async () => {
closeDeleteDialog();

try {
await announcementsApi.deleteAnnouncementByID(announcementToDelete!.id);

alertApi.post({ message: 'Announcement deleted.', severity: 'success' });
} catch (err) {
alertApi.post({ message: (err as Error).message, severity: 'error' });
}

refresh();
};

return (
<ItemCardGrid>
{announcements!.map((announcement, index) => (
<AnnouncementCard
key={index}
announcement={announcement}
onChange={refresh}
/>
))}
</ItemCardGrid>
<>
<ItemCardGrid>
{announcements!.map((announcement, index) => (
<AnnouncementCard
key={index}
announcement={announcement}
onDelete={() => openDeleteDialog(announcement)}
/>
))}
</ItemCardGrid>

<DeleteAnnouncementDialog
open={isDeleteDialogOpen}
onCancel={onCancelDelete}
onConfirm={onConfirmDelete}
/>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { Button, Dialog, DialogActions, DialogTitle } from '@material-ui/core';

export type DeleteAnnouncementDialogProps = {
open: boolean;
onConfirm: () => any;
onCancel: () => any;
};

export const DeleteAnnouncementDialog = (
props: DeleteAnnouncementDialogProps,
) => {
const { open, onConfirm, onCancel } = props;

return (
<Dialog open={open} onClose={onCancel}>
<DialogTitle>
Are you sure you want to delete this announcement?
</DialogTitle>

<DialogActions>
<Button onClick={onCancel} color="default">
Cancel
</Button>

<Button onClick={onConfirm} color="secondary">
Delete
</Button>
</DialogActions>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback, useState } from 'react';
import { Announcement } from '../../api';

export type DeleteAnnouncementDialogState = {
open: (a: Announcement) => void;
close: () => void;

isOpen: boolean;
announcement?: Announcement;
};

export function useDeleteAnnouncementDialogState(): DeleteAnnouncementDialogState {
const [state, setState] = useState<{
open: boolean;
announcement?: Announcement;
}>({ open: false });

const setOpen = useCallback(
(a: Announcement) => {
setState({
open: true,
announcement: a,
});
},
[setState],
);

const setClosed = useCallback(() => {
setState({
open: false,
announcement: undefined,
});
}, [setState]);

return {
open: setOpen,
close: setClosed,

announcement: state.announcement,
isOpen: state.open,
};
}

0 comments on commit 528302a

Please sign in to comment.