This commit is contained in:
seb
2026-08-02 19:21:21 +02:00
parent b787549a85
commit 5309b1174b
6 changed files with 194 additions and 19 deletions

View File

@@ -2,15 +2,19 @@ import { Component } from 'react';
import { connect } from 'react-redux';
import Box from '@mui/material/Box';
import CircularProgress from '@mui/material/CircularProgress';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';
import { enqueueSnackbar } from 'notistack';
import BackendError from '../../components/BackendError';
import { NewCategoryTile, CategoryBreadcrumbs } from '../../components/category';
import { NewArticleTile } from '../../components/article';
import { notifyError } from '../../utils/notify';
import {
ArticleTile,
BackTile,
CategoryTile,
TILE_SIZE,
tileBaseSx,
} from '../../components/tiles';
import withCategoryRoute from './withCategoryRoute';
import { artikelDetailPath, articleSku } from './articleRoute';
@@ -26,6 +30,7 @@ import {
loadCategoryArticles,
loadCategoryTree,
navigateToCategory,
renameCategory,
selectCanNavigateBack,
selectCategoryArticles,
selectCategoryArticlesStatus,
@@ -34,6 +39,7 @@ import {
selectCategoryError,
selectCategoryTreeStatus,
selectChildCategories,
selectRenameMode,
} from '../../store/categorySlice';
const gridSx = {
@@ -43,6 +49,13 @@ const gridSx = {
};
class ArtikelKategorienPage extends Component {
constructor(props) {
super(props);
this.state = { drafts: {} };
this.handleRenameSubmit = this.handleRenameSubmit.bind(this);
this.handleDraftChange = this.handleDraftChange.bind(this);
}
componentDidMount() {
this.ensureTreeLoaded();
this.syncCategoryFromUrl();
@@ -127,6 +140,29 @@ class ArtikelKategorienPage extends Component {
navigate(buildCategoryPath(categories, rootCategoryId, categoryId));
};
handleDraftChange(categoryId, value) {
this.setState((state) => ({
drafts: { ...state.drafts, [categoryId]: value },
}));
}
handleRenameSubmit = async (categoryId, name) => {
const trimmed = String(name ?? '').trim();
if (!trimmed) {
enqueueSnackbar('Name ist erforderlich.', { variant: 'error' });
return;
}
try {
await this.props.renameCategory({
categoryId,
name: trimmed,
}).unwrap();
enqueueSnackbar('Kategorie umbenannt.', { variant: 'success' });
} catch (err) {
notifyError(err);
}
};
handleRetryTree = () => {
if (this.props.companyId) this.props.loadCategoryTree();
};
@@ -161,6 +197,7 @@ class ArtikelKategorienPage extends Component {
currentCategoryId,
childCategories,
articles,
renameMode,
} = this.props;
if (!companyId) {
@@ -218,15 +255,62 @@ class ArtikelKategorienPage extends Component {
<BackTile onClick={this.handleNavigateBack} />
)}
{childCategories.map((item) => (
<CategoryTile
key={item.id}
label={categoryDisplayName(item.name, item.id, rootCategoryId)}
onClick={() => this.navigateToCategoryById(item.id)}
/>
))}
{childCategories.map((item) => {
const label = categoryDisplayName(item.name, item.id, rootCategoryId);
if (renameMode) {
const draftName =
this.state.drafts[item.id] !== undefined
? this.state.drafts[item.id]
: label;
return (
<Box
key={item.id}
component="form"
onSubmit={(event) => {
event.preventDefault();
void this.handleRenameSubmit(item.id, this.state.drafts[item.id] ?? label);
}}
sx={{
...tileBaseSx,
cursor: 'default',
alignItems: 'center',
justifyContent: 'center',
my: 0.5,
bgcolor: 'action.hover',
'&:hover': { bgcolor: 'action.hover' },
}}
>
<TextField
fullWidth
size="small"
variant="standard"
value={draftName}
onChange={(e) => this.handleDraftChange(item.id, e.target.value)}
slotProps={{ inputLabel: { shrink: true } }}
sx={{
mx: 0.5,
'& .MuiInput-underline:before, & .MuiInput-underline:after': {
borderBottom: 'none',
},
'& .MuiInputBase-input': {
textAlign: 'center',
fontWeight: 600,
},
}}
/>
</Box>
);
}
return (
<CategoryTile
key={item.id}
label={label}
onClick={() => this.navigateToCategoryById(item.id)}
/>
);
})}
{articles.map((item) => (
{!renameMode && articles.map((item) => (
<ArticleTile
key={item.id}
label={item.name != null ? item.name.trim() : undefined}
@@ -237,10 +321,12 @@ class ArtikelKategorienPage extends Component {
))}
<NewCategoryTile parentId={currentCategoryId} />
<NewArticleTile
parentId={currentCategoryId}
onOpenArticle={this.handleArticleClick}
/>
{!renameMode && (
<NewArticleTile
parentId={currentCategoryId}
onOpenArticle={this.handleArticleClick}
/>
)}
</Box>
{showArticlesLoading && (
@@ -265,12 +351,14 @@ const mapStateToProps = (state) => ({
childCategories: selectChildCategories(state),
articles: selectCategoryArticles(state),
canGoBack: selectCanNavigateBack(state),
renameMode: selectRenameMode(state),
});
const mapDispatchToProps = {
loadCategoryTree,
loadCategoryArticles,
navigateToCategory,
renameCategory,
};
export default withCategoryRoute(connect(mapStateToProps, mapDispatchToProps)(ArtikelKategorienPage));