refactor: add custom alert component and remove all other Alert standard components in all components
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
import { useForm } from "@tanstack/react-form";
|
import { useForm } from "@tanstack/react-form";
|
||||||
import { Alert, Button, Input } from "@mui/joy";
|
import { Button, Input } from "@mui/joy";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { signInUser } from "../utils/api/auth";
|
import { signInUser } from "../utils/api/auth";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
import { useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import type { AlertInterface } from "../misc/interfaces";
|
import type { AlertInterface } from "../misc/interfaces";
|
||||||
|
import { MyAlert } from "./MyAlert.tsx";
|
||||||
|
|
||||||
export const LoginCard = () => {
|
export const LoginCard = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -17,6 +18,15 @@ export const LoginCard = () => {
|
|||||||
text: "",
|
text: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAlert({
|
||||||
|
isAlert: true,
|
||||||
|
type: "primary",
|
||||||
|
header: t("success"),
|
||||||
|
text: t("logout-success-text"),
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const form = useForm({
|
const form = useForm({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
username: "",
|
username: "",
|
||||||
@@ -77,15 +87,11 @@ export const LoginCard = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
variant="soft"
|
type={alert.type}
|
||||||
color={alert.type}
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
<form.Field name="username">
|
<form.Field name="username">
|
||||||
{(field) => (
|
{(field) => (
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { Alert } from "@mui/joy";
|
||||||
|
|
||||||
|
interface MyAlertProps {
|
||||||
|
type: "success" | "warning" | "danger" | "neutral" | "primary";
|
||||||
|
header: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MyAlert = (props: MyAlertProps) => {
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
variant="soft"
|
||||||
|
color={props.type}
|
||||||
|
className="rounded-2xl drop-shadow-sm"
|
||||||
|
>
|
||||||
|
{props.header}
|
||||||
|
<br />
|
||||||
|
{props.text}
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -50,7 +50,7 @@ export const Sidebar = () => {
|
|||||||
<Button
|
<Button
|
||||||
variant="soft"
|
variant="soft"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="lg:hidden transition-transform duration-200 ease-out"
|
className="transition-transform duration-200 ease-out"
|
||||||
onClick={() => setIsOpen((open) => !open)}
|
onClick={() => setIsOpen((open) => !open)}
|
||||||
startDecorator={
|
startDecorator={
|
||||||
<span
|
<span
|
||||||
@@ -61,7 +61,10 @@ export const Sidebar = () => {
|
|||||||
{isOpen ? <CloseIcon /> : <MenuIcon />}
|
{isOpen ? <CloseIcon /> : <MenuIcon />}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
sx={{ display: { lg: "none" } }}
|
sx={{
|
||||||
|
display: "inline-flex",
|
||||||
|
"@media (min-width: 1024px)": { display: "none" },
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isOpen ? t("close") : t("menu")}
|
{isOpen ? t("close") : t("menu")}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -110,7 +113,7 @@ export const Sidebar = () => {
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
Cookies.remove("token");
|
Cookies.remove("token");
|
||||||
handleNavigate("/login");
|
handleNavigate("/login?logout=true");
|
||||||
}}
|
}}
|
||||||
color="danger"
|
color="danger"
|
||||||
startDecorator={<ExitToAppIcon />}
|
startDecorator={<ExitToAppIcon />}
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
import {
|
import { Button, DialogContent, DialogTitle, Input, Modal, ModalDialog, Stack, } from "@mui/joy";
|
||||||
Alert,
|
|
||||||
Button,
|
|
||||||
DialogContent,
|
|
||||||
DialogTitle,
|
|
||||||
Input,
|
|
||||||
Modal,
|
|
||||||
ModalDialog,
|
|
||||||
Stack,
|
|
||||||
} from "@mui/joy";
|
|
||||||
import { useForm } from "@tanstack/react-form";
|
import { useForm } from "@tanstack/react-form";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import type { AlertInterface, NewStorage } from "../../misc/interfaces";
|
import type { AlertInterface, NewStorage } from "../../misc/interfaces";
|
||||||
import { mutateNewStorage } from "../../utils/api/storages";
|
import { mutateNewStorage } from "../../utils/api/storages";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { MyAlert } from "../MyAlert.tsx";
|
||||||
|
|
||||||
interface AddStorageModalProps {
|
interface AddStorageModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -107,15 +99,11 @@ export const AddStorageModal = (props: AddStorageModalProps) => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</form>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
variant="soft"
|
type={alert.type}
|
||||||
color={alert.type}
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</ModalDialog>
|
</ModalDialog>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -1,4 +1,11 @@
|
|||||||
import { Alert, Button, DialogTitle, Input, Modal, ModalDialog, Stack, } from "@mui/joy";
|
import {
|
||||||
|
Button,
|
||||||
|
DialogTitle,
|
||||||
|
Input,
|
||||||
|
Modal,
|
||||||
|
ModalDialog,
|
||||||
|
Stack,
|
||||||
|
} from "@mui/joy";
|
||||||
import { useForm } from "@tanstack/react-form";
|
import { useForm } from "@tanstack/react-form";
|
||||||
import { useMutation } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -6,6 +13,7 @@ import type { AlertInterface, ChangePasswordIntf } from "../../misc/interfaces";
|
|||||||
import { mutatePassword } from "../../utils/api/auth";
|
import { mutatePassword } from "../../utils/api/auth";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { USER_ERROR_CODE } from "@stockhome/shared";
|
import { USER_ERROR_CODE } from "@stockhome/shared";
|
||||||
|
import { MyAlert } from "../MyAlert.tsx";
|
||||||
|
|
||||||
interface ChangePasswordProps {
|
interface ChangePasswordProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@@ -140,15 +148,11 @@ export const ChangePasswordModal = (props: ChangePasswordProps) => {
|
|||||||
</Stack>
|
</Stack>
|
||||||
</form>
|
</form>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
variant="soft"
|
type={alert.type}
|
||||||
color={alert.type}
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</ModalDialog>
|
</ModalDialog>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
Alert,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
@@ -22,10 +21,10 @@ import type {
|
|||||||
} from "../misc/interfaces";
|
} from "../misc/interfaces";
|
||||||
import type { ApiError } from "../utils/api/apiError";
|
import type { ApiError } from "../utils/api/apiError";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
export const AddProduct = () => {
|
export const AddProduct = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [success, setSuccess] = useState(false);
|
|
||||||
const [alert, setAlert] = useState<AlertInterface>({
|
const [alert, setAlert] = useState<AlertInterface>({
|
||||||
isAlert: false,
|
isAlert: false,
|
||||||
type: "neutral",
|
type: "neutral",
|
||||||
@@ -69,7 +68,6 @@ export const AddProduct = () => {
|
|||||||
storage_location_uuid: "",
|
storage_location_uuid: "",
|
||||||
},
|
},
|
||||||
onSubmit: async ({ value }) => {
|
onSubmit: async ({ value }) => {
|
||||||
setSuccess(false);
|
|
||||||
mutate(value);
|
mutate(value);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -77,7 +75,12 @@ export const AddProduct = () => {
|
|||||||
const { mutate, isPending } = useMutation({
|
const { mutate, isPending } = useMutation({
|
||||||
mutationFn: (values: ProductFormValues) => createProduct(values),
|
mutationFn: (values: ProductFormValues) => createProduct(values),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setSuccess(true);
|
setAlert({
|
||||||
|
isAlert: true,
|
||||||
|
type: "success",
|
||||||
|
header: "",
|
||||||
|
text: "",
|
||||||
|
});
|
||||||
},
|
},
|
||||||
onError: showError,
|
onError: showError,
|
||||||
});
|
});
|
||||||
@@ -287,28 +290,11 @@ export const AddProduct = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
color={alert.type}
|
type={alert.type}
|
||||||
variant="soft"
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{success && (
|
|
||||||
<Alert
|
|
||||||
color="success"
|
|
||||||
variant="soft"
|
|
||||||
className="rounded-2xl border border-emerald-200/70 bg-emerald-50/80 text-emerald-700 shadow-[0_14px_30px_rgba(16,185,129,0.18)]"
|
|
||||||
>
|
|
||||||
<div className="flex w-full items-center justify-between">
|
|
||||||
<Typography level="body-sm" className="text-emerald-700">
|
|
||||||
{t("success")}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,15 +1,5 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import {
|
import { Avatar, Button, Checkbox, Chip, CircularProgress, Sheet, Table, Typography, } from "@mui/joy";
|
||||||
Alert,
|
|
||||||
Avatar,
|
|
||||||
Button,
|
|
||||||
Checkbox,
|
|
||||||
Chip,
|
|
||||||
CircularProgress,
|
|
||||||
Sheet,
|
|
||||||
Table,
|
|
||||||
Typography,
|
|
||||||
} from "@mui/joy";
|
|
||||||
import { useNavigate } from "@tanstack/react-router";
|
import { useNavigate } from "@tanstack/react-router";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
@@ -19,6 +9,8 @@ import { formatDate } from "../utils/uxFncs";
|
|||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import type { AlertInterface, ProductRow } from "../misc/interfaces";
|
import type { AlertInterface, ProductRow } from "../misc/interfaces";
|
||||||
import type { ApiError } from "../utils/api/apiError";
|
import type { ApiError } from "../utils/api/apiError";
|
||||||
|
import CategoryIcon from "@mui/icons-material/category";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
export const InventoryPage = () => {
|
export const InventoryPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -127,20 +119,12 @@ export const InventoryPage = () => {
|
|||||||
{productsIsLoading && <CircularProgress size="sm" />}
|
{productsIsLoading && <CircularProgress size="sm" />}
|
||||||
</div>
|
</div>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert type={alert.type} header={alert.header} text={alert.text} />
|
||||||
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
|
<Sheet
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
className="mt-6 flex min-h-0 flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm sm:h-[calc(100vh-260px)]"
|
className="mt-6 flex min-h-0 w-full max-w-full flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm sm:h-[calc(100vh-260px)]"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between border-b border-slate-200 px-6 py-4 text-slate-700">
|
<div className="flex items-center justify-between border-b border-slate-200 px-6 py-4 text-slate-700">
|
||||||
<Typography level="body-lg" fontWeight="bold">
|
<Typography level="body-lg" fontWeight="bold">
|
||||||
@@ -163,8 +147,9 @@ export const InventoryPage = () => {
|
|||||||
stripe="odd"
|
stripe="odd"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
hoverRow
|
hoverRow
|
||||||
className="min-w-240 text-slate-700"
|
className="w-full text-slate-700"
|
||||||
sx={{
|
sx={{
|
||||||
|
tableLayout: "fixed",
|
||||||
"--TableCell-headBackground":
|
"--TableCell-headBackground":
|
||||||
"var(--joy-palette-background-surface)",
|
"var(--joy-palette-background-surface)",
|
||||||
"& thead": {
|
"& thead": {
|
||||||
@@ -176,23 +161,48 @@ export const InventoryPage = () => {
|
|||||||
"& thead tr": {
|
"& thead tr": {
|
||||||
backgroundColor: "rgb(248 250 252)",
|
backgroundColor: "rgb(248 250 252)",
|
||||||
},
|
},
|
||||||
"& thead th:nth-child(2)": {
|
|
||||||
width: "40%",
|
|
||||||
},
|
|
||||||
"& thead th:nth-child(3)": {
|
|
||||||
width: "14%",
|
|
||||||
},
|
|
||||||
"& thead th": {
|
"& thead th": {
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
backgroundColor: "rgb(248 250 252)",
|
backgroundColor: "rgb(248 250 252)",
|
||||||
backgroundImage: "none",
|
backgroundImage: "none",
|
||||||
},
|
},
|
||||||
|
"& thead th:nth-child(1)": {
|
||||||
|
width: "44px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(2)": {
|
||||||
|
width: "22%",
|
||||||
|
minWidth: "160px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(3)": {
|
||||||
|
width: "9%",
|
||||||
|
minWidth: "70px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(4)": {
|
||||||
|
width: "12%",
|
||||||
|
minWidth: "90px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(5)": {
|
||||||
|
width: "17%",
|
||||||
|
minWidth: "120px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(6)": {
|
||||||
|
width: "13%",
|
||||||
|
minWidth: "100px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(7)": {
|
||||||
|
width: "13%",
|
||||||
|
minWidth: "100px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(8)": {
|
||||||
|
width: "14%",
|
||||||
|
minWidth: "100px",
|
||||||
|
},
|
||||||
"& tr > *:nth-child(n+4)": { textAlign: "left" },
|
"& tr > *:nth-child(n+4)": { textAlign: "left" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="text-slate-600">
|
<tr className="text-slate-600">
|
||||||
<th className="px-4 py-4">
|
<th className="px-2 py-4">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={rows.length > 0 && selected.length === rows.length}
|
checked={rows.length > 0 && selected.length === rows.length}
|
||||||
indeterminate={
|
indeterminate={
|
||||||
@@ -203,13 +213,13 @@ export const InventoryPage = () => {
|
|||||||
sx={{ verticalAlign: "sub" }}
|
sx={{ verticalAlign: "sub" }}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th className="px-6 py-4">{t("product-name")}</th>
|
<th className="px-3 py-4">{t("product-name")}</th>
|
||||||
<th className="px-6 py-4">{t("price")}</th>
|
<th className="px-3 py-4">{t("price")}</th>
|
||||||
<th className="px-6 py-4">{t("stock")}</th>
|
<th className="px-3 py-4">{t("stock")}</th>
|
||||||
<th className="px-6 py-4">{t("storage-place")}</th>
|
<th className="px-3 py-4">{t("storage-place")}</th>
|
||||||
<th className="px-6 py-4">{t("expiry-date")}</th>
|
<th className="px-3 py-4">{t("expiry-date")}</th>
|
||||||
<th className="px-6 py-4">{t("bottling-date")}</th>
|
<th className="px-3 py-4">{t("bottling-date")}</th>
|
||||||
<th className="px-6 py-4 text-right">{t("actions")}</th>
|
<th className="px-3 py-4 text-right">{t("actions")}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -225,61 +235,81 @@ export const InventoryPage = () => {
|
|||||||
aria-checked={isItemSelected}
|
aria-checked={isItemSelected}
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
>
|
>
|
||||||
<th scope="row" className="px-4 py-5">
|
<th scope="row" className="px-2 py-5">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={isItemSelected}
|
checked={isItemSelected}
|
||||||
slotProps={{ input: { "aria-labelledby": labelId } }}
|
slotProps={{ input: { "aria-labelledby": labelId } }}
|
||||||
sx={{ verticalAlign: "top" }}
|
sx={{ verticalAlign: "top" }}
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th id={labelId} scope="row" className="px-6 py-5">
|
<th
|
||||||
<div className="flex items-center gap-4">
|
id={labelId}
|
||||||
<Avatar size="lg" variant="soft" src={row.imageUrl} />
|
scope="row"
|
||||||
|
className="px-3 py-5 overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="flex min-w-0 items-center gap-3">
|
||||||
|
<Avatar size="lg" variant="soft" className="shrink-0">
|
||||||
|
<CategoryIcon />
|
||||||
|
</Avatar>
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<Typography
|
<Typography
|
||||||
level="title-md"
|
level="title-md"
|
||||||
className="text-slate-900"
|
className="text-slate-900 truncate"
|
||||||
>
|
>
|
||||||
{row.name}
|
{row.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
level="body-sm"
|
level="body-sm"
|
||||||
className="text-slate-500"
|
className="text-slate-500 truncate"
|
||||||
>
|
>
|
||||||
{row.description}
|
{row.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<td className="px-6 py-5">
|
<td className="px-3 py-5 overflow-hidden">
|
||||||
<Typography level="title-md">{row.price}</Typography>
|
<Typography level="title-md" className="truncate">
|
||||||
<Typography level="body-sm" className="text-slate-400">
|
{row.price}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
level="body-sm"
|
||||||
|
className="truncate text-slate-400"
|
||||||
|
>
|
||||||
{Cookies.get("currency")}
|
{Cookies.get("currency")}
|
||||||
</Typography>
|
</Typography>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-5">
|
<td className="px-3 py-5 overflow-hidden">
|
||||||
<Chip
|
<Chip
|
||||||
variant="soft"
|
variant="soft"
|
||||||
color="neutral"
|
color="neutral"
|
||||||
size="lg"
|
size="lg"
|
||||||
className="px-3"
|
className="max-w-full px-3"
|
||||||
>
|
>
|
||||||
{row.stock}
|
<span className="truncate">{row.stock}</span>
|
||||||
</Chip>
|
</Chip>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-5">
|
<td className="px-3 py-5 overflow-hidden">
|
||||||
<Typography level="title-md">{row.location}</Typography>
|
<Typography level="title-md" className="truncate">
|
||||||
<Typography level="body-sm" className="text-slate-500">
|
{row.location}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
level="body-sm"
|
||||||
|
className="truncate text-slate-500"
|
||||||
|
>
|
||||||
{row.locationDetail}
|
{row.locationDetail}
|
||||||
</Typography>
|
</Typography>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-5">
|
<td className="px-3 py-5 overflow-hidden">
|
||||||
<Typography level="title-md">{row.expiryDate}</Typography>
|
<Typography level="title-md" className="truncate">
|
||||||
|
{row.expiryDate}
|
||||||
|
</Typography>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-5">
|
<td className="px-3 py-5 overflow-hidden">
|
||||||
<Typography level="title-md">{row.refillDate}</Typography>
|
<Typography level="title-md" className="truncate">
|
||||||
|
{row.refillDate}
|
||||||
|
</Typography>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-6 py-5 text-right">
|
<td className="px-3 py-5 text-right">
|
||||||
<Button
|
<Button
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
navigate({
|
navigate({
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { getStorages } from "../utils/api/storages.ts";
|
import { getStorages } from "../utils/api/storages.ts";
|
||||||
import {
|
import {
|
||||||
Alert,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
@@ -26,6 +25,7 @@ import type {
|
|||||||
import type { ApiError } from "../utils/api/apiError";
|
import type { ApiError } from "../utils/api/apiError";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import ElectricBoltIcon from "@mui/icons-material/ElectricBolt";
|
import ElectricBoltIcon from "@mui/icons-material/ElectricBolt";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
export const ProductQuickView = () => {
|
export const ProductQuickView = () => {
|
||||||
const uuid = window.location.search.split("uuid=")[1];
|
const uuid = window.location.search.split("uuid=")[1];
|
||||||
@@ -165,7 +165,7 @@ export const ProductQuickView = () => {
|
|||||||
form.handleSubmit();
|
form.handleSubmit();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="grid gap-5 lg:grid-cols-[1.2fr_1fr]">
|
<div className="gap-5 lg:grid-cols-[1.2fr_1fr]">
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<Typography level="title-md" className="text-slate-900">
|
<Typography level="title-md" className="text-slate-900">
|
||||||
@@ -338,28 +338,11 @@ export const ProductQuickView = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
color={alert.type}
|
type={alert.type}
|
||||||
variant="soft"
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{success && (
|
|
||||||
<Alert
|
|
||||||
color="success"
|
|
||||||
variant="soft"
|
|
||||||
className="rounded-2xl border border-emerald-200/70 bg-emerald-50/80 text-emerald-700 shadow-[0_14px_30px_rgba(16,185,129,0.18)]"
|
|
||||||
>
|
|
||||||
<div className="flex w-full items-center justify-between">
|
|
||||||
<Typography level="body-sm" className="text-emerald-700">
|
|
||||||
{t("success")}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
import {
|
import { Button, Chip, CircularProgress, Divider, Input, Sheet, Typography, } from "@mui/joy";
|
||||||
Alert,
|
|
||||||
Button,
|
|
||||||
Chip,
|
|
||||||
CircularProgress,
|
|
||||||
Divider,
|
|
||||||
Input,
|
|
||||||
Sheet,
|
|
||||||
Typography,
|
|
||||||
} from "@mui/joy";
|
|
||||||
import { useForm } from "@tanstack/react-form";
|
import { useForm } from "@tanstack/react-form";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
@@ -17,6 +8,7 @@ import type { ApiError } from "../utils/api/apiError";
|
|||||||
import { fetchSettings, mutateSettings } from "../utils/api/settings";
|
import { fetchSettings, mutateSettings } from "../utils/api/settings";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { ChangePasswordModal } from "../components/modals/ChangePasswordModal";
|
import { ChangePasswordModal } from "../components/modals/ChangePasswordModal";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
export const Settings = () => {
|
export const Settings = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -118,15 +110,7 @@ export const Settings = () => {
|
|||||||
|
|
||||||
<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">
|
<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.isAlert && (
|
||||||
<Alert
|
<MyAlert type={alert.type} header={alert.header} text={alert.text} />
|
||||||
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 ? (
|
{settingsPending ? (
|
||||||
<div className="flex items-center justify-center py-16">
|
<div className="flex items-center justify-center py-16">
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { getStorages } from "../utils/api/storages";
|
import { getStorages } from "../utils/api/storages";
|
||||||
import {
|
import { Button, CircularProgress, Sheet, Table, Typography } from "@mui/joy";
|
||||||
Alert,
|
|
||||||
Button,
|
|
||||||
CircularProgress,
|
|
||||||
Sheet,
|
|
||||||
Table,
|
|
||||||
Typography,
|
|
||||||
} from "@mui/joy";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import type { AlertInterface, Storage } from "../misc/interfaces";
|
import type { AlertInterface, Storage } from "../misc/interfaces";
|
||||||
import type { ApiError } from "../utils/api/apiError";
|
import type { ApiError } from "../utils/api/apiError";
|
||||||
@@ -15,6 +8,7 @@ import { StorageRow } from "../components/StorageRow";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { AddStorageModal } from "../components/modals/AddStorageModal";
|
import { AddStorageModal } from "../components/modals/AddStorageModal";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
export const Storages = () => {
|
export const Storages = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -74,21 +68,13 @@ export const Storages = () => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert type={alert.type} header={alert.header} text={alert.text} />
|
||||||
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>
|
</div>
|
||||||
|
|
||||||
<Sheet
|
<Sheet
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
className="mt-6 flex min-h-0 flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm sm:h-[calc(100vh-260px)]"
|
className="mt-6 flex min-h-0 w-full max-w-full flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white/80 shadow-sm sm:h-[calc(100vh-260px)]"
|
||||||
>
|
>
|
||||||
<AddStorageModal isOpen={modal} setOpen={setModal} />
|
<AddStorageModal isOpen={modal} setOpen={setModal} />
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@@ -108,8 +94,9 @@ export const Storages = () => {
|
|||||||
stripe="odd"
|
stripe="odd"
|
||||||
variant="plain"
|
variant="plain"
|
||||||
hoverRow
|
hoverRow
|
||||||
className="min-w-240 text-slate-700"
|
className="w-full text-slate-700"
|
||||||
sx={{
|
sx={{
|
||||||
|
tableLayout: "fixed",
|
||||||
"--TableCell-headBackground":
|
"--TableCell-headBackground":
|
||||||
"var(--joy-palette-background-surface)",
|
"var(--joy-palette-background-surface)",
|
||||||
"& thead": {
|
"& thead": {
|
||||||
@@ -121,27 +108,41 @@ export const Storages = () => {
|
|||||||
"& thead tr": {
|
"& thead tr": {
|
||||||
backgroundColor: "rgb(248 250 252)",
|
backgroundColor: "rgb(248 250 252)",
|
||||||
},
|
},
|
||||||
"& thead th:nth-child(2)": {
|
|
||||||
width: "40%",
|
|
||||||
},
|
|
||||||
"& thead th:nth-child(3)": {
|
|
||||||
width: "14%",
|
|
||||||
},
|
|
||||||
"& thead th": {
|
"& thead th": {
|
||||||
zIndex: 2,
|
zIndex: 2,
|
||||||
backgroundColor: "rgb(248 250 252)",
|
backgroundColor: "rgb(248 250 252)",
|
||||||
backgroundImage: "none",
|
backgroundImage: "none",
|
||||||
},
|
},
|
||||||
"& tr > *:nth-child(n+4)": { textAlign: "left" },
|
"& thead th:nth-child(1)": {
|
||||||
|
width: "26%",
|
||||||
|
minWidth: "140px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(2)": {
|
||||||
|
width: "34%",
|
||||||
|
minWidth: "160px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(3)": {
|
||||||
|
width: "16%",
|
||||||
|
minWidth: "110px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(4)": {
|
||||||
|
width: "16%",
|
||||||
|
minWidth: "110px",
|
||||||
|
},
|
||||||
|
"& thead th:nth-child(5)": {
|
||||||
|
width: "8%",
|
||||||
|
minWidth: "80px",
|
||||||
|
},
|
||||||
|
"& tr > *:nth-child(n+3)": { textAlign: "left" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="text-slate-600">
|
<tr className="text-slate-600">
|
||||||
<th className="px-6 py-4">{t("storage-name")}</th>
|
<th className="px-3 py-4">{t("storage-name")}</th>
|
||||||
<th className="px-6 py-4">{t("description")}</th>
|
<th className="px-3 py-4">{t("description")}</th>
|
||||||
<th className="px-6 py-4">{t("created-at")}</th>
|
<th className="px-3 py-4">{t("created-at")}</th>
|
||||||
<th className="px-6 py-4">{t("updated-at")}</th>
|
<th className="px-3 py-4">{t("updated-at")}</th>
|
||||||
<th className="px-6 py-4 text-right"></th>
|
<th className="px-3 py-4 text-right"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { getStorages } from "../utils/api/storages.ts";
|
import { getStorages } from "../utils/api/storages.ts";
|
||||||
import {
|
import {
|
||||||
Alert,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
Chip,
|
Chip,
|
||||||
@@ -27,6 +26,7 @@ import type { ApiError } from "../utils/api/apiError";
|
|||||||
import QrCodeIcon from "@mui/icons-material/QrCode";
|
import QrCodeIcon from "@mui/icons-material/QrCode";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import QRCode from "qrcode";
|
import QRCode from "qrcode";
|
||||||
|
import { MyAlert } from "../components/MyAlert.tsx";
|
||||||
|
|
||||||
interface ViewProductProps {
|
interface ViewProductProps {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
@@ -369,28 +369,11 @@ export const ViewProduct = (props: ViewProductProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{alert.isAlert && (
|
{alert.isAlert && (
|
||||||
<Alert
|
<MyAlert
|
||||||
color={alert.type}
|
type={alert.type}
|
||||||
variant="soft"
|
header={alert.header}
|
||||||
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)]"
|
text={alert.text}
|
||||||
>
|
/>
|
||||||
{alert.header}
|
|
||||||
<br />
|
|
||||||
{alert.text}
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
{success && (
|
|
||||||
<Alert
|
|
||||||
color="success"
|
|
||||||
variant="soft"
|
|
||||||
className="rounded-2xl border border-emerald-200/70 bg-emerald-50/80 text-emerald-700 shadow-[0_14px_30px_rgba(16,185,129,0.18)]"
|
|
||||||
>
|
|
||||||
<div className="flex w-full items-center justify-between">
|
|
||||||
<Typography level="body-sm" className="text-emerald-700">
|
|
||||||
{t("success")}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
"success": "Erfolg",
|
"success": "Erfolg",
|
||||||
"submit": "Absenden",
|
"submit": "Absenden",
|
||||||
|
"logout-success-text": "Logout erfolgreich!",
|
||||||
"SU005": "Das Passwort wurde erfolgreich geändert!",
|
"SU005": "Das Passwort wurde erfolgreich geändert!",
|
||||||
"SE001": "Die Einstellungen wurden erfolgreich geändert!",
|
"SE001": "Die Einstellungen wurden erfolgreich geändert!",
|
||||||
"EG001": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.",
|
"EG001": "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut.",
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
"error": "Error",
|
"error": "Error",
|
||||||
"success": "Success",
|
"success": "Success",
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
|
"logout-success-text": "Logout successful!",
|
||||||
"SU005": "Your password is updated successfully!",
|
"SU005": "Your password is updated successfully!",
|
||||||
"SE001": "The settings are updated successfully!",
|
"SE001": "The settings are updated successfully!",
|
||||||
"EG001": "An unexpected error occurred. Please try again later.",
|
"EG001": "An unexpected error occurred. Please try again later.",
|
||||||
|
|||||||
Reference in New Issue
Block a user