import React, { useEffect, useMemo, useState } from 'react' import Modal from '../../ui/Modal' import { Checkbox, NovaSelect } from '../../ui' function relationTypeForSection(sectionKey, sectionOptions, relationTypeOptions) { const section = sectionOptions.find((option) => option.value === sectionKey) return section?.relation_types?.[0] || relationTypeOptions?.[0]?.value || 'artwork' } function emptyRelation(sectionOptions, relationTypeOptions) { const sectionKey = sectionOptions?.[0]?.value || 'featured_artworks' const relationType = relationTypeForSection(sectionKey, sectionOptions, relationTypeOptions) return { section_key: sectionKey, related_type: relationType, related_id: '', context_label: '', sort_order: 0, is_featured: false, preview: null, query: '', } } function SearchResultList({ items, loading, selectedId, onSelect }) { if (loading) { return
Searching campaign entities…
} if (!Array.isArray(items) || items.length === 0) { return
Search by title, slug, creator, or project name to attach curated content.
} return (
{items.map((item) => ( ))}
) } export default function WorldRelationPickerModal({ open, onClose, onSave, initialRelation, sectionOptions, relationTypeOptions, searchEntities }) { const [draft, setDraft] = useState(() => emptyRelation(sectionOptions, relationTypeOptions)) const [results, setResults] = useState([]) const [loading, setLoading] = useState(false) useEffect(() => { if (!open) return const nextDraft = initialRelation || emptyRelation(sectionOptions, relationTypeOptions) setDraft({ ...nextDraft, query: nextDraft.query || nextDraft.preview?.title || '', }) setResults([]) setLoading(false) }, [open, initialRelation, sectionOptions, relationTypeOptions]) const selectedSection = useMemo(() => sectionOptions.find((option) => option.value === draft.section_key), [sectionOptions, draft.section_key]) const availableRelationTypes = useMemo(() => relationTypeOptions.filter((option) => !selectedSection?.relation_types?.length || selectedSection.relation_types.includes(option.value)), [relationTypeOptions, selectedSection]) const selectedPreview = useMemo(() => { if (draft.preview) return draft.preview return results.find((item) => String(item.id) === String(draft.related_id)) || null }, [draft.preview, draft.related_id, results]) useEffect(() => { if (!open || availableRelationTypes.length === 0) return if (availableRelationTypes.some((option) => option.value === draft.related_type)) return setDraft((current) => ({ ...current, related_type: availableRelationTypes[0].value, related_id: '', preview: null, })) }, [open, availableRelationTypes, draft.related_type]) useEffect(() => { if (!open || !draft.related_type) { setResults([]) setLoading(false) return undefined } let cancelled = false const timeoutId = window.setTimeout(async () => { setLoading(true) try { const items = await searchEntities(draft.related_type, draft.query || '') if (!cancelled) { setResults(Array.isArray(items) ? items : []) } } finally { if (!cancelled) { setLoading(false) } } }, draft.query ? 220 : 0) return () => { cancelled = true window.clearTimeout(timeoutId) } }, [open, draft.related_type, draft.query, searchEntities]) const actionLabel = initialRelation?.related_id ? 'Save relation' : 'Attach relation' const canSubmit = Boolean(draft.related_id) const nextRelation = selectedPreview ? { ...draft, preview: selectedPreview } : draft const footer = ( <> ) return (
setDraft((current) => { const nextSectionKey = String(nextValue || '') return { ...current, section_key: nextSectionKey, related_type: relationTypeForSection(nextSectionKey, sectionOptions, relationTypeOptions), related_id: '', preview: null, } })} options={sectionOptions} searchable={false} className="bg-black/20" /> setDraft((current) => ({ ...current, related_type: String(nextValue || ''), related_id: '', preview: null }))} options={availableRelationTypes} searchable={false} className="bg-black/20" />
setDraft((current) => ({ ...current, related_id: item.id, preview: item, query: item.title }))} /> {selectedPreview ? (
Selected: {selectedPreview.title}
{selectedPreview.subtitle ?
{selectedPreview.subtitle}
: null} {Array.isArray(selectedPreview.meta) && selectedPreview.meta.length > 0 ?
{selectedPreview.meta.map((entry) => {entry})}
: null}
Section: {selectedSection?.label || draft.section_key} · {draft.is_featured ? 'Featured relation' : 'Standard relation'}
) : null}
setDraft((current) => ({ ...current, is_featured: event.target.checked }))} label="Featured relation" size={20} variant="accent" />
) }