48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
"use client";
|
|
"use client";
|
|
|
|
import * as React from "react";
|
|
import { FormProvider, useForm } from "react-hook-form";
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
export type BaseFormProps<T extends Record<string, any>> = {
|
|
defaultValues?: Partial<T>;
|
|
onSubmit: (values: T) => Promise<void> | void;
|
|
children?: React.ReactNode;
|
|
submitLabel?: string;
|
|
};
|
|
|
|
export default function BaseForm<T extends Record<string, any>>({
|
|
defaultValues,
|
|
onSubmit,
|
|
children,
|
|
submitLabel = "Save",
|
|
}: BaseFormProps<T>) {
|
|
const methods = useForm<T>({ defaultValues: defaultValues as any });
|
|
|
|
// If parent provides new defaultValues (e.g. after an async fetch), reset the form
|
|
React.useEffect(() => {
|
|
if (defaultValues) {
|
|
methods.reset(defaultValues as any);
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [JSON.stringify(defaultValues)]);
|
|
|
|
return (
|
|
<FormProvider {...methods}>
|
|
<form
|
|
onSubmit={methods.handleSubmit(async (v: any) => {
|
|
await onSubmit(v as T);
|
|
})}
|
|
className="space-y-4"
|
|
>
|
|
{children}
|
|
|
|
<div className="flex items-center gap-2">
|
|
<Button type="submit">{submitLabel}</Button>
|
|
</div>
|
|
</form>
|
|
</FormProvider>
|
|
);
|
|
}
|