import { Button as RaButton } from './Button';
import { Toolbar } from '@/components/ra-forms';
import { PlusCircleOutlined } from '@ant-design/icons';
import { Breakpoint, Button, Dialog, DialogContent } from '@mui/material';
import { CreateBase, UseCreateMutateParams, useNotify, useResourceContext, useTranslate } from 'ra-core';
import { ButtonProps, CreateButton, CreateButtonProps, CreateProps, SaveButton } from 'ra-ui-materialui';
import React, { Children, PropsWithChildren, useCallback, useState } from 'react';
import { FieldValues, useFormContext } from 'react-hook-form';
import { useQueryClient } from 'react-query';
function updateColl(old: any, data: any) {
const id = data.id;
if (!old) return [data];
const index = old.findIndex((record: any) => record.id === id);
if (index === -1) {
return [...old, data];
}
return [...old.slice(0, index), { ...old[index], ...data }, ...old.slice(index + 1)];
}
function setManyReferenceQueryData(res: any, data: any) {
const result = res && res.data ? { data: updateColl(res.data, data), total: res.total + 1 } : res;
return result;
}
function setManyQueryData(coll: any, data: any) {
return coll && coll.length > 0 ? updateColl(coll, data) : coll;
}
function setListQueryData(res: any, data: any) {
return res && res.data ? { ...res, data: updateColl(res.data, data), total: res.total + 1 } : res;
}
type ResponsiveButtonProps = CreateButtonProps &
ButtonProps & {
label?: string;
onClick?: () => void;
disableFloatingButton?: boolean;
};
function ResponsiveButton(props: ResponsiveButtonProps): JSX.Element {
const { disableFloatingButton, label = 'ra.action.create', startIcon = , ...rest } = props;
const handleClick = useCallback(
(event: any) => {
(event as Event).preventDefault();
props?.onClick?.();
},
[props]
);
return disableFloatingButton ? (
{startIcon as any}
) : (
{startIcon as any}
);
}
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 translate = useTranslate();
const handleClick = useCallback(
(event: any) => {
(event as Event).preventDefault();
(event as Event).stopPropagation();
handleSubmit((fieldValues) => onSubmit(fieldValues, closeDialog))();
},
[handleSubmit, onSubmit, closeDialog]
);
return (
);
}
type CreateInDialogButtonProps = PropsWithChildren &
CreateProps &
ResponsiveButtonProps & {
maxWidth: Breakpoint;
fullWidth?: boolean;
fullScreen?: boolean;
/**
* Indicates whether the floating button should be disabled.
* Default is false, this mean that the floating button will be displayed on small screens.
* **If you have multiple buttons on the same page, they will be displayed over each other! **
*/
disableFloatingButton?: 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.
* 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, where only the dialog surface is needed. Defaults to false.
*/
hideTrigger?: boolean;
};
function CreateInDialogButton(props: CreateInDialogButtonProps) {
const {
children,
maxWidth = 'md',
fullWidth = true,
fullScreen,
hideTrigger = false,
open: openProp,
onOpenChange,
onSubmit,
mutationOptions,
scroll = 'body',
...rest
} = props;
const queryClient = useQueryClient();
const resource = useResourceContext();
const translate = useTranslate();
const Child = Children.only(children);
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 notify = useNotify();
const handleOpen = useCallback(() => setOpenState(true), [setOpenState]);
const handleClose = useCallback(() => setOpenState(false), [setOpenState]);
const handleSuccess = useCallback(
(data: any, params: UseCreateMutateParams, context: unknown) => {
const now = Date.now();
const updatedAt = now;
queryClient.setQueryData([resource, 'getOne', { id: data.id }], data);
queryClient.setQueriesData([resource, 'getList'], (res: any) => setListQueryData(res, data), {
updatedAt
});
queryClient.setQueriesData([resource, 'getMany'], (coll: any) => setManyQueryData(coll, data), {
updatedAt
});
queryClient.setQueriesData([resource, 'getManyReference'], (res: any) => setManyReferenceQueryData(res, data), {
updatedAt
});
handleClose();
notify('ra.notification.created', { messageArgs: { smart_count: 1 } });
props?.mutationOptions?.onSuccess?.(data, params, context);
},
[handleClose, notify, props.mutationOptions, queryClient, resource]
);
return (
<>
{!hideTrigger && }
>
);
}
export { CreateInDialogButton };
export type { CreateInDialogButtonProps };