u
This commit is contained in:
@@ -29,12 +29,17 @@
|
||||
*/
|
||||
|
||||
import { Automat } from 'react-automat';
|
||||
import { article as articleApi } from '../api';
|
||||
import authAutomat from './authAutomat';
|
||||
import categoryAutomat, { whenCategoryTreeReady } from './categoryAutomat';
|
||||
import sseAutomat from './sseAutomat';
|
||||
import {
|
||||
categoryViews,
|
||||
collectLoadedCategoryViewData,
|
||||
loadAllCategoryViews,
|
||||
invalidateAllCategoryViews,
|
||||
updateArticleInCategoryViews,
|
||||
removeArticleBySku,
|
||||
} from './categoryViewAutomat';
|
||||
|
||||
/**
|
||||
@@ -98,7 +103,7 @@ function scheduleRebuild() {
|
||||
function toIndexRecord(article, categoryId) {
|
||||
const eans = article.eans ?? article.eanCodes ?? article.ean ?? null;
|
||||
const childCount = Number(article.childCount) || 0;
|
||||
const price = article.price ?? article.net ?? article.vknetto ?? null;
|
||||
const price = article.price ?? article.net ?? article.vknetto ?? (Array.isArray(article.prices) ? (article.prices.find((p) => p.minmultiplier === 1)?.net ?? article.prices[0]?.net) : null);
|
||||
const warehouses = Array.isArray(article.warehouses) ? article.warehouses : [];
|
||||
const trackStock = article.track_stock ?? article.trackStock;
|
||||
const stock = trackStock === false
|
||||
@@ -111,6 +116,9 @@ function toIndexRecord(article, categoryId) {
|
||||
const available = article.available != null && !Number.isNaN(Number(article.available))
|
||||
? Number(article.available)
|
||||
: stock;
|
||||
const categories = categoryId != null
|
||||
? String(categoryId)
|
||||
: (Array.isArray(article.categoryIds) ? article.categoryIds.join(',') : (article.categories ?? null));
|
||||
|
||||
return {
|
||||
...article,
|
||||
@@ -126,7 +134,7 @@ function toIndexRecord(article, categoryId) {
|
||||
? article.articlewarehousesummary
|
||||
: [],
|
||||
eans: Array.isArray(eans) ? eans.filter(Boolean) : eans ? [eans] : [],
|
||||
categories: categoryId != null ? String(categoryId) : null,
|
||||
categories,
|
||||
isParent: Boolean(article.isParent ?? article.is_parent ?? (childCount > 0)),
|
||||
childCount,
|
||||
};
|
||||
@@ -258,6 +266,32 @@ const actions = {
|
||||
return items;
|
||||
},
|
||||
|
||||
/**
|
||||
* Refetches and updates a single article in the index and category views by SKU.
|
||||
*
|
||||
* @param {string|number} sku Article SKU.
|
||||
* @returns {Promise<object|null>} Fresh article or null.
|
||||
*/
|
||||
async updateArticleBySku(sku) {
|
||||
const key = String(sku);
|
||||
try {
|
||||
const res = await articleApi.getBySku(key);
|
||||
const article = res?.article;
|
||||
if (article) {
|
||||
updateArticleIndexRecord(article);
|
||||
return article;
|
||||
}
|
||||
return null;
|
||||
} catch (err) {
|
||||
if (err?.status === 404 || err?.statusCode === 404) {
|
||||
removeArticleBySku(key);
|
||||
const nextItems = articleIndexAutomat.state.items.filter((r) => String(r.sku) !== key);
|
||||
articleIndexAutomat.setState({ items: nextItems });
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
/** Reset to idle state (logout / company switch). */
|
||||
reset() {
|
||||
inflightEnsure = null;
|
||||
@@ -294,6 +328,72 @@ authAutomat.subscribe((auth) => {
|
||||
if (auth.status === 'anon') actions.reset();
|
||||
});
|
||||
|
||||
// Upstream Trigger: sseAutomat
|
||||
if (sseAutomat?.actions?.onArticle) {
|
||||
sseAutomat.actions.onArticle(async (sku) => {
|
||||
if (articleIndexAutomat.state.status === 'ready') {
|
||||
await actions.updateArticleBySku(sku);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (sseAutomat?.actions?.on) {
|
||||
sseAutomat.actions.on('articles', () => {
|
||||
invalidateAllCategoryViews();
|
||||
void actions.reload().catch(() => {});
|
||||
});
|
||||
|
||||
sseAutomat.actions.on('warehouse', () => {
|
||||
invalidateAllCategoryViews();
|
||||
void actions.reload().catch(() => {});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a single article record in the derived index and loaded category views.
|
||||
*
|
||||
* @param {object} article Article detail or row.
|
||||
* @returns {Array<ArticleIndexRecord>|undefined} Updated items array.
|
||||
*/
|
||||
export function updateArticleIndexRecord(article) {
|
||||
if (!article || article.sku == null) return;
|
||||
const key = String(article.sku);
|
||||
updateArticleInCategoryViews(article);
|
||||
|
||||
const items = articleIndexAutomat.state.items;
|
||||
if (!items || !items.length) return;
|
||||
|
||||
const existingIndex = items.findIndex((r) => String(r.sku) === key);
|
||||
const categoryIds = Array.isArray(article.categoryIds)
|
||||
? article.categoryIds.map(String)
|
||||
: [];
|
||||
const primaryCatId = categoryIds[0] ?? null;
|
||||
|
||||
const record = toIndexRecord(article, primaryCatId);
|
||||
if (categoryIds.length > 0) {
|
||||
record.categories = categoryIds.join(',');
|
||||
}
|
||||
|
||||
let nextItems;
|
||||
if (existingIndex >= 0) {
|
||||
const existing = items[existingIndex];
|
||||
nextItems = [...items];
|
||||
nextItems[existingIndex] = {
|
||||
...existing,
|
||||
...record,
|
||||
categories: record.categories ?? existing.categories,
|
||||
smallThumbBinary: article.smallThumbBinary ?? article.photos?.[0]?.smallThumbBinary ?? existing.smallThumbBinary,
|
||||
brand: article.brand ?? existing.brand,
|
||||
brandName: article.brand?.name ?? article.brandName ?? existing.brandName,
|
||||
};
|
||||
} else {
|
||||
nextItems = [...items, record];
|
||||
}
|
||||
|
||||
articleIndexAutomat.setState({ items: nextItems });
|
||||
return nextItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches a single record's name in the derived index (optimistic update).
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user