feat: add auto form value provider

This commit is contained in:
bennykok 2024-01-31 11:39:13 +08:00
parent 2d033570f4
commit e3a1d24304

View File

@ -23,6 +23,33 @@ import * as React from "react";
import { useState } from "react"; import { useState } from "react";
import type { UnknownKeysParam, ZodObject, ZodRawShape, z } from "zod"; import type { UnknownKeysParam, ZodObject, ZodRawShape, z } from "zod";
type ContextType = [Partial<any>, React.Dispatch<React.SetStateAction<any>>];
const AutoFormValueContext = React.createContext<ContextType | null>(null);
function AutoFormValueProvider<Z extends ZodObject<any, any>>({
children,
value,
}: {
children: React.ReactNode;
value: ContextType;
}) {
return (
<AutoFormValueContext.Provider value={value}>
{children}
</AutoFormValueContext.Provider>
);
}
export function useAutoFormValueContext<Z extends ZodObject<any, any>>() {
const context = React.useContext(AutoFormValueContext);
// if (!context) {
// throw new Error("useInsertModal must be used within a InsertModalProvider");
// }
return context;
}
export function InsertModal< export function InsertModal<
K extends ZodRawShape, K extends ZodRawShape,
Y extends UnknownKeysParam, Y extends UnknownKeysParam,
@ -41,65 +68,73 @@ export function InsertModal<
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [isLoading, setIsLoading] = React.useState(false); const [isLoading, setIsLoading] = React.useState(false);
const a = useState<Partial<z.infer<Z>>>({});
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <AutoFormValueProvider value={a}>
{/* <DialogTrigger disabled={props.disabled}> */} <Dialog open={open} onOpenChange={setOpen}>
{props.tooltip ? ( {/* <DialogTrigger disabled={props.disabled}> */}
<Tooltip> {props.tooltip ? (
<TooltipTrigger asChild> <Tooltip>
<Button <TooltipTrigger asChild>
variant="default" <Button
className={props.disabled ? "opacity-50" : ""} variant="default"
onClick={() => { className={props.disabled ? "opacity-50" : ""}
if (props.disabled) return; onClick={() => {
setOpen(true); if (props.disabled) return;
}} setOpen(true);
> }}
{props.buttonTitle ?? props.title} >
</Button> {props.buttonTitle ?? props.title}
</TooltipTrigger> </Button>
<TooltipContent> </TooltipTrigger>
<p>{props.tooltip}</p> <TooltipContent>
</TooltipContent> <p>{props.tooltip}</p>
</Tooltip> </TooltipContent>
) : ( </Tooltip>
<Button ) : (
variant="default" <Button
disabled={props.disabled} variant="default"
onClick={() => { disabled={props.disabled}
setOpen(true); onClick={() => {
}} setOpen(true);
}}
>
{props.title}
</Button>
)}
{/* </DialogTrigger> */}
<DialogContent
className={cn("sm:max-w-[425px]", props.dialogClassName)}
> >
{props.title} <DialogHeader>
</Button> <DialogTitle>{props.title}</DialogTitle>
)} <DialogDescription>{props.description}</DialogDescription>
{/* </DialogTrigger> */} </DialogHeader>
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}> {/* <ScrollArea> */}
<DialogHeader> <AutoForm
<DialogTitle>{props.title}</DialogTitle> values={values}
<DialogDescription>{props.description}</DialogDescription> onValuesChange={setValues}
</DialogHeader> fieldConfig={props.fieldConfig}
{/* <ScrollArea> */} formSchema={props.formSchema}
<AutoForm onSubmit={async (data) => {
fieldConfig={props.fieldConfig} setIsLoading(true);
formSchema={props.formSchema} await callServerPromise(props.serverAction(data));
onSubmit={async (data) => { setIsLoading(false);
setIsLoading(true); setOpen(false);
await callServerPromise(props.serverAction(data)); }}
setIsLoading(false); >
setOpen(false); <div className="flex justify-end">
}} <AutoFormSubmit>
> Save Changes
<div className="flex justify-end"> {isLoading && <LoadingIcon />}
<AutoFormSubmit> </AutoFormSubmit>
Save Changes </div>
{isLoading && <LoadingIcon />} </AutoForm>
</AutoFormSubmit> {/* </ScrollArea> */}
</div> </DialogContent>
</AutoForm> </Dialog>
{/* </ScrollArea> */} </AutoFormValueProvider>
</DialogContent>
</Dialog>
); );
} }
@ -138,49 +173,53 @@ export function UpdateModal<
}, [props.data]); }, [props.data]);
return ( return (
<Dialog open={open} onOpenChange={setOpen}> <AutoFormValueProvider value={[values, setValues]}>
{props.trigger ?? ( <Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger {props.trigger ?? (
className="appearance-none hover:cursor-pointer" <DialogTrigger
asChild className="appearance-none hover:cursor-pointer"
onClick={() => { asChild
setOpen(true); onClick={() => {
}} setOpen(true);
}}
>
{props.trigger}
</DialogTrigger>
)}
<DialogContent
className={cn("sm:max-w-[425px]", props.dialogClassName)}
> >
{props.trigger} <DialogHeader>
</DialogTrigger> <DialogTitle>{props.title}</DialogTitle>
)} <DialogDescription>{props.description}</DialogDescription>
<DialogContent className={cn("sm:max-w-[425px]", props.dialogClassName)}> </DialogHeader>
<DialogHeader> <AutoForm
<DialogTitle>{props.title}</DialogTitle> values={values}
<DialogDescription>{props.description}</DialogDescription> onValuesChange={setValues}
</DialogHeader> fieldConfig={props.fieldConfig}
<AutoForm formSchema={props.formSchema}
values={values} onSubmit={async (data) => {
onValuesChange={setValues} setIsLoading(true);
fieldConfig={props.fieldConfig} await callServerPromise(
formSchema={props.formSchema} props.serverAction({
onSubmit={async (data) => { ...data,
setIsLoading(true); id: props.data.id,
await callServerPromise( }),
props.serverAction({ );
...data, setIsLoading(false);
id: props.data.id, setOpen(false);
}), }}
); >
setIsLoading(false); <div className="flex justify-end flex-wrap gap-2">
setOpen(false); {props.extraButtons}
}} <AutoFormSubmit>
> Save Changes
<div className="flex justify-end flex-wrap gap-2"> {isLoading && <LoadingIcon />}
{props.extraButtons} </AutoFormSubmit>
<AutoFormSubmit> </div>
Save Changes </AutoForm>
{isLoading && <LoadingIcon />} </DialogContent>
</AutoFormSubmit> </Dialog>
</div> </AutoFormValueProvider>
</AutoForm>
</DialogContent>
</Dialog>
); );
} }