diff --git a/messages/en.json b/messages/en.json
index e355932..d10d513 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -93,6 +93,7 @@
"settings_form_description": "Description",
"settings_form_keywords": "keywords",
"settings_form_language": "Language",
+ "settings_form_select_language": "Please select language",
"settings_ui_title": "Settings",
"settings_messages_update_success": "Updated settings successfully!",
"settings_messages_update_fail": "Update fail!",
diff --git a/messages/vi.json b/messages/vi.json
index b76505f..4239ace 100644
--- a/messages/vi.json
+++ b/messages/vi.json
@@ -93,6 +93,7 @@
"settings_form_description": "Mô tả website",
"settings_form_keywords": "Từ khóa",
"settings_form_language": "Ngôn ngữ",
+ "settings_form_select_language": "Hãy chọn ngôn ngữ",
"settings_ui_title": "Cài đặt",
"settings_messages_update_success": "Cập nhật cài đặt thành công!",
"settings_messages_update_fail": "Cập nhật cài đặt thất bại!",
diff --git a/src/components/form/admin-ban-user-form.tsx b/src/components/form/admin-ban-user-form.tsx
index 815ba55..1d09900 100644
--- a/src/components/form/admin-ban-user-form.tsx
+++ b/src/components/form/admin-ban-user-form.tsx
@@ -1,21 +1,12 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { userBanSchema } from '@/service/user.schema';
import { WarningIcon } from '@phosphor-icons/react';
-import { useForm } from '@tanstack/react-form';
import { UserWithRole } from 'better-auth/plugins';
import { Alert, AlertDescription, AlertTitle } from '../ui/alert';
import { Button } from '../ui/button';
import { DialogClose, DialogFooter } from '../ui/dialog';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '../ui/select';
-import { Textarea } from '../ui/textarea';
+import { Field, FieldGroup } from '../ui/field';
import { useBanContext } from '../user/ban-user-dialog';
type FormProps = {
@@ -25,7 +16,7 @@ type FormProps = {
const BanUserForm = ({ data }: FormProps) => {
const { setSubmitData, setOpen, setOpenConfirm } = useBanContext();
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
id: data.id,
banReason: '',
@@ -59,99 +50,33 @@ const BanUserForm = ({ data }: FormProps) => {
{m.profile_form_name()}: {data.name}
- adá
+ {data.name}
-
{
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.users_page_ui_form_ban_reason()}:
-
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.users_page_ui_form_ban_exp()}
-
-
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => (
+
+ )}
+
@@ -159,9 +84,12 @@ const BanUserForm = ({ data }: FormProps) => {
{m.ui_cancel_btn()}
-
+
+
+
diff --git a/src/components/form/admin-create-user-form.tsx b/src/components/form/admin-create-user-form.tsx
index 0f8cfd4..9343b54 100644
--- a/src/components/form/admin-create-user-form.tsx
+++ b/src/components/form/admin-create-user-form.tsx
@@ -1,22 +1,14 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { usersQueries } from '@/service/queries';
import { createUser } from '@/service/user.api';
-import { RoleEnum, userCreateSchema } from '@/service/user.schema';
+import { userCreateSchema } from '@/service/user.schema';
import { ReturnError } from '@/types/common';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { Button } from '../ui/button';
import { DialogClose, DialogFooter } from '../ui/dialog';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '../ui/select';
+import { Field, FieldGroup } from '../ui/field';
type FormProps = {
onSubmit: (open: boolean) => void;
@@ -44,7 +36,7 @@ const AdminCreateUserForm = ({ onSubmit }: FormProps) => {
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
email: '',
password: '',
@@ -70,114 +62,33 @@ const AdminCreateUserForm = ({ onSubmit }: FormProps) => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.login_page_form_email()}:
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="email"
- />
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.login_page_form_password()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.profile_form_name()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="text"
- />
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.profile_form_role()}
-
-
- {isInvalid && }
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
@@ -185,9 +96,9 @@ const AdminCreateUserForm = ({ onSubmit }: FormProps) => {
{m.ui_cancel_btn()}
-
+
+
+
diff --git a/src/components/form/admin-set-password-form.tsx b/src/components/form/admin-set-password-form.tsx
index 830b31e..a0a3f4c 100644
--- a/src/components/form/admin-set-password-form.tsx
+++ b/src/components/form/admin-set-password-form.tsx
@@ -1,16 +1,15 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { usersQueries } from '@/service/queries';
import { setUserPassword } from '@/service/user.api';
import { userSetPasswordSchema } from '@/service/user.schema';
import { ReturnError } from '@/types/common';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { UserWithRole } from 'better-auth/plugins';
import { toast } from 'sonner';
import { Button } from '../ui/button';
import { DialogClose, DialogFooter } from '../ui/dialog';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
+import { Field, FieldGroup } from '../ui/field';
type FormProps = {
data: UserWithRole;
@@ -39,7 +38,7 @@ const AdminSetPasswordForm = ({ data, onSubmit }: FormProps) => {
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
id: data.id,
password: '',
@@ -62,49 +61,14 @@ const AdminSetPasswordForm = ({ data, onSubmit }: FormProps) => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.change_password_form_new_password()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && }
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
@@ -112,7 +76,9 @@ const AdminSetPasswordForm = ({ data, onSubmit }: FormProps) => {
{m.ui_cancel_btn()}
-
+
+
+
diff --git a/src/components/form/admin-set-user-role-form.tsx b/src/components/form/admin-set-user-role-form.tsx
index 6f8031e..00c3094 100644
--- a/src/components/form/admin-set-user-role-form.tsx
+++ b/src/components/form/admin-set-user-role-form.tsx
@@ -1,23 +1,15 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { usersQueries } from '@/service/queries';
import { setUserRole } from '@/service/user.api';
-import { RoleEnum, userUpdateRoleSchema } from '@/service/user.schema';
+import { userUpdateRoleSchema } from '@/service/user.schema';
import { ReturnError } from '@/types/common';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { UserWithRole } from 'better-auth/plugins';
import { toast } from 'sonner';
import { Button } from '../ui/button';
import { DialogClose, DialogFooter } from '../ui/dialog';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '../ui/select';
+import { Field, FieldGroup } from '../ui/field';
type SetRoleFormProps = {
data: UserWithRole;
@@ -51,7 +43,7 @@ const AdminSetUserRoleForm = ({ data, onSubmit }: SetRoleFormProps) => {
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues: userUpdateRoleSchema.parse(defaultFormValues),
validators: {
onChange: userUpdateRoleSchema,
@@ -72,61 +64,21 @@ const AdminSetUserRoleForm = ({ data, onSubmit }: SetRoleFormProps) => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.profile_form_role()}
-
-
- {isInvalid && }
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
@@ -134,7 +86,9 @@ const AdminSetUserRoleForm = ({ data, onSubmit }: SetRoleFormProps) => {
{m.ui_cancel_btn()}
-
+
+
+
diff --git a/src/components/form/admin-update-user-info-form.tsx b/src/components/form/admin-update-user-info-form.tsx
index bf5f4b0..e16b08f 100644
--- a/src/components/form/admin-update-user-info-form.tsx
+++ b/src/components/form/admin-update-user-info-form.tsx
@@ -1,16 +1,15 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { usersQueries } from '@/service/queries';
import { updateUserInformation } from '@/service/user.api';
import { userUpdateInfoSchema } from '@/service/user.schema';
import { ReturnError } from '@/types/common';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { UserWithRole } from 'better-auth/plugins';
import { toast } from 'sonner';
import { Button } from '../ui/button';
import { DialogClose, DialogFooter } from '../ui/dialog';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
+import { Field, FieldGroup } from '../ui/field';
type UpdateUserFormProps = {
data: UserWithRole;
@@ -38,7 +37,7 @@ const AdminUpdateUserInfoForm = ({ data, onSubmit }: UpdateUserFormProps) => {
});
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
id: data.id,
name: data.name,
@@ -61,49 +60,12 @@ const AdminUpdateUserInfoForm = ({ data, onSubmit }: UpdateUserFormProps) => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {isInvalid && }
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.profile_form_name()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="text"
- />
- {isInvalid && }
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => }
+
@@ -111,7 +73,9 @@ const AdminUpdateUserInfoForm = ({ data, onSubmit }: UpdateUserFormProps) => {
{m.ui_cancel_btn()}
-
+
+
+
diff --git a/src/components/form/change-password-form.tsx b/src/components/form/change-password-form.tsx
index 6ea2ca7..25eaa92 100644
--- a/src/components/form/change-password-form.tsx
+++ b/src/components/form/change-password-form.tsx
@@ -1,43 +1,14 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { authClient } from '@/lib/auth-client';
import { m } from '@/paraglide/messages';
+import {
+ ChangePassword,
+ ChangePasswordFormSchema,
+} from '@/service/user.schema';
import { KeyIcon } from '@phosphor-icons/react';
-import { useForm } from '@tanstack/react-form';
import { toast } from 'sonner';
-import z from 'zod';
-import { Button } from '../ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
-
-const ChangePasswordFormSchema = z
- .object({
- currentPassword: z.string().nonempty(
- m.common_is_required({
- field: m.change_password_form_current_password(),
- }),
- ),
- newPassword: z.string().nonempty(
- m.common_is_required({
- field: m.change_password_form_new_password(),
- }),
- ),
- confirmPassword: z.string().nonempty(
- m.common_is_required({
- field: m.change_password_form_confirm_password(),
- }),
- ),
- })
- .superRefine((data, ctx) => {
- if (data.newPassword !== data.confirmPassword) {
- ctx.addIssue({
- path: ['confirmPassword'],
- code: z.ZodIssueCode.custom,
- message: m.change_password_messages_password_not_match(),
- });
- }
- });
-
-type ChangePassword = z.infer;
+import { Field, FieldGroup } from '../ui/field';
const defaultValues: ChangePassword = {
currentPassword: '',
@@ -46,7 +17,7 @@ const defaultValues: ChangePassword = {
};
const ChangePasswordForm = () => {
- const form = useForm({
+ const form = useAppForm({
defaultValues,
validators: {
onSubmit: ChangePasswordFormSchema,
@@ -98,86 +69,33 @@ const ChangePasswordForm = () => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.change_password_form_current_password()}:
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.change_password_form_new_password()}:
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.change_password_form_confirm_password()}:
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => (
+
+ )}
+
-
+
+
+
diff --git a/src/components/form/form-components.tsx b/src/components/form/form-components.tsx
new file mode 100644
index 0000000..a0b046e
--- /dev/null
+++ b/src/components/form/form-components.tsx
@@ -0,0 +1,218 @@
+import { useFieldContext, useFormContext } from '@/hooks/use-app-form';
+import { RoleEnum } from '@/service/user.schema';
+import { useStore } from '@tanstack/react-form';
+import { type VariantProps } from 'class-variance-authority';
+import { Button, buttonVariants } from '../ui/button';
+import { Field, FieldError, FieldLabel } from '../ui/field';
+import { Input } from '../ui/input';
+import * as ShadcnSelect from '../ui/select';
+import { Textarea } from '../ui/textarea';
+
+export function SubscribeButton({
+ label,
+ variant = 'default',
+}: {
+ label: string;
+} & VariantProps) {
+ const form = useFormContext();
+ return (
+ state.isSubmitting}>
+ {(isSubmitting) => (
+
+ )}
+
+ );
+}
+
+export function HiddenField() {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+
+ {isInvalid && }
+
+ );
+}
+
+export function TextField({
+ label,
+ placeholder,
+ type = 'text',
+}: {
+ label: string;
+ placeholder?: string;
+ type?: string;
+}) {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+ {label}:
+ field.handleChange(e.target.value)}
+ aria-invalid={isInvalid}
+ type={type}
+ />
+ {isInvalid && }
+
+ );
+}
+
+export function FileField({
+ label,
+ className,
+ ...props
+}: {
+ label: string;
+ className?: string;
+} & React.ComponentProps<'input'>) {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+ {label}:
+
+ {isInvalid && }
+
+ );
+}
+
+export function TextArea({
+ label,
+ rows = 4,
+}: {
+ label: string;
+ rows?: number;
+}) {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+ {label}:
+
+ );
+}
+
+export function Select({
+ label,
+ values,
+ placeholder,
+ isRole = false,
+}: {
+ label: string;
+ values: Array<{ label: string; value: string }>;
+ placeholder?: string;
+ isRole?: boolean;
+}) {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+ {label}:
+
+ isRole
+ ? field.handleChange(RoleEnum.parse(value))
+ : field.handleChange(value)
+ }
+ >
+
+
+
+
+
+ {label}
+ {values.map((value) => (
+
+ {value.label}
+
+ ))}
+
+
+
+ {isInvalid && }
+
+ );
+}
+
+export function SelectNumber({
+ label,
+ values,
+ placeholder,
+}: {
+ label: string;
+ values: Array<{ label: string; value: string }>;
+ placeholder?: string;
+}) {
+ const field = useFieldContext();
+ const errors = useStore(field.store, (state) => state.meta.errors);
+ const isInvalid = field.state.meta.isTouched && !field.state.meta.isValid;
+
+ return (
+
+ {label}:
+ field.handleChange(Number(value))}
+ >
+
+
+
+
+
+ {label}
+ {values.map((value) => (
+
+ {value.label}
+
+ ))}
+
+
+
+ {isInvalid && }
+
+ );
+}
diff --git a/src/components/form/profile-form.tsx b/src/components/form/profile-form.tsx
index 3f707fc..fdb8d7b 100644
--- a/src/components/form/profile-form.tsx
+++ b/src/components/form/profile-form.tsx
@@ -1,18 +1,17 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { authClient } from '@/lib/auth-client';
import { m } from '@/paraglide/messages';
import { uploadProfileImage } from '@/service/profile.api';
import { ProfileInput, profileUpdateSchema } from '@/service/profile.schema';
import { UserCircleIcon } from '@phosphor-icons/react';
-import { useForm } from '@tanstack/react-form';
import { useQueryClient } from '@tanstack/react-query';
import { useRef } from 'react';
import { toast } from 'sonner';
import { useAuth } from '../auth/auth-provider';
import AvatarUser from '../avatar/avatar-user';
import RoleBadge from '../avatar/role-badge';
-import { Button } from '../ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
+import { Field, FieldGroup, FieldLabel } from '../ui/field';
import { Input } from '../ui/input';
const defaultValues: ProfileInput = {
@@ -25,7 +24,7 @@ const ProfileForm = () => {
const { data: session, isPending } = useAuth();
const queryClient = useQueryClient();
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
...defaultValues,
name: session?.user?.name || '',
@@ -102,58 +101,20 @@ const ProfileForm = () => {
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.profile_form_name()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
+
+ {(field) => }
+
{m.profile_form_email()}
{
-
+
+
+
diff --git a/src/components/form/settings-form.tsx b/src/components/form/settings-form.tsx
index 4eea632..11e7e70 100644
--- a/src/components/form/settings-form.tsx
+++ b/src/components/form/settings-form.tsx
@@ -1,18 +1,15 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { settingQueries } from '@/service/queries';
import { updateAdminSettings } from '@/service/setting.api';
import { settingSchema, SettingsInput } from '@/service/setting.schema';
import { ReturnError } from '@/types/common';
import { GearIcon } from '@phosphor-icons/react';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
-import { Button } from '../ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
+import { Field, FieldGroup } from '../ui/field';
import { Skeleton } from '../ui/skeleton';
-import { Textarea } from '../ui/textarea';
const defaultValues: SettingsInput = {
site_name: '',
@@ -41,7 +38,7 @@ const SettingsForm = () => {
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues: {
...defaultValues,
site_name: settings?.site_name?.value || '',
@@ -78,85 +75,21 @@ const SettingsForm = () => {
}}
>
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.settings_form_name()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.settings_form_description()}
-
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.settings_form_keywords()}
-
-
- );
- }}
- />
+
+ {(field) => }
+
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => }
+
-
+
+
+
diff --git a/src/components/form/signin-form.tsx b/src/components/form/signin-form.tsx
index 51e96bd..115af79 100644
--- a/src/components/form/signin-form.tsx
+++ b/src/components/form/signin-form.tsx
@@ -1,14 +1,13 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { authClient } from '@/lib/auth-client';
import { m } from '@/paraglide/messages';
-import { useForm } from '@tanstack/react-form';
import { useQueryClient } from '@tanstack/react-query';
import { createLink, useNavigate } from '@tanstack/react-router';
import { toast } from 'sonner';
import z from 'zod';
import { Button } from '../ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import { Input } from '../ui/input';
+import { Field, FieldGroup } from '../ui/field';
const SignInFormSchema = z.object({
email: z
@@ -27,7 +26,8 @@ const ButtonLink = createLink(Button);
const SignInForm = () => {
const navigate = useNavigate();
const queryClient = useQueryClient();
- const form = useForm({
+
+ const form = useAppForm({
defaultValues: {
email: '',
password: '',
@@ -91,62 +91,26 @@ const SignInForm = () => {
Or continue with */}
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.login_page_form_email()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="email"
- placeholder="m@example.com"
- autoComplete="off"
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.login_page_form_password()}
-
- field.handleChange(e.target.value)}
- aria-invalid={isInvalid}
- type="password"
- />
- {isInvalid && (
-
- )}
-
- );
- }}
- />
+
+ {(field) => (
+
+ )}
+
+
+ {(field) => (
+
+ )}
+
-
+
+
+
{m.ui_cancel_btn()}
diff --git a/src/components/form/user-settings-form.tsx b/src/components/form/user-settings-form.tsx
index 6f5f04a..4e3c314 100644
--- a/src/components/form/user-settings-form.tsx
+++ b/src/components/form/user-settings-form.tsx
@@ -1,3 +1,4 @@
+import { useAppForm } from '@/hooks/use-app-form';
import { m } from '@/paraglide/messages';
import { Locale, setLocale } from '@/paraglide/runtime';
import { settingQueries } from '@/service/queries';
@@ -5,20 +6,11 @@ import { updateUserSettings } from '@/service/setting.api';
import { UserSettingInput, userSettingSchema } from '@/service/setting.schema';
import { ReturnError } from '@/types/common';
import { GearIcon } from '@phosphor-icons/react';
-import { useForm } from '@tanstack/react-form';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';
import { toast } from 'sonner';
-import { Button } from '../ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '../ui/card';
-import { Field, FieldError, FieldGroup, FieldLabel } from '../ui/field';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '../ui/select';
+import { Field, FieldGroup } from '../ui/field';
import { Skeleton } from '../ui/skeleton';
const defaultValues: UserSettingInput = {
@@ -49,7 +41,7 @@ const UserSettingsForm = () => {
},
});
- const form = useForm({
+ const form = useAppForm({
defaultValues,
validators: {
onSubmit: userSettingSchema,
@@ -68,6 +60,13 @@ const UserSettingsForm = () => {
}
}, [data, form]);
+ if (isLoading)
+ return (
+
+
+
+ );
+
return (
@@ -86,47 +85,22 @@ const UserSettingsForm = () => {
}}
>
- {isLoading ? (
-
-
-
-
- ) : (
- {
- const isInvalid =
- field.state.meta.isTouched && !field.state.meta.isValid;
- return (
-
-
- {m.settings_form_language()}
-
-
- {isInvalid && (
-
- )}
-
- );
- }}
- />
- )}
+
+ {(field) => (
+
+ )}
+
-
+
+
+
diff --git a/src/components/user/add-new-user-dialog.tsx b/src/components/user/add-new-user-dialog.tsx
index 164716a..9ff36f0 100644
--- a/src/components/user/add-new-user-dialog.tsx
+++ b/src/components/user/add-new-user-dialog.tsx
@@ -18,8 +18,8 @@ const AddNewUserButton = () => {
const prevent = usePreventAutoFocus();
return (
-