This commit is contained in:
seb
2026-10-02 08:24:42 +02:00
parent 20e53fee04
commit be111e8f7c
4 changed files with 71 additions and 18 deletions

View File

@@ -89,7 +89,6 @@ class BrandEdit extends Component {
<TextField <TextField
{...params} {...params}
inputRef={inputRef} inputRef={inputRef}
label="Marke"
size="small" size="small"
slotProps={{ slotProps={{
...params.slotProps, ...params.slotProps,
@@ -103,10 +102,6 @@ class BrandEdit extends Component {
params.slotProps?.input?.startAdornment params.slotProps?.input?.startAdornment
), ),
}, },
inputLabel: {
...params.slotProps?.inputLabel,
shrink: true,
},
}} }}
/> />
)} )}
@@ -183,6 +178,7 @@ export default class ArticleViewBrand extends PureComponent {
return ( return (
<EditablePanelTile <EditablePanelTile
title="Marke"
wide={1} wide={1}
minHeight={SECOND_ROW_MIN_HEIGHT} minHeight={SECOND_ROW_MIN_HEIGHT}
color="#e9d5ff" color="#e9d5ff"

View File

@@ -91,7 +91,6 @@ class EansDisplay extends Component {
const { sku, eans } = this.props; const { sku, eans } = this.props;
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<PanelValue label="SKU">{sku}</PanelValue>
<SkuBarcode value={sku} /> <SkuBarcode value={sku} />
{(eans ?? []).map((ean) => ( {(eans ?? []).map((ean) => (
<PanelValue key={ean} label="EAN"> <PanelValue key={ean} label="EAN">
@@ -108,7 +107,6 @@ class EansEdit extends Component {
const { sku, draft, onChange, inputRef } = this.props; const { sku, draft, onChange, inputRef } = this.props;
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<PanelValue label="SKU">{sku}</PanelValue>
<SkuBarcode value={sku} /> <SkuBarcode value={sku} />
<Box sx={{ mt: 2 }}> <Box sx={{ mt: 2 }}>
<Autocomplete <Autocomplete
@@ -160,6 +158,7 @@ export default class ArticleViewEANs extends PureComponent {
return ( return (
<EditablePanelTile <EditablePanelTile
title={articleData.sku}
wide={1} wide={1}
minHeight={SECOND_ROW_MIN_HEIGHT} minHeight={SECOND_ROW_MIN_HEIGHT}
color="#e2e8f0" color="#e2e8f0"

View File

@@ -8,6 +8,7 @@ import AccountTreeIcon from '@mui/icons-material/AccountTree';
import SettingsIcon from '@mui/icons-material/Settings'; import SettingsIcon from '@mui/icons-material/Settings';
import PointOfSaleIcon from '@mui/icons-material/PointOfSale'; import PointOfSaleIcon from '@mui/icons-material/PointOfSale';
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera'; import PhotoCameraIcon from '@mui/icons-material/PhotoCamera';
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
import ThumbHashImage from '../article/ThumbHashImage'; import ThumbHashImage from '../article/ThumbHashImage';
import { thumb } from '../../api'; import { thumb } from '../../api';
import { tileBaseSx } from 'dashgui/tiles'; import { tileBaseSx } from 'dashgui/tiles';
@@ -20,6 +21,7 @@ import { tileBaseSx } from 'dashgui/tiles';
function TopBand({ onSettingsClick, settingsTab, terminalCount, onPlacementClick }) { function TopBand({ onSettingsClick, settingsTab, terminalCount, onPlacementClick }) {
const isTerminalMode = settingsTab >= 0 && settingsTab < terminalCount; const isTerminalMode = settingsTab >= 0 && settingsTab < terminalCount;
const isPhotoMode = settingsTab === -2; const isPhotoMode = settingsTab === -2;
const isDeleteMode = settingsTab === -3;
const handleSx = { const handleSx = {
position: 'absolute', position: 'absolute',
@@ -61,13 +63,19 @@ function TopBand({ onSettingsClick, settingsTab, terminalCount, onPlacementClick
...handleSx, ...handleSx,
left: '50%', left: '50%',
transform: 'translate(-50%, -50%)', transform: 'translate(-50%, -50%)',
color: isTerminalMode || isPhotoMode ? 'primary.main' : 'common.white', color: isDeleteMode
? 'error.main'
: isTerminalMode || isPhotoMode
? 'primary.main'
: 'common.white',
}} }}
> >
{isTerminalMode ? ( {isTerminalMode ? (
<PointOfSaleIcon sx={{ fontSize: 28 }} /> <PointOfSaleIcon sx={{ fontSize: 28 }} />
) : isPhotoMode ? ( ) : isPhotoMode ? (
<PhotoCameraIcon sx={{ fontSize: 28 }} /> <PhotoCameraIcon sx={{ fontSize: 28 }} />
) : isDeleteMode ? (
<DeleteOutlinedIcon sx={{ fontSize: 28 }} />
) : ( ) : (
<SettingsIcon sx={{ fontSize: 28 }} /> <SettingsIcon sx={{ fontSize: 28 }} />
)} )}
@@ -94,7 +102,8 @@ function TopBand({ onSettingsClick, settingsTab, terminalCount, onPlacementClick
/** /**
* Middle row (1/3): gray band — TextField or terminal toggle. * Middle row (1/3): gray band — TextField or terminal toggle.
*/ */
function MiddleBand({ settingsTab, nameInput, terminals, categoryPosterminalIds, onTerminalToggle, onPhotoUpload, onPhotoDelete, fullHash }) { function MiddleBand({ settingsTab, nameInput, terminals, categoryPosterminalIds, onTerminalToggle, fullHash }) {
const isActionTab = settingsTab === -2 || settingsTab === -3;
const fillSx = { const fillSx = {
width: '100%', width: '100%',
height: '100%', height: '100%',
@@ -103,6 +112,13 @@ function MiddleBand({ settingsTab, nameInput, terminals, categoryPosterminalIds,
justifyContent: 'center', justifyContent: 'center',
bgcolor: 'grey.300', bgcolor: 'grey.300',
px: 1, px: 1,
...(isActionTab
? {
'&:hover': {
bgcolor: settingsTab === -3 ? 'rgba(211, 47, 47, 0.12)' : 'grey.400',
},
}
: {}),
}; };
// Show terminal-specific toggle when on a terminal tab // Show terminal-specific toggle when on a terminal tab
@@ -139,9 +155,27 @@ function MiddleBand({ settingsTab, nameInput, terminals, categoryPosterminalIds,
<Typography <Typography
variant="caption" variant="caption"
noWrap noWrap
sx={{ maxWidth: 80, color: 'text.secondary' }} sx={{ maxWidth: 100, color: 'text.secondary' }}
> >
{fullHash ? 'Löschen' : 'Hochladen'} {fullHash ? 'Bild löschen' : 'Hochladen'}
</Typography>
</Box>
</Box>
);
}
// Show category deletion UI when on delete tab
if (settingsTab === -3) {
return (
<Box sx={fillSx}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<DeleteOutlinedIcon sx={{ fontSize: 20, color: 'error.main' }} />
<Typography
variant="caption"
noWrap
sx={{ maxWidth: 120, color: 'error.main', fontWeight: 600 }}
>
Kategorie löschen
</Typography> </Typography>
</Box> </Box>
</Box> </Box>
@@ -218,7 +252,7 @@ class CategoryBackdrop extends PureComponent {
* lower half = gray band with chevrons + delete * lower half = gray band with chevrons + delete
*/ */
export class CategoryTile extends Component { export class CategoryTile extends Component {
state = { settingsTab: -1 }; // -1 = rename, -2 = photo, 0..n-1 = terminal index state = { settingsTab: -1 }; // -1 = rename, -2 = photo, -3 = delete, 0..n-1 = terminal index
handleClick = () => { handleClick = () => {
this.props.onClick?.(); this.props.onClick?.();
@@ -235,22 +269,33 @@ export class CategoryTile extends Component {
const { terminals } = this.props; const { terminals } = this.props;
const terminalCount = terminals?.length || 0; const terminalCount = terminals?.length || 0;
this.setState((prev) => { this.setState((prev) => {
const next = prev.settingsTab + 1; let nextTab;
// Cycle: photo (-2) → rename (-1) → terminal 0 → ... → terminal n-1 → photo (-2) if (prev.settingsTab === -1) {
const nextTab = next >= terminalCount ? -2 : next; nextTab = terminalCount > 0 ? 0 : -2;
} else if (prev.settingsTab >= 0 && prev.settingsTab < terminalCount - 1) {
nextTab = prev.settingsTab + 1;
} else if (prev.settingsTab === terminalCount - 1 || prev.settingsTab >= 0) {
nextTab = -2;
} else if (prev.settingsTab === -2) {
nextTab = -3;
} else {
nextTab = -1;
}
return { settingsTab: nextTab }; return { settingsTab: nextTab };
}); });
}; };
handleMiddleBandClick = () => { handleMiddleBandClick = () => {
const { settingsTab } = this.state; const { settingsTab } = this.state;
const { onPhotoUpload, onPhotoDelete, fullHash } = this.props; const { onPhotoUpload, onPhotoDelete, fullHash, onDelete } = this.props;
if (settingsTab === -2) { if (settingsTab === -2) {
if (fullHash) { if (fullHash) {
onPhotoDelete?.(); onPhotoDelete?.();
} else { } else {
onPhotoUpload?.(); onPhotoUpload?.();
} }
} else if (settingsTab === -3) {
onDelete?.();
} }
}; };
@@ -302,6 +347,7 @@ export class CategoryTile extends Component {
onPhotoDelete, onPhotoDelete,
onPlacementClick, onPlacementClick,
onOpen, onOpen,
onDelete,
...rest ...rest
} = this.props; } = this.props;
const { settingsTab } = this.state; const { settingsTab } = this.state;
@@ -328,7 +374,7 @@ export class CategoryTile extends Component {
bottom: '33.33%', bottom: '33.33%',
left: 0, left: 0,
right: 0, right: 0,
cursor: settingsTab === -2 ? 'pointer' : 'default', cursor: settingsTab === -2 || settingsTab === -3 ? 'pointer' : 'default',
}} }}
> >
<MiddleBand <MiddleBand

View File

@@ -1,4 +1,4 @@
import { Component, PureComponent, createRef } from 'react'; import { PureComponent, createRef } from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
@@ -320,6 +320,17 @@ class ArtikelKategorienPage extends PureComponent {
if (path) this.props.navigate(path); if (path) this.props.navigate(path);
}; };
handleDeleteCategory = async (cat) => {
const name = cat.name || `Kategorie #${cat.id}`;
if (!window.confirm(`Kategorie „${name}“ wirklich löschen?`)) return;
try {
await categoryAutomat.actions.deleteCategory(cat.id);
enqueueSnackbar(`Kategorie „${name}“ gelöscht.`, { variant: 'success' });
} catch (err) {
notifyError(err);
}
};
render() { render() {
const { const {
companyId, companyId,
@@ -462,6 +473,7 @@ class ArtikelKategorienPage extends PureComponent {
void categoryAutomat.actions.deleteCategoryImage(item.id) void categoryAutomat.actions.deleteCategoryImage(item.id)
.catch(notifyError); .catch(notifyError);
}, },
onDelete: () => this.handleDeleteCategory(item),
nameInput: ( nameInput: (
<TextField <TextField
value={draftName} value={draftName}