import { Component } from 'react'; import { EditablePanelTile } from '../../panels'; import SingleLineTextEdit from '../../SingleLineTextEdit'; import { StorageManagerContext } from '../../../api/storageManagerContext'; import { requireObject } from '../../../utils/apiShape'; import { getCategoryBreadcrumbs } from '../../../store/categorySlice'; import { Box, Chip, IconButton } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import CategoryPickerDialog from '../CategoryPickerDialog'; const articleNameTextSx = { fontWeight: 700, lineHeight: 1.2, }; const articleNameFieldSx = { '& .MuiInputBase-input': { fontSize: '2.125rem', ...articleNameTextSx, }, }; const articleNameFieldHiddenSx = { ...articleNameFieldSx, userSelect: 'text', '& .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', }; const columnSx = { display: 'flex', flexDirection: 'column', flex: 1, alignSelf: 'stretch', }; function draftDirty(draft, saved) { const nameDiff = draft.name.trim() !== String(saved.name ?? '').trim(); const a = draft.categoryIds ?? []; const b = saved.categoryIds ?? []; const catDiff = a.length !== b.length || [...a].map(String).sort().join(',') !== [...b].map(String).sort().join(','); return nameDiff || catDiff; } function draftValid(draft) { return draft.name.trim().length > 0 && (draft.categoryIds?.length ?? 0) > 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(' | '); } function categoryLabels(categoryIds, categories, rootCategoryId) { return (categoryIds ?? []) .map((id) => ({ id, label: buildCategoryLabel(categories, id, rootCategoryId) })) .filter((c) => c.label); } class CategoryPills extends Component { constructor(props) { super(props); this.state = { pickerOpen: false }; } handleRemoveCategory = (removeId) => { const { categoryIds, onCategoryIdsChange } = this.props; const remaining = categoryIds.filter((id) => String(id) !== String(removeId)); onCategoryIdsChange?.(remaining); }; handleOpenPicker = () => { this.setState({ pickerOpen: true }); }; handleClosePicker = () => { this.setState({ pickerOpen: false }); }; render() { const { categoryLabels: labels, categoryIds, categories, rootCategoryId, sku, editMode, onCategoryIdsChange, } = this.props; const { pickerOpen } = this.state; return ( <> {labels.map(({ id, label }) => ( 1 ? () => this.handleRemoveCategory(id) : undefined } /> ))} {editMode ? ( ) : null} ); } } class NameDisplay extends Component { render() { const { name, categoryIds, categories, rootCategoryId, sku } = this.props; const labels = categoryLabels(categoryIds, categories, rootCategoryId); return ( {}} sx={articleNameFieldHiddenSx} /> {labels.length > 0 ? ( ) : null} ); } } class NameEdit extends Component { render() { const { draft, onChange, inputRef, categories, rootCategoryId, sku, } = this.props; const labels = categoryLabels(draft.categoryIds, categories, rootCategoryId); return ( onChange({ ...draft, name })} sx={articleNameFieldSx} /> onChange({ ...draft, categoryIds })} /> ); } } export default class ArticleViewName extends Component { static contextType = StorageManagerContext; handleSave = async (draft) => { const { article: articleData, onArticleUpdated } = this.props; const store = this.context; const name = draft.name.trim(); const categoryIds = draft.categoryIds ?? []; const [nameRes] = await Promise.all([ store.article.update(articleData.sku, { name }), store.article.setCategories(articleData.sku, { categoryIds }), ]); requireObject(nameRes, 'PATCH /api/article/:sku'); requireObject(nameRes.article, 'article'); onArticleUpdated?.(nameRes.article); }; render() { const { article: articleData, categories, rootCategoryId } = this.props; const savedCategoryIds = articleData.categoryIds ?? []; const value = { name: articleData.name ?? '', categoryIds: [...savedCategoryIds] }; return ( } edit={ } /> ); } }