This commit is contained in:
seb
2026-10-08 20:12:37 +02:00
parent 930bd33072
commit fa6d910723
2 changed files with 65 additions and 53 deletions

View File

@@ -4,7 +4,7 @@ import SingleLineTextEdit from 'dashgui/SingleLineTextEdit';
import { getCategoryState } from '../../../automats/categoryAutomat'; import { getCategoryState } from '../../../automats/categoryAutomat';
import artikelAutomat from '../../../automats/artikelAutomat'; import artikelAutomat from '../../../automats/artikelAutomat';
import { getCategoryBreadcrumbs, categoryDisplayName } from '../../../utils/categoryUtils'; import { getCategoryBreadcrumbs, categoryDisplayName } from '../../../utils/categoryUtils';
import { Box, Chip, IconButton } from '@mui/material'; import { Box, Chip, IconButton, Typography } from '@mui/material';
import AddIcon from '@mui/icons-material/Add'; import AddIcon from '@mui/icons-material/Add';
import CategoryPickerDialog from '../CategoryPickerDialog'; import CategoryPickerDialog from '../CategoryPickerDialog';
import { notifyError } from '../../../utils/notify'; import { notifyError } from '../../../utils/notify';
@@ -66,8 +66,9 @@ function categoryIdsChanged(a, b) {
function draftDirty(draft, saved) { function draftDirty(draft, saved) {
const nameDiff = draft.name.trim() !== String(saved.name ?? '').trim(); const nameDiff = draft.name.trim() !== String(saved.name ?? '').trim();
const seoDiff = String(draft.seo ?? '').trim() !== String(saved.seo ?? '').trim();
const catDiff = categoryIdsChanged(draft.categoryIds, saved.categoryIds); const catDiff = categoryIdsChanged(draft.categoryIds, saved.categoryIds);
return nameDiff || catDiff; return nameDiff || seoDiff || catDiff;
} }
function draftValid(draft) { function draftValid(draft) {
@@ -207,10 +208,10 @@ class CategoryPills extends Component {
class NameDisplay extends Component { class NameDisplay extends Component {
render() { render() {
const { name, categoryIds } = this.props; const { name, seo, categoryIds } = this.props;
return ( return (
<Box sx={columnSx}> <Box sx={columnSx}>
<Box sx={{ flex: 1, display: 'flex', alignItems: 'center' }}> <Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
<SingleLineTextEdit <SingleLineTextEdit
label="Name" label="Name"
value={name} value={name}
@@ -218,6 +219,13 @@ class NameDisplay extends Component {
onChange={() => {}} onChange={() => {}}
sx={articleNameFieldHiddenSx} sx={articleNameFieldHiddenSx}
/> />
{seo ? (
<Box sx={{ px: 1.75, mt: -0.5, userSelect: 'text' }}>
<Typography variant="body2" color="text.secondary">
{seo}
</Typography>
</Box>
) : null}
</Box> </Box>
{(categoryIds?.length ?? 0) > 0 ? ( {(categoryIds?.length ?? 0) > 0 ? (
<CategoryPills categoryIds={categoryIds} editMode={false} /> <CategoryPills categoryIds={categoryIds} editMode={false} />
@@ -232,13 +240,15 @@ class NameEdit extends Component {
super(props); super(props);
this.state = { this.state = {
name: props.name, name: props.name,
seo: props.seo ?? '',
categoryIds: [...(props.categoryIds ?? [])], categoryIds: [...(props.categoryIds ?? [])],
}; };
} }
componentDidMount() { componentDidMount() {
const { onNameDraftChange, onCategoryIdsDraftChange } = this.props; const { onNameDraftChange, onSeoDraftChange, onCategoryIdsDraftChange } = this.props;
onNameDraftChange?.(this.state.name); onNameDraftChange?.(this.state.name);
onSeoDraftChange?.(this.state.seo);
onCategoryIdsDraftChange?.(this.state.categoryIds); onCategoryIdsDraftChange?.(this.state.categoryIds);
} }
@@ -247,22 +257,35 @@ class NameEdit extends Component {
this.props.onNameDraftChange?.(name); this.props.onNameDraftChange?.(name);
}; };
handleSeoChange = (seo) => {
this.setState({ seo });
this.props.onSeoDraftChange?.(seo);
};
handleCategoryIdsChange = (categoryIds) => { handleCategoryIdsChange = (categoryIds) => {
this.setState({ categoryIds }); this.setState({ categoryIds });
this.props.onCategoryIdsDraftChange?.(categoryIds); this.props.onCategoryIdsDraftChange?.(categoryIds);
}; };
render() { render() {
const { name, categoryIds } = this.state; const { name, seo, categoryIds } = this.state;
return ( return (
<Box sx={columnSx}> <Box sx={columnSx}>
<Box sx={{ flex: 1, display: 'flex', alignItems: 'center' }}> <Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
<SingleLineTextEdit <SingleLineTextEdit
label="Name" label="Name"
value={name} value={name}
onChange={this.handleNameChange} onChange={this.handleNameChange}
sx={articleNameFieldSx} sx={articleNameFieldSx}
/> />
<Box sx={{ mt: 1 }}>
<SingleLineTextEdit
label="SEO"
value={seo}
size="small"
onChange={this.handleSeoChange}
/>
</Box>
</Box> </Box>
<CategoryPills <CategoryPills
categoryIds={categoryIds} categoryIds={categoryIds}
@@ -279,6 +302,7 @@ export default class ArticleViewName extends PureComponent {
super(props); super(props);
this.state = { this.state = {
nameDraft: null, nameDraft: null,
seoDraft: null,
categoryIdsDraft: null, categoryIdsDraft: null,
}; };
} }
@@ -287,23 +311,33 @@ export default class ArticleViewName extends PureComponent {
this.setState({ nameDraft: name }); this.setState({ nameDraft: name });
}; };
handleSeoDraftChange = (seo) => {
this.setState({ seoDraft: seo });
};
handleCategoryIdsDraftChange = (categoryIds) => { handleCategoryIdsDraftChange = (categoryIds) => {
this.setState({ categoryIdsDraft: categoryIds }); this.setState({ categoryIdsDraft: categoryIds });
}; };
handleSave = async () => { handleSave = async () => {
const { article: articleData, onArticleUpdated } = this.props; const { article: articleData, onArticleUpdated } = this.props;
const { nameDraft, categoryIdsDraft } = this.state; const { nameDraft, seoDraft, categoryIdsDraft } = this.state;
const name = nameDraft.trim(); const name = nameDraft != null ? nameDraft.trim() : String(articleData.name ?? '').trim();
const categoryIds = categoryIdsDraft; const seo = seoDraft != null ? seoDraft.trim() : String(articleData.seo ?? articleData.seoDescription ?? '').trim();
const categoryIds = categoryIdsDraft ?? (articleData.categoryIds ?? []);
const nameChanged = name !== String(articleData.name ?? '').trim(); const nameChanged = name !== String(articleData.name ?? '').trim();
const seoChanged = seo !== String(articleData.seo ?? articleData.seoDescription ?? '').trim();
const categoriesChanged = categoryIdsChanged(categoryIds, articleData.categoryIds); const categoriesChanged = categoryIdsChanged(categoryIds, articleData.categoryIds);
let article = null; let article = null;
if (nameChanged) { if (nameChanged || seoChanged) {
const nameRes = await artikelAutomat.actions.update(articleData.sku, { name }); const updateBody = {};
article = nameRes.article; if (nameChanged) updateBody.name = name;
if (seoChanged) updateBody.seo = seo;
const res = await artikelAutomat.actions.update(articleData.sku, updateBody);
article = res.article;
} }
if (categoriesChanged) { if (categoriesChanged) {
@@ -312,17 +346,26 @@ export default class ArticleViewName extends PureComponent {
} }
if (article) onArticleUpdated?.(article); if (article) onArticleUpdated?.(article);
this.setState({ nameDraft: null, categoryIdsDraft: null }); this.setState({ nameDraft: null, seoDraft: null, categoryIdsDraft: null });
}; };
render() { render() {
const { article: articleData } = this.props; const { article: articleData } = this.props;
const { nameDraft, categoryIdsDraft } = this.state; const { nameDraft, seoDraft, categoryIdsDraft } = this.state;
const savedCategoryIds = articleData.categoryIds ?? []; const savedCategoryIds = articleData.categoryIds ?? [];
const value = { name: articleData.name ?? '', categoryIds: [...savedCategoryIds] }; const savedSeo = articleData.seo ?? articleData.seoDescription ?? '';
const value = {
name: articleData.name ?? '',
seo: savedSeo,
categoryIds: [...savedCategoryIds],
};
const draft = const draft =
nameDraft != null && categoryIdsDraft != null nameDraft != null && categoryIdsDraft != null
? { name: nameDraft, categoryIds: categoryIdsDraft } ? {
name: nameDraft,
seo: seoDraft ?? savedSeo,
categoryIds: categoryIdsDraft,
}
: null; : null;
return ( return (
@@ -339,14 +382,17 @@ export default class ArticleViewName extends PureComponent {
display={ display={
<NameDisplay <NameDisplay
name={value.name} name={value.name}
seo={value.seo}
categoryIds={value.categoryIds} categoryIds={value.categoryIds}
/> />
} }
edit={ edit={
<NameEdit <NameEdit
name={value.name} name={value.name}
seo={value.seo}
categoryIds={value.categoryIds} categoryIds={value.categoryIds}
onNameDraftChange={this.handleNameDraftChange} onNameDraftChange={this.handleNameDraftChange}
onSeoDraftChange={this.handleSeoDraftChange}
onCategoryIdsDraftChange={this.handleCategoryIdsDraftChange} onCategoryIdsDraftChange={this.handleCategoryIdsDraftChange}
/> />
} }

View File

@@ -1,37 +1,10 @@
import { Component } from 'react'; import { Component } from 'react';
import Box from '@mui/material/Box'; import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
function PanelValue({ label, children }) { function PanelHtmlValue({ html }) {
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 PanelHtmlValue({ label, html }) {
if (html == null || html === '') return null; if (html == null || html === '') return null;
return ( return (
<Box sx={{ mb: 1.5 }}> <Box sx={{ mb: 1.5 }}>
{label ? (
<Typography
variant="caption"
color="text.secondary"
display="block"
sx={{ mb: 0.5, fontWeight: 500 }}
>
{label}
</Typography>
) : null}
<Box <Box
sx={(theme) => ({ sx={(theme) => ({
p: 1.5, p: 1.5,
@@ -83,14 +56,7 @@ function PanelHtmlValue({ label, html }) {
export default class ArticleSeoTab extends Component { export default class ArticleSeoTab extends Component {
render() { render() {
const { article: articleData } = this.props; const { article: articleData } = this.props;
const seo = articleData.seo ?? articleData.seoDescription;
const desc = articleData.desc ?? articleData.description; const desc = articleData.desc ?? articleData.description;
return ( return <PanelHtmlValue html={desc} />;
<>
<PanelValue label="Slug">{articleData.slug}</PanelValue>
<PanelValue label="SEO">{seo}</PanelValue>
<PanelHtmlValue label="Beschreibung" html={desc} />
</>
);
} }
} }