import { Button } from './Button';
import { Toolbar } from '@/components/ra-forms';
import { Breakpoint, Dialog, DialogContent } from '@mui/material';
import { EditBase, UseUpdateMutateParams, useNotify, useRecordContext } from 'ra-core';
import { EditButton, EditProps, SaveButton } from 'ra-ui-materialui';
import React, { Children, PropsWithChildren, useCallback, useState } from 'react';
import { FieldValues, useFormContext } from 'react-hook-form';
type ResponsiveButtonProps = {
label?: string;
onClick: () => void;
};
function ResponsiveButton(props: ResponsiveButtonProps): JSX.Element {
const handleClick = useCallback(
(event: any) => {
(event as Event).preventDefault();
(event as Event).stopPropagation();
props?.onClick?.();
},
[props]
);
// @ts-ignore - I need to allow the label prop to be a ReactNode
return ;
}
type CloseDialogFunction = () => void;
type SubmitFunction = (values: FieldValues, closeDialog: CloseDialogFunction) => void;
type SubmitButtonProps = {
onSubmit: SubmitFunction;
closeDialog: CloseDialogFunction;
};
function SubmitButton(props: SubmitButtonProps) {
const { onSubmit, closeDialog } = props;
const { handleSubmit } = useFormContext();
const handleClick = useCallback(
(event: any) => {
(event as Event).preventDefault();
(event as Event).stopPropagation();
handleSubmit((fieldValues) => onSubmit(fieldValues, closeDialog))();
},
[handleSubmit, onSubmit, closeDialog]
);
return (
);
}
type EditInDialogButtonProps = PropsWithChildren &
EditProps &
ResponsiveButtonProps & {
maxWidth: Breakpoint;
fullWidth?: boolean;
fullScreen?: boolean;
scroll: 'paper' | 'body' | undefined;
/**
* Custom handler for the submit event, in this case you are responsible for closing the dialog.
* @example
*
* const handleSubmit = (values, closeDialog) => {
* console.log(values); // { title: 'Hello World' }
* closeDialog();
* }
*
*
*
*
*
*
*/
onSubmit?: SubmitFunction;
/**
* Controlled open state. When provided, the dialog becomes externally controlled
* (the internal state is ignored). Enables opening the dialog programmatically,
* e.g. from a `Datagrid` `rowClick` handler. Omit to keep the default uncontrolled behavior.
*/
open?: boolean;
/**
* Called when the dialog should open or close. Use together with `open`.
* Receives the next open state.
*/
onOpenChange?: (open: boolean) => void;
/**
* When true, the trigger button is not rendered. Useful when the dialog is driven
* externally (e.g. by `rowClick`), where only the dialog surface is needed.
* Defaults to false (renders the trigger button).
*/
hideTrigger?: boolean;
};
function EditInDialogButton(props: EditInDialogButtonProps): JSX.Element {
const {
children,
maxWidth = 'md',
fullWidth = true,
fullScreen,
hideTrigger = false,
open: openProp,
onOpenChange,
mutationOptions,
onSubmit,
scroll = 'body',
...rest
} = props;
const notify = useNotify();
const isControlled = openProp !== undefined;
const [internalOpen, setInternalOpen] = useState(false);
const open = isControlled ? openProp : internalOpen;
const setOpenState = useCallback(
(next: boolean) => {
if (!isControlled) setInternalOpen(next);
onOpenChange?.(next);
},
[isControlled, onOpenChange]
);
const Child = Children.only(children);
const handleOpen = useCallback(() => setOpenState(true), [setOpenState]);
const handleClose = useCallback(() => setOpenState(false), [setOpenState]);
const handleSuccess = useCallback(
(data: any, params: UseUpdateMutateParams, context: unknown) => {
handleClose();
notify('ra.notification.updated', {
messageArgs: { smart_count: 1 },
undoable: props?.mutationMode === 'undoable'
});
props?.mutationOptions?.onSuccess?.(data, params, context);
},
[handleClose, notify, props.mutationOptions, props.mutationMode]
);
const record = useRecordContext();
return (
<>
{!hideTrigger && }
{record ? (
) : null}
>
);
}
export { EditInDialogButton };
export type { EditInDialogButtonProps };