Allow artworks to have one primary category and extra secondaries.

Keep artwork_category as membership, store a deterministic primary_category_id, and let upload plus studio pick up to five additional same-type categories without changing canonical URLs.
This commit is contained in:
test
2026-09-20 14:50:12 +02:00
parent 4d60a876af
commit 232880e01f
43 changed files with 2896 additions and 565 deletions
@@ -0,0 +1,14 @@
import { describe, expect, it } from 'vitest'
import { additionalCategoryOptions } from './uploadUtils'
describe('additionalCategoryOptions', () => {
it('excludes the primary leaf and sorts remaining names alphabetically', () => {
const options = additionalCategoryOptions([
{ id: '10', name: 'Zebra', children: [{ id: '11', name: 'Moon' }] },
{ id: '12', name: 'Apple', children: [{ id: '13', name: 'City' }] },
], '11')
expect(options.map((option) => option.name)).toEqual(['Apple', 'City', 'Zebra'])
expect(options.map((option) => option.id)).not.toContain('11')
})
})
+27
View File
@@ -103,6 +103,33 @@ export function buildCategoryTree(contentTypes = []) {
return Array.from(rootsById.values())
}
export function compareCategoryNames(a, b) {
return String(a?.name || '').localeCompare(String(b?.name || ''), undefined, {
numeric: true,
sensitivity: 'base',
})
}
export function additionalCategoryOptions(roots = [], primaryId = '') {
const options = []
const seen = new Set()
const primary = String(primaryId || '')
roots.forEach((root) => {
const items = [root, ...(Array.isArray(root.children) ? root.children : [])]
items.forEach((item) => {
const id = String(item?.id || '')
if (!id || id === primary || seen.has(id)) {
return
}
seen.add(id)
options.push({ id, name: item.name || `Category ${id}` })
})
})
return options.sort(compareCategoryNames)
}
// ─── Content type helpers ─────────────────────────────────────────────────────
export function getContentTypeValue(type) {
if (!type) return ''