162 lines
4.5 KiB
JavaScript
162 lines
4.5 KiB
JavaScript
import { Component, PureComponent } from 'react';
|
|
import Autocomplete from '@mui/material/Autocomplete';
|
|
import TextField from '@mui/material/TextField';
|
|
import Typography from '@mui/material/Typography';
|
|
import Box from '@mui/material/Box';
|
|
import { EditablePanelTile } from '../../panels';
|
|
import { StorageManagerContext } from '../../../api/storageManagerContext';
|
|
import { requireDefined, requireObject } from '../../../utils/apiShape';
|
|
import { notifyError } from '../../../utils/notify';
|
|
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>
|
|
);
|
|
}
|
|
}
|
|
|
|
function brandDraftValue(article) {
|
|
return { name: article?.brand?.name ?? '' };
|
|
}
|
|
|
|
function brandDraftDirty(draft, saved) {
|
|
return String(draft.name ?? '').trim() !== String(saved.name ?? '').trim();
|
|
}
|
|
|
|
function brandDraftValid(draft) {
|
|
return String(draft.name ?? '').trim().length > 0;
|
|
}
|
|
|
|
const SECOND_ROW_MIN_HEIGHT = 220;
|
|
|
|
class BrandEdit extends Component {
|
|
render() {
|
|
const { draft, onChange, inputRef, brands } = this.props;
|
|
return (
|
|
<Autocomplete
|
|
fullWidth
|
|
freeSolo
|
|
options={brands}
|
|
value={draft.name ?? ''}
|
|
inputValue={draft.name ?? ''}
|
|
getOptionLabel={(option) =>
|
|
typeof option === 'string' ? option : String(option.name ?? '')
|
|
}
|
|
onInputChange={(_event, value) => onChange({ name: value })}
|
|
onChange={(_event, option) => {
|
|
onChange({ name: option ? String(option.name ?? '') : '' });
|
|
}}
|
|
renderInput={(params) => (
|
|
<TextField
|
|
{...params}
|
|
inputRef={inputRef}
|
|
label="Marke"
|
|
size="small"
|
|
slotProps={{ inputLabel: { shrink: true } }}
|
|
/>
|
|
)}
|
|
/>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default class ArticleViewBrand extends PureComponent {
|
|
static contextType = StorageManagerContext;
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
const brands = this.context?.brands;
|
|
this.state = {
|
|
brands: brands ?? [],
|
|
};
|
|
this._cancelled = false;
|
|
this._brandsReady = brands != null;
|
|
}
|
|
|
|
componentDidMount() {
|
|
this._cancelled = false;
|
|
if (this._brandsReady) return;
|
|
this.context.brandPromise
|
|
.then((list) => {
|
|
if (!this._cancelled) this.setState({ brands: list });
|
|
})
|
|
.catch((err) => {
|
|
if (!this._cancelled) notifyError(err);
|
|
});
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this._cancelled = true;
|
|
}
|
|
|
|
handleSave = async (draft) => {
|
|
const { article: articleData, onArticleUpdated } = this.props;
|
|
const store = this.context;
|
|
const { brands } = this.state;
|
|
const name = String(draft.name ?? '').trim();
|
|
if (!name) {
|
|
throw new Error('Bitte eine Marke angeben.');
|
|
}
|
|
|
|
const existing = brands.find(
|
|
(row) => String(row.name ?? '').toLowerCase() === name.toLowerCase(),
|
|
);
|
|
|
|
let brandId;
|
|
if (existing) {
|
|
brandId = existing.id;
|
|
} else {
|
|
const createdRes = await store.brand.upsert({ name });
|
|
requireObject(createdRes, 'PUT /api/brand');
|
|
requireObject(createdRes.brand, 'brand');
|
|
requireDefined(createdRes.brand.id, 'brand.id');
|
|
brandId = createdRes.brand.id;
|
|
const nextBrands = await store.updateBrand();
|
|
this.setState({ brands: nextBrands });
|
|
}
|
|
|
|
const res = await store.article.setBrand(articleData.sku, { brandId });
|
|
requireObject(res, 'PUT /api/article/:sku/brand');
|
|
requireObject(res.article, 'article');
|
|
onArticleUpdated?.(res.article);
|
|
};
|
|
|
|
render() {
|
|
const { article: articleData } = this.props;
|
|
const { brands } = this.state;
|
|
const value = brandDraftValue(articleData);
|
|
|
|
return (
|
|
<EditablePanelTile
|
|
wide={1}
|
|
minHeight={SECOND_ROW_MIN_HEIGHT}
|
|
color="#e9d5ff"
|
|
value={value}
|
|
onSave={this.handleSave}
|
|
isDirty={brandDraftDirty}
|
|
canSave={brandDraftValid}
|
|
display={<PanelValue>{value.name || null}</PanelValue>}
|
|
edit={({ draft, onChange, inputRef }) => (
|
|
<BrandEdit
|
|
brands={brands}
|
|
draft={draft}
|
|
onChange={onChange}
|
|
inputRef={inputRef}
|
|
/>
|
|
)}
|
|
/>
|
|
);
|
|
}
|
|
}
|