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:
MMD
2026-09-16 20:31:01 +03:30
parent ae977e5e66
commit 7b3ae3cb60
3 changed files with 40 additions and 7 deletions
+11
View File
@@ -1218,6 +1218,17 @@ export const api = {
brandsList: async (): Promise<{ id: string; name: string }[]> => {
return getData<{ id: string; name: string }[]>(`/brands?page_size=${PAGE_SIZE}`);
},
// مشخصه‌ها — رجیستری سراسری (attribute-definitions)، مستقل از تاپیک/دسته/برند.
// ویزارد از این لیست به‌عنوان منبع سراسری مشخصه‌ها استفاده می‌کند تا مشخصه‌های
// ثبت‌شده در پیشنهادهای قبلی همیشه در دسترس باشند.
specsList: async (): Promise<string[]> => {
const raw = await getData<{ label?: string; attribute_key?: string }[]>(
`/attribute-definitions?page_size=${PAGE_SIZE}`,
);
return raw
.map((d) => (d.label || "").trim() || (d.attribute_key || "").replace(/^spec_/, "").trim())
.filter(Boolean);
},
// ---------- واحدها (از بک‌اند) ----------
unitsList: async (): Promise<RawUnit[]> => {