Skip to content

Commit 357b557

Browse files
committed
Introduce useDeleteController
1 parent 72dbd01 commit 357b557

File tree

6 files changed

+371
-266
lines changed

6 files changed

+371
-266
lines changed

packages/ra-core/src/controller/button/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ import useDeleteWithUndoController from './useDeleteWithUndoController';
22
import useDeleteWithConfirmController from './useDeleteWithConfirmController';
33

44
export { useDeleteWithUndoController, useDeleteWithConfirmController };
5+
export * from './useDeleteController';
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
import { useCallback } from 'react';
2+
import { UseMutationOptions } from '@tanstack/react-query';
3+
4+
import { useDelete } from '../../dataProvider';
5+
import { useUnselect } from '../';
6+
import { useRedirect, RedirectionSideEffect } from '../../routing';
7+
import { useNotify } from '../../notification';
8+
import { RaRecord, MutationMode, DeleteParams } from '../../types';
9+
import { useResourceContext } from '../../core';
10+
import { useTranslate } from '../../i18n';
11+
12+
/**
13+
* Prepare a set of callbacks for a delete button guarded by confirmation dialog
14+
*
15+
* @example
16+
*
17+
* const DeleteButton = ({
18+
* resource,
19+
* record,
20+
* redirect,
21+
* onClick,
22+
* ...rest
23+
* }) => {
24+
* const {
25+
* open,
26+
* isPending,
27+
* handleDialogOpen,
28+
* handleDialogClose,
29+
* handleDelete,
30+
* } = useDeleteWithConfirmController({
31+
* resource,
32+
* record,
33+
* redirect,
34+
* onClick,
35+
* });
36+
*
37+
* return (
38+
* <Fragment>
39+
* <Button
40+
* onClick={handleDialogOpen}
41+
* label="ra.action.delete"
42+
* {...rest}
43+
* >
44+
* {icon}
45+
* </Button>
46+
* <Confirm
47+
* isOpen={open}
48+
* loading={isPending}
49+
* title="ra.message.delete_title"
50+
* content="ra.message.delete_content"
51+
* titleTranslateOptions={{
52+
* name: resource,
53+
* id: record.id,
54+
* }}
55+
* contentTranslateOptions={{
56+
* name: resource,
57+
* id: record.id,
58+
* }}
59+
* onConfirm={handleDelete}
60+
* onClose={handleDialogClose}
61+
* />
62+
* </Fragment>
63+
* );
64+
* };
65+
*/
66+
export const useDeleteController = <
67+
RecordType extends RaRecord = any,
68+
ErrorType = Error,
69+
>(
70+
props: UseDeleteControllerParams<RecordType, ErrorType>
71+
): UseDeleteControllerReturn => {
72+
const { mutationMode } = props;
73+
const {
74+
record,
75+
redirect: redirectTo = 'list',
76+
mutationOptions = {},
77+
successMessage,
78+
} = props as UseDeleteControllerParams<RecordType, ErrorType>;
79+
const { meta: mutationMeta, ...otherMutationOptions } = mutationOptions;
80+
const resource = useResourceContext(props);
81+
const notify = useNotify();
82+
const unselect = useUnselect(resource);
83+
const redirect = useRedirect();
84+
const translate = useTranslate();
85+
86+
const [deleteOne, { isPending }] = useDelete<RecordType, ErrorType>(
87+
resource,
88+
undefined,
89+
{
90+
onSuccess: () => {
91+
notify(
92+
successMessage ??
93+
`resources.${resource}.notifications.deleted`,
94+
{
95+
type: 'info',
96+
messageArgs: {
97+
smart_count: 1,
98+
_: translate('ra.notification.deleted', {
99+
smart_count: 1,
100+
}),
101+
},
102+
undoable: mutationMode === 'undoable',
103+
}
104+
);
105+
record && unselect([record.id]);
106+
redirect(redirectTo, resource);
107+
},
108+
onError: error => {
109+
notify(
110+
typeof error === 'string'
111+
? error
112+
: (error as Error)?.message ||
113+
'ra.notification.http_error',
114+
{
115+
type: 'error',
116+
messageArgs: {
117+
_:
118+
typeof error === 'string'
119+
? error
120+
: (error as Error)?.message
121+
? (error as Error).message
122+
: undefined,
123+
},
124+
}
125+
);
126+
},
127+
}
128+
);
129+
130+
const handleDelete = useCallback(() => {
131+
if (!record) {
132+
throw new Error(
133+
'The record cannot be deleted because no record has been passed'
134+
);
135+
}
136+
deleteOne(
137+
resource,
138+
{
139+
id: record.id,
140+
previousData: record,
141+
meta: mutationMeta,
142+
},
143+
{
144+
mutationMode,
145+
...otherMutationOptions,
146+
}
147+
);
148+
}, [
149+
deleteOne,
150+
mutationMeta,
151+
mutationMode,
152+
otherMutationOptions,
153+
record,
154+
resource,
155+
]);
156+
157+
return {
158+
isPending,
159+
isLoading: isPending,
160+
handleDelete,
161+
};
162+
};
163+
164+
export interface UseDeleteControllerParams<
165+
RecordType extends RaRecord = any,
166+
MutationOptionsError = unknown,
167+
> {
168+
mutationMode?: MutationMode;
169+
mutationOptions?: UseMutationOptions<
170+
RecordType,
171+
MutationOptionsError,
172+
DeleteParams<RecordType>
173+
>;
174+
record?: RecordType;
175+
redirect?: RedirectionSideEffect;
176+
resource?: string;
177+
successMessage?: string;
178+
}
179+
180+
export interface UseDeleteControllerReturn {
181+
isLoading: boolean;
182+
isPending: boolean;
183+
handleDelete: () => void;
184+
}

0 commit comments

Comments
 (0)