From a3f2a73ca090fd1b2f1fcaeeb2507b5b12d02786 Mon Sep 17 00:00:00 2001 From: Sergey Kozyrenko Date: Tue, 7 Jul 2026 12:49:32 +0700 Subject: [PATCH] feat(forms): migrate auth forms to useAppForm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move login, password-change, email-change, and name-change onto the shared useAppForm wrapper — the last data-entry forms still on raw useForm. These were already on react-hook-form's default timing (onSubmit + onChange revalidate), so this is behavior-neutral: it only routes them through the single timing source so none can later drift to eager validation, and keeps every form consistent. Schemas and submit buttons (FormSubmitButton) are untouched, so the password policy and login flow are unchanged. Co-Authored-By: Claude Opus 4.8 --- frontend/src/features/authentication/email-change-form.tsx | 7 +++---- frontend/src/features/authentication/login-form.tsx | 7 +++---- frontend/src/features/authentication/name-change-form.tsx | 7 +++---- .../src/features/authentication/password-change-form.tsx | 7 +++---- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/frontend/src/features/authentication/email-change-form.tsx b/frontend/src/features/authentication/email-change-form.tsx index cbca2709..c8603522 100644 --- a/frontend/src/features/authentication/email-change-form.tsx +++ b/frontend/src/features/authentication/email-change-form.tsx @@ -1,6 +1,4 @@ -import { zodResolver } from '@hookform/resolvers/zod'; import { useState } from 'react'; -import { useForm } from 'react-hook-form'; import { toast } from 'sonner'; import * as z from 'zod'; @@ -9,6 +7,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from ' import { FormSubmitButton } from '@/components/ui/form-submit-button'; import { Input } from '@/components/ui/input'; import { InputPassword } from '@/components/ui/input-password'; +import { useAppForm } from '@/hooks/use-app-form'; import { api, resolveApiErrorMessage } from '@/lib/axios'; import { useUser } from '@/providers/user-provider'; @@ -41,12 +40,12 @@ export function EmailChangeForm({ onCancel, onSuccess }: EmailChangeFormProps) { const [error, setError] = useState(null); const { patchUser, refreshAuthInfo } = useUser(); - const form = useForm({ + const form = useAppForm({ defaultValues: { currentPassword: '', newEmail: '', }, - resolver: zodResolver(emailChangeSchema), + schema: emailChangeSchema, }); const handleSubmit = async (values: EmailChangeFormValues) => { diff --git a/frontend/src/features/authentication/login-form.tsx b/frontend/src/features/authentication/login-form.tsx index 6174efd7..5c75e2d9 100644 --- a/frontend/src/features/authentication/login-form.tsx +++ b/frontend/src/features/authentication/login-form.tsx @@ -1,6 +1,4 @@ -import { zodResolver } from '@hookform/resolvers/zod'; import { useState } from 'react'; -import { useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; import { z } from 'zod'; @@ -13,6 +11,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from ' import { FormSubmitButton } from '@/components/ui/form-submit-button'; import { Input } from '@/components/ui/input'; import { InputPassword } from '@/components/ui/input-password'; +import { useAppForm } from '@/hooks/use-app-form'; import { routes } from '@/lib/routes'; import { useUser } from '@/providers/user-provider'; @@ -63,12 +62,12 @@ interface LoginFormProps { } function LoginForm({ providers, returnUrl = routes.newFlow }: LoginFormProps) { - const form = useForm>({ + const form = useAppForm>({ defaultValues: { mail: '', password: '', }, - resolver: zodResolver(formSchema), + schema: formSchema, }); const [isSubmitting, setIsSubmitting] = useState(false); const [error, setError] = useState(null); diff --git a/frontend/src/features/authentication/name-change-form.tsx b/frontend/src/features/authentication/name-change-form.tsx index cccc4b5f..6e321596 100644 --- a/frontend/src/features/authentication/name-change-form.tsx +++ b/frontend/src/features/authentication/name-change-form.tsx @@ -1,6 +1,4 @@ -import { zodResolver } from '@hookform/resolvers/zod'; import { useState } from 'react'; -import { useForm } from 'react-hook-form'; import { toast } from 'sonner'; import * as z from 'zod'; @@ -8,6 +6,7 @@ import { Button } from '@/components/ui/button'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { FormSubmitButton } from '@/components/ui/form-submit-button'; import { Input } from '@/components/ui/input'; +import { useAppForm } from '@/hooks/use-app-form'; import { api, resolveApiErrorMessage } from '@/lib/axios'; import { useUser } from '@/providers/user-provider'; @@ -35,11 +34,11 @@ export function NameChangeForm({ onCancel, onSuccess }: NameChangeFormProps) { const [error, setError] = useState(null); const { authInfo, patchUser, refreshAuthInfo } = useUser(); - const form = useForm({ + const form = useAppForm({ defaultValues: { name: authInfo?.user?.name ?? '', }, - resolver: zodResolver(nameChangeSchema), + schema: nameChangeSchema, }); const handleSubmit = async (values: NameChangeFormValues) => { diff --git a/frontend/src/features/authentication/password-change-form.tsx b/frontend/src/features/authentication/password-change-form.tsx index fce450e4..84b5656b 100644 --- a/frontend/src/features/authentication/password-change-form.tsx +++ b/frontend/src/features/authentication/password-change-form.tsx @@ -1,6 +1,4 @@ -import { zodResolver } from '@hookform/resolvers/zod'; import { type ComponentProps, useState } from 'react'; -import { useForm } from 'react-hook-form'; import { toast } from 'sonner'; import * as z from 'zod'; @@ -8,6 +6,7 @@ import { Button } from '@/components/ui/button'; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; import { FormSubmitButton } from '@/components/ui/form-submit-button'; import { InputPassword } from '@/components/ui/input-password'; +import { useAppForm } from '@/hooks/use-app-form'; import { api, resolveApiErrorMessage } from '@/lib/axios'; import { cn } from '@/lib/utils'; @@ -74,13 +73,13 @@ export function PasswordChangeForm({ }: PasswordChangeFormProps) { const [error, setError] = useState(null); - const form = useForm({ + const form = useAppForm({ defaultValues: { confirmPassword: '', currentPassword: '', newPassword: '', }, - resolver: zodResolver(passwordChangeSchema), + schema: passwordChangeSchema, }); const handleSubmit = async (values: PasswordChangeFormValues) => {