|
1 | 1 | "use client"; |
2 | 2 |
|
| 3 | +import { WEBSITE_NAME_REGEX } from "@databuddy/validation"; |
3 | 4 | import { zodResolver } from "@hookform/resolvers/zod"; |
4 | 5 | import { useEffect } from "react"; |
5 | | -import { useForm } from "react-hook-form"; |
| 6 | +import { type SubmitHandler, useForm } from "react-hook-form"; |
6 | 7 | import { toast } from "sonner"; |
7 | 8 | import { z } from "zod"; |
8 | 9 | import { useOrganizationsContext } from "@/components/providers/organizations-provider"; |
@@ -41,7 +42,11 @@ const domainRegex = |
41 | 42 | const wwwRegex = /^www\./; |
42 | 43 |
|
43 | 44 | const formSchema = z.object({ |
44 | | - name: z.string().min(1, "Name is required"), |
| 45 | + name: z |
| 46 | + .string() |
| 47 | + .trim() |
| 48 | + .min(1, "Name is required") |
| 49 | + .regex(WEBSITE_NAME_REGEX, "Use alphanumeric, spaces, -, _, or ."), |
45 | 50 | domain: z |
46 | 51 | .string() |
47 | 52 | .min(1, "Domain is required") |
@@ -72,6 +77,7 @@ export function WebsiteDialog({ |
72 | 77 |
|
73 | 78 | const form = useForm<FormData>({ |
74 | 79 | resolver: zodResolver(formSchema), |
| 80 | + mode: "onBlur", |
75 | 81 | defaultValues: { |
76 | 82 | name: "", |
77 | 83 | domain: "", |
@@ -117,8 +123,7 @@ export function WebsiteDialog({ |
117 | 123 | return rpcError?.message || defaultMessage; |
118 | 124 | }; |
119 | 125 |
|
120 | | - const handleSubmit = async () => { |
121 | | - const formData = form.getValues(); |
| 126 | + const handleSubmit: SubmitHandler<FormData> = async (formData) => { |
122 | 127 | const submissionData: CreateWebsiteData = { |
123 | 128 | name: formData.name, |
124 | 129 | domain: formData.domain, |
@@ -154,7 +159,10 @@ export function WebsiteDialog({ |
154 | 159 | const isPending = |
155 | 160 | createWebsiteMutation.isPending || updateWebsiteMutation.isPending; |
156 | 161 |
|
157 | | - const isSubmitDisabled = !(form.formState.isValid && form.formState.isDirty); |
| 162 | + // Should not access directly (form.formState.isValid); that doesn't trigger re-render |
| 163 | + // https://react-hook-form.com/docs/useform/formstate |
| 164 | + const { isValid, isDirty } = form.formState; |
| 165 | + const isSubmitDisabled = !(isValid && isDirty); |
158 | 166 |
|
159 | 167 | return ( |
160 | 168 | <FormDialog |
|
0 commit comments