feat: add i18n translated form errors (#509)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
import Link from "next/link";
|
||||
import { Button, Group, Stack, Textarea, TextInput } from "@mantine/core";
|
||||
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import type { TranslationFunction } from "@homarr/translation";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import type { z } from "@homarr/validation";
|
||||
@@ -25,14 +25,13 @@ export const AppForm = (props: AppFormProps) => {
|
||||
props;
|
||||
const t = useI18n();
|
||||
|
||||
const form = useForm({
|
||||
const form = useZodForm(validation.app.manage, {
|
||||
initialValues: initialValues ?? {
|
||||
name: "",
|
||||
description: "",
|
||||
iconUrl: "",
|
||||
href: "",
|
||||
},
|
||||
validate: zodResolver(validation.app.manage),
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -41,9 +40,7 @@ export const AppForm = (props: AppFormProps) => {
|
||||
<TextInput {...form.getInputProps("name")} withAsterisk label="Name" />
|
||||
<IconPicker
|
||||
initialValue={initialValues?.iconUrl}
|
||||
onChange={(iconUrl) => {
|
||||
form.setFieldValue("iconUrl", iconUrl);
|
||||
}}
|
||||
{...form.getInputProps("iconUrl")}
|
||||
/>
|
||||
<Textarea {...form.getInputProps("description")} label="Description" />
|
||||
<TextInput {...form.getInputProps("href")} label="URL" />
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useI18n } from "@homarr/translation/client";
|
||||
import { integrationSecretIcons } from "./_integration-secret-icons";
|
||||
|
||||
interface IntegrationSecretInputProps {
|
||||
withAsterisk?: boolean;
|
||||
label?: string;
|
||||
kind: IntegrationSecretKind;
|
||||
value?: string;
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
getAllSecretKindOptions,
|
||||
getDefaultSecretKinds,
|
||||
} from "@homarr/definitions";
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { useConfirmModal } from "@homarr/modals";
|
||||
import {
|
||||
showErrorNotification,
|
||||
@@ -55,9 +55,8 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => {
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
const form = useForm<FormType>({
|
||||
const form = useZodForm(validation.integration.update.omit({ id: true }), {
|
||||
initialValues: initialFormValues,
|
||||
validate: zodResolver(validation.integration.update.omit({ id: true })),
|
||||
onValuesChange,
|
||||
});
|
||||
const { mutateAsync, isPending } = clientApi.integration.update.useMutation();
|
||||
@@ -103,11 +102,13 @@ export const EditIntegrationForm = ({ integration }: EditIntegrationForm) => {
|
||||
<TestConnectionNoticeAlert />
|
||||
|
||||
<TextInput
|
||||
withAsterisk
|
||||
label={t("integration.field.name.label")}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
withAsterisk
|
||||
label={t("integration.field.url.label")}
|
||||
{...form.getInputProps("url")}
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
} from "@homarr/definitions";
|
||||
import { getAllSecretKindOptions } from "@homarr/definitions";
|
||||
import type { UseFormReturnType } from "@homarr/form";
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import {
|
||||
showErrorNotification,
|
||||
showSuccessNotification,
|
||||
@@ -60,9 +60,8 @@ export const NewIntegrationForm = ({
|
||||
initialFormValue: initialFormValues,
|
||||
});
|
||||
const router = useRouter();
|
||||
const form = useForm<FormType>({
|
||||
const form = useZodForm(validation.integration.create.omit({ kind: true }), {
|
||||
initialValues: initialFormValues,
|
||||
validate: zodResolver(validation.integration.create.omit({ kind: true })),
|
||||
onValuesChange,
|
||||
});
|
||||
const { mutateAsync, isPending } = clientApi.integration.create.useMutation();
|
||||
@@ -100,11 +99,13 @@ export const NewIntegrationForm = ({
|
||||
<TestConnectionNoticeAlert />
|
||||
|
||||
<TextInput
|
||||
withAsterisk
|
||||
label={t("integration.field.name.label")}
|
||||
{...form.getInputProps("name")}
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
withAsterisk
|
||||
label={t("integration.field.url.label")}
|
||||
{...form.getInputProps("url")}
|
||||
/>
|
||||
@@ -119,6 +120,7 @@ export const NewIntegrationForm = ({
|
||||
)}
|
||||
{form.values.secrets.map(({ kind }, index) => (
|
||||
<IntegrationSecretInput
|
||||
withAsterisk
|
||||
key={kind}
|
||||
kind={kind}
|
||||
{...form.getInputProps(`secrets.${index}.value`)}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
|
||||
import type { RouterInputs, RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import {
|
||||
showErrorNotification,
|
||||
showSuccessNotification,
|
||||
@@ -38,14 +38,11 @@ export const UserProfileForm = ({ user }: UserProfileFormProps) => {
|
||||
});
|
||||
},
|
||||
});
|
||||
const form = useForm({
|
||||
const form = useZodForm(validation.user.editProfile.omit({ id: true }), {
|
||||
initialValues: {
|
||||
name: user.name ?? "",
|
||||
email: user.email ?? "",
|
||||
},
|
||||
validate: zodResolver(validation.user.editProfile.omit({ id: true })),
|
||||
validateInputOnBlur: true,
|
||||
validateInputOnChange: true,
|
||||
});
|
||||
|
||||
const handleSubmit = useCallback(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Button, Fieldset, Group, PasswordInput, Stack } from "@mantine/core";
|
||||
import type { RouterInputs, RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import {
|
||||
showErrorNotification,
|
||||
showSuccessNotification,
|
||||
@@ -37,15 +37,13 @@ export const ChangePasswordForm = ({ user }: ChangePasswordFormProps) => {
|
||||
});
|
||||
},
|
||||
});
|
||||
const form = useForm<FormType>({
|
||||
const form = useZodForm(validation.user.changePassword, {
|
||||
initialValues: {
|
||||
previousPassword: "",
|
||||
/* Require previous password if the current user want's to change his password */
|
||||
previousPassword: session?.user.id === user.id ? "" : "_",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
validate: zodResolver(validation.user.changePassword),
|
||||
validateInputOnBlur: true,
|
||||
validateInputOnChange: true,
|
||||
});
|
||||
|
||||
const handleSubmit = (values: FormType) => {
|
||||
|
||||
@@ -14,9 +14,10 @@ import {
|
||||
import { IconUserCheck } from "@tabler/icons-react";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useForm, zodResolver } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import { validation, z } from "@homarr/validation";
|
||||
import { createCustomErrorParams } from "@homarr/validation/form";
|
||||
|
||||
import { StepperNavigationComponent } from "./stepper-navigation.component";
|
||||
|
||||
@@ -40,40 +41,36 @@ export const UserCreateStepperComponent = () => {
|
||||
|
||||
const { mutateAsync, isPending } = clientApi.user.create.useMutation();
|
||||
|
||||
const generalForm = useForm({
|
||||
initialValues: {
|
||||
username: "",
|
||||
email: undefined,
|
||||
const generalForm = useZodForm(
|
||||
z.object({
|
||||
username: z.string().min(1),
|
||||
email: z.string().email().or(z.string().length(0).optional()),
|
||||
}),
|
||||
{
|
||||
initialValues: {
|
||||
username: "",
|
||||
email: "",
|
||||
},
|
||||
},
|
||||
validate: zodResolver(
|
||||
z.object({
|
||||
username: z.string().min(1),
|
||||
email: z.string().email().or(z.string().length(0).optional()),
|
||||
}),
|
||||
),
|
||||
validateInputOnBlur: true,
|
||||
validateInputOnChange: true,
|
||||
});
|
||||
);
|
||||
|
||||
const securityForm = useForm({
|
||||
initialValues: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
const securityForm = useZodForm(
|
||||
z
|
||||
.object({
|
||||
password: validation.user.password,
|
||||
confirmPassword: z.string(),
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword, {
|
||||
path: ["confirmPassword"],
|
||||
params: createCustomErrorParams("passwordsDoNotMatch"),
|
||||
}),
|
||||
{
|
||||
initialValues: {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
},
|
||||
},
|
||||
validate: zodResolver(
|
||||
z
|
||||
.object({
|
||||
password: validation.user.password,
|
||||
confirmPassword: z.string(),
|
||||
})
|
||||
.refine((data) => data.password === data.confirmPassword, {
|
||||
path: ["confirmPassword"],
|
||||
message: "Passwords do not match",
|
||||
}),
|
||||
),
|
||||
validateInputOnBlur: true,
|
||||
validateInputOnChange: true,
|
||||
});
|
||||
);
|
||||
|
||||
const allForms = useMemo(
|
||||
() => [generalForm, securityForm],
|
||||
|
||||
@@ -4,12 +4,13 @@ import { useCallback } from "react";
|
||||
import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useForm } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import {
|
||||
showErrorNotification,
|
||||
showSuccessNotification,
|
||||
} from "@homarr/notifications";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { validation } from "@homarr/validation";
|
||||
|
||||
import { revalidatePathActionAsync } from "~/app/revalidatePathAction";
|
||||
|
||||
@@ -23,7 +24,7 @@ interface RenameGroupFormProps {
|
||||
export const RenameGroupForm = ({ group }: RenameGroupFormProps) => {
|
||||
const t = useI18n();
|
||||
const { mutate, isPending } = clientApi.group.updateGroup.useMutation();
|
||||
const form = useForm<FormType>({
|
||||
const form = useZodForm(validation.group.update.pick({ name: true }), {
|
||||
initialValues: {
|
||||
name: group.name,
|
||||
},
|
||||
|
||||
@@ -4,13 +4,14 @@ import { useCallback } from "react";
|
||||
import { Button, Group, Stack, TextInput } from "@mantine/core";
|
||||
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useForm } from "@homarr/form";
|
||||
import { useZodForm } from "@homarr/form";
|
||||
import { createModal, useModalAction } from "@homarr/modals";
|
||||
import {
|
||||
showErrorNotification,
|
||||
showSuccessNotification,
|
||||
} from "@homarr/notifications";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { validation } from "@homarr/validation";
|
||||
|
||||
import { revalidatePathActionAsync } from "~/app/revalidatePathAction";
|
||||
|
||||
@@ -32,7 +33,7 @@ export const AddGroup = () => {
|
||||
const AddGroupModal = createModal<void>(({ actions }) => {
|
||||
const t = useI18n();
|
||||
const { mutate, isPending } = clientApi.group.createGroup.useMutation();
|
||||
const form = useForm({
|
||||
const form = useZodForm(validation.group.create, {
|
||||
initialValues: {
|
||||
name: "",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user