From fd015ad1b7f5dcc3f4c75320088ef60f2be75e91 Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Fri, 3 Apr 2026 15:25:33 +0700 Subject: [PATCH] refactor(catalog): default valid selections and minimal action panel --- .../catalog/CatalogConfigurator.vue | 178 ++++++------------ 1 file changed, 57 insertions(+), 121 deletions(-) diff --git a/app/components/catalog/CatalogConfigurator.vue b/app/components/catalog/CatalogConfigurator.vue index 48fde26..3aeaef7 100644 --- a/app/components/catalog/CatalogConfigurator.vue +++ b/app/components/catalog/CatalogConfigurator.vue @@ -194,12 +194,14 @@ function requiredKeys(group: ProductGroup) { return visibleFields(group).map((field) => field.key); } -function createGroupState(): GroupState { +function createGroupState(group: ProductGroup): GroupState { + const firstProduct = group.products[0]; + return { - widthMm: null, - lengthM: null, - thicknessMicron: null, - sleeveBrand: null, + widthMm: firstProduct?.widthMm ?? null, + lengthM: firstProduct?.lengthM ?? null, + thicknessMicron: firstProduct?.thicknessMicron ?? null, + sleeveBrand: firstProduct?.sleeveBrand ?? null, isExpanded: false, }; } @@ -216,14 +218,14 @@ watch( } for (const group of groups) { - groupStates[group.key] ??= createGroupState(); + groupStates[group.key] ??= createGroupState(group); } }, { immediate: true }, ); function getGroupState(group: ProductGroup) { - groupStates[group.key] ??= createGroupState(); + groupStates[group.key] ??= createGroupState(group); return groupStates[group.key]; } @@ -252,61 +254,6 @@ function selectedProduct(group: ProductGroup) { return matches.length === 1 ? matches[0] : null; } -function remainingSelectionCount(group: ProductGroup) { - const state = getGroupState(group); - return requiredKeys(group).filter((key) => state[key] === null).length; -} - -function pluralize(value: number, one: string, few: string, many: string) { - const mod10 = value % 10; - const mod100 = value % 100; - - if (mod10 === 1 && mod100 !== 11) { - return one; - } - if (mod10 >= 2 && mod10 <= 4 && (mod100 < 12 || mod100 > 14)) { - return few; - } - return many; -} - -function selectionHeadline(group: ProductGroup) { - const product = selectedProduct(group); - if (product) { - return `SKU ${product.sku}`; - } - - const remaining = remainingSelectionCount(group); - if (remaining > 0) { - return `Выберите еще ${remaining} ${pluralize(remaining, 'параметр', 'параметра', 'параметров')}`; - } - - return 'Комбинация не найдена'; -} - -function selectionDescription(group: ProductGroup) { - const product = selectedProduct(group); - if (product) { - return [ - product.widthMm ? `${product.widthMm} мм` : null, - product.lengthM ? `${product.lengthM} м` : null, - product.thicknessMicron ? `${product.thicknessMicron} мкм` : null, - normalizeText(product.sleeveBrand) || null, - ].filter(Boolean).join(' • '); - } - - const remaining = remainingSelectionCount(group); - if (remaining > 0) { - return 'Переключатели ниже собирают точную модификацию товара.'; - } - - return 'Разверните весь список, если нужна ручная проверка вариантов.'; -} - -function addButtonLabel(group: ProductGroup) { - return selectedProduct(group) ? 'В корзину' : 'Выбрать параметры'; -} - function boxQuantityLabel(group: ProductGroup) { const product = selectedProduct(group); if (product?.quantityPerBoxOptions.length) { @@ -349,17 +296,25 @@ function isOptionAvailable(group: ProductGroup, field: ParamFieldKey, option: Pa function updateField(group: ProductGroup, field: ParamFieldKey, value: ParamValue) { const state = getGroupState(group); state[field] = value as GroupState[typeof field]; -} -function clearField(group: ProductGroup, field: ParamFieldKey) { - getGroupState(group)[field] = null; -} - -function clearSelection(group: ProductGroup) { - const state = getGroupState(group); - for (const key of PARAM_KEYS) { - state[key] = null; + const resolved = selectedProduct(group); + if (resolved) { + return; } + + const fallback = group.products.find((product) => product[field] === value) ?? group.products[0]; + if (!fallback) { + return; + } + + state.widthMm = fallback.widthMm ?? null; + state.lengthM = fallback.lengthM ?? null; + state.thicknessMicron = fallback.thicknessMicron ?? null; + state.sleeveBrand = fallback.sleeveBrand ?? null; +} + +function articleLabel(group: ProductGroup) { + return selectedProduct(group)?.sku ?? '—'; } function toggleExpanded(group: ProductGroup) { @@ -441,26 +396,16 @@ function decrementSelected(group: ProductGroup) {
Тип товара
-