diff --git a/00-backend/datasource/database.sqlite b/00-backend/datasource/database.sqlite index 6049a25..3ed449b 100644 Binary files a/00-backend/datasource/database.sqlite and b/00-backend/datasource/database.sqlite differ diff --git a/01-frontend/public/locales/de/translation.json b/01-frontend/public/locales/de/translation.json index d0d83b1..1ec3081 100644 --- a/01-frontend/public/locales/de/translation.json +++ b/01-frontend/public/locales/de/translation.json @@ -102,6 +102,11 @@ "surname": "Nachname", "language": "Sprache", "password": "Passwort", - "adminize": "Admin ernennen", - "unadminize": "Admin abernennen", + "actualPrice": "Endpreis in €", + "stock": "Bestand", + "price100": "Preis in ct", + "discount100": "Rabatt in %", + "deleteProduct": "Produkt löschen", + "description": "Beschreibung", + "images": "Bilder" } diff --git a/01-frontend/public/locales/en/translation.json b/01-frontend/public/locales/en/translation.json index 98eb829..baac535 100644 --- a/01-frontend/public/locales/en/translation.json +++ b/01-frontend/public/locales/en/translation.json @@ -102,6 +102,11 @@ "surname": "Surname", "language": "Language", "password": "Password", - "adminize": "Make Admin", - "unadminize": "Revoke Admin" + "actualPrice": "Price in €", + "stock": "Stock", + "price100": "Price in ct", + "discount100": "Discount in %", + "deleteProduct": "Delete Product", + "description": "Description", + "images": "Images" } \ No newline at end of file diff --git a/01-frontend/src/components/Item.tsx b/01-frontend/src/components/Item.tsx index 8c1ddd9..81895ca 100644 --- a/01-frontend/src/components/Item.tsx +++ b/01-frontend/src/components/Item.tsx @@ -5,6 +5,7 @@ type Item = { description: string; price100: number; stock: number; + stockExpected: number; category: string; rating: number; discount100: number; diff --git a/01-frontend/src/helper/adminpanel/ItemsInfo.tsx b/01-frontend/src/helper/adminpanel/ItemsInfo.tsx index c233e0d..ed5ae6c 100644 --- a/01-frontend/src/helper/adminpanel/ItemsInfo.tsx +++ b/01-frontend/src/helper/adminpanel/ItemsInfo.tsx @@ -1,27 +1,199 @@ -import { Typography, Box, useTheme } from "@mui/material"; +import DeleteIcon from "@mui/icons-material/Delete"; +import EditIcon from "@mui/icons-material/Edit"; +import {Box, Button, IconButton, Toolbar, useTheme} from "@mui/material"; +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} from "@mui/x-charts"; -export default function ItemInfo() { +export default function ItemsInfo() { const theme = useTheme(); + const {t} = useTranslation(); + + //TODO: add colors to gauges for rating adn stock + function mapValueToColor(minVal: number, maxVal: number, actualVal: number): string { + const clamped = Math.min(Math.max(actualVal, minVal), maxVal); + + // Calculate interpolation ratio (0-1) + const ratio = maxVal !== minVal + ? (clamped - minVal) / (maxVal - minVal) + : 0; + + const red = Math.floor(255 * (1 - ratio)); + const green = Math.floor(255 * ratio) + + const redHex = red.toString(16).padStart(2, '0').toUpperCase(); + const greenHex = green.toString(16).padStart(2, '0').toUpperCase(); + + return `#${redHex}${greenHex}00`; // Blue is always 00 + } + + function handleIconEdit(item: Item) { + //TODO: implement + console.log("IconEdit", item); + } + + const _rows: Item[] = [ + { + id: "1", + uuid: "uuid123", + name: "Item", + description: "Super duper geil wichtiger text ", + price100: 1000, + stock: 100, + stockExpected: 1200, + category: "garden", + rating: 5, + discount100: 21, + }, + { + id: "2", + uuid: "uuid12312412", + name: "Schlauch", + description: "Schlauchiger Schlauch für Schlauchige Angelegenheiten", + price100: 10, + stock: 50, + stockExpected: 100, + category: "technicalComponents", + rating: 10, + discount100: 21, + }, + ] + + //TODO: get per REST + const [rows, setRows] = useState(_rows); + const [selectedRows, setSelectedRows] = useState>(new Set()); + + const handleSelectionChange = (newSelection: GridRowSelectionModel) => { + setSelectedRows(newSelection.ids); + }; + + const handleDeleteSelected = async () => { + selectedRows.forEach((row) => { + //TODO: send delete command, or send deleteall + console.log(row); + }) + + setRows(rows.filter((row) => !selectedRows.has(row.id))); + }; + + const columns: GridColDef<(typeof rows)[number]>[] = [ + {field: 'id', headerName: 'ID', width: 60}, + { + field: 'uuid', + headerName: "UUID", + type: "string", + width: 120, + editable: true + }, + { + field: 'name', + headerName: t('name'), + width: 150, + editable: true, + }, + { + field: 'category', + headerName: t('category'), + width: 150, + editable: true, + }, + { + field: 'description', + headerName: t('description'), + width: 150, + editable: true, + }, + { + field: 'price100', + headerName: t('price100'), + width: 100, + editable: true, + type: 'number' + }, + { + field: 'discount100', + headerName: t('discount100'), + width: 120, + editable: true, + type: 'number' + }, + { + field: 'stock', + headerName: t('stock'), + width: 100, + editable: true, + type: 'number', + renderCell: params => + }, + { + field: 'rating', + headerName: t('rating'), + width: 100, + editable: true, + type: 'number', + renderCell: params => + }, + { //edit billing information button + field: "actualPrice", + headerName: t('actualPrice'), + width: 90, + editable: false, + valueGetter: (_, row) => (row.price100 / 100 * ((100-row.discount100)/100)).toFixed(2) + }, + { + field: 'images', + headerName: t('images'), + width: 90, + editable: false, + renderCell: params => handleIconEdit(params.row)}> , + } + ]; + + useEffect(() => { + console.log(mapValueToColor(0,10,2)) + console.log(mapValueToColor(0,10,7)) + }, []); return ( - - 🚧 Under construction... - + ( + + + + )}} + showToolbar + processRowUpdate={(updatedRow, originalRow) => { + setRows(rows.map(row => row.id === updatedRow.id ? updatedRow : row)); + //TODO: make REST callback + return updatedRow; + }} + /> ); }