From b131f33fbef9cb0c444e50e5298a9527acaa000f Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Fri, 3 Apr 2026 18:38:42 +0700 Subject: [PATCH] Make catalog filters adjust to valid combinations --- .../catalog/CatalogConfigurator.vue | 109 +++++++++++++----- 1 file changed, 79 insertions(+), 30 deletions(-) diff --git a/app/components/catalog/CatalogConfigurator.vue b/app/components/catalog/CatalogConfigurator.vue index ca50914..5ca16c6 100644 --- a/app/components/catalog/CatalogConfigurator.vue +++ b/app/components/catalog/CatalogConfigurator.vue @@ -239,7 +239,7 @@ watch( for (const key of Object.keys(groupStates)) { if (!keys.has(key)) { - delete groupStates[key]; + Reflect.deleteProperty(groupStates, key); } } @@ -269,11 +269,6 @@ function matchesProductState(product: ParsedProduct, state: GroupState, keys: Pa }); } -function matchingProducts(group: ProductGroup) { - const state = getGroupState(group); - return group.products.filter((product) => matchesProductState(product, state, requiredKeys(group))); -} - function selectedProduct(group: ProductGroup) { const keys = requiredKeys(group); const state = getGroupState(group); @@ -303,6 +298,14 @@ function formatOptionLabel(field: ParamFieldKey, value: ParamValue) { return String(value); } +function productHasOption(product: ParsedProduct, field: ParamFieldKey, option: ParamValue) { + if (field === 'quantityPerBox') { + return product.quantityPerBoxOptions.includes(String(option)); + } + + return product[field] === option; +} + function isOptionAvailable(group: ProductGroup, field: ParamFieldKey, option: ParamValue) { const state = getGroupState(group); const scopedState = { @@ -313,25 +316,73 @@ function isOptionAvailable(group: ProductGroup, field: ParamFieldKey, option: Pa return group.products.some((product) => matchesProductState(product, scopedState, requiredKeys(group))); } -function updateField(group: ProductGroup, field: ParamFieldKey, value: ParamValue) { +function pickBestProductForOption(group: ProductGroup, field: ParamFieldKey, option: ParamValue) { const state = getGroupState(group); - state[field] = value as GroupState[typeof field]; + const candidates = group.products.filter((product) => productHasOption(product, field, option)); - const resolved = selectedProduct(group); - if (resolved) { + if (candidates.length === 0) { + return null; + } + + return [...candidates].sort((a, b) => { + let aScore = 0; + let bScore = 0; + + for (const key of PARAM_KEYS) { + if (key === field) { + continue; + } + + const selectedValue = state[key]; + if (selectedValue === null) { + continue; + } + + if (productHasOption(a, key, selectedValue)) { + aScore += 1; + } + if (productHasOption(b, key, selectedValue)) { + bScore += 1; + } + } + + if (aScore !== bScore) { + return bScore - aScore; + } + + return compareProducts(a, b); + })[0]; +} + +function applyProductToState(state: GroupState, product: ParsedProduct, preferredBoxOption: ParamValue | null = null) { + state.widthMm = product.widthMm ?? null; + state.lengthM = product.lengthM ?? null; + state.thicknessMicron = product.thicknessMicron ?? null; + state.sleeveBrand = product.sleeveBrand ?? null; + + if (preferredBoxOption !== null && product.quantityPerBoxOptions.includes(String(preferredBoxOption))) { + state.quantityPerBox = String(preferredBoxOption); return; } - const fallback = group.products.find((product) => product[field] === value) ?? group.products[0]; + state.quantityPerBox = product.quantityPerBoxOptions[0] ?? null; +} + +function updateField(group: ProductGroup, field: ParamFieldKey, value: ParamValue) { + const state = getGroupState(group); + const fallback = pickBestProductForOption(group, field, value); if (!fallback) { return; } - state.widthMm = fallback.widthMm ?? null; - state.lengthM = fallback.lengthM ?? null; - state.thicknessMicron = fallback.thicknessMicron ?? null; - state.sleeveBrand = fallback.sleeveBrand ?? null; - state.quantityPerBox = fallback.quantityPerBoxOptions[0] ?? null; + applyProductToState(state, fallback, field === 'quantityPerBox' ? value : state.quantityPerBox); + + if (field === 'quantityPerBox') { + state.quantityPerBox = String(value); + return; + } + + state[field] = value as GroupState[typeof field]; } function articleLabel(group: ProductGroup) { @@ -451,14 +502,14 @@ function decrementSelected(group: ProductGroup) {