mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-20 11:22:55 -05:00
fix: FormProvider
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
|
||||
import { TProduct, ZProduct } from "@formbricks/types/product";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@formbricks/ui/Form";
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormProvider } from "@formbricks/ui/Form";
|
||||
import { Input } from "@formbricks/ui/Input";
|
||||
|
||||
import { updateProductAction } from "../actions";
|
||||
@@ -28,7 +27,6 @@ export const EditProductNameForm: React.FC<EditProductNameProps> = ({
|
||||
environmentId,
|
||||
isProductNameEditDisabled,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const form = useForm<TEditProductName>({
|
||||
defaultValues: {
|
||||
name: product.name,
|
||||
@@ -59,7 +57,6 @@ export const EditProductNameForm: React.FC<EditProductNameProps> = ({
|
||||
|
||||
if (!!updatedProduct?.id) {
|
||||
toast.success("Product name updated successfully.");
|
||||
router.refresh();
|
||||
form.resetField("name", { defaultValue: updatedProduct.name });
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -69,41 +66,40 @@ export const EditProductNameForm: React.FC<EditProductNameProps> = ({
|
||||
};
|
||||
|
||||
return !isProductNameEditDisabled ? (
|
||||
<Form
|
||||
{...form}
|
||||
className="w-full max-w-sm items-center space-y-2"
|
||||
onSubmit={form.handleSubmit(updateProduct)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel htmlFor="name">What's your product called?</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
id="name"
|
||||
{...field}
|
||||
placeholder="Product Name"
|
||||
autoComplete="off"
|
||||
required
|
||||
isInvalid={!!nameError}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormProvider {...form}>
|
||||
<form className="w-full max-w-sm items-center space-y-2" onSubmit={form.handleSubmit(updateProduct)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel htmlFor="name">What's your product called?</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="text"
|
||||
id="name"
|
||||
{...field}
|
||||
placeholder="Product Name"
|
||||
autoComplete="off"
|
||||
required
|
||||
isInvalid={!!nameError}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
Update
|
||||
</Button>
|
||||
</Form>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
Update
|
||||
</Button>
|
||||
</form>
|
||||
</FormProvider>
|
||||
) : (
|
||||
<p className="text-sm text-red-700">Only Owners, Admins and Editors can perform this action.</p>
|
||||
);
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
import toast from "react-hot-toast";
|
||||
import { z } from "zod";
|
||||
|
||||
import { TProduct, ZProduct } from "@formbricks/types/product";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@formbricks/ui/Form";
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage, FormProvider } from "@formbricks/ui/Form";
|
||||
import { Input } from "@formbricks/ui/Input";
|
||||
|
||||
import { updateProductAction } from "../actions";
|
||||
@@ -23,8 +22,6 @@ const ZProductRecontactDaysInput = ZProduct.pick({ recontactDays: true });
|
||||
type EditWaitingTimeFormValues = z.infer<typeof ZProductRecontactDaysInput>;
|
||||
|
||||
export const EditWaitingTimeForm: React.FC<EditWaitingTimeProps> = ({ product, environmentId }) => {
|
||||
const router = useRouter();
|
||||
|
||||
const form = useForm<EditWaitingTimeFormValues>({
|
||||
defaultValues: {
|
||||
recontactDays: product.recontactDays,
|
||||
@@ -40,7 +37,6 @@ export const EditWaitingTimeForm: React.FC<EditWaitingTimeProps> = ({ product, e
|
||||
const updatedProduct = await updateProductAction(environmentId, product.id, data);
|
||||
if (!!updatedProduct?.id) {
|
||||
toast.success("Waiting period updated successfully.");
|
||||
router.refresh();
|
||||
form.resetField("recontactDays", { defaultValue: updatedProduct.recontactDays });
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -49,45 +45,46 @@ export const EditWaitingTimeForm: React.FC<EditWaitingTimeProps> = ({ product, e
|
||||
};
|
||||
|
||||
return (
|
||||
<Form
|
||||
{...form}
|
||||
className="flex w-full max-w-sm flex-col space-y-4"
|
||||
onSubmit={form.handleSubmit(updateWaitingTime)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="recontactDays"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel htmlFor="recontactDays">Wait X days before showing next survey:</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
id="recontactDays"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (value === "") {
|
||||
field.onChange("");
|
||||
}
|
||||
<FormProvider {...form}>
|
||||
<form
|
||||
className="flex w-full max-w-sm flex-col space-y-4"
|
||||
onSubmit={form.handleSubmit(updateWaitingTime)}>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="recontactDays"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel htmlFor="recontactDays">Wait X days before showing next survey:</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
id="recontactDays"
|
||||
{...field}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (value === "") {
|
||||
field.onChange("");
|
||||
}
|
||||
|
||||
field.onChange(parseInt(value, 10));
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
field.onChange(parseInt(value, 10));
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
className="w-fit"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
Update
|
||||
</Button>
|
||||
</Form>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="darkCTA"
|
||||
size="sm"
|
||||
className="w-fit"
|
||||
loading={isSubmitting}
|
||||
disabled={isSubmitting || !isDirty}>
|
||||
Update
|
||||
</Button>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { z } from "zod";
|
||||
import { cn } from "@formbricks/lib/cn";
|
||||
import { TProduct } from "@formbricks/types/product";
|
||||
import { Button } from "@formbricks/ui/Button";
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel } from "@formbricks/ui/Form";
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormProvider } from "@formbricks/ui/Form";
|
||||
import { Label } from "@formbricks/ui/Label";
|
||||
import { getPlacementStyle } from "@formbricks/ui/PreviewSurvey/lib/utils";
|
||||
import { RadioGroup, RadioGroupItem } from "@formbricks/ui/RadioGroup";
|
||||
@@ -68,124 +68,126 @@ export const EditPlacementForm = ({ product }: EditPlacementProps) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form} className="w-full items-center" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="flex">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="placement"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
}}
|
||||
className="h-full">
|
||||
{placements.map((placement) => (
|
||||
<div key={placement.value} className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem
|
||||
id={placement.value}
|
||||
value={placement.value}
|
||||
disabled={placement.disabled}
|
||||
checked={field.value === placement.value}
|
||||
/>
|
||||
<Label htmlFor={placement.value} className="text-slate-900">
|
||||
{placement.name}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
clickOutsideClose ? "" : "cursor-not-allowed",
|
||||
"relative ml-8 h-40 w-full rounded",
|
||||
overlayStyle
|
||||
)}>
|
||||
<FormProvider {...form}>
|
||||
<form className="w-full items-center" onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="flex">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="placement"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value);
|
||||
}}
|
||||
className="h-full">
|
||||
{placements.map((placement) => (
|
||||
<div key={placement.value} className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem
|
||||
id={placement.value}
|
||||
value={placement.value}
|
||||
disabled={placement.disabled}
|
||||
checked={field.value === placement.value}
|
||||
/>
|
||||
<Label htmlFor={placement.value} className="text-slate-900">
|
||||
{placement.name}
|
||||
</Label>
|
||||
</div>
|
||||
))}
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute h-16 w-16 cursor-default rounded bg-slate-700",
|
||||
getPlacementStyle(currentPlacement)
|
||||
)}></div>
|
||||
clickOutsideClose ? "" : "cursor-not-allowed",
|
||||
"relative ml-8 h-40 w-full rounded",
|
||||
overlayStyle
|
||||
)}>
|
||||
<div
|
||||
className={cn(
|
||||
"absolute h-16 w-16 cursor-default rounded bg-slate-700",
|
||||
getPlacementStyle(currentPlacement)
|
||||
)}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{currentPlacement === "center" && (
|
||||
<>
|
||||
<div className="mt-6 space-y-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="darkOverlay"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="font-semibold">Centered modal overlay color</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value === "darkOverlay");
|
||||
}}
|
||||
className="flex space-x-4">
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="lightOverlay" value="lightOverlay" checked={!field.value} />
|
||||
<Label htmlFor="lightOverlay" className="text-slate-900">
|
||||
Light Overlay
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="darkOverlay" value="darkOverlay" checked={field.value} />
|
||||
<Label htmlFor="darkOverlay" className="text-slate-900">
|
||||
Dark Overlay
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6 space-y-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="clickOutsideClose"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="font-semibold">
|
||||
Allow users to exit by clicking outside the study
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value === "allow");
|
||||
}}
|
||||
className="flex space-x-4">
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="disallow" value="disallow" checked={!field.value} />
|
||||
<Label htmlFor="disallow" className="text-slate-900">
|
||||
Don't Allow
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="allow" value="allow" checked={field.value} />
|
||||
<Label htmlFor="allow" className="text-slate-900">
|
||||
Allow
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{currentPlacement === "center" && (
|
||||
<>
|
||||
<div className="mt-6 space-y-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="darkOverlay"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="font-semibold">Centered modal overlay color</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value === "darkOverlay");
|
||||
}}
|
||||
className="flex space-x-4">
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="lightOverlay" value="lightOverlay" checked={!field.value} />
|
||||
<Label htmlFor="lightOverlay" className="text-slate-900">
|
||||
Light Overlay
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="darkOverlay" value="darkOverlay" checked={field.value} />
|
||||
<Label htmlFor="darkOverlay" className="text-slate-900">
|
||||
Dark Overlay
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6 space-y-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="clickOutsideClose"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="font-semibold">
|
||||
Allow users to exit by clicking outside the study
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value === "allow");
|
||||
}}
|
||||
className="flex space-x-4">
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="disallow" value="disallow" checked={!field.value} />
|
||||
<Label htmlFor="disallow" className="text-slate-900">
|
||||
Don't Allow
|
||||
</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2 whitespace-nowrap">
|
||||
<RadioGroupItem id="allow" value="allow" checked={field.value} />
|
||||
<Label htmlFor="allow" className="text-slate-900">
|
||||
Allow
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Button variant="darkCTA" className="mt-4 w-fit" size="sm" loading={isSubmitting}>
|
||||
Save
|
||||
</Button>
|
||||
</Form>
|
||||
<Button variant="darkCTA" className="mt-4 w-fit" size="sm" loading={isSubmitting}>
|
||||
Save
|
||||
</Button>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
FieldPath,
|
||||
FieldValues,
|
||||
FormProvider,
|
||||
FormProviderProps,
|
||||
useFormContext,
|
||||
} from "react-hook-form";
|
||||
|
||||
@@ -17,17 +16,6 @@ import { cn } from "@formbricks/lib/cn";
|
||||
|
||||
import { Label } from "../Label";
|
||||
|
||||
type FormProps<TFieldValues extends FieldValues = FieldValues> = FormProviderProps<TFieldValues> &
|
||||
React.FormHTMLAttributes<HTMLFormElement>;
|
||||
|
||||
const Form = <TFieldValues extends FieldValues>({ children, ...props }: FormProps<TFieldValues>) => {
|
||||
return (
|
||||
<FormProvider {...props}>
|
||||
<form {...props}>{children}</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
|
||||
type FormFieldContextValue<
|
||||
TFieldValues extends FieldValues = FieldValues,
|
||||
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
||||
@@ -154,4 +142,13 @@ const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<
|
||||
);
|
||||
FormMessage.displayName = "FormMessage";
|
||||
|
||||
export { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField };
|
||||
export {
|
||||
useFormField,
|
||||
FormProvider,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormMessage,
|
||||
FormField,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user