import { useCallback, useMemo } from 'react';
import { useUpdate, UseUpdateOptions } from '../../dataProvider/useUpdate';
import { useRedirect, RedirectionSideEffect } from '../../routing/useRedirect';
import { useNotify } from '../../notification/useNotify';
import { RaRecord, MutationMode } from '../../types';
import { useRecordContext } from '../record/useRecordContext';
import { useResourceContext } from '../../core/useResourceContext';
import { useTranslate } from '../../i18n/useTranslate';
/**
* Prepare a set of callbacks for an update button
*
* @example
* const UpdateButton = ({
* resource,
* record,
* redirect,
* ...rest
* }) => {
* const {
* isPending,
* handleUpdate,
* } = useUpdateController({
* mutationMode: 'pessimistic',
* resource,
* record,
* redirect,
* });
*
* const [open, setOpen] = useState(false);
*
* return (
*
*
* handleUpdate()}
* onClose={() => setOpen(false)}
* />
*
* );
* };
*/
export const useUpdateController = <
RecordType extends RaRecord = any,
ErrorType = Error,
>(
props: UseUpdateControllerParams
): UseUpdateControllerReturn => {
const {
redirect: redirectTo = false,
mutationMode = 'undoable',
mutationOptions = {},
successMessage,
} = props;
const { meta: mutationMeta, ...otherMutationOptions } = mutationOptions;
const record = useRecordContext(props);
const resource = useResourceContext(props);
const notify = useNotify();
const redirect = useRedirect();
const translate = useTranslate();
const [updateOne, { isPending }] = useUpdate(
resource,
undefined,
{
onSuccess: () => {
notify(
successMessage ??
`resources.${resource}.notifications.updated`,
{
type: 'info',
messageArgs: {
smart_count: 1,
_: translate('ra.notification.updated', {
smart_count: 1,
}),
},
undoable: mutationMode === 'undoable',
}
);
redirect(redirectTo, resource);
},
onError: (error: any) => {
notify(
typeof error === 'string'
? error
: error?.message || 'ra.notification.http_error',
{
type: 'error',
messageArgs: {
_:
typeof error === 'string'
? error
: (error as Error)?.message,
},
}
);
},
mutationMode,
...otherMutationOptions,
}
);
const handleUpdate = useCallback(
(data: Partial) => {
if (!record) {
throw new Error(
'The record cannot be updated because no record has been passed'
);
}
updateOne(resource, {
id: record.id,
data,
previousData: record,
meta: mutationMeta,
});
},
[updateOne, mutationMeta, record, resource]
);
return useMemo(
() => ({
isPending,
isLoading: isPending,
handleUpdate,
}),
[isPending, handleUpdate]
);
};
export interface UseUpdateControllerParams<
RecordType extends RaRecord = any,
MutationOptionsError = unknown,
> {
mutationMode?: MutationMode;
mutationOptions?: UseUpdateOptions;
record?: RecordType;
redirect?: RedirectionSideEffect;
resource?: string;
successMessage?: string;
}
export interface UseUpdateControllerReturn {
isLoading: boolean;
isPending: boolean;
handleUpdate: (data: Partial) => void;
}