u
This commit is contained in:
@@ -8,9 +8,6 @@ import ListItem from '@mui/material/ListItem';
|
||||
import Stack from '@mui/material/Stack';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Chip from '@mui/material/Chip';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import DeleteOutlinedIcon from '@mui/icons-material/DeleteOutlined';
|
||||
import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
|
||||
import TuneIcon from '@mui/icons-material/Tune';
|
||||
@@ -47,12 +44,10 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
properties: initialProperties,
|
||||
propDrafts: draftsFrom(initialProperties, 'name'),
|
||||
newPropName: '',
|
||||
newPropExclusive: true,
|
||||
|
||||
attributes: initialAttributes,
|
||||
attrDrafts: draftsFrom(initialAttributes, 'name'),
|
||||
newAttrName: '',
|
||||
newAttrExclusive: true,
|
||||
selectedAttributeId: initialSelectedAttrId,
|
||||
|
||||
valDrafts: draftsFrom(
|
||||
@@ -333,13 +328,13 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleCreateProperty() {
|
||||
const name = this.state.newPropName.trim();
|
||||
if (!name || this.state.busyKey != null) return;
|
||||
if (!name) return;
|
||||
|
||||
this.setState({ busyKey: 'new-prop' });
|
||||
try {
|
||||
const row = await propertyAutomat.actions.createProperty({
|
||||
name,
|
||||
exclusive: this.state.newPropExclusive,
|
||||
exclusive: true,
|
||||
});
|
||||
if (this._cancelled) return;
|
||||
this.setState({ newPropName: '', busyKey: null });
|
||||
@@ -353,7 +348,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleTogglePropertyExclusive(prop, e) {
|
||||
e?.stopPropagation();
|
||||
if (this.state.busyKey != null) return;
|
||||
|
||||
const nextExclusive = !prop.exclusive;
|
||||
this.setState({ busyKey: `prop-ex-${prop.id}` });
|
||||
@@ -380,7 +374,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (draft === prop.name || this.state.busyKey != null) return;
|
||||
if (draft === prop.name) return;
|
||||
|
||||
this.setState({ busyKey: `prop-${prop.id}` });
|
||||
try {
|
||||
@@ -399,7 +393,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}
|
||||
|
||||
async handleDeleteProperty(prop) {
|
||||
if (this.state.busyKey != null) return;
|
||||
if (!window.confirm(`Merkmal „${prop.name}" wirklich löschen?`)) {
|
||||
return;
|
||||
}
|
||||
@@ -421,13 +414,13 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleCreateAttribute() {
|
||||
const name = this.state.newAttrName.trim();
|
||||
if (!name || this.state.busyKey != null) return;
|
||||
if (!name) return;
|
||||
|
||||
this.setState({ busyKey: 'new-attr' });
|
||||
try {
|
||||
const row = await attributeAutomat.actions.createAttribute({
|
||||
name,
|
||||
exclusive: this.state.newAttrExclusive,
|
||||
exclusive: true,
|
||||
});
|
||||
if (this._cancelled) return;
|
||||
this.setState({
|
||||
@@ -451,7 +444,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (draft === attr.name || this.state.busyKey != null) return;
|
||||
if (draft === attr.name) return;
|
||||
|
||||
this.setState({ busyKey: `attr-${attr.id}` });
|
||||
try {
|
||||
@@ -471,7 +464,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleToggleAttributeExclusive(attr, e) {
|
||||
e?.stopPropagation();
|
||||
if (this.state.busyKey != null) return;
|
||||
|
||||
const nextExclusive = !attr.exclusive;
|
||||
this.setState({ busyKey: `attr-ex-${attr.id}` });
|
||||
@@ -492,7 +484,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleDeleteAttribute(attr, e) {
|
||||
e?.stopPropagation();
|
||||
if (this.state.busyKey != null) return;
|
||||
if (!window.confirm(`Attribut „${attr.name}" und alle zugehörigen Werte wirklich löschen?`)) {
|
||||
return;
|
||||
}
|
||||
@@ -523,7 +514,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
|
||||
async handleCreateValue(attrId) {
|
||||
const text = this.state.newValText.trim();
|
||||
if (!text || this.state.busyKey != null || !attrId) return;
|
||||
if (!text || !attrId) return;
|
||||
|
||||
this.setState({ busyKey: 'new-val' });
|
||||
try {
|
||||
@@ -546,7 +537,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (draft === val.value || this.state.busyKey != null) return;
|
||||
if (draft === val.value) return;
|
||||
|
||||
this.setState({ busyKey: `val-${val.id}` });
|
||||
try {
|
||||
@@ -565,7 +556,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}
|
||||
|
||||
async handleDeleteValue(val) {
|
||||
if (this.state.busyKey != null) return;
|
||||
if (!window.confirm(`Wert „${val.value}" wirklich löschen?`)) {
|
||||
return;
|
||||
}
|
||||
@@ -591,18 +581,15 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
properties,
|
||||
propDrafts,
|
||||
newPropName,
|
||||
newPropExclusive,
|
||||
attributes,
|
||||
attrDrafts,
|
||||
newAttrName,
|
||||
newAttrExclusive,
|
||||
selectedAttributeId,
|
||||
valDrafts,
|
||||
newValText,
|
||||
busyKey,
|
||||
} = this.state;
|
||||
|
||||
const busy = busyKey != null;
|
||||
|
||||
if (attrStatus === 'loading' && propStatus === 'loading' && !properties.length && !attributes.length) {
|
||||
return (
|
||||
@@ -638,7 +625,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
||||
Auswahl-Merkmale
|
||||
</Typography>
|
||||
<Chip label={attributes.length} size="small" sx={{ ml: 'auto', fontWeight: 600, height: 20 }} />
|
||||
</Box>
|
||||
|
||||
<List dense disablePadding ref={this.attrListRef}>
|
||||
@@ -693,7 +679,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={attrDrafts[a.id] ?? ''}
|
||||
disabled={busy}
|
||||
onChange={(next) =>
|
||||
this.setState((prev) => ({
|
||||
attrDrafts: { ...prev.attrDrafts, [a.id]: next },
|
||||
@@ -717,34 +702,29 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
a.exclusive
|
||||
? 'Einzelauswahl (Artikel kann max. 1 Wert wählen)'
|
||||
: 'Mehrfachauswahl (Artikel kann mehrere Werte wählen)'
|
||||
}
|
||||
>
|
||||
<Chip
|
||||
label={a.exclusive ? '1x' : 'Multi'}
|
||||
<Chip
|
||||
label="Multi"
|
||||
size="small"
|
||||
color={a.exclusive ? 'primary' : 'default'}
|
||||
variant={a.exclusive ? 'filled' : 'outlined'}
|
||||
color={a.exclusive ? 'default' : 'success'}
|
||||
variant="filled"
|
||||
onClick={(e) => void this.handleToggleAttributeExclusive(a, e)}
|
||||
aria-pressed={!a.exclusive}
|
||||
sx={{
|
||||
height: 22,
|
||||
fontSize: '0.72rem',
|
||||
fontWeight: 600,
|
||||
cursor: 'pointer',
|
||||
flexShrink: 0,
|
||||
...(a.exclusive
|
||||
? { bgcolor: 'grey.300', color: 'text.secondary' }
|
||||
: null),
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<IconButton
|
||||
edge="end"
|
||||
size="small"
|
||||
aria-label={`„${a.name}" löschen`}
|
||||
disabled={busy}
|
||||
onClick={(e) => void this.handleDeleteAttribute(a, e)}
|
||||
sx={{ flexShrink: 0 }}
|
||||
>
|
||||
@@ -761,7 +741,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={newAttrName}
|
||||
disabled={busy}
|
||||
onChange={(next) => this.setState({ newAttrName: next })}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
@@ -774,29 +753,12 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={busy || !newAttrName.trim()}
|
||||
disabled={!newAttrName.trim()}
|
||||
onClick={() => void this.handleCreateAttribute()}
|
||||
>
|
||||
{busyKey === 'new-attr' ? '…' : 'Hinzufügen'}
|
||||
</Button>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
size="small"
|
||||
checked={newAttrExclusive}
|
||||
disabled={busy}
|
||||
onChange={(e) => this.setState({ newAttrExclusive: e.target.checked })}
|
||||
sx={{ p: 0.5 }}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Einzelauswahl (max. 1 Wert pro Artikel)
|
||||
</Typography>
|
||||
}
|
||||
sx={{ ml: 0.5, mt: -0.5 }}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</PanelTile>
|
||||
@@ -807,15 +769,8 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
<LabelImportantIcon sx={{ color: 'text.secondary', fontSize: 20 }} />
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
||||
{selectedAttr ? `Werte für „${selectedAttr.name}“` : 'Werte'}
|
||||
{selectedAttr ? `Werte für Auswahl-Merkmal „${selectedAttr.name}“` : 'Werte'}
|
||||
</Typography>
|
||||
{selectedAttr ? (
|
||||
<Chip
|
||||
label={selectedValues.length}
|
||||
size="small"
|
||||
sx={{ ml: 'auto', fontWeight: 600, height: 20 }}
|
||||
/>
|
||||
) : null}
|
||||
</Box>
|
||||
|
||||
{!selectedAttr ? (
|
||||
@@ -825,12 +780,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
) : (
|
||||
<>
|
||||
<List dense disablePadding ref={this.valListRef}>
|
||||
{selectedValues.length === 0 ? (
|
||||
<Typography variant="body2" color="text.secondary" sx={{ py: 1 }}>
|
||||
Noch keine Werte für „{selectedAttr.name}“ hinterlegt.
|
||||
</Typography>
|
||||
) : (
|
||||
selectedValues.map((v) => (
|
||||
{selectedValues.map((v) => (
|
||||
<ListItem
|
||||
key={v.id}
|
||||
disableGutters
|
||||
@@ -855,7 +805,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={valDrafts[v.id] ?? ''}
|
||||
disabled={busy}
|
||||
onChange={(next) =>
|
||||
this.setState((prev) => ({
|
||||
valDrafts: { ...prev.valDrafts, [v.id]: next },
|
||||
@@ -881,14 +830,12 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
edge="end"
|
||||
size="small"
|
||||
aria-label={`„${v.value}" löschen`}
|
||||
disabled={busy}
|
||||
onClick={() => void this.handleDeleteValue(v)}
|
||||
>
|
||||
<DeleteOutlinedIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</ListItem>
|
||||
))
|
||||
)}
|
||||
))}
|
||||
</List>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
||||
@@ -896,7 +843,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={newValText}
|
||||
disabled={busy}
|
||||
onChange={(next) => this.setState({ newValText: next })}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
@@ -909,7 +855,7 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={busy || !newValText.trim()}
|
||||
disabled={!newValText.trim()}
|
||||
onClick={() => void this.handleCreateValue(selectedAttr.id)}
|
||||
>
|
||||
{busyKey === 'new-val' ? '…' : 'Hinzufügen'}
|
||||
@@ -928,7 +874,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Typography variant="subtitle1" sx={{ fontWeight: 600 }}>
|
||||
Text-Merkmale
|
||||
</Typography>
|
||||
<Chip label={properties.length} size="small" sx={{ ml: 'auto', fontWeight: 600, height: 20 }} />
|
||||
</Box>
|
||||
|
||||
<List dense disablePadding ref={this.propListRef}>
|
||||
@@ -957,7 +902,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={propDrafts[p.id] ?? ''}
|
||||
disabled={busy}
|
||||
onChange={(next) =>
|
||||
this.setState((prev) => ({
|
||||
propDrafts: { ...prev.propDrafts, [p.id]: next },
|
||||
@@ -979,33 +923,28 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
}}
|
||||
sx={{ flex: 1 }}
|
||||
/>
|
||||
<Tooltip
|
||||
title={
|
||||
p.exclusive
|
||||
? 'Einzelauswahl (Artikel kann max. 1 Wert für dieses Merkmal haben)'
|
||||
: 'Mehrfachauswahl (Artikel kann mehrere Werte für dieses Merkmal haben)'
|
||||
}
|
||||
>
|
||||
<Chip
|
||||
label={p.exclusive ? '1x' : 'Multi'}
|
||||
<Chip
|
||||
label="Multi"
|
||||
size="small"
|
||||
color={p.exclusive ? 'primary' : 'default'}
|
||||
variant={p.exclusive ? 'filled' : 'outlined'}
|
||||
color={p.exclusive ? 'default' : 'success'}
|
||||
variant="filled"
|
||||
onClick={(e) => void this.handleTogglePropertyExclusive(p, e)}
|
||||
aria-pressed={!p.exclusive}
|
||||
sx={{
|
||||
height: 22,
|
||||
fontSize: '0.72rem',
|
||||
fontWeight: 600,
|
||||
cursor: 'pointer',
|
||||
flexShrink: 0,
|
||||
...(p.exclusive
|
||||
? { bgcolor: 'grey.300', color: 'text.secondary' }
|
||||
: null),
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
edge="end"
|
||||
size="small"
|
||||
aria-label={`„${p.name}" löschen`}
|
||||
disabled={busy}
|
||||
onClick={() => void this.handleDeleteProperty(p)}
|
||||
>
|
||||
<DeleteOutlinedIcon fontSize="small" />
|
||||
@@ -1020,7 +959,6 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
size="small"
|
||||
label=""
|
||||
value={newPropName}
|
||||
disabled={busy}
|
||||
onChange={(next) => this.setState({ newPropName: next })}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
@@ -1033,29 +971,12 @@ class ArtikelMerkmalePage extends PureComponent {
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
disabled={busy || !newPropName.trim()}
|
||||
disabled={!newPropName.trim()}
|
||||
onClick={() => void this.handleCreateProperty()}
|
||||
>
|
||||
{busyKey === 'new-prop' ? '…' : 'Hinzufügen'}
|
||||
</Button>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
size="small"
|
||||
checked={newPropExclusive}
|
||||
disabled={busy}
|
||||
onChange={(e) => this.setState({ newPropExclusive: e.target.checked })}
|
||||
sx={{ p: 0.5 }}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Einzelauswahl (max. 1 Wert pro Artikel)
|
||||
</Typography>
|
||||
}
|
||||
sx={{ ml: 0.5, mt: -0.5 }}
|
||||
/>
|
||||
</Box>
|
||||
</Stack>
|
||||
</PanelTile>
|
||||
|
||||
Reference in New Issue
Block a user