From fa54e113c3586672f657c8fdcbaafbe085d7e91c Mon Sep 17 00:00:00 2001 From: Ty Balascio Date: Fri, 25 Sep 2026 11:56:28 -0700 Subject: [PATCH] fix(fe): match fig-/feat- tags by slug, and echo Figure selections to tags Two fixes in the review form: - figTags/featTags filtered on tag.name.startsWith('fig-'), but the live store marks the family on the SLUG (slug 'fig-chat', name 'Chatoyant'), so the figure/feature tag groups rendered empty. Match slug OR name. - Echo Figure selections transparently: picking a Figure attribute term auto-selects the same-named fig-* tag and vice versa, so the Woo product carries the figure in both the pa_fig attribute and the fig-* tag without the owner picking it twice. --- frontend/src/review/ReviewForm.svelte | 45 +++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/frontend/src/review/ReviewForm.svelte b/frontend/src/review/ReviewForm.svelte index cb6224e..3feb599 100644 --- a/frontend/src/review/ReviewForm.svelte +++ b/frontend/src/review/ReviewForm.svelte @@ -43,8 +43,10 @@ $: gradeTerms = attributeByName('Grade')?.terms ?? []; $: thicknessTerms = attributeByName('Thickness')?.terms ?? []; $: moistureTerms = attributeByName('Moisture')?.terms ?? []; - $: figTags = (taxonomy?.tags ?? []).filter((t) => t.name.startsWith('fig-')); - $: featTags = (taxonomy?.tags ?? []).filter((t) => t.name.startsWith('feat-')); + // The fig-/feat- family marker is on the tag SLUG (slug 'fig-chat', name + // 'Chatoyant'), so match slug OR name (METADATA-30: bare names are kept). + $: figTags = (taxonomy?.tags ?? []).filter((t) => t.slug.startsWith('fig-') || t.name.startsWith('fig-')); + $: featTags = (taxonomy?.tags ?? []).filter((t) => t.slug.startsWith('feat-') || t.name.startsWith('feat-')); $: speciesName = (id: number | null) => categories.find((c) => c.id === id)?.name ?? ''; $: figureName = figureTerms.find((t) => t.id === (slab.figureTermIds?.[0] ?? null))?.name ?? null; @@ -150,12 +152,43 @@ primaryCatId = nextPrimary(selected, primaryCatId); regenerateCopy(); } + // Figure selections echo transparently between the Figure attribute terms + // (pa_fig) and the synced fig-* product tags, so the Woo product carries the + // same figure in both places without the owner picking it twice. Matched + // case-insensitively on the display name (attribute "Curly" -> tag "Curly"). + const normName = (s: string) => s.trim().toLowerCase(); + + function echoFigTag(termId: number, selected: boolean) { + const term = figureTerms.find((t) => t.id === termId); + if (!term) return; + const key = normName(term.name); + const match = figTags.find((t) => normName(t.name) === key); + if (match) figTagIds = toggleTag(figTagIds, match.id, selected); + } + + function echoFigTerm(tagId: number, selected: boolean) { + const tag = figTags.find((t) => t.id === tagId); + if (!tag) return; + const key = normName(tag.name); + const match = figureTerms.find((t) => normName(t.name) === key); + if (match) figIds = selected ? [...new Set([...figIds, match.id])] : figIds.filter((x) => x !== match.id); + } + function toggleFig(id: number) { - figIds = figIds.includes(id) ? figIds.filter((x) => x !== id) : [...figIds, id]; + const next = figIds.includes(id) ? figIds.filter((x) => x !== id) : [...figIds, id]; + figIds = next; + echoFigTag(id, next.includes(id)); regenerateCopy(); } - function toggleTag(list: number[], id: number): number[] { - return list.includes(id) ? list.filter((x) => x !== id) : [...list, id]; + function toggleFigTag(id: number) { + const next = toggleTag(figTagIds, id); + figTagIds = next; + echoFigTerm(id, next.includes(id)); + regenerateCopy(); + } + function toggleTag(list: number[], id: number, forceSelected?: boolean): number[] { + const on = forceSelected ?? !list.includes(id); + return on ? [...new Set([...list, id])] : list.filter((x) => x !== id); } // ── Call 2: long description (METADATA-115) with template fallback ── @@ -293,7 +326,7 @@
Figure tags {#each figTags as t (t.id)} - + {/each}
{/if}