import React from 'react' import { Head, Link, usePage } from '@inertiajs/react' function requestJson(url, { method = 'GET', body } = {}) { return fetch(url, { method, credentials: 'same-origin', headers: { Accept: 'application/json', 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '', 'X-Requested-With': 'XMLHttpRequest', }, body: body ? JSON.stringify(body) : undefined, }).then(async (response) => { const payload = await response.json().catch(() => ({})) if (!response.ok) throw new Error(payload?.message || 'Request failed') return payload }) } export default function NovaCardsCollectionAdmin() { const { props } = usePage() const [collections, setCollections] = React.useState(props.collections || []) const [selectedId, setSelectedId] = React.useState(props.collections?.[0]?.id || null) const [cardId, setCardId] = React.useState('') const [cardNote, setCardNote] = React.useState('') const endpoints = props.endpoints || {} const admins = props.admins || [] const cards = props.cards || [] const selected = React.useMemo(() => collections.find((entry) => entry.id === selectedId) || null, [collections, selectedId]) const [form, setForm] = React.useState(() => ({ user_id: admins[0]?.id || '', slug: '', name: '', description: '', visibility: 'public', official: true, featured: false, })) React.useEffect(() => { if (!selected) { setForm({ user_id: admins[0]?.id || '', slug: '', name: '', description: '', visibility: 'public', official: true, featured: false }) return } setForm({ user_id: selected.owner?.id || admins[0]?.id || '', slug: selected.slug || '', name: selected.name || '', description: selected.description || '', visibility: selected.visibility || 'public', official: Boolean(selected.official), featured: Boolean(selected.featured), }) }, [admins, selected]) async function saveCollection() { const isExisting = Boolean(selectedId) const url = isExisting ? String(endpoints.updatePattern || '').replace('__COLLECTION__', String(selectedId)) : endpoints.store const response = await requestJson(url, { method: isExisting ? 'PATCH' : 'POST', body: form }) if (isExisting) { setCollections((current) => current.map((entry) => (entry.id === selectedId ? response.collection : entry))) } else { setCollections((current) => [response.collection, ...current]) setSelectedId(response.collection.id) } } async function attachCard() { if (!selectedId || !cardId) return const response = await requestJson(String(endpoints.attachCardPattern || '').replace('__COLLECTION__', String(selectedId)), { method: 'POST', body: { card_id: Number(cardId), note: cardNote || null }, }) setCollections((current) => current.map((entry) => (entry.id === selectedId ? response.collection : entry))) setCardId('') setCardNote('') } async function detachCard(collectionId, currentCardId) { const response = await requestJson( String(endpoints.detachCardPattern || '') .replace('__COLLECTION__', String(collectionId)) .replace('__CARD__', String(currentCardId)), { method: 'DELETE' }, ) setCollections((current) => current.map((entry) => (entry.id === collectionId ? response.collection : entry))) } return (

Editorial layer

Official and public card collections

Create editorial collections, assign owners, and curate the public card sets that the v2 browse surface links to.

Back to cards
Collections
{collections.map((collection) => ( ))}
Collection editor
setForm((current) => ({ ...current, name: event.target.value }))} placeholder="Collection name" className="rounded-2xl border border-white/10 bg-[#0d1726] px-4 py-3 text-white" /> setForm((current) => ({ ...current, slug: event.target.value }))} placeholder="Slug" className="rounded-2xl border border-white/10 bg-[#0d1726] px-4 py-3 text-white" />