diff --git a/packages/frontend/src/components/AppConnectionRow/index.tsx b/packages/frontend/src/components/AppConnectionRow/index.tsx index e4d8ac777..b0fbd0520 100644 --- a/packages/frontend/src/components/AppConnectionRow/index.tsx +++ b/packages/frontend/src/components/AppConnectionRow/index.tsx @@ -3,7 +3,7 @@ import type { IConnection } from '@plumber/types' import * as React from 'react' import { useCallback, useRef, useState } from 'react' import { useLazyQuery, useMutation } from '@apollo/client' -import { Card } from '@chakra-ui/react' +import { Card, useDisclosure } from '@chakra-ui/react' import CheckCircleIcon from '@mui/icons-material/CheckCircle' import ErrorIcon from '@mui/icons-material/Error' import MoreHorizIcon from '@mui/icons-material/MoreHoriz' @@ -15,6 +15,7 @@ import { useToast } from '@opengovsg/design-system-react' import { DateTime } from 'luxon' import ConnectionContextMenu from '@/components/AppConnectionContextMenu' +import MenuAlertDialog from '@/components/MenuAlertDialog' import { DELETE_CONNECTION } from '@/graphql/mutations/delete-connection' import { TEST_CONNECTION } from '@/graphql/queries/test-connection' import useFormatMessage from '@/hooks/useFormatMessage' @@ -46,39 +47,39 @@ function AppConnectionRow(props: AppConnectionRowProps): React.ReactElement { setTimeout(() => setVerificationVisible(false), 3000) }, }) - const [deleteConnection] = useMutation(DELETE_CONNECTION) + const [deleteConnection, { loading: isDeletingConnection }] = + useMutation(DELETE_CONNECTION) const formatMessage = useFormatMessage() const { id, key, formattedData, createdAt, flowCount } = props.connection const contextButtonRef = useRef(null) const [anchorEl, setAnchorEl] = useState(null) + const cancelRef = useRef(null) + const { + isOpen: isDialogOpen, + onOpen: onDialogOpen, + onClose: onDialogClose, + } = useDisclosure() const handleClose = () => { setAnchorEl(null) } - const onContextMenuClick = () => setAnchorEl(contextButtonRef.current) - const onContextMenuAction = useCallback( - async ( - _event: React.MouseEvent, - action: { [key: string]: string }, - ) => { - if (action.type === 'delete') { - await deleteConnection({ - variables: { input: { id } }, - update: (cache) => { - const connectionCacheId = cache.identify({ - __typename: 'Connection', - id, - }) - - cache.evict({ - id: connectionCacheId, - }) - }, + const onConnectionDelete = useCallback(async () => { + await deleteConnection({ + variables: { input: { id } }, + update: (cache) => { + const connectionCacheId = cache.identify({ + __typename: 'Connection', + id, }) - + cache.evict({ + id: connectionCacheId, + }) + }, + onCompleted: () => { + onDialogClose() toast({ title: 'The connection has been deleted.', status: 'success', @@ -86,6 +87,18 @@ function AppConnectionRow(props: AppConnectionRowProps): React.ReactElement { isClosable: true, position: 'bottom-right', }) + }, + }) + }, [deleteConnection, id, toast, onDialogClose]) + + const onContextMenuClick = () => setAnchorEl(contextButtonRef.current) + const onContextMenuAction = useCallback( + async ( + _event: React.MouseEvent, + action: { [key: string]: string }, + ) => { + if (action.type === 'delete') { + onDialogOpen() } else if (action.type === 'test') { setVerificationVisible(true) const testResults = await testConnection({ @@ -101,7 +114,7 @@ function AppConnectionRow(props: AppConnectionRowProps): React.ReactElement { } } }, - [deleteConnection, id, testConnection, toast], + [id, onDialogOpen, testConnection], ) const relativeCreatedAt = DateTime.fromMillis( @@ -195,6 +208,15 @@ function AppConnectionRow(props: AppConnectionRowProps): React.ReactElement { anchorEl={anchorEl} /> )} + ) } diff --git a/packages/frontend/src/components/FlowRow/FlowContextMenu.tsx b/packages/frontend/src/components/FlowRow/FlowContextMenu.tsx index a4118ee07..2640b1691 100644 --- a/packages/frontend/src/components/FlowRow/FlowContextMenu.tsx +++ b/packages/frontend/src/components/FlowRow/FlowContextMenu.tsx @@ -23,12 +23,11 @@ import { useToast, } from '@opengovsg/design-system-react' +import MenuAlertDialog, { AlertDialogType } from '@/components/MenuAlertDialog' import * as URLS from '@/config/urls' import { DELETE_FLOW } from '@/graphql/mutations/delete-flow' import { DUPLICATE_FLOW } from '@/graphql/mutations/duplicate-flow' -import MenuAlertDialog, { AlertDialogType } from './MenuAlertDialog' - interface FlowContextMenuProps { flow: IFlow } @@ -184,7 +183,8 @@ export default function FlowContextMenu(props: FlowContextMenuProps) { isDialogOpen={isDialogOpen} cancelRef={cancelRef} onDialogClose={onDialogClose} - type={dialogType} + dialogHeader="Pipe" + dialogType={dialogType} onClick={dialogType === 'delete' ? onFlowDelete : onFlowDuplicate} isLoading={dialogType === 'delete' ? isDeletingFlow : isDuplicatingFlow} /> diff --git a/packages/frontend/src/components/FlowRow/MenuAlertDialog.tsx b/packages/frontend/src/components/MenuAlertDialog/index.tsx similarity index 72% rename from packages/frontend/src/components/FlowRow/MenuAlertDialog.tsx rename to packages/frontend/src/components/MenuAlertDialog/index.tsx index fa3d623d1..facedb9f9 100644 --- a/packages/frontend/src/components/FlowRow/MenuAlertDialog.tsx +++ b/packages/frontend/src/components/MenuAlertDialog/index.tsx @@ -9,12 +9,14 @@ import { import { Button } from '@opengovsg/design-system-react' export type AlertDialogType = 'delete' | 'duplicate' +export type AlertHeaderType = 'Connection' | 'Pipe' | 'Tile' interface MenuAlertDialogProps { isDialogOpen: boolean cancelRef: React.RefObject onDialogClose: () => void - type: AlertDialogType + dialogType: AlertDialogType + dialogHeader: AlertHeaderType onClick: () => void isLoading: boolean } @@ -25,12 +27,15 @@ interface AlertDialogContent { buttonText: string } -function getAlertDialogContent(type: AlertDialogType): AlertDialogContent { - switch (type) { +function getAlertDialogContent( + dialogHeader: AlertHeaderType, + dialogType: AlertDialogType, +): AlertDialogContent { + switch (dialogType) { case 'delete': return { - header: 'Delete Pipe', - body: "Are you sure you want to delete this pipe? You can't undo this action afterwards.", + header: `Delete ${dialogHeader}`, + body: `Are you sure you want to delete this ${dialogHeader?.toLowerCase()}? You can't undo this action afterwards.`, buttonText: 'Delete', } case 'duplicate': @@ -43,9 +48,19 @@ function getAlertDialogContent(type: AlertDialogType): AlertDialogContent { } export default function MenuAlertDialog(props: MenuAlertDialogProps) { - const { isDialogOpen, cancelRef, onDialogClose, type, onClick, isLoading } = - props - const { header, body, buttonText } = getAlertDialogContent(type) + const { + isDialogOpen, + cancelRef, + onDialogClose, + dialogHeader, + dialogType, + onClick, + isLoading, + } = props + const { header, body, buttonText } = getAlertDialogContent( + dialogHeader, + dialogType, + ) return ( { const navigate = useNavigate() + const toast = useToast() const [deleteTable, { loading: isDeletingTable }] = useMutation( DELETE_TABLE, { @@ -73,7 +69,14 @@ const TileListItem = ({ table }: { table: TableMetadata }): JSX.Element => { const deleteTile = useCallback(async () => { await deleteTable() onDialogClose() - }, [deleteTable, onDialogClose]) + toast({ + title: 'The tile has been deleted.', + status: 'success', + duration: 3000, + isClosable: true, + position: 'top', + }) + }, [deleteTable, onDialogClose, toast]) return ( @@ -145,40 +148,15 @@ const TileListItem = ({ table }: { table: TableMetadata }): JSX.Element => { - - - - Delete Tile - - - {"Are you sure? You can't undo this action afterwards."} - - - - - - - - - + ) }