Simplify catalog option controls
This commit is contained in:
@@ -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="flex items-center justify-between gap-3">
|
||||||
<div class="text-sm font-semibold text-[#123824]">{{ group.label }}</div>
|
<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>
|
||||||
|
|||||||
Reference in New Issue
Block a user