Added NewItemDialog without query connection.
This commit is contained in:
Binary file not shown.
@@ -149,5 +149,8 @@
|
|||||||
"imageUploadedSuccessfully": "Bild hochgeladen",
|
"imageUploadedSuccessfully": "Bild hochgeladen",
|
||||||
"uploading": "Lädt hoch...",
|
"uploading": "Lädt hoch...",
|
||||||
"upload": "Hochladen",
|
"upload": "Hochladen",
|
||||||
"imageUploadNoticeFs": "Die Auflösung der Farming Station beträgt 720 x 960 px"
|
"imageUploadNoticeFs": "Die Auflösung der Farming Station beträgt 720 x 960 px",
|
||||||
|
"itemCreatedSuccessfully": "Artikel erfolgreich erstellt",
|
||||||
|
"createNewItem": "Neuen Artikel erstellen",
|
||||||
|
"stockExpected": "Erwarteter Bestand"
|
||||||
}
|
}
|
||||||
@@ -149,5 +149,8 @@
|
|||||||
"imageUploadedSuccessfully": "Uploaded Image Successfully",
|
"imageUploadedSuccessfully": "Uploaded Image Successfully",
|
||||||
"uploading": "Uploading...",
|
"uploading": "Uploading...",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"imageUploadNoticeFs": "The Resolution of the Farming Station is 720 x 960 px"
|
"imageUploadNoticeFs": "The Resolution of the Farming Station is 720 x 960 px",
|
||||||
|
"itemCreatedSuccessfully": "Item created successfully",
|
||||||
|
"createNewItem": "Create New Item",
|
||||||
|
"stockExpected": "Expected Stock"
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,27 @@
|
|||||||
import DeleteIcon from "@mui/icons-material/Delete";
|
import DeleteIcon from "@mui/icons-material/Delete";
|
||||||
import EditIcon from "@mui/icons-material/Edit";
|
import EditIcon from "@mui/icons-material/Edit";
|
||||||
import {Box, Button, IconButton, Toolbar, useTheme} from "@mui/material";
|
import { Box, Button, IconButton, Toolbar, useTheme } from "@mui/material";
|
||||||
|
import { Gauge, gaugeClasses } from "@mui/x-charts";
|
||||||
|
import { DataGrid, GridColDef, GridRowId, GridRowSelectionModel } from "@mui/x-data-grid";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import Item from "../../components/Item";
|
import Item from "../../components/Item";
|
||||||
import {useTranslation} from "react-i18next";
|
|
||||||
import {DataGrid, GridColDef, GridRowId, GridRowSelectionModel} from "@mui/x-data-grid";
|
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
import {Gauge, gaugeClasses} from "@mui/x-charts";
|
|
||||||
import {useAccount} from "../AccountProvider.tsx";
|
|
||||||
import {useQuery} from "@tanstack/react-query";
|
|
||||||
import {fetchItems} from "../query/Queries.tsx";
|
|
||||||
import { mapValueToColor } from "../../util/ColorUtil.tsx";
|
import { mapValueToColor } from "../../util/ColorUtil.tsx";
|
||||||
|
import { useAccount } from "../AccountProvider.tsx";
|
||||||
|
import { fetchItems } from "../query/Queries.tsx";
|
||||||
import ItemImageDialog from "./ItemImageDialog.tsx";
|
import ItemImageDialog from "./ItemImageDialog.tsx";
|
||||||
|
import NewItemDialog from "./NewItemDialog.tsx";
|
||||||
|
|
||||||
export default function ItemsInfo() {
|
export default function ItemsInfo() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [rows, setRows] = useState<Item[]>([]);
|
const [rows, setRows] = useState<Item[]>([]);
|
||||||
const [selectedRows, setSelectedRows] = useState<Set<GridRowId>>(new Set());
|
const [selectedRows, setSelectedRows] = useState<Set<GridRowId>>(new Set());
|
||||||
|
|
||||||
const [editImageDialog, setEditImageDialog] = useState(false);
|
const [editImageDialog, setEditImageDialog] = useState(false);
|
||||||
|
const [newItemDialog, setNewItemDialog] = useState(false);
|
||||||
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
|
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
|
||||||
const [isFarmStationImage, setIsFarmStationImage] = useState(false);
|
const [isFarmStationImage, setIsFarmStationImage] = useState(false);
|
||||||
|
|
||||||
@@ -41,10 +43,10 @@ export default function ItemsInfo() {
|
|||||||
|
|
||||||
|
|
||||||
function handleAddItem() {
|
function handleAddItem() {
|
||||||
//TODO: flsp
|
setNewItemDialog(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const {user: loginData} = useAccount();
|
const { user: loginData } = useAccount();
|
||||||
|
|
||||||
const { data } = useQuery({
|
const { data } = useQuery({
|
||||||
queryKey: ["fetchItems", loginData],
|
queryKey: ["fetchItems", loginData],
|
||||||
@@ -73,7 +75,7 @@ export default function ItemsInfo() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const columns: GridColDef<(typeof rows)[number]>[] = [
|
const columns: GridColDef<(typeof rows)[number]>[] = [
|
||||||
{field: 'id', headerName: 'ID', width: 60},
|
{ field: 'id', headerName: 'ID', width: 60 },
|
||||||
{
|
{
|
||||||
field: 'uuid',
|
field: 'uuid',
|
||||||
headerName: t('uuid'),
|
headerName: t('uuid'),
|
||||||
@@ -123,7 +125,7 @@ export default function ItemsInfo() {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
renderCell: params => <Gauge value={Math.min(params.row.stock, params.row.stockExpected)} valueMin={0} valueMax={params.row.stockExpected} startAngle={-90} endAngle={90} sx={{
|
renderCell: params => <Gauge value={Math.min(params.row.stock, params.row.stockExpected)} valueMin={0} valueMax={params.row.stockExpected} startAngle={-90} endAngle={90} sx={{
|
||||||
[`& .${gaugeClasses.valueArc}`]: {
|
[`& .${gaugeClasses.valueArc}`]: {
|
||||||
fill: () => {return mapValueToColor(0, params.row.stockExpected, params.row.stock)},
|
fill: () => { return mapValueToColor(0, params.row.stockExpected, params.row.stock) },
|
||||||
},
|
},
|
||||||
}} text={() => `${params.row.stock}`} />
|
}} text={() => `${params.row.stock}`} />
|
||||||
},
|
},
|
||||||
@@ -135,7 +137,7 @@ export default function ItemsInfo() {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
renderCell: params => <Gauge value={Math.min(params.row.rating, 10)} valueMin={0} valueMax={10} startAngle={-90} endAngle={90} sx={{
|
renderCell: params => <Gauge value={Math.min(params.row.rating, 10)} valueMin={0} valueMax={10} startAngle={-90} endAngle={90} sx={{
|
||||||
[`& .${gaugeClasses.valueArc}`]: {
|
[`& .${gaugeClasses.valueArc}`]: {
|
||||||
fill: () => {return mapValueToColor(0, 10, params.row.rating)},
|
fill: () => { return mapValueToColor(0, 10, params.row.rating) },
|
||||||
},
|
},
|
||||||
}} text={() => `${params.row.rating.toFixed(2)}`} />
|
}} text={() => `${params.row.rating.toFixed(2)}`} />
|
||||||
},
|
},
|
||||||
@@ -144,21 +146,21 @@ export default function ItemsInfo() {
|
|||||||
headerName: t('actualPrice'),
|
headerName: t('actualPrice'),
|
||||||
width: 90,
|
width: 90,
|
||||||
editable: false,
|
editable: false,
|
||||||
valueGetter: (_, row) => (row.price100 / 100 * ((100-row.discount100)/100)).toFixed(2)
|
valueGetter: (_, row) => (row.price100 / 100 * ((100 - row.discount100) / 100)).toFixed(2)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'images',
|
field: 'images',
|
||||||
headerName: t('images'),
|
headerName: t('images'),
|
||||||
width: 90,
|
width: 90,
|
||||||
editable: false,
|
editable: false,
|
||||||
renderCell: params => <IconButton onClick={() => handleImageEdit(params.row)}> <EditIcon/> </IconButton>,
|
renderCell: params => <IconButton onClick={() => handleImageEdit(params.row)}> <EditIcon /> </IconButton>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'farmImage',
|
field: 'farmImage',
|
||||||
headerName: t('fsImage'),
|
headerName: t('fsImage'),
|
||||||
width: 90,
|
width: 90,
|
||||||
editable: false,
|
editable: false,
|
||||||
renderCell: params => <IconButton onClick={() => handleFarmImageEdit(params.row)}> <EditIcon/> </IconButton>,
|
renderCell: params => <IconButton onClick={() => handleFarmImageEdit(params.row)}> <EditIcon /> </IconButton>,
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -177,12 +179,13 @@ export default function ItemsInfo() {
|
|||||||
checkboxSelection
|
checkboxSelection
|
||||||
disableRowSelectionOnClick
|
disableRowSelectionOnClick
|
||||||
onRowSelectionModelChange={handleSelectionChange}
|
onRowSelectionModelChange={handleSelectionChange}
|
||||||
slots={{ toolbar: () => (
|
slots={{
|
||||||
|
toolbar: () => (
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="error"
|
color="error"
|
||||||
startIcon={<DeleteIcon/>}
|
startIcon={<DeleteIcon />}
|
||||||
onClick={handleDeleteSelected}
|
onClick={handleDeleteSelected}
|
||||||
disabled={selectedRows.size === 0}
|
disabled={selectedRows.size === 0}
|
||||||
sx={{
|
sx={{
|
||||||
@@ -194,9 +197,8 @@ export default function ItemsInfo() {
|
|||||||
<Button
|
<Button
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
startIcon={<DeleteIcon/>}
|
startIcon={<DeleteIcon />}
|
||||||
onClick={handleAddItem}
|
onClick={handleAddItem}
|
||||||
disabled={selectedRows.size === 0}
|
|
||||||
sx={{
|
sx={{
|
||||||
marginRight: 1
|
marginRight: 1
|
||||||
}}
|
}}
|
||||||
@@ -204,7 +206,8 @@ export default function ItemsInfo() {
|
|||||||
{t('addProduct')}
|
{t('addProduct')}
|
||||||
</Button>
|
</Button>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
)}}
|
)
|
||||||
|
}}
|
||||||
showToolbar
|
showToolbar
|
||||||
processRowUpdate={(updatedRow) => {
|
processRowUpdate={(updatedRow) => {
|
||||||
setRows(rows.map(row => row.id === updatedRow.id ? updatedRow : row));
|
setRows(rows.map(row => row.id === updatedRow.id ? updatedRow : row));
|
||||||
@@ -224,6 +227,11 @@ export default function ItemsInfo() {
|
|||||||
isFarmStationImage={isFarmStationImage}
|
isFarmStationImage={isFarmStationImage}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<NewItemDialog
|
||||||
|
open={newItemDialog}
|
||||||
|
onClose={() => setNewItemDialog(false)}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
157
01-frontend/src/helper/adminpanel/NewItemDialog.tsx
Normal file
157
01-frontend/src/helper/adminpanel/NewItemDialog.tsx
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
|
||||||
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
|
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
Box,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
IconButton,
|
||||||
|
TextField,
|
||||||
|
Typography
|
||||||
|
} from '@mui/material';
|
||||||
|
import { useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Item } from '../../components/Item';
|
||||||
|
|
||||||
|
interface NewItemDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NewItemDialog({ open, onClose }: NewItemDialogProps) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [item, setItem] = useState<Item>({
|
||||||
|
id: 0,
|
||||||
|
uuid: "",
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
price100: 0,
|
||||||
|
stock: 0,
|
||||||
|
stockExpected: 1,
|
||||||
|
category: "",
|
||||||
|
rating: -1,
|
||||||
|
discount100: 0,
|
||||||
|
});
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [success, setSuccess] = useState(false);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setError(null);
|
||||||
|
setSuccess(false);
|
||||||
|
setLoading(false);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setItem({ ...item, [e.target.name]: e.target.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
setSuccess(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<DialogTitle sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
{t('createNewItem')}
|
||||||
|
<IconButton onClick={handleClose} size="small">
|
||||||
|
<CloseIcon />
|
||||||
|
</IconButton>
|
||||||
|
</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent>
|
||||||
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2, py: 1 }}>
|
||||||
|
{/* Name, Kategorie, Beschreibung, Preis, Rabatt, Bestand, Bestand erwartet */}
|
||||||
|
<TextField
|
||||||
|
label={t("name")}
|
||||||
|
name="name"
|
||||||
|
value={item.name}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("category")}
|
||||||
|
name="category"
|
||||||
|
value={item.category}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("description")}
|
||||||
|
name="description"
|
||||||
|
value={item.description}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("price100")}
|
||||||
|
name="price100"
|
||||||
|
value={item.price100}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
type='number'
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("discount100")}
|
||||||
|
name="discount100"
|
||||||
|
value={item.discount100}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
type='number'
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("stockExpected")}
|
||||||
|
name="stockExpected"
|
||||||
|
value={item.stockExpected}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
type='number'
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label={t("stock")}
|
||||||
|
name="stock"
|
||||||
|
value={item.stock}
|
||||||
|
onChange={handleChange}
|
||||||
|
fullWidth
|
||||||
|
type='number'
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Error Message */}
|
||||||
|
{error && (
|
||||||
|
<Alert severity="error" onClose={() => setError(null)}>
|
||||||
|
{error}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Success Message */}
|
||||||
|
{success && (
|
||||||
|
<Alert severity="success">
|
||||||
|
{t('itemCreatedSuccessfully')}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</DialogContent>
|
||||||
|
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleSave} disabled={loading}>
|
||||||
|
{t('save')}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleClose} disabled={loading}>
|
||||||
|
{t('cancel')}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user