feat(wizard): cache مشخصه globally instead of per topic/category/brand
The specs combobox drew only from materials in the selected topic, further
narrowed by the row's category and brand, so a spec was offered only when
some material in that topic shared the same category AND brand. On a new
quote the user therefore lost specs recorded in earlier quotes.
- api.specsList(): new global source reading the attribute-definitions
registry (topic/category/brand independent)
- materialOptions('spec'): unions the registry, specs of all materials,
and specs typed in sibling rows — no topic/category/brand filter
- EditModal: same global registry added to its spec options
Verified the registry endpoint returns labels and that the union includes
specs absent from material attributes (e.g. 'مسی').
This commit is contained in:
@@ -75,10 +75,10 @@ export function materialOptions(
|
||||
field: "cat" | "brand" | "spec",
|
||||
allItems: ItemDraft[] = [],
|
||||
apiBrands: string[] = [],
|
||||
apiSpecs: string[] = [],
|
||||
): string[] {
|
||||
let list = materials.filter((m) => topic && normalize(m.topic) === normalize(topic));
|
||||
const cat = item.cat.trim();
|
||||
const brand = item.brand.trim();
|
||||
|
||||
const fromRows = (sel: (it: ItemDraft) => string | string[]): string[] => {
|
||||
const out = new Set<string>();
|
||||
@@ -96,15 +96,21 @@ export function materialOptions(
|
||||
fromRows((it) => it.cat).forEach((c) => base.add(c));
|
||||
return [...base].sort((a, b) => a.localeCompare(b, "fa"));
|
||||
}
|
||||
if (cat) list = list.filter((m) => normalize(m.category) === normalize(cat));
|
||||
if (field === "brand") {
|
||||
// برند سراسری است — مستقل از تاپیک و دسته
|
||||
const allBrands = new Set(materials.map((m) => m.brand).filter(Boolean));
|
||||
apiBrands.forEach((b) => b && allBrands.add(b));
|
||||
fromRows((it) => it.brand).forEach((b) => allBrands.add(b));
|
||||
return [...allBrands].sort((a, b) => a.localeCompare(b, "fa"));
|
||||
}
|
||||
if (brand) list = list.filter((m) => normalize(m.brand) === normalize(brand));
|
||||
const base = new Set(list.flatMap((m) => (m.specs || []).filter(Boolean)));
|
||||
if (cat) list = list.filter((m) => normalize(m.category) === normalize(cat));
|
||||
// مشخصهها سراسری هستند: رجیستری attribute-definitions + مشخصههای همهی
|
||||
// متریالها + مشخصههای تایپشده در سایر ردیفها. به تاپیک/دسته/برندِ قلمِ
|
||||
// فعلی گره نمیخورند تا هنگام افزودن پیشنهاد جدید همیشه در دسترس باشند.
|
||||
const base = new Set<string>();
|
||||
apiSpecs.forEach((s) => s && base.add(s));
|
||||
materials.forEach((m) => (m.specs || []).forEach((s) => s && base.add(s)));
|
||||
list.forEach((m) => (m.specs || []).forEach((s) => s && base.add(s)));
|
||||
fromRows((it) => it.specs).forEach((s) => base.add(s));
|
||||
return [...base].sort((a, b) => a.localeCompare(b, "fa"));
|
||||
}
|
||||
@@ -135,6 +141,7 @@ export function Step2LineItems({ items, onItemsChange, selectedTopic, onRemember
|
||||
}, [materials]);
|
||||
|
||||
const [brandOptions, setBrandOptions] = useState<string[]>([]);
|
||||
const [specOptions, setSpecOptions] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
let alive = true;
|
||||
@@ -150,6 +157,10 @@ export function Step2LineItems({ items, onItemsChange, selectedTopic, onRemember
|
||||
.brandsList()
|
||||
.then((list) => alive && setBrandOptions(list.map((b) => b.name).filter(Boolean)))
|
||||
.catch(() => {});
|
||||
void api
|
||||
.specsList()
|
||||
.then((list) => alive && setSpecOptions(list))
|
||||
.catch(() => {});
|
||||
return () => { alive = false; };
|
||||
}, []);
|
||||
|
||||
@@ -240,7 +251,7 @@ export function Step2LineItems({ items, onItemsChange, selectedTopic, onRemember
|
||||
<MultiSelectCombobox
|
||||
values={it.specs}
|
||||
onChange={(specs) => patch(it.tempId, { specs })}
|
||||
options={materialOptions(materials, selectedTopic, it, "spec", items)}
|
||||
options={materialOptions(materials, selectedTopic, it, "spec", items, [], specOptions)}
|
||||
placeholder="مشخصه"
|
||||
className="min-w-0"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user