addded error codes and improved error handling
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
# Errors
|
||||
|
||||
Here you will find all Error codes and its meaning. Error or status codes that are starting with an s are success codes.
|
||||
|
||||
## Error codes
|
||||
|
||||
### `eu006`
|
||||
|
||||
**Meaning:** There is an error while changing the password. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Make sure that you have entered the correct previous password and that the double check passwords are matching.
|
||||
|
||||
### `eu004`
|
||||
|
||||
**Meaning:** There is an error while updating the settings. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** This error should not occur in the frontend. If so, please create an issue in this repository.
|
||||
|
||||
### `eu005`
|
||||
|
||||
**Meaning:** There is an error while fetching the app settings. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** This error should not occur in the frontend. If so, please create an issue in this repository.
|
||||
|
||||
### `eu001`
|
||||
|
||||
**Meaning:** Username or password is wrong. _HTTP-Code: **404**_
|
||||
|
||||
**Solution:** Check the username and password and try again.
|
||||
|
||||
### `eu002`
|
||||
|
||||
**Meaning:** The user is deactivated. _HTTP-Code: **403**_
|
||||
|
||||
**Solution:** Contact an admin to reactivate the account.
|
||||
|
||||
### `eu003`
|
||||
|
||||
**Meaning:** There is an error while updating the last login timestamp. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** This error should not occur in the frontend. If so, please create an issue in this repository.
|
||||
|
||||
### `ep001`
|
||||
|
||||
**Meaning:** There is an error while creating a product. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Verify that all required fields are provided and valid, then try again.
|
||||
|
||||
### `ep002`
|
||||
|
||||
**Meaning:** There is an error while fetching products. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
|
||||
### `ep003`
|
||||
|
||||
**Meaning:** There is an error while fetching a product. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Ensure the product exists and try again.
|
||||
|
||||
### `ep004`
|
||||
|
||||
**Meaning:** There is an error while updating the product amount. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Check the amount value and try again.
|
||||
|
||||
### `ep005`
|
||||
|
||||
**Meaning:** There is an error while updating a product. _HTTP-Code: **406**_
|
||||
|
||||
**Solution:** Verify the product data and try again.
|
||||
|
||||
### `ep006`
|
||||
|
||||
**Meaning:** There is an error while deleting products. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
|
||||
### `es001`
|
||||
|
||||
**Meaning:** There is an error while fetching storage locations. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
|
||||
### `es000`
|
||||
|
||||
**Meaning:** The request body is invalid. _HTTP-Code: **400**_
|
||||
|
||||
**Solution:** Provide a storage name. The description is optional.
|
||||
|
||||
### `es002`
|
||||
|
||||
**Meaning:** There is an error while creating a storage location. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
|
||||
### `es003`
|
||||
|
||||
**Meaning:** There is an error while updating a storage location. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
|
||||
### `es004`
|
||||
|
||||
**Meaning:** There is an error while deleting a storage location. _HTTP-Code: **500**_
|
||||
|
||||
**Solution:** Try again later. If the error persists, create an issue in this repository.
|
||||
@@ -72,3 +72,20 @@ export const getSettings = async () => {
|
||||
return { code: "eu005" };
|
||||
}
|
||||
};
|
||||
|
||||
export const changePassword = async (
|
||||
username,
|
||||
currentPasswordUser,
|
||||
newPassword,
|
||||
) => {
|
||||
const [result] = await pool.query(
|
||||
`UPDATE users SET password = ? WHERE username = ? AND password = ?;`,
|
||||
[newPassword, username, currentPasswordUser],
|
||||
);
|
||||
|
||||
if (result.affectedRows > 0) {
|
||||
return { code: "su005" };
|
||||
} else {
|
||||
return { code: "eu006" };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
loginUser,
|
||||
updateSettings,
|
||||
getSettings,
|
||||
changePassword,
|
||||
} from "./database/users.database.js";
|
||||
dotenv.config();
|
||||
const router = express.Router();
|
||||
@@ -18,8 +19,6 @@ router.post("/update-app-settings", authenticate, async (req, res) => {
|
||||
const appName = req.body.appName;
|
||||
const currency = req.body.currency;
|
||||
|
||||
console.log(req.body);
|
||||
|
||||
const result = await updateSettings(req.body);
|
||||
|
||||
if (result.code === "su003") {
|
||||
@@ -91,7 +90,7 @@ router.post("/login", async (req, res) => {
|
||||
const token = await generateToken(result.data);
|
||||
const login = await loginUser(result.data.username);
|
||||
|
||||
if (login.code === "e003") {
|
||||
if (login.code === "eu003") {
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
code: "eu003",
|
||||
@@ -111,4 +110,26 @@ router.post("/login", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/change-password", authenticate, async (req, res) => {
|
||||
const currentPassword = req.body.currentPassword;
|
||||
const newPassword = req.body.newPassword;
|
||||
const username = req.user.username;
|
||||
|
||||
const result = await changePassword(username, currentPassword, newPassword);
|
||||
|
||||
if (result.code === "su005") {
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
code: result.code,
|
||||
});
|
||||
}
|
||||
|
||||
if (result.code === "eu006") {
|
||||
res.status(406).json({
|
||||
success: false,
|
||||
code: result.code,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -61,3 +61,8 @@ export type ProductRow = {
|
||||
expiryDate: string;
|
||||
refillDate: string;
|
||||
};
|
||||
|
||||
export type ChangePasswordIntf = {
|
||||
currentPassword: string;
|
||||
newPassword: string;
|
||||
};
|
||||
|
||||
@@ -11,22 +11,53 @@ import {
|
||||
Typography,
|
||||
} from "@mui/joy";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { createProduct } from "../utils/api/products";
|
||||
import { getStorages } from "../utils/api/storages";
|
||||
import type { ProductFormValues } from "../misc/interfaces";
|
||||
import type {
|
||||
ProductFormValues,
|
||||
AlertInterface,
|
||||
Storage,
|
||||
} from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export const AddProduct = () => {
|
||||
const { t } = useTranslation();
|
||||
const [success, setSuccess] = useState(false);
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const { data: storages } = useQuery({
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: storages,
|
||||
isError: storagesError,
|
||||
error: storagesErrorObj,
|
||||
} = useQuery<Storage[], ApiError>({
|
||||
queryKey: ["storages"],
|
||||
queryFn: () => getStorages(),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (storagesError && storagesErrorObj) {
|
||||
showError(storagesErrorObj);
|
||||
}
|
||||
}, [storagesError, storagesErrorObj]);
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
amount: 0,
|
||||
@@ -48,6 +79,7 @@ export const AddProduct = () => {
|
||||
onSuccess: () => {
|
||||
setSuccess(true);
|
||||
},
|
||||
onError: showError,
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -227,13 +259,11 @@ export const AddProduct = () => {
|
||||
variant="outlined"
|
||||
className="rounded-2xl bg-white/90"
|
||||
>
|
||||
{storages?.map(
|
||||
(storage: { uuid: string; name: string }) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
),
|
||||
)}
|
||||
{storages?.map((storage) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</form.Field>
|
||||
@@ -255,6 +285,17 @@ export const AddProduct = () => {
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
{alert.isAlert && (
|
||||
<Alert
|
||||
color={alert.type}
|
||||
variant="soft"
|
||||
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>
|
||||
)}
|
||||
{success && (
|
||||
<Alert
|
||||
color="success"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Typography,
|
||||
Button,
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
Avatar,
|
||||
Chip,
|
||||
Checkbox,
|
||||
Alert,
|
||||
} from "@mui/joy";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -17,17 +18,46 @@ import { deleteSelectedProducts, getProducts } from "../utils/api/products";
|
||||
import { formatDate } from "../utils/uxFncs";
|
||||
import Cookies from "js-cookie";
|
||||
import type { ProductRow } from "../misc/interfaces";
|
||||
import type { AlertInterface } from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
|
||||
export const InventoryPage = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const { data: productsData, isLoading: productsIsLoading } = useQuery({
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: productsData,
|
||||
isLoading: productsIsLoading,
|
||||
isError: productsError,
|
||||
error: productsErrorObj,
|
||||
} = useQuery<any[], ApiError>({
|
||||
queryKey: ["products"],
|
||||
queryFn: getProducts,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (productsError && productsErrorObj) {
|
||||
showError(productsErrorObj);
|
||||
}
|
||||
}, [productsError, productsErrorObj]);
|
||||
|
||||
const rows: ProductRow[] = (productsData ?? []).map(
|
||||
(product: any, index: number) => ({
|
||||
id: String(product?.uuid ?? index),
|
||||
@@ -37,6 +67,8 @@ export const InventoryPage = () => {
|
||||
imageUrl: product?.picture ?? undefined,
|
||||
price: product?.price ? String(product.price) : "-",
|
||||
stock: `${product?.amount ?? 0} ${t("pcs")}`,
|
||||
stockLabel: String(product?.amount ?? 0),
|
||||
stockStatus: (product?.amount ?? 0) > 0 ? "ok" : "missing",
|
||||
location: product?.storage_location_name ?? "-",
|
||||
locationDetail: "",
|
||||
expiryDate: formatDate(product?.expiry_date),
|
||||
@@ -52,6 +84,7 @@ export const InventoryPage = () => {
|
||||
setSelected([]);
|
||||
queryClient.invalidateQueries({ queryKey: ["products"] });
|
||||
},
|
||||
onError: showError,
|
||||
});
|
||||
|
||||
const handleSelectAllClick = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@@ -94,6 +127,17 @@ export const InventoryPage = () => {
|
||||
</Button>
|
||||
{productsIsLoading && <CircularProgress size="sm" />}
|
||||
</div>
|
||||
{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>
|
||||
)}
|
||||
|
||||
<Sheet
|
||||
variant="outlined"
|
||||
|
||||
@@ -17,8 +17,13 @@ import { useEffect, useState } from "react";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { mutateProduct, getProductDetails } from "../utils/api/products.ts";
|
||||
import { toInputDate } from "../utils/uxFncs";
|
||||
import type { ProductFormValues } from "../misc/interfaces";
|
||||
import type { productDetailsInterface } from "../misc/interfaces";
|
||||
import type {
|
||||
ProductFormValues,
|
||||
productDetailsInterface,
|
||||
AlertInterface,
|
||||
Storage,
|
||||
} from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
import Cookies from "js-cookie";
|
||||
import ElectricBoltIcon from "@mui/icons-material/ElectricBolt";
|
||||
|
||||
@@ -27,21 +32,55 @@ export const ProductQuickView = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const [success, setSuccess] = useState(false);
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: productDetails,
|
||||
isLoading: productDetailsLoading,
|
||||
isSuccess,
|
||||
} = useQuery<productDetailsInterface>({
|
||||
isError: productDetailsError,
|
||||
error: productDetailsErrorObj,
|
||||
} = useQuery<productDetailsInterface, ApiError>({
|
||||
queryKey: ["product", uuid],
|
||||
queryFn: () => getProductDetails(uuid),
|
||||
});
|
||||
|
||||
const { data: storages } = useQuery({
|
||||
const {
|
||||
data: storages,
|
||||
isError: storagesError,
|
||||
error: storagesErrorObj,
|
||||
} = useQuery<Storage[], ApiError>({
|
||||
queryKey: ["storages"],
|
||||
queryFn: () => getStorages(),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (productDetailsError && productDetailsErrorObj) {
|
||||
showError(productDetailsErrorObj);
|
||||
}
|
||||
}, [productDetailsError, productDetailsErrorObj]);
|
||||
|
||||
useEffect(() => {
|
||||
if (storagesError && storagesErrorObj) {
|
||||
showError(storagesErrorObj);
|
||||
}
|
||||
}, [storagesError, storagesErrorObj]);
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
amount: 0,
|
||||
@@ -73,6 +112,7 @@ export const ProductQuickView = () => {
|
||||
setSuccess(true);
|
||||
queryClient.invalidateQueries({ queryKey: ["product", variables.uuid] });
|
||||
},
|
||||
onError: showError,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -271,13 +311,11 @@ export const ProductQuickView = () => {
|
||||
variant="outlined"
|
||||
className="rounded-2xl bg-white/90"
|
||||
>
|
||||
{storages?.map(
|
||||
(storage: { uuid: string; name: string }) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
),
|
||||
)}
|
||||
{storages?.map((storage) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</form.Field>
|
||||
@@ -299,6 +337,17 @@ export const ProductQuickView = () => {
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
{alert.isAlert && (
|
||||
<Alert
|
||||
color={alert.type}
|
||||
variant="soft"
|
||||
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>
|
||||
)}
|
||||
{success && (
|
||||
<Alert
|
||||
color="success"
|
||||
|
||||
@@ -6,31 +6,68 @@ import {
|
||||
Sheet,
|
||||
Chip,
|
||||
Divider,
|
||||
Alert,
|
||||
} from "@mui/joy";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import Cookies from "js-cookie";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { SettingsIntf } from "../misc/interfaces";
|
||||
import type { AlertInterface } from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
import { mutateSettings, fetchSettings } from "../utils/api/settings";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ChangePasswordModal } from "../components/modals/ChangePasswordModal";
|
||||
|
||||
export const Settings = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const [modal, setModal] = useState(false);
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: settings,
|
||||
isPending: settingsPending,
|
||||
isSuccess: settingsSuccess,
|
||||
} = useQuery({
|
||||
isError: settingsError,
|
||||
error: settingsErrorObj,
|
||||
} = useQuery<{ data: { value: string }[] }, ApiError>({
|
||||
queryKey: ["settings"],
|
||||
queryFn: fetchSettings,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
Cookies.set("app-name", settings?.data[0].value);
|
||||
Cookies.set("currency", settings?.data[1].value);
|
||||
if (settingsError && settingsErrorObj) {
|
||||
showError(settingsErrorObj);
|
||||
}
|
||||
}, [settingsError, settingsErrorObj]);
|
||||
|
||||
useEffect(() => {
|
||||
const appName = settings?.data?.[0]?.value;
|
||||
const currency = settings?.data?.[1]?.value;
|
||||
|
||||
if (appName) {
|
||||
Cookies.set("app-name", appName);
|
||||
}
|
||||
|
||||
if (currency) {
|
||||
Cookies.set("currency", currency);
|
||||
}
|
||||
}, [settingsSuccess]);
|
||||
|
||||
const form = useForm({
|
||||
@@ -48,10 +85,12 @@ export const Settings = () => {
|
||||
onSuccess() {
|
||||
queryClient.invalidateQueries({ queryKey: ["settings"] });
|
||||
},
|
||||
onError: showError,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChangePasswordModal isOpen={modal} setOpen={setModal} />
|
||||
<div className="space-y-6">
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<div className="space-y-1">
|
||||
@@ -73,6 +112,17 @@ export const Settings = () => {
|
||||
</div>
|
||||
|
||||
<Sheet className="mt-6 rounded-3xl border border-white/70 bg-white/80 p-6 shadow-[0_24px_60px_rgba(12,38,78,0.12)] backdrop-blur">
|
||||
{alert.isAlert && (
|
||||
<Alert
|
||||
variant="soft"
|
||||
color={alert.type}
|
||||
className="mb-6 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>
|
||||
)}
|
||||
{settingsPending ? (
|
||||
<div className="flex items-center justify-center py-16">
|
||||
<CircularProgress size="lg" />
|
||||
@@ -143,10 +193,19 @@ export const Settings = () => {
|
||||
<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]"
|
||||
color="primary"
|
||||
className="rounded-2xl text-white shadow-[0_16px_36px_rgba(11,107,203,0.35)] transition hover:-translate-y-0.5 hover:bg-[#095aa7]"
|
||||
>
|
||||
{t("save")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setModal(true)}
|
||||
size="lg"
|
||||
color="warning"
|
||||
className="rounded-2xl text-white shadow-[0_16px_36px_rgba(11,107,203,0.35)] transition hover:-translate-y-0.5 hover:bg-[#095aa7]"
|
||||
>
|
||||
{t("change-password")}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
|
||||
@@ -1,22 +1,58 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getStorages } from "../utils/api/storages";
|
||||
import { Sheet, Table, Button, CircularProgress, Typography } from "@mui/joy";
|
||||
import {
|
||||
Sheet,
|
||||
Table,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Typography,
|
||||
Alert,
|
||||
} from "@mui/joy";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { Storage } from "../misc/interfaces";
|
||||
import type { AlertInterface } from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
import { StorageRow } from "../components/StorageRow";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { AddStorageModal } from "../components/modals/AddStorageModal";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
|
||||
export const Storages = () => {
|
||||
const { t } = useTranslation();
|
||||
const [modal, setModal] = useState(false);
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const { data: storages, isLoading } = useQuery({
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: storages,
|
||||
isLoading,
|
||||
isError: storagesError,
|
||||
error: storagesErrorObj,
|
||||
} = useQuery<Storage[], ApiError>({
|
||||
queryKey: ["storages"],
|
||||
queryFn: () => getStorages(),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (storagesError && storagesErrorObj) {
|
||||
showError(storagesErrorObj);
|
||||
}
|
||||
}, [storagesError, storagesErrorObj]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-col gap-4">
|
||||
@@ -38,6 +74,17 @@ export const Storages = () => {
|
||||
{t("add")}
|
||||
</Button>
|
||||
</div>
|
||||
{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>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Sheet
|
||||
@@ -100,7 +147,11 @@ export const Storages = () => {
|
||||
</thead>
|
||||
<tbody>
|
||||
{storages?.map((storage: Storage) => (
|
||||
<StorageRow key={storage.uuid} storage={storage} />
|
||||
<StorageRow
|
||||
key={storage.uuid}
|
||||
storage={storage}
|
||||
onError={showError}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
|
||||
@@ -17,8 +17,13 @@ import { useEffect, useState } from "react";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { mutateProduct, getProductDetails } from "../utils/api/products.ts";
|
||||
import { toInputDate } from "../utils/uxFncs";
|
||||
import type { ProductFormValues } from "../misc/interfaces";
|
||||
import type { productDetailsInterface } from "../misc/interfaces";
|
||||
import type {
|
||||
ProductFormValues,
|
||||
productDetailsInterface,
|
||||
AlertInterface,
|
||||
Storage,
|
||||
} from "../misc/interfaces";
|
||||
import type { ApiError } from "../utils/api/apiError";
|
||||
import QrCodeIcon from "@mui/icons-material/QrCode";
|
||||
import Cookies from "js-cookie";
|
||||
import QRCode from "qrcode";
|
||||
@@ -32,21 +37,55 @@ export const ViewProduct = (props: ViewProductProps) => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
const [success, setSuccess] = useState(false);
|
||||
const [alert, setAlert] = useState<AlertInterface>({
|
||||
isAlert: false,
|
||||
type: "neutral",
|
||||
header: "",
|
||||
text: "",
|
||||
});
|
||||
|
||||
const showError = (error: unknown) => {
|
||||
const errorCode = (error as { code?: string })?.code;
|
||||
setAlert({
|
||||
isAlert: true,
|
||||
type: "danger",
|
||||
header: t("error"),
|
||||
text: errorCode ? t(errorCode) : t("unknown-error"),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
data: productDetails,
|
||||
isLoading: productDetailsLoading,
|
||||
isSuccess,
|
||||
} = useQuery<productDetailsInterface>({
|
||||
isError: productDetailsError,
|
||||
error: productDetailsErrorObj,
|
||||
} = useQuery<productDetailsInterface, ApiError>({
|
||||
queryKey: ["product", uuid],
|
||||
queryFn: () => getProductDetails(uuid),
|
||||
});
|
||||
|
||||
const { data: storages } = useQuery({
|
||||
const {
|
||||
data: storages,
|
||||
isError: storagesError,
|
||||
error: storagesErrorObj,
|
||||
} = useQuery<Storage[], ApiError>({
|
||||
queryKey: ["storages"],
|
||||
queryFn: () => getStorages(),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (productDetailsError && productDetailsErrorObj) {
|
||||
showError(productDetailsErrorObj);
|
||||
}
|
||||
}, [productDetailsError, productDetailsErrorObj]);
|
||||
|
||||
useEffect(() => {
|
||||
if (storagesError && storagesErrorObj) {
|
||||
showError(storagesErrorObj);
|
||||
}
|
||||
}, [storagesError, storagesErrorObj]);
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
amount: 0,
|
||||
@@ -78,6 +117,7 @@ export const ViewProduct = (props: ViewProductProps) => {
|
||||
setSuccess(true);
|
||||
queryClient.invalidateQueries({ queryKey: ["product", variables.uuid] });
|
||||
},
|
||||
onError: showError,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -289,13 +329,11 @@ export const ViewProduct = (props: ViewProductProps) => {
|
||||
variant="outlined"
|
||||
className="rounded-2xl bg-white/90"
|
||||
>
|
||||
{storages?.map(
|
||||
(storage: { uuid: string; name: string }) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
),
|
||||
)}
|
||||
{storages?.map((storage) => (
|
||||
<Option key={storage.uuid} value={storage.uuid}>
|
||||
{storage.name}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
)}
|
||||
</form.Field>
|
||||
@@ -326,6 +364,17 @@ export const ViewProduct = (props: ViewProductProps) => {
|
||||
{t("save")}
|
||||
</Button>
|
||||
</div>
|
||||
{alert.isAlert && (
|
||||
<Alert
|
||||
color={alert.type}
|
||||
variant="soft"
|
||||
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>
|
||||
)}
|
||||
{success && (
|
||||
<Alert
|
||||
color="success"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
export type ApiError = Error & { code?: string };
|
||||
|
||||
export const createApiError = (
|
||||
code?: string,
|
||||
message: string = "Request failed",
|
||||
): ApiError => {
|
||||
const error = new Error(message) as ApiError;
|
||||
error.code = code || "unknown-error";
|
||||
return error;
|
||||
};
|
||||
@@ -1,8 +1,9 @@
|
||||
import { API_BASE } from "../../config/api.config";
|
||||
import Cookies from "js-cookie";
|
||||
import type { TFunction } from "i18next";
|
||||
import { toast } from "react-toastify";
|
||||
import { fetchSettings } from "./settings";
|
||||
import type { ChangePasswordIntf } from "../../misc/interfaces";
|
||||
import { createApiError } from "./apiError";
|
||||
|
||||
export async function isAuthenticated() {
|
||||
if (Cookies.get("token")) {
|
||||
@@ -52,11 +53,33 @@ export async function signInUser(
|
||||
}
|
||||
|
||||
Cookies.remove("token");
|
||||
toast.error(t(response.code));
|
||||
return { ok: false as const };
|
||||
throw createApiError(response.code, t(response.code || "unknown-error"));
|
||||
}
|
||||
|
||||
export function signOutUser() {
|
||||
Cookies.remove("token");
|
||||
return { ok: true as const };
|
||||
}
|
||||
|
||||
export const mutatePassword = async (payload: ChangePasswordIntf) => {
|
||||
const result = await fetch(`${API_BASE}/users/change-password`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
currentPassword: payload.currentPassword,
|
||||
newPassword: payload.newPassword,
|
||||
}),
|
||||
});
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "su005") {
|
||||
return { code: response.code };
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Change password failed");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { API_BASE } from "../../config/api.config";
|
||||
import Cookies from "js-cookie";
|
||||
import type { ProductFormValues } from "../../misc/interfaces";
|
||||
import { createApiError } from "./apiError";
|
||||
|
||||
export const getProducts = async () => {
|
||||
const result = await fetch(`${API_BASE}/products/all-products`, {
|
||||
@@ -12,13 +13,11 @@ export const getProducts = async () => {
|
||||
});
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "ep002") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "sp002") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Get products failed");
|
||||
};
|
||||
|
||||
export const getProductDetails = async (uuid: string) => {
|
||||
@@ -32,13 +31,11 @@ export const getProductDetails = async (uuid: string) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "ep003") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "sp003") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Get product details failed");
|
||||
};
|
||||
|
||||
export const mutateProduct = async (
|
||||
@@ -66,13 +63,11 @@ export const mutateProduct = async (
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "ep004") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "sp004") {
|
||||
if (response.code === "sp005") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Update product failed");
|
||||
};
|
||||
|
||||
export const deleteSelectedProducts = async (uuids: string[]) => {
|
||||
@@ -88,7 +83,11 @@ export const deleteSelectedProducts = async (uuids: string[]) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
console.log(response);
|
||||
if (response.code === "sp006") {
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Delete products failed");
|
||||
};
|
||||
|
||||
export const createProduct = async (values: ProductFormValues) => {
|
||||
@@ -114,11 +113,9 @@ export const createProduct = async (values: ProductFormValues) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "ep001") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "sp001") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Create product failed");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { API_BASE } from "../../config/api.config";
|
||||
import Cookies from "js-cookie";
|
||||
import type { SettingsIntf } from "../../misc/interfaces";
|
||||
import { createApiError } from "./apiError";
|
||||
|
||||
export const fetchSettings = async () => {
|
||||
const result = await fetch(`${API_BASE}/users/settings`, {
|
||||
@@ -14,13 +15,11 @@ export const fetchSettings = async () => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "eu005") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "su004") {
|
||||
return { success: true, data: response.data, code: response.code };
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Fetch settings failed");
|
||||
};
|
||||
|
||||
export const mutateSettings = async (payload: SettingsIntf) => {
|
||||
@@ -36,11 +35,9 @@ export const mutateSettings = async (payload: SettingsIntf) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "eu004") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "su003") {
|
||||
return { success: true, code: response.code };
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Update settings failed");
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { API_BASE } from "../../config/api.config";
|
||||
import Cookies from "js-cookie";
|
||||
import type { NewStorage, Storage } from "../../misc/interfaces";
|
||||
import { createApiError } from "./apiError";
|
||||
|
||||
export const getStorages = async () => {
|
||||
const result = await fetch(`${API_BASE}/storage/all-storages`, {
|
||||
@@ -13,13 +14,11 @@ export const getStorages = async () => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "es001") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "ss001") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Get storages failed");
|
||||
};
|
||||
|
||||
export const mutateNewStorage = async (values: NewStorage) => {
|
||||
@@ -35,13 +34,11 @@ export const mutateNewStorage = async (values: NewStorage) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "es002") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "ss002") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Create storage failed");
|
||||
};
|
||||
|
||||
export const updateStorage = async (
|
||||
@@ -63,13 +60,11 @@ export const updateStorage = async (
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "ep001") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "sp001") {
|
||||
if (response.code === "ss003") {
|
||||
return response.data;
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Update storage failed");
|
||||
};
|
||||
|
||||
export const deleteStorage = async (uuid: string) => {
|
||||
@@ -84,11 +79,9 @@ export const deleteStorage = async (uuid: string) => {
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "es004") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "ss004") {
|
||||
return { success: true, code: response.code };
|
||||
}
|
||||
|
||||
throw createApiError(response.code, "Delete storage failed");
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user