Files
dashfront/src/components/article/boxes/ArticleViewName.jsx

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>
)}
/>
);
}