This commit is contained in:
seb
2026-10-08 04:41:27 +02:00
parent ab2e8c92fb
commit b01ebccf90
6 changed files with 796 additions and 362 deletions

View File

@@ -39,6 +39,8 @@ import articleIndexAutomat from '../../../automats/articleIndexAutomat';
import {
MAGENTA_PANEL,
SHADOW_CARD,
WHITE,
alpha,
} from '../../../colors';
export default class ArticleViewLists extends PureComponent {
@@ -1095,9 +1097,21 @@ export default class ArticleViewLists extends PureComponent {
assignedMatch?.attributeValue ||
null;
const siblings = (parentArticle?.children || []).filter(
(c) => c.sku !== articleData.sku && c.id !== articleData.id
const childrenList = parentArticle?.children || [];
const hasSelf = childrenList.some(
(c) => c.sku === articleData.sku || (articleData.id != null && c.id === articleData.id)
);
const siblings = hasSelf
? childrenList
: [
...childrenList,
{
id: articleData.id,
sku: articleData.sku,
name: articleData.name,
attributeValue: variationValue,
},
];
return (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1, flex: 1, minHeight: 0 }}>
@@ -1206,10 +1220,10 @@ export default class ArticleViewLists extends PureComponent {
</Box>
</Box>
{/* Link(s) Geschwister */}
{/* Varianten */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.4, mt: 0.5 }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: 'text.secondary' }}>
Geschwister:
Varianten:
</Typography>
{siblings.length === 0 ? (
<Typography variant="body2" color="text.secondary" sx={{ py: 0.5, fontSize: '0.8rem' }}>
@@ -1217,82 +1231,131 @@ export default class ArticleViewLists extends PureComponent {
</Typography>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
{siblings.map((sibling) => (
<Box
key={sibling.id || sibling.sku}
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 1,
py: 0.6,
borderRadius: 1,
bgcolor: 'background.paper',
border: '1px solid',
borderColor: 'divider',
transition: 'all 0.15s ease-in-out',
'&:hover': {
borderColor: 'primary.main',
boxShadow: SHADOW_CARD,
},
}}
>
<Link
component={RouterLink}
to={artikelDetailPath(sibling.sku)}
{siblings.map((sibling) => {
const isSelf =
sibling.sku === articleData.sku ||
(articleData.id != null && sibling.id === articleData.id);
return (
<Box
key={sibling.id || sibling.sku}
sx={{
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
textDecoration: 'none',
color: 'inherit',
py: 0.25,
cursor: 'pointer',
'&:hover .child-name': {
color: 'primary.main',
},
'&:hover .child-sku': {
color: 'primary.dark',
textDecoration: 'underline',
},
alignItems: 'center',
justifyContent: 'space-between',
px: 1,
py: 0.6,
borderRadius: 1,
bgcolor: isSelf ? alpha(WHITE, 0.6) : 'background.paper',
border: '1px solid',
borderColor: 'divider',
transition: 'all 0.15s ease-in-out',
...(!isSelf && {
'&:hover': {
borderColor: 'primary.main',
boxShadow: SHADOW_CARD,
},
}),
}}
>
<Typography
className="child-name"
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
transition: 'color 0.15s ease',
}}
>
{sibling.attributeValue || sibling.name || sibling.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
className="child-sku"
variant="caption"
{isSelf ? (
<Box
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'primary.main',
fontFamily: 'monospace',
letterSpacing: '0.02em',
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
py: 0.25,
}}
>
{sibling.sku}
</Typography>
<OpenInNewIcon sx={{ fontSize: 13, color: 'primary.main', opacity: 0.8 }} />
</Box>
</Link>
</Box>
))}
<Typography
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
}}
>
{sibling.attributeValue || variationValue || sibling.name || sibling.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
variant="caption"
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'text.secondary',
fontFamily: 'monospace',
letterSpacing: '0.02em',
}}
>
{sibling.sku}
</Typography>
</Box>
</Box>
) : (
<Link
component={RouterLink}
to={artikelDetailPath(sibling.sku)}
sx={{
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
textDecoration: 'none',
color: 'inherit',
py: 0.25,
cursor: 'pointer',
'&:hover .child-name': {
color: 'primary.main',
},
'&:hover .child-sku': {
color: 'primary.dark',
textDecoration: 'underline',
},
}}
>
<Typography
className="child-name"
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
transition: 'color 0.15s ease',
}}
>
{sibling.attributeValue || sibling.name || sibling.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
className="child-sku"
variant="caption"
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'primary.main',
fontFamily: 'monospace',
letterSpacing: '0.02em',
}}
>
{sibling.sku}
</Typography>
<OpenInNewIcon sx={{ fontSize: 13, color: 'primary.main', opacity: 0.8 }} />
</Box>
</Link>
)}
</Box>
);
})}
</Box>
)}
</Box>
@@ -1510,6 +1573,176 @@ export default class ArticleViewLists extends PureComponent {
) : null}
</Box>
{/* Vaterartikel */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.4, mt: 0.25 }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: 'text.secondary' }}>
Vaterartikel:
</Typography>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 1,
py: 0.6,
borderRadius: 1,
bgcolor: alpha(WHITE, 0.6),
border: '1px solid',
borderColor: 'divider',
}}
>
<Box
sx={{
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
py: 0.25,
}}
>
<Typography
className="link-title"
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
}}
>
{articleData.name || articleData.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
className="link-sku"
variant="caption"
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'text.secondary',
fontFamily: 'monospace',
letterSpacing: '0.02em',
}}
>
{articleData.sku}
</Typography>
</Box>
</Box>
</Box>
</Box>
{/* Varianten */}
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.4, mt: 0.5 }}>
<Typography variant="caption" sx={{ fontWeight: 600, color: 'text.secondary' }}>
Varianten:
</Typography>
{children.length === 0 ? (
<Typography variant="body2" color="text.secondary" sx={{ py: 1, fontSize: '0.8rem' }}>
Noch keine Varianten angelegt.
</Typography>
) : (
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5 }}>
{children.map((child) => (
<Box
key={child.id || child.sku}
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 1,
py: 0.6,
borderRadius: 1,
bgcolor: 'background.paper',
border: '1px solid',
borderColor: 'divider',
transition: 'all 0.15s ease-in-out',
'&:hover': {
borderColor: 'primary.main',
boxShadow: SHADOW_CARD,
},
}}
>
<Link
component={RouterLink}
to={artikelDetailPath(child.sku)}
sx={{
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
textDecoration: 'none',
color: 'inherit',
py: 0.25,
mr: 1,
cursor: 'pointer',
'&:hover .child-name': {
color: 'primary.main',
},
'&:hover .child-sku': {
color: 'primary.dark',
textDecoration: 'underline',
},
}}
>
<Typography
className="child-name"
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
transition: 'color 0.15s ease',
}}
>
{child.attributeValue || child.name || child.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
className="child-sku"
variant="caption"
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'primary.main',
fontFamily: 'monospace',
letterSpacing: '0.02em',
display: 'inline-flex',
alignItems: 'center',
gap: 0.35,
}}
>
{child.sku}
</Typography>
<OpenInNewIcon sx={{ fontSize: 13, color: 'primary.main', opacity: 0.8 }} />
</Box>
</Link>
<IconButton
size="small"
disabled={busy}
onClick={() => this.handleOpenRemoveDialog(child)}
title="Variante entfernen"
sx={{
p: 0.35,
color: 'text.secondary',
'&:hover': { color: 'error.main' },
}}
>
<DeleteOutlinedIcon sx={{ fontSize: 17 }} />
</IconButton>
</Box>
))}
</Box>
)}
</Box>
{/* Add Child Variant Row */}
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mt: 0.5 }}>
{isCustomChildValue || availableParentValues.length === 0 ? (
@@ -1533,7 +1766,17 @@ export default class ArticleViewLists extends PureComponent {
label="Variante"
value={selectedChildValueId}
disabled={busy}
onChange={(e) => this.setState({ selectedChildValueId: e.target.value })}
onChange={(e) => {
if (e.target.value === '__custom__') {
this.setState({
isCustomChildValue: true,
selectedChildValueId: '',
newChildText: '',
});
} else {
this.setState({ selectedChildValueId: e.target.value });
}
}}
sx={{ flex: 1, minWidth: 0 }}
>
<MenuItem value="" disabled>
@@ -1544,6 +1787,9 @@ export default class ArticleViewLists extends PureComponent {
{v.value}
</MenuItem>
))}
<MenuItem value="__custom__">
<em>+ Neuer Wert...</em>
</MenuItem>
</TextInput>
)}
@@ -1597,117 +1843,6 @@ export default class ArticleViewLists extends PureComponent {
</Link>
</Box>
) : null}
{/* Children List */}
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 0.5,
mt: 0.5,
}}
>
{children.length === 0 ? (
<Typography variant="body2" color="text.secondary" sx={{ py: 1, fontSize: '0.8rem' }}>
Noch keine Varianten angelegt.
</Typography>
) : (
children.map((child) => (
<Box
key={child.id || child.sku}
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
px: 1,
py: 0.6,
borderRadius: 1,
bgcolor: 'background.paper',
border: '1px solid',
borderColor: 'divider',
transition: 'all 0.15s ease-in-out',
'&:hover': {
borderColor: 'primary.main',
boxShadow: SHADOW_CARD,
},
}}
>
<Link
component={RouterLink}
to={artikelDetailPath(child.sku)}
sx={{
minWidth: 0,
flex: 1,
display: 'flex',
flexDirection: 'column',
textDecoration: 'none',
color: 'inherit',
py: 0.25,
mr: 1,
cursor: 'pointer',
'&:hover .child-name': {
color: 'primary.main',
},
'&:hover .child-sku': {
color: 'primary.dark',
textDecoration: 'underline',
},
}}
>
<Typography
className="child-name"
variant="body2"
sx={{
fontWeight: 600,
fontSize: '0.86rem',
lineHeight: 1.3,
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
color: 'text.primary',
transition: 'color 0.15s ease',
}}
>
{child.attributeValue || child.name || child.sku}
</Typography>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.4, mt: 0.2 }}>
<Typography
className="child-sku"
variant="caption"
sx={{
fontSize: '0.78rem',
fontWeight: 600,
color: 'primary.main',
fontFamily: 'monospace',
letterSpacing: '0.02em',
display: 'inline-flex',
alignItems: 'center',
gap: 0.35,
}}
>
{child.sku}
</Typography>
<OpenInNewIcon sx={{ fontSize: 13, color: 'primary.main', opacity: 0.8 }} />
</Box>
</Link>
<IconButton
size="small"
disabled={busy}
onClick={() => this.handleOpenRemoveDialog(child)}
title="Variante entfernen"
sx={{
p: 0.35,
color: 'text.secondary',
'&:hover': { color: 'error.main' },
}}
>
<DeleteOutlinedIcon sx={{ fontSize: 17 }} />
</IconButton>
</Box>
))
)}
</Box>
</Box>
) : isChild && parentSku ? (
/* ── Mode 2: Child Variant Article ───────────────────────────────── */