import * as React from 'react'; import { ReactElement } from 'react'; import PropTypes from 'prop-types'; import ActionDelete from '@mui/icons-material/Delete'; import inflection from 'inflection'; import { SxProps, alpha, styled, useTheme } from '@mui/material/styles'; import { DeleteManyParams, MutationMode, RaRecord, useDeleteMany, useListContext, useNotify, useRefresh, useResourceContext, useSafeSetState, useTranslate } from 'ra-core'; import { BulkActionProps, Button, ButtonProps, Confirm } from 'react-admin'; import { UseMutationOptions } from 'react-query'; import _ from 'lodash'; import { Box, Typography } from '@mui/material'; import { DeleteFilled } from '@ant-design/icons'; /** * BulkDeleteWithConfirmButton component allows you to delete multiple records with a confirmation dialog. * * This component extends the functionality of the react-admin BulkDeleteWithConfirmButton by adding * two optional methods, `onSuccess` and `onError`, to the props. These methods allow users * to extend what happens in the `onSuccess` and `onError` methods of the `useDeleteMany` hook. * * @example * { * // Custom success logic * }} * onError={() => { * // Custom error logic * }} * /> */ function BulkDeleteWithConfirmButton(props: BulkDeleteWithConfirmButtonProps) { const { confirmTitle, confirmContent, confirmColor = 'primary', dialogSx, icon = defaultIcon, label = 'ra.action.delete', mutationMode = 'pessimistic', mutationOptions = {}, onClick, onSuccess: externalOnSuccess, onError: externalOnError, ...rest } = props; const { meta: mutationMeta, ...otherMutationOptions } = mutationOptions; const { selectedIds, onUnselectItems } = useListContext(props); const [isOpen, setOpen] = useSafeSetState(false); const notify = useNotify(); const resource = useResourceContext(props); const refresh = useRefresh(); const translate = useTranslate(); const theme = useTheme(); const [deleteMany, { isLoading }] = useDeleteMany( resource, { ids: selectedIds, meta: mutationMeta }, { // @ts-ignore onSuccess: () => { refresh(); notify('ra.notification.deleted', { type: 'info', messageArgs: { smart_count: selectedIds.length }, undoable: mutationMode === 'undoable' }); onUnselectItems(); setOpen(false); if (externalOnSuccess && _.isFunction(externalOnSuccess)) { externalOnSuccess(); } }, // @ts-ignore onError: (error: Error) => { notify(typeof error === 'string' ? error : error.message || 'ra.notification.http_error', { type: 'error', messageArgs: { _: typeof error === 'string' ? error : error && error.message ? error.message : undefined } }); setOpen(false); if (externalOnError && _.isFunction(externalOnError)) { externalOnError(); } }, mutationMode, ...otherMutationOptions } ); function handleClick(e: any) { setOpen(true); e.stopPropagation(); } function handleDialogClose() { setOpen(false); } function handleDelete(e: any) { deleteMany(); if (typeof onClick === 'function') { onClick(e); } } return ( <> {icon} ) } content={ confirmContent || ( {translate('ra.message.bulk_delete_content', { _: 'ra.message.bulk_delete_content', smart_count: selectedIds.length, name: translate(`resources.${resource}.forcedCaseName`, { smart_count: selectedIds.length, _: inflection.humanize( translate(`resources.${resource}.name`, { smart_count: selectedIds.length, _: inflection.inflect(resource, selectedIds.length) }), true ) }) })} ) } confirmColor={confirmColor} translateOptions={{ smart_count: selectedIds.length, name: translate(`resources.${resource}.forcedCaseName`, { smart_count: selectedIds.length, _: inflection.humanize( translate(`resources.${resource}.name`, { smart_count: selectedIds.length, _: inflection.inflect(resource, selectedIds.length) }), true ) }) }} onConfirm={handleDelete} onClose={handleDialogClose} /> ); } function sanitizeRestProps({ classes, filterValues, label, selectedIds, ...rest }: Omit) { return rest; } interface BulkDeleteWithConfirmButtonProps extends BulkActionProps, ButtonProps { confirmContent?: React.ReactNode; confirmTitle?: React.ReactNode; confirmColor?: 'primary' | 'warning'; dialogSx?: SxProps; icon?: ReactElement; mutationMode: MutationMode; mutationOptions?: UseMutationOptions> & { meta?: any; }; /** * Optional custom success logic to be executed after the default onSuccess logic. * This method allows users to extend what happens in the onSuccess method of the useDeleteMany hook. */ onSuccess?: () => void; /** * Optional custom error logic to be executed after the default onError logic. * This method allows users to extend what happens in the onError method of the useDeleteMany hook. */ onError?: () => void; } const PREFIX = 'RaBulkDeleteWithConfirmButton'; const StyledButton = styled(Button, { name: PREFIX, overridesResolver: (styles) => styles.root })(({ theme }) => ({ color: theme.palette.error.main, '&:hover': { backgroundColor: alpha(theme.palette.error.main, 0.12), // Reset on mouse devices '@media (hover: none)': { backgroundColor: 'transparent' } } })); const defaultIcon = ; BulkDeleteWithConfirmButton.propTypes = { confirmTitle: PropTypes.node, confirmContent: PropTypes.node, confirmColor: PropTypes.string, dialogSx: PropTypes.object, icon: PropTypes.element, label: PropTypes.string, mutationMode: PropTypes.oneOf(['pessimistic', 'optimistic', 'undoable']), resource: PropTypes.string, selectedIds: PropTypes.arrayOf(PropTypes.any), onSuccess: PropTypes.func, onError: PropTypes.func }; export { BulkDeleteWithConfirmButton }; export type { BulkDeleteWithConfirmButtonProps };