From cb9762b0d60e9a45dd3c4199abb215c9b24710f5 Mon Sep 17 00:00:00 2001 From: adonis Date: Sat, 5 Sep 2026 10:12:16 +0330 Subject: [PATCH] fix(products): treat SSE list as full active catalog Stop keeping deactivated products when the stream shrinks, update prices in place to avoid grid flicker, and only keep admin-active items. Co-authored-by: Cursor --- .../composables/useProductsPageData.ts | 88 ++++++++++--------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/src/views/base/products/composables/useProductsPageData.ts b/src/views/base/products/composables/useProductsPageData.ts index 43d2f74..a5c9266 100644 --- a/src/views/base/products/composables/useProductsPageData.ts +++ b/src/views/base/products/composables/useProductsPageData.ts @@ -117,48 +117,17 @@ function mergeLiveProductList(incoming: Product[], current?: Product[]): Product }) } -/** فقط محصول فعال ادمین (باز) — نه show لحظه‌ای ساعت/مظنه */ +/** فقط محصول فعال ادمین (باز) — فیلد خالی/undefined را فعال نگیر */ function isActiveProduct(product: Product): boolean { const active = product.active as unknown - return active !== false && active !== 0 && active !== '0' -} - -/** استریم گاهی لیست ناقص می‌فرستد — عضوهای قبلی را دور نریز. */ -function mergeSocketProductMembership(incoming: Product[], current?: Product[]): Product[] { - if (!current?.length) return incoming - - const incomingById = new Map(incoming.map((item) => [item.id, item])) - const currentIds = new Set(current.map((item) => item.id)) - const hasAdded = incoming.some((item) => !currentIds.has(item.id)) - const missingFromIncoming = current.some((item) => !incomingById.has(item.id)) - - if (missingFromIncoming && !hasAdded && incoming.length < current.length) { - return current.map((item) => { - const updated = incomingById.get(item.id) - return updated ? { ...item, ...updated } : item - }) - } - - const merged = incoming.map((item) => { - const prev = current.find((row) => row.id === item.id) - return prev ? { ...prev, ...item } : item - }) - - if (missingFromIncoming) { - for (const item of current) { - if (!incomingById.has(item.id)) { - merged.push(item) - } - } - } - - return merged + return active === true || active === 1 || active === '1' } function applyProductsList(products: Product[]) { const visible = products.filter(isActiveProduct) const sorted = sortProductsByInventory(visible) productsFirstItems.value = sorted + getProductsCatalogRef().value = sorted pruneEmptyTypeItems() if ( @@ -172,6 +141,46 @@ function applyProductsList(products: Product[]) { productsPageLoading.value = false } +/** + * SSE همیشه لیست کامل محصولات فعال را می‌فرستد. + * عضو جدید/حذف‌شده را از همان لیست بگیر؛ فقط عکس را از نسخهٔ قبلی نگه دار. + * آپدیت قیمت روی همان آبجکت‌ها تا گرید نپرد. + */ +function applySocketProductList(incoming: Product[], current?: Product[]) { + const next = sortProductsByInventory( + mergeLiveProductList(incoming, current).filter(isActiveProduct), + ) + + if (!current?.length) { + applyProductsList(next) + return + } + + const nextById = new Map(next.map((item) => [item.id, item])) + const currentIds = new Set(current.map((item) => item.id)) + const nextIds = new Set(next.map((item) => item.id)) + const membershipChanged = + next.length !== current.length || + next.some((item) => !currentIds.has(item.id)) || + current.some((item) => !nextIds.has(item.id)) + + if (membershipChanged) { + applyProductsList(next) + return + } + + current.forEach((item) => { + const updated = nextById.get(item.id) + if (updated) { + Object.assign(item, updated) + } + }) + + getProductsCatalogRef().value = current + changeProductsTab() + productsPageLoading.value = false +} + export async function refreshProductsPageData() { try { const fresh = await getProductsCatalog(true) @@ -189,13 +198,10 @@ export function applyProductsListFromSocket(products: Product[]) { } const base = - getProductsCatalogRef().value.length - ? getProductsCatalogRef().value - : productsFirstItems.value - const withImages = mergeLiveProductList(products, base) - const merged = mergeSocketProductMembership(withImages, base) - getProductsCatalogRef().value = merged - applyProductsList(merged) + productsFirstItems.value?.length + ? productsFirstItems.value + : getProductsCatalogRef().value + applySocketProductList(products, base) } function startProductListPolling() {