131 lines
3.9 KiB
JavaScript
131 lines
3.9 KiB
JavaScript
import { EditablePanelTile } from '../../panels';
|
|
import SingleLineTextEdit from '../../SingleLineTextEdit';
|
|
import { article } from '../../../api';
|
|
import { requireObject } from '../../../utils/apiShape';
|
|
import { PANEL_TILE_KEYS } from '../../../theme';
|
|
import { getCategoryBreadcrumbs } from '../../../store/categorySlice';
|
|
import { Box, Chip } from '@mui/material';
|
|
|
|
const articleNameTextSx = {
|
|
fontWeight: 700,
|
|
lineHeight: 1.2,
|
|
};
|
|
|
|
const articleNameFieldSx = {
|
|
'& .MuiInputBase-input': {
|
|
fontSize: '2.125rem',
|
|
...articleNameTextSx,
|
|
},
|
|
};
|
|
|
|
const articleNameFieldHiddenSx = {
|
|
...articleNameFieldSx,
|
|
pointerEvents: 'none',
|
|
'& .MuiOutlinedInput-notchedOutline': {
|
|
borderColor: 'transparent',
|
|
},
|
|
'& .MuiOutlinedInput-root:hover .MuiOutlinedInput-notchedOutline': {
|
|
borderColor: 'transparent',
|
|
},
|
|
'& .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline': {
|
|
borderColor: 'transparent',
|
|
},
|
|
'& .MuiInputLabel-root': {
|
|
visibility: 'hidden',
|
|
},
|
|
};
|
|
|
|
const pillsContainerSx = {
|
|
display: 'flex',
|
|
flexWrap: 'wrap',
|
|
gap: 0.5,
|
|
mt: 'auto',
|
|
};
|
|
|
|
function nameDraftDirty(draft, saved) {
|
|
return draft.name.trim() !== String(saved.name ?? '').trim();
|
|
}
|
|
|
|
function nameDraftValid(draft) {
|
|
return draft.name.trim().length > 0;
|
|
}
|
|
|
|
const headerTileSx = {
|
|
minHeight: 0,
|
|
};
|
|
|
|
function buildCategoryLabel(categories, categoryId, rootCategoryId) {
|
|
if (!categories || categoryId == null) return '';
|
|
const crumbs = getCategoryBreadcrumbs(categories, categoryId, rootCategoryId);
|
|
if (crumbs.length === 0) return '';
|
|
return crumbs.map((c) => c.name).join(' | ');
|
|
}
|
|
|
|
export default function ArticleViewName({ article: articleData, categories, rootCategoryId, onArticleUpdated }) {
|
|
const handleSave = async (draft) => {
|
|
const name = draft.name.trim();
|
|
const res = await article.update(articleData.sku, { name });
|
|
requireObject(res, 'PATCH /api/article/:sku');
|
|
requireObject(res.article, 'article');
|
|
onArticleUpdated?.(res.article);
|
|
};
|
|
|
|
const categoryIds = articleData.categoryIds ?? [];
|
|
const categoryLabels = categoryIds
|
|
.map((id) => ({ id, label: buildCategoryLabel(categories, id, rootCategoryId) }))
|
|
.filter((c) => c.label);
|
|
|
|
return (
|
|
<EditablePanelTile
|
|
wide={3}
|
|
tileKey={PANEL_TILE_KEYS.name}
|
|
minHeight={0}
|
|
sx={headerTileSx}
|
|
value={{ name: articleData.name ?? '' }}
|
|
onSave={handleSave}
|
|
isDirty={nameDraftDirty}
|
|
canSave={nameDraftValid}
|
|
renderDisplay={({ name }) => (
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', flex: 1, alignSelf: 'stretch' }}>
|
|
<Box sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
|
|
<SingleLineTextEdit
|
|
label="Name"
|
|
value={name}
|
|
readOnly
|
|
onChange={() => {}}
|
|
sx={articleNameFieldHiddenSx}
|
|
/>
|
|
</Box>
|
|
{categoryLabels.length > 0 && (
|
|
<Box sx={pillsContainerSx}>
|
|
{categoryLabels.map(({ id, label }) => (
|
|
<Chip key={id} label={label} size="small" variant="outlined" />
|
|
))}
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
)}
|
|
renderEdit={(draft, onChange, inputRef) => (
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', flex: 1, alignSelf: 'stretch' }}>
|
|
<Box sx={{ flex: 1, display: 'flex', alignItems: 'center' }}>
|
|
<SingleLineTextEdit
|
|
inputRef={inputRef}
|
|
label="Name"
|
|
value={draft.name}
|
|
onChange={(name) => onChange({ name })}
|
|
sx={articleNameFieldSx}
|
|
/>
|
|
</Box>
|
|
{categoryLabels.length > 0 && (
|
|
<Box sx={pillsContainerSx}>
|
|
{categoryLabels.map(({ id, label }) => (
|
|
<Chip key={id} label={label} size="small" variant="outlined" />
|
|
))}
|
|
</Box>
|
|
)}
|
|
</Box>
|
|
)}
|
|
/>
|
|
);
|
|
}
|