refactor(catalog): move box selection into configurator
This commit is contained in:
@@ -4,7 +4,7 @@ import { ClientProductsDocument, type ClientProductsQuery } from '~/composables/
|
||||
import { useClientCart } from '~/composables/useClientCart';
|
||||
|
||||
type ProductNode = ClientProductsQuery['clientProducts'][number];
|
||||
type ParamFieldKey = 'widthMm' | 'lengthM' | 'thicknessMicron' | 'sleeveBrand';
|
||||
type ParamFieldKey = 'widthMm' | 'lengthM' | 'thicknessMicron' | 'sleeveBrand' | 'quantityPerBox';
|
||||
type ParamValue = number | string;
|
||||
|
||||
type ParsedProduct = ProductNode & {
|
||||
@@ -23,15 +23,17 @@ type GroupState = {
|
||||
lengthM: number | null;
|
||||
thicknessMicron: number | null;
|
||||
sleeveBrand: string | null;
|
||||
quantityPerBox: string | null;
|
||||
isExpanded: boolean;
|
||||
};
|
||||
|
||||
const PARAM_KEYS: ParamFieldKey[] = ['widthMm', 'lengthM', 'thicknessMicron', 'sleeveBrand'];
|
||||
const PARAM_KEYS: ParamFieldKey[] = ['widthMm', 'lengthM', 'thicknessMicron', 'sleeveBrand', 'quantityPerBox'];
|
||||
const parameterFields: Array<{ key: ParamFieldKey; label: string }> = [
|
||||
{ key: 'widthMm', label: 'Ширина' },
|
||||
{ key: 'lengthM', label: 'Длина' },
|
||||
{ key: 'thicknessMicron', label: 'Толщина' },
|
||||
{ key: 'sleeveBrand', label: 'Втулка' },
|
||||
{ key: 'quantityPerBox', label: 'Короб' },
|
||||
];
|
||||
|
||||
const coverPresets = [
|
||||
@@ -177,6 +179,13 @@ function getAllFieldOptions(group: ProductGroup, field: ParamFieldKey) {
|
||||
const values = new Set<ParamValue>();
|
||||
|
||||
for (const product of group.products) {
|
||||
if (field === 'quantityPerBox') {
|
||||
for (const option of product.quantityPerBoxOptions) {
|
||||
values.add(option);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = product[field];
|
||||
if (value !== null && value !== undefined) {
|
||||
values.add(value);
|
||||
@@ -202,6 +211,7 @@ function createGroupState(group: ProductGroup): GroupState {
|
||||
lengthM: firstProduct?.lengthM ?? null,
|
||||
thicknessMicron: firstProduct?.thicknessMicron ?? null,
|
||||
sleeveBrand: firstProduct?.sleeveBrand ?? null,
|
||||
quantityPerBox: firstProduct?.quantityPerBoxOptions[0] ?? null,
|
||||
isExpanded: false,
|
||||
};
|
||||
}
|
||||
@@ -230,7 +240,17 @@ function getGroupState(group: ProductGroup) {
|
||||
}
|
||||
|
||||
function matchesProductState(product: ParsedProduct, state: GroupState, keys: ParamFieldKey[]) {
|
||||
return keys.every((key) => state[key] === null || product[key] === state[key]);
|
||||
return keys.every((key) => {
|
||||
if (state[key] === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key === 'quantityPerBox') {
|
||||
return product.quantityPerBoxOptions.includes(String(state[key]));
|
||||
}
|
||||
|
||||
return product[key] === state[key];
|
||||
});
|
||||
}
|
||||
|
||||
function matchingProducts(group: ProductGroup) {
|
||||
@@ -254,22 +274,6 @@ function selectedProduct(group: ProductGroup) {
|
||||
return matches.length === 1 ? matches[0] : null;
|
||||
}
|
||||
|
||||
function boxQuantityLabel(group: ProductGroup) {
|
||||
const product = selectedProduct(group);
|
||||
if (product?.quantityPerBoxOptions.length) {
|
||||
return product.quantityPerBoxOptions.join(' / ');
|
||||
}
|
||||
|
||||
const values = new Set<string>();
|
||||
for (const item of group.products) {
|
||||
for (const option of item.quantityPerBoxOptions) {
|
||||
values.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
return sortParamValues([...values]).join(' / ') || '—';
|
||||
}
|
||||
|
||||
function formatOptionLabel(field: ParamFieldKey, value: ParamValue) {
|
||||
if (field === 'widthMm') {
|
||||
return `${value} мм`;
|
||||
@@ -311,6 +315,7 @@ function updateField(group: ProductGroup, field: ParamFieldKey, value: ParamValu
|
||||
state.lengthM = fallback.lengthM ?? null;
|
||||
state.thicknessMicron = fallback.thicknessMicron ?? null;
|
||||
state.sleeveBrand = fallback.sleeveBrand ?? null;
|
||||
state.quantityPerBox = fallback.quantityPerBoxOptions[0] ?? null;
|
||||
}
|
||||
|
||||
function articleLabel(group: ProductGroup) {
|
||||
@@ -439,15 +444,13 @@ function decrementSelected(group: ProductGroup) {
|
||||
<aside class="rounded-[28px] bg-base-100 p-4 md:p-5 xl:col-span-1">
|
||||
<div class="flex h-full flex-col justify-between gap-4">
|
||||
<div class="space-y-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-[0.18em] text-base-content/45">Артикул</p>
|
||||
<p class="text-xl font-bold text-[#163624]">{{ articleLabel(group) }}</p>
|
||||
<p class="text-xs leading-5 text-base-content/65">Короб: {{ boxQuantityLabel(group) }}</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<button
|
||||
v-if="selectedQty(group) === 0"
|
||||
class="btn btn-success h-11 w-full rounded-full border-0 text-sm font-semibold text-success-content"
|
||||
class="btn h-11 w-full rounded-full border-0 bg-[#139957] text-sm font-semibold text-white hover:bg-[#0d854a]"
|
||||
:disabled="!selectedProduct(group)"
|
||||
@click="incrementSelected(group)"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user