u
This commit is contained in:
@@ -61,31 +61,36 @@ class EansDisplay extends Component {
|
||||
|
||||
class EansEdit extends Component {
|
||||
render() {
|
||||
const { draft, onChange, inputRef } = this.props;
|
||||
const { sku, draft, onChange, inputRef } = this.props;
|
||||
return (
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
multiple
|
||||
freeSolo
|
||||
options={[]}
|
||||
value={draft.eans ?? []}
|
||||
onChange={(_event, eans) => onChange({ eans })}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
inputRef={inputRef}
|
||||
label="EANs (Enter zum Hinzufügen)"
|
||||
size="small"
|
||||
slotProps={{
|
||||
...params.slotProps,
|
||||
inputLabel: {
|
||||
...params.slotProps?.inputLabel,
|
||||
shrink: true,
|
||||
},
|
||||
}}
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<PanelValue label="SKU">{sku}</PanelValue>
|
||||
<Box sx={{ mt: 3 }}>
|
||||
<Autocomplete
|
||||
fullWidth
|
||||
multiple
|
||||
freeSolo
|
||||
options={[]}
|
||||
value={draft.eans ?? []}
|
||||
onChange={(_event, eans) => onChange({ eans })}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
inputRef={inputRef}
|
||||
label="EANs (Enter zum Hinzufügen)"
|
||||
size="small"
|
||||
slotProps={{
|
||||
...params.slotProps,
|
||||
inputLabel: {
|
||||
...params.slotProps?.inputLabel,
|
||||
shrink: true,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +126,12 @@ export default class ArticleViewEANs extends PureComponent {
|
||||
canSave={eansDraftValid}
|
||||
display={<EansDisplay sku={articleData.sku} eans={value.eans} />}
|
||||
edit={({ draft, onChange, inputRef }) => (
|
||||
<EansEdit draft={draft} onChange={onChange} inputRef={inputRef} />
|
||||
<EansEdit
|
||||
sku={articleData.sku}
|
||||
draft={draft}
|
||||
onChange={onChange}
|
||||
inputRef={inputRef}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -40,6 +40,8 @@ const articlePriceTextSx = {
|
||||
|
||||
const articlePriceFieldSx = {
|
||||
flexShrink: 0,
|
||||
width: 'auto',
|
||||
mr: 11,
|
||||
'& .MuiOutlinedInput-root': {
|
||||
alignItems: 'baseline',
|
||||
flexShrink: 0,
|
||||
@@ -186,7 +188,6 @@ class PriceAmountField extends Component {
|
||||
onChange?.(event.target.value);
|
||||
}
|
||||
}
|
||||
fullWidth
|
||||
error={error}
|
||||
sx={readOnly ? articlePriceFieldHiddenSx : articlePriceFieldSx}
|
||||
slotProps={{
|
||||
|
||||
@@ -1,39 +1,210 @@
|
||||
import { Component, PureComponent } from 'react';
|
||||
import { PureComponent } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import WarehouseIcon from '@mui/icons-material/Warehouse';
|
||||
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
|
||||
import { PanelTile } from 'dashgui/panels';
|
||||
import { formatStock } from '../../../pages/artikel/searchFormat';
|
||||
|
||||
class PanelValue extends Component {
|
||||
render() {
|
||||
const { label, children } = this.props;
|
||||
if (children == null || children === '') return null;
|
||||
return (
|
||||
<Box sx={{ mb: 1 }}>
|
||||
{label ? (
|
||||
<Typography variant="caption" color="text.secondary" display="block">
|
||||
{label}
|
||||
</Typography>
|
||||
) : null}
|
||||
<Typography variant="body2" component="div">
|
||||
{children}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
import ArticleStockAdjustDialog from '../ArticleStockAdjustDialog';
|
||||
|
||||
const SECOND_ROW_MIN_HEIGHT = 220;
|
||||
|
||||
export default class ArticleViewStock extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
adjustOpen: false,
|
||||
};
|
||||
this.handleOpenAdjust = this.handleOpenAdjust.bind(this);
|
||||
this.handleCloseAdjust = this.handleCloseAdjust.bind(this);
|
||||
}
|
||||
|
||||
handleOpenAdjust() {
|
||||
this.setState({ adjustOpen: true });
|
||||
}
|
||||
|
||||
handleCloseAdjust() {
|
||||
this.setState({ adjustOpen: false });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { article: articleData } = this.props;
|
||||
const { adjustOpen } = this.state;
|
||||
const warehouses = Array.isArray(articleData?.warehouses)
|
||||
? articleData.warehouses
|
||||
: [];
|
||||
const hasWarehouses = warehouses.length > 0;
|
||||
|
||||
const totalStock = hasWarehouses
|
||||
? warehouses.reduce((sum, wh) => sum + (Number(wh.stock) || 0), 0)
|
||||
: articleData?.stock != null
|
||||
? Number(articleData.stock)
|
||||
: 0;
|
||||
|
||||
const rawUnit =
|
||||
articleData?.unit?.symbol ||
|
||||
articleData?.unit?.name ||
|
||||
'';
|
||||
const unit =
|
||||
rawUnit && !['stk', 'stück', 'pc', 'stk.'].includes(rawUnit.trim().toLowerCase())
|
||||
? rawUnit
|
||||
: '';
|
||||
|
||||
return (
|
||||
<PanelTile wide={1} minHeight={SECOND_ROW_MIN_HEIGHT} color="#bbf7d0">
|
||||
<PanelValue>
|
||||
{articleData.stock != null ? formatStock(articleData.stock) : null}
|
||||
</PanelValue>
|
||||
<>
|
||||
<PanelTile
|
||||
wide={1}
|
||||
minHeight={SECOND_ROW_MIN_HEIGHT}
|
||||
color="#bbf7d0"
|
||||
action={{
|
||||
label: 'Bestand anpassen',
|
||||
icon: EditOutlinedIcon,
|
||||
onClick: this.handleOpenAdjust,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
justifyContent: 'space-between',
|
||||
}}
|
||||
>
|
||||
{/* Top section: Headline and Total Stock */}
|
||||
<Box>
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.6,
|
||||
fontWeight: 600,
|
||||
display: 'block',
|
||||
}}
|
||||
>
|
||||
Bestand
|
||||
</Typography>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'baseline',
|
||||
gap: 0.75,
|
||||
my: 0.5,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
component="div"
|
||||
sx={{
|
||||
fontSize: '2.4rem',
|
||||
fontWeight: 700,
|
||||
lineHeight: 1.1,
|
||||
letterSpacing: '-0.02em',
|
||||
color: totalStock > 0 ? 'text.primary' : 'text.secondary',
|
||||
}}
|
||||
>
|
||||
{formatStock(totalStock)}
|
||||
</Typography>
|
||||
{unit ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{ fontWeight: 500 }}
|
||||
>
|
||||
{unit}
|
||||
</Typography>
|
||||
) : null}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Bottom section: Per-warehouse breakdown */}
|
||||
{hasWarehouses ? (
|
||||
<Box
|
||||
sx={{
|
||||
mt: 1,
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflowY: 'auto',
|
||||
pr: 0.5,
|
||||
'&::-webkit-scrollbar': { width: 4 },
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.15)',
|
||||
borderRadius: 2,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
|
||||
{warehouses.map((wh) => (
|
||||
<Box
|
||||
key={wh.id}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
py: 0.35,
|
||||
px: 0.75,
|
||||
borderRadius: 1,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.55)',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
minWidth: 0,
|
||||
mr: 1,
|
||||
}}
|
||||
>
|
||||
<WarehouseIcon
|
||||
sx={{
|
||||
fontSize: 15,
|
||||
color: 'text.secondary',
|
||||
mr: 0.5,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="body2"
|
||||
noWrap
|
||||
title={wh.name}
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
fontSize: '0.82rem',
|
||||
color: 'text.primary',
|
||||
}}
|
||||
>
|
||||
{wh.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{
|
||||
fontWeight: 700,
|
||||
fontSize: '0.82rem',
|
||||
flexShrink: 0,
|
||||
color:
|
||||
Number(wh.stock) > 0
|
||||
? 'text.primary'
|
||||
: 'text.secondary',
|
||||
}}
|
||||
>
|
||||
{formatStock(wh.stock)}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
) : null}
|
||||
</Box>
|
||||
</PanelTile>
|
||||
);
|
||||
}
|
||||
|
||||
<ArticleStockAdjustDialog
|
||||
open={adjustOpen}
|
||||
onClose={this.handleCloseAdjust}
|
||||
article={articleData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user