addded error codes and improved error handling

This commit is contained in:
2026-06-04 15:32:51 +02:00
parent faebe54db3
commit c42bdea047
19 changed files with 730 additions and 96 deletions
+35 -1
View File
@@ -1,13 +1,21 @@
import { useForm } from "@tanstack/react-form";
import { Input, Button } from "@mui/joy";
import { Input, Button, Alert } from "@mui/joy";
import { useMutation } from "@tanstack/react-query";
import { signInUser } from "../utils/api/auth";
import { useTranslation } from "react-i18next";
import { useNavigate } from "@tanstack/react-router";
import { useState } from "react";
import type { AlertInterface } from "../misc/interfaces";
export const LoginCard = () => {
const { t } = useTranslation();
const navigate = useNavigate();
const [alert, setAlert] = useState<AlertInterface>({
isAlert: false,
type: "neutral",
header: "",
text: "",
});
const form = useForm({
defaultValues: {
@@ -29,9 +37,24 @@ export const LoginCard = () => {
}) => signInUser(username, password, t),
onSuccess: (result) => {
if (result.ok) {
setAlert({
isAlert: false,
type: "neutral",
header: "",
text: "",
});
navigate({ to: "/app/inventory" });
}
},
onError: (error: unknown) => {
const errorCode = (error as { code?: string })?.code;
setAlert({
isAlert: true,
type: "danger",
header: t("error"),
text: errorCode ? t(errorCode) : t("unknown-error"),
});
},
});
return (
@@ -53,6 +76,17 @@ export const LoginCard = () => {
form.handleSubmit();
}}
>
{alert.isAlert && (
<Alert
variant="soft"
color={alert.type}
className="rounded-2xl border border-rose-200/70 bg-rose-50/80 text-rose-700 shadow-[0_12px_30px_rgba(220,38,38,0.12)]"
>
{alert.header}
<br />
{alert.text}
</Alert>
)}
<form.Field name="username">
{(field) => (
<Input
+4 -1
View File
@@ -9,9 +9,10 @@ import { useTranslation } from "react-i18next";
interface StorageRowProps {
storage: Storage;
onError: (error: unknown) => void;
}
export const StorageRow = ({ storage }: StorageRowProps) => {
export const StorageRow = ({ storage, onError }: StorageRowProps) => {
const { t } = useTranslation();
const queryClient = useQueryClient();
@@ -22,6 +23,7 @@ export const StorageRow = ({ storage }: StorageRowProps) => {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["storages"] });
},
onError,
});
const deleteMutation = useMutation({
@@ -29,6 +31,7 @@ export const StorageRow = ({ storage }: StorageRowProps) => {
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["storages"] });
},
onError,
});
const form = useForm({
@@ -47,7 +47,7 @@ export const AddStorageModal = (props: AddStorageModalProps) => {
isAlert: true,
type: "danger",
header: t("error"),
text: error.code ? t(`errors.${error.code}`) : t("unknown-error"),
text: error.code ? t(error.code) : t("unknown-error"),
});
},
onSuccess: () => {
@@ -0,0 +1,134 @@
import {
Modal,
ModalDialog,
DialogTitle,
Stack,
Input,
Button,
Alert,
} from "@mui/joy";
import { useForm } from "@tanstack/react-form";
import { useMutation } from "@tanstack/react-query";
import { useTranslation } from "react-i18next";
import type { ChangePasswordIntf, AlertInterface } from "../../misc/interfaces";
import { mutatePassword } from "../../utils/api/auth";
import { useState } from "react";
interface ChangePasswordProps {
isOpen: boolean;
setOpen: (value: boolean) => void;
}
export const ChangePasswordModal = (props: ChangePasswordProps) => {
const { t } = useTranslation();
const [alert, setAlert] = useState<AlertInterface>({
isAlert: false,
type: "neutral",
header: "",
text: "",
});
const form = useForm({
defaultValues: {
currentPassword: "",
newPassword: "",
newPasswordRep: "",
},
onSubmit: async ({ value }) => {
mutate(value);
},
});
const { mutate } = useMutation({
mutationFn: (values: ChangePasswordIntf) => mutatePassword(values),
onError: (error: { code?: string }) => {
setAlert({
isAlert: true,
type: "danger",
header: t("error"),
text: error.code ? t(error.code) : t("unknown-error"),
});
},
onSuccess: () => {
props.setOpen(false);
},
});
return (
<>
<Modal open={props.isOpen} onClose={() => props.setOpen(false)}>
<ModalDialog className="rounded-3xl border border-white/70 bg-white/90 p-6 shadow-[0_30px_70px_rgba(12,38,78,0.2)] backdrop-blur">
<DialogTitle className="text-slate-900">
{t("new-password-title")}
</DialogTitle>
<form
onSubmit={(e) => {
e.preventDefault();
form.handleSubmit();
}}
>
<Stack spacing={2} className="mt-4">
<form.Field name="currentPassword">
{(field) => (
<Input
type="password"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
placeholder={t("current-password")}
variant="outlined"
size="lg"
className="rounded-2xl bg-white/90 shadow-[0_10px_24px_rgba(15,23,42,0.08)]"
/>
)}
</form.Field>
<form.Field name="newPassword">
{(field) => (
<Input
type="password"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
placeholder={t("new-password")}
variant="outlined"
size="lg"
className="rounded-2xl bg-white/90 shadow-[0_10px_24px_rgba(15,23,42,0.08)]"
/>
)}
</form.Field>
<form.Field name="newPasswordRep">
{(field) => (
<Input
type="password"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
placeholder={t("new-password-rep")}
variant="outlined"
size="lg"
className="rounded-2xl bg-white/90 shadow-[0_10px_24px_rgba(15,23,42,0.08)]"
/>
)}
</form.Field>
<Button
type="submit"
size="lg"
className="rounded-2xl bg-[#0b6bcb] text-white shadow-[0_16px_36px_rgba(11,107,203,0.35)] transition hover:-translate-y-0.5 hover:bg-[#095aa7]"
>
{t("change")}
</Button>
</Stack>
</form>
{alert.isAlert && (
<Alert
variant="soft"
color={alert.type}
className="mt-4 rounded-2xl border border-rose-200/70 bg-rose-50/80 text-rose-700 shadow-[0_12px_30px_rgba(220,38,38,0.12)]"
>
{alert.header}
<br />
{alert.text}
</Alert>
)}
</ModalDialog>
</Modal>
</>
);
};