fix: properly sync category lists when article categories change

- Update patchArticleInLists reducer to add/remove articles from category lists
- Articles are now correctly added to rootArticles and current category's articles
- Articles are correctly removed when no longer in a category
- Remove unnecessary loadCategoryTree dispatch (reducer handles sync now)
This commit is contained in:
seb
2026-08-03 09:17:50 +02:00
parent 78be835388
commit 686a192b1a
2 changed files with 53 additions and 3 deletions

View File

@@ -12,6 +12,8 @@ import {
patchArticleInLists, patchArticleInLists,
removeArticleBySku, removeArticleBySku,
selectCategoryRootId, selectCategoryRootId,
loadCategoryArticles,
selectCurrentCategoryId,
} from '../../store/categorySlice'; } from '../../store/categorySlice';
import ArticleTileTab from './ArticleTileTab'; import ArticleTileTab from './ArticleTileTab';
@@ -33,6 +35,7 @@ export default function ArticleView({
const dispatch = useDispatch(); const dispatch = useDispatch();
const categories = useSelector((state) => state.category.categories); const categories = useSelector((state) => state.category.categories);
const rootCategoryId = useSelector(selectCategoryRootId); const rootCategoryId = useSelector(selectCategoryRootId);
const currentCategoryId = useSelector(selectCurrentCategoryId);
const syncCategoryListPhoto = (next) => { const syncCategoryListPhoto = (next) => {
const photo = primaryPhoto(next); const photo = primaryPhoto(next);
@@ -57,6 +60,12 @@ export default function ArticleView({
categoryIds: next.categoryIds, categoryIds: next.categoryIds,
}), }),
); );
// Reload articles to reflect the update
// The reducer handles removing from lists where article no longer belongs
if (currentCategoryId != null && String(currentCategoryId) !== String(rootCategoryId)) {
dispatch(loadCategoryArticles(currentCategoryId));
}
}; };
const handleArticleDeleted = () => { const handleArticleDeleted = () => {

View File

@@ -343,14 +343,55 @@ const categorySlice = createSlice({
state.articlesTotal = state.articles.length; state.articlesTotal = state.articles.length;
state.rootArticles = state.rootArticles.filter((row) => row.sku !== sku); state.rootArticles = state.rootArticles.filter((row) => row.sku !== sku);
}, },
/** Keep category tile list in sync with article detail (e.g. after photo upload). */ /** Keep category tile list in sync with article detail (e.g. after photo upload or category change). */
patchArticleInLists(state, action) { patchArticleInLists(state, action) {
const { sku, ...fields } = action.payload; const { sku, categoryIds, ...fields } = action.payload;
if (sku == null) return; if (sku == null) return;
// Merge fields into existing article in both lists
const patchList = (list) => const patchList = (list) =>
list.map((row) => (row.sku === sku ? { ...row, ...fields } : row)); list.map((row) => {
if (row.sku !== sku) return row;
return { ...row, ...fields };
});
state.articles = patchList(state.articles); state.articles = patchList(state.articles);
state.rootArticles = patchList(state.rootArticles); state.rootArticles = patchList(state.rootArticles);
if (categoryIds === undefined) return;
const newCategoryIds = categoryIds ?? [];
// Helper: find the article object in either list
const findArticle = (list) => list.find((row) => row.sku === sku);
const articleObj = findArticle(state.articles) || findArticle(state.rootArticles);
if (!articleObj) return;
// Handle root category membership
if (state.rootCategoryId != null) {
const inRootCategory = newCategoryIds.some(
(id) => String(id) === String(state.rootCategoryId),
);
const alreadyInRoot = state.rootArticles.some((row) => row.sku === sku);
if (!inRootCategory) {
state.rootArticles = state.rootArticles.filter((row) => row.sku !== sku);
} else if (!alreadyInRoot) {
state.rootArticles = [...state.rootArticles, articleObj];
}
}
// Handle current category membership
if (state.currentCategoryId != null) {
const inCurrentCategory = newCategoryIds.some(
(id) => String(id) === String(state.currentCategoryId),
);
const alreadyInCurrent = state.articles.some((row) => row.sku === sku);
if (!inCurrentCategory) {
state.articles = state.articles.filter((row) => row.sku !== sku);
state.articlesTotal = state.articles.length;
} else if (!alreadyInCurrent) {
state.articles = [...state.articles, articleObj];
state.articlesTotal = state.articles.length;
}
}
}, },
}, },
extraReducers: (builder) => { extraReducers: (builder) => {