295 lines
8.6 KiB
JavaScript
295 lines
8.6 KiB
JavaScript
import { Component } from 'react';
|
|
import Box from '@mui/material/Box';
|
|
import Button from '@mui/material/Button';
|
|
import Tab from '@mui/material/Tab';
|
|
import Tabs from '@mui/material/Tabs';
|
|
import Typography from '@mui/material/Typography';
|
|
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
|
import CategoryIcon from '@mui/icons-material/Category';
|
|
import DeleteIcon from '@mui/icons-material/Delete';
|
|
import HistoryIcon from '@mui/icons-material/History';
|
|
import LabelIcon from '@mui/icons-material/Label';
|
|
import LocalShippingIcon from '@mui/icons-material/LocalShipping';
|
|
import ManageSearchIcon from '@mui/icons-material/ManageSearch';
|
|
import SettingsIcon from '@mui/icons-material/Settings';
|
|
import { article } from '../../api';
|
|
import { notifyError } from '../../utils/notify';
|
|
import { PanelTile } from '../panels';
|
|
import { PANEL_TILE_BORDER_RADIUS, responsiveColumnSpan } from '../panels/panelTileLayout';
|
|
|
|
const TAB = {
|
|
history: 'history',
|
|
supplier: 'supplier',
|
|
seo: 'seo',
|
|
label: 'label',
|
|
attributes: 'attributes',
|
|
compound: 'compound',
|
|
settings: 'settings',
|
|
};
|
|
|
|
const ALWAYS_TABS = [
|
|
{ id: TAB.history, label: 'History', color: '#fed7aa', Icon: HistoryIcon },
|
|
{ id: TAB.supplier, label: 'Supplier', color: '#bbf7d0', Icon: LocalShippingIcon },
|
|
{ id: TAB.seo, label: 'SEO & Beschreibung', color: '#99f6e4', Icon: ManageSearchIcon },
|
|
{ id: TAB.label, label: 'Label', color: '#fde68a', Icon: LabelIcon },
|
|
{ id: TAB.attributes, label: 'Attribute und Merkmale', color: '#bfdbfe', Icon: CategoryIcon },
|
|
];
|
|
|
|
const COMPOUND_TAB = {
|
|
id: TAB.compound,
|
|
label: 'Compound Editor',
|
|
color: '#e9d5ff',
|
|
Icon: AccountTreeIcon,
|
|
};
|
|
|
|
const SETTINGS_TAB = {
|
|
id: TAB.settings,
|
|
label: 'Einstellungen',
|
|
color: '#fca5a5',
|
|
Icon: SettingsIcon,
|
|
};
|
|
|
|
function isCompoundArticle(article) {
|
|
return (
|
|
article?.articleListCount > 0 ||
|
|
article?.optionsCount > 0 ||
|
|
article?.childCount > 0 ||
|
|
article?.fatherArticleId != null
|
|
);
|
|
}
|
|
|
|
function visibleTabs(article) {
|
|
const tabs = [...ALWAYS_TABS];
|
|
if (isCompoundArticle(article)) {
|
|
tabs.push(COMPOUND_TAB);
|
|
}
|
|
tabs.push(SETTINGS_TAB);
|
|
return tabs;
|
|
}
|
|
|
|
function PanelValue({ label, children }) {
|
|
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 Placeholder({ label }) {
|
|
return (
|
|
<Typography variant="body2" color="text.secondary">
|
|
{label} — noch nicht verfügbar.
|
|
</Typography>
|
|
);
|
|
}
|
|
|
|
class ArticleTileTab extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = { tab: TAB.seo, busy: false };
|
|
this.handleTabChange = this.handleTabChange.bind(this);
|
|
this.handleDeleteArticle = this.handleDeleteArticle.bind(this);
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
if (prevProps.article === this.props.article) return;
|
|
const tabs = visibleTabs(this.props.article);
|
|
if (!tabs.some((row) => row.id === this.state.tab)) {
|
|
this.setState({ tab: TAB.seo });
|
|
}
|
|
}
|
|
|
|
handleTabChange(_event, tab) {
|
|
this.setState({ tab });
|
|
}
|
|
|
|
async handleDeleteArticle() {
|
|
const { article: articleData, onArticleDeleted } = this.props;
|
|
if (this.state.busy) return;
|
|
if (!window.confirm(`Artikel „${articleData.name ?? articleData.sku}“ wirklich löschen?`)) {
|
|
return;
|
|
}
|
|
|
|
this.setState({ busy: true });
|
|
try {
|
|
await article.delete(articleData.sku);
|
|
onArticleDeleted?.(articleData);
|
|
} catch (err) {
|
|
notifyError(err);
|
|
this.setState({ busy: false });
|
|
}
|
|
}
|
|
|
|
renderSeo() {
|
|
const { article: articleData } = this.props;
|
|
return (
|
|
<>
|
|
<PanelValue label="Slug">{articleData.slug}</PanelValue>
|
|
<PanelValue label="SEO-Titel">{articleData.seoTitle}</PanelValue>
|
|
<PanelValue label="SEO-Beschreibung">{articleData.seoDescription}</PanelValue>
|
|
<PanelValue label="Beschreibung">{articleData.description}</PanelValue>
|
|
</>
|
|
);
|
|
}
|
|
|
|
renderSettings() {
|
|
const { busy } = this.state;
|
|
return (
|
|
<Box>
|
|
<Button
|
|
type="button"
|
|
color="error"
|
|
variant="contained"
|
|
startIcon={<DeleteIcon />}
|
|
disabled={busy}
|
|
onClick={() => void this.handleDeleteArticle()}
|
|
>
|
|
Artikel löschen
|
|
</Button>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
renderPanel() {
|
|
switch (this.state.tab) {
|
|
case TAB.history:
|
|
return <Placeholder label="History" />;
|
|
case TAB.supplier:
|
|
return <Placeholder label="Supplier" />;
|
|
case TAB.seo:
|
|
return this.renderSeo();
|
|
case TAB.label:
|
|
return <Placeholder label="Label" />;
|
|
case TAB.attributes:
|
|
return <Placeholder label="Attribute und Merkmale" />;
|
|
case TAB.compound:
|
|
return <Placeholder label="Compound Editor" />;
|
|
case TAB.settings:
|
|
return this.renderSettings();
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const { article: articleData, wide = 3, minHeight = 200, sx, tileKey } = this.props;
|
|
const tabs = visibleTabs(articleData);
|
|
const { tab } = this.state;
|
|
const active = tabs.find((row) => row.id === tab) ?? ALWAYS_TABS.find((row) => row.id === TAB.seo);
|
|
const activeColor = active?.color;
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
gridColumn: responsiveColumnSpan(wide),
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
minWidth: 0,
|
|
filter:
|
|
'drop-shadow(0px 2px 4px rgba(0,0,0,0.2)) drop-shadow(0px 4px 5px rgba(0,0,0,0.14)) drop-shadow(0px 1px 10px rgba(0,0,0,0.12))',
|
|
}}
|
|
>
|
|
<Tabs
|
|
value={tab}
|
|
onChange={this.handleTabChange}
|
|
variant="standard"
|
|
TabIndicatorProps={{ sx: { display: 'none', height: 0 } }}
|
|
sx={{
|
|
position: 'relative',
|
|
zIndex: 1,
|
|
minHeight: 56,
|
|
px: 0,
|
|
mb: 0,
|
|
borderBottom: 'none',
|
|
overflow: 'visible',
|
|
'& .MuiTabs-scroller': {
|
|
px: 0,
|
|
borderBottom: 'none',
|
|
overflow: 'visible !important',
|
|
},
|
|
'& .MuiTabs-list, & .MuiTabs-flexContainer': {
|
|
flexWrap: 'wrap-reverse',
|
|
columnGap: 3,
|
|
rowGap: 0,
|
|
alignItems: 'stretch',
|
|
alignContent: 'flex-end',
|
|
},
|
|
'& .MuiTabs-indicator': { display: 'none' },
|
|
'& .MuiTab-root': {
|
|
flexShrink: 0,
|
|
maxWidth: 'none',
|
|
minHeight: 56,
|
|
marginBottom: 0,
|
|
},
|
|
}}
|
|
>
|
|
{tabs.map((row) => {
|
|
const selected = tab === row.id;
|
|
const { Icon } = row;
|
|
return (
|
|
<Tab
|
|
key={row.id}
|
|
value={row.id}
|
|
aria-label={row.label}
|
|
title={row.label}
|
|
icon={<Icon sx={{ fontSize: 40 }} />}
|
|
sx={{
|
|
minHeight: 56,
|
|
minWidth: 64,
|
|
py: 0.5,
|
|
px: 1.25,
|
|
border: 'none',
|
|
borderBottom: 'none',
|
|
borderRadius: '8px 8px 0 0',
|
|
textTransform: 'none',
|
|
bgcolor: row.color,
|
|
opacity: selected ? 1 : 0.72,
|
|
color: 'text.primary',
|
|
zIndex: selected ? 2 : 1,
|
|
boxShadow: 'none',
|
|
'&.Mui-selected': {
|
|
color: 'text.primary',
|
|
borderBottom: 'none',
|
|
},
|
|
}}
|
|
/>
|
|
);
|
|
})}
|
|
</Tabs>
|
|
<PanelTile
|
|
wide={wide}
|
|
minHeight={minHeight}
|
|
tileKey={tileKey}
|
|
elevation={0}
|
|
sx={{
|
|
gridColumn: 'auto',
|
|
width: '100%',
|
|
bgcolor: activeColor,
|
|
borderTopLeftRadius: 0,
|
|
borderTopRightRadius: (theme) =>
|
|
`${(theme.shape.borderRadius || 4) * PANEL_TILE_BORDER_RADIUS}px`,
|
|
borderBottomLeftRadius: (theme) =>
|
|
`${(theme.shape.borderRadius || 4) * PANEL_TILE_BORDER_RADIUS}px`,
|
|
borderBottomRightRadius: (theme) =>
|
|
`${(theme.shape.borderRadius || 4) * PANEL_TILE_BORDER_RADIUS}px`,
|
|
boxShadow: 'none',
|
|
...sx,
|
|
}}
|
|
>
|
|
{this.renderPanel()}
|
|
</PanelTile>
|
|
</Box>
|
|
);
|
|
}
|
|
}
|
|
|
|
export default ArticleTileTab;
|