Simplify catalog option controls

This commit is contained in:
Ruslan Bakiev
2026-04-09 17:27:25 +07:00
parent 6f1df4bf00
commit 2b134940f0

View File

@@ -34,7 +34,6 @@ type CatalogSettingForm = {
sleeveOptions: string[]; sleeveOptions: string[];
colorOptions: string[]; colorOptions: string[];
labelOptions: string[]; labelOptions: string[];
drafts: Record<OptionKey, string>;
}; };
type OptionGroupDefinition = { type OptionGroupDefinition = {
key: OptionKey; key: OptionKey;
@@ -72,17 +71,6 @@ function toInputValue(value: number | null | undefined) {
return value == null ? '' : String(value); return value == null ? '' : String(value);
} }
function createDrafts(): Record<OptionKey, string> {
return {
widthOptionsMm: '',
lengthOptionsM: '',
thicknessOptionsMicron: '',
sleeveOptions: '',
colorOptions: '',
labelOptions: '',
};
}
function parseOptionalInteger(value: string) { function parseOptionalInteger(value: string) {
const normalized = value.trim(); const normalized = value.trim();
if (!normalized) { if (!normalized) {
@@ -135,7 +123,6 @@ function createForm(item: CatalogSettingItem): CatalogSettingForm {
sleeveOptions: normalizeOptionList(item.sleeveOptions, 'text'), sleeveOptions: normalizeOptionList(item.sleeveOptions, 'text'),
colorOptions: normalizeOptionList(item.colorOptions, 'text'), colorOptions: normalizeOptionList(item.colorOptions, 'text'),
labelOptions: normalizeOptionList(item.labelOptions, 'text'), labelOptions: normalizeOptionList(item.labelOptions, 'text'),
drafts: createDrafts(),
}; };
} }
@@ -144,20 +131,28 @@ function formFor(item: CatalogSettingItem) {
return forms[item.productType]; return forms[item.productType];
} }
function addOption(form: CatalogSettingForm, group: OptionGroupDefinition) { function addOption(form: CatalogSettingForm, group: OptionGroupDefinition, rawValue: string) {
const value = normalizeOptionEntry(form.drafts[group.key], group.kind); const value = normalizeOptionEntry(rawValue, group.kind);
if (!value) { if (!value) {
return; return;
} }
form[group.key] = normalizeOptionList([...form[group.key], value], group.kind); form[group.key] = normalizeOptionList([...form[group.key], value], group.kind);
form.drafts[group.key] = '';
} }
function removeOption(form: CatalogSettingForm, groupKey: OptionKey, value: string) { function removeOption(form: CatalogSettingForm, groupKey: OptionKey, value: string) {
form[groupKey] = form[groupKey].filter((item) => item !== value); form[groupKey] = form[groupKey].filter((item) => item !== value);
} }
function openAddOptionPrompt(form: CatalogSettingForm, group: OptionGroupDefinition) {
const value = window.prompt(group.placeholder, '');
if (value == null) {
return;
}
addOption(form, group, value);
}
function optionChipLabel(value: string, group: OptionGroupDefinition) { function optionChipLabel(value: string, group: OptionGroupDefinition) {
return group.suffix ? `${value} ${group.suffix}` : value; return group.suffix ? `${value} ${group.suffix}` : value;
} }
@@ -311,21 +306,30 @@ async function saveAllSettings() {
<div <div
v-for="group in OPTION_GROUPS" v-for="group in OPTION_GROUPS"
:key="`${item.productType}-${group.key}`" :key="`${item.productType}-${group.key}`"
class="rounded-[20px] bg-white p-4" class="group rounded-[20px] bg-white p-4"
> >
<div class="space-y-3"> <div class="space-y-3">
<div class="text-sm font-semibold text-[#123824]">{{ group.label }}</div> <div class="flex items-center justify-between gap-3">
<div class="text-sm font-semibold text-[#123824]">{{ group.label }}</div>
<button
type="button"
class="inline-flex h-7 w-7 items-center justify-center rounded-full border border-[#d6e7dc] text-sm font-semibold text-[#6a8a78] opacity-0 transition group-hover:opacity-100 hover:border-[#9ccbb0] hover:text-[#155c3a]"
@click="openAddOptionPrompt(formFor(item), group)"
>
+
</button>
</div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<button <button
v-for="value in formFor(item)[group.key]" v-for="value in formFor(item)[group.key]"
:key="`${item.productType}-${group.key}-${value}`" :key="`${item.productType}-${group.key}-${value}`"
type="button" type="button"
class="inline-flex items-center gap-2 rounded-full bg-[#eef7f1] px-3 py-1 text-xs font-semibold text-[#1d5a3c]" class="group/chip inline-flex items-center gap-2 rounded-full bg-[#eef7f1] px-3 py-1 text-xs font-semibold text-[#1d5a3c]"
@click="removeOption(formFor(item), group.key, value)" @click="removeOption(formFor(item), group.key, value)"
> >
<span>{{ optionChipLabel(value, group) }}</span> <span>{{ optionChipLabel(value, group) }}</span>
<span class="text-[11px] leading-none text-[#6a8a78]">×</span> <span class="text-[11px] leading-none text-[#6a8a78] opacity-0 transition group-hover/chip:opacity-100">×</span>
</button> </button>
<span <span
@@ -336,24 +340,6 @@ async function saveAllSettings() {
</span> </span>
</div> </div>
<div class="flex flex-col gap-2 md:flex-row">
<input
v-model="formFor(item).drafts[group.key]"
:type="group.kind === 'number' ? 'number' : 'text'"
:min="group.kind === 'number' ? '1' : undefined"
:step="group.kind === 'number' ? '1' : undefined"
class="input manager-field w-full"
:placeholder="group.placeholder"
@keydown.enter.prevent="addOption(formFor(item), group)"
>
<button
type="button"
class="btn h-11 rounded-full border-0 bg-[#dff2e7] px-5 text-sm font-semibold text-[#155c3a] hover:bg-[#caead8]"
@click="addOption(formFor(item), group)"
>
Добавить
</button>
</div>
</div> </div>
</div> </div>
</div> </div>