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}
)
}