import React, { useEffect, useState } from 'react' import { router } from '@inertiajs/react' import { studioSurface, trackStudioEvent } from '../../utils/studioEvents' function formatDate(value) { if (!value) return 'Unscheduled' const date = new Date(value) if (Number.isNaN(date.getTime())) return 'Unscheduled' return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) } function metricValue(item, key) { return Number(item?.metrics?.[key] ?? 0).toLocaleString() } function readinessClasses(readiness) { if (!readiness) return 'border-white/15 bg-white/5 text-slate-300' if (readiness.can_publish && readiness.score >= readiness.max) return 'border-emerald-400/30 bg-emerald-400/10 text-emerald-100' if (readiness.can_publish) return 'border-sky-400/30 bg-sky-400/10 text-sky-100' return 'border-amber-400/30 bg-amber-400/10 text-amber-100' } function statusClasses(status) { switch (status) { case 'published': return 'border-emerald-400/30 bg-emerald-400/10 text-emerald-200' case 'draft': case 'pending_review': return 'border-amber-400/30 bg-amber-400/10 text-amber-100' case 'scheduled': case 'processing': return 'border-sky-400/30 bg-sky-400/10 text-sky-100' case 'archived': case 'hidden': case 'rejected': return 'border-white/15 bg-white/5 text-slate-300' default: return 'border-white/15 bg-white/5 text-slate-200' } } function ActionLink({ href, icon, label, onClick }) { if (!href) return null return ( {label} ) } function RequestActionButton({ action, onExecute, busyKey }) { if (!action || action.type !== 'request') return null const isBusy = busyKey === `${action.key}:${action.url}` return ( ) } function PreviewLink({ item }) { if (!item?.preview_url) return null return } function GridCard({ item, onExecuteAction, busyKey }) { const handleEditClick = () => { trackStudioEvent('studio_item_edited', { surface: studioSurface(), module: item.module, item_module: item.module, item_id: item.numeric_id, meta: { action: 'edit', }, }) } return (
{item.image_url ? ( {item.title} ) : (
)}
{item.module_label}

{item.title}

{item.subtitle || item.visibility || 'Untitled metadata'}

{String(item.status || 'unknown').replace('_', ' ')}
{item.workflow?.readiness && (
{item.workflow.readiness.label} {item.workflow.is_stale_draft && ( Stale draft )} {item.workflow.readiness.score}/{item.workflow.readiness.max} ready
)}

{item.description || 'No description yet.'}

{Array.isArray(item.workflow?.readiness?.missing) && item.workflow.readiness.missing.length > 0 && (
{item.workflow.readiness.missing.slice(0, 2).join(' • ')}
)}
Views
{metricValue(item, 'views')}
Reactions
{metricValue(item, 'appreciation')}
Comments
{metricValue(item, 'comments')}
Updated {formatDate(item.updated_at)} {item.published_at && Published {formatDate(item.published_at)}}
{(item.actions || []).map((action) => ( ))}
{Array.isArray(item.workflow?.cross_module_actions) && item.workflow.cross_module_actions.length > 0 && (
{item.workflow.cross_module_actions.slice(0, 2).map((action) => ( ))}
)}
) } function ListRow({ item, onExecuteAction, busyKey }) { const handleEditClick = () => { trackStudioEvent('studio_item_edited', { surface: studioSurface(), module: item.module, item_module: item.module, item_id: item.numeric_id, meta: { action: 'edit', }, }) } return (
{item.image_url ? ( {item.title} ) : (
)}
{item.module_label} {String(item.status || 'unknown').replace('_', ' ')}

{item.title}

{item.subtitle || item.visibility || 'Untitled metadata'}

{item.description || 'No description yet.'}

{item.workflow?.readiness && ( {item.workflow.readiness.label} )} {item.workflow?.is_stale_draft && ( Stale draft )}
{metricValue(item, 'views')} views {metricValue(item, 'appreciation')} reactions {metricValue(item, 'comments')} comments Updated {formatDate(item.updated_at)}
{Array.isArray(item.workflow?.readiness?.missing) && item.workflow.readiness.missing.length > 0 && (
{item.workflow.readiness.missing.slice(0, 2).join(' • ')}
)}
{(item.actions || []).map((action) => ( ))} {(item.workflow?.cross_module_actions || []).slice(0, 2).map((action) => ( ))}
) } function AdvancedFilterControl({ filter, onChange }) { if (filter.type === 'select') { return ( ) } return ( ) } export default function StudioContentBrowser({ listing, quickCreate = [], hideModuleFilter = false, hideBucketFilter = false, emptyTitle = 'Nothing here yet', emptyBody = 'Try adjusting filters or create something new.', }) { const [viewMode, setViewMode] = useState('grid') const [busyKey, setBusyKey] = useState(null) const filters = listing?.filters || {} const items = listing?.items || [] const meta = listing?.meta || {} const advancedFilters = listing?.advanced_filters || [] useEffect(() => { const stored = window.localStorage.getItem('studio-content-view') if (stored === 'grid' || stored === 'list') { setViewMode(stored) return } if (listing?.default_view === 'grid' || listing?.default_view === 'list') { setViewMode(listing.default_view) } }, [listing?.default_view]) const updateQuery = (patch) => { const next = { ...filters, ...patch, } if (patch.page == null) { next.page = 1 } trackStudioEvent('studio_filter_used', { surface: studioSurface(), module: filters.module || listing?.module || null, meta: { patch, }, }) router.get(window.location.pathname, next, { preserveScroll: true, preserveState: true, replace: true, }) } const updateView = (nextMode) => { setViewMode(nextMode) window.localStorage.setItem('studio-content-view', nextMode) trackStudioEvent('studio_filter_used', { surface: studioSurface(), module: filters.module || listing?.module || null, meta: { view_mode: nextMode, }, }) } const executeAction = async (action) => { if (!action?.url || action.type !== 'request') { return } if (action.confirm && !window.confirm(action.confirm)) { return } const requestKey = `${action.key}:${action.url}` setBusyKey(requestKey) try { const response = await fetch(action.url, { method: String(action.method || 'post').toUpperCase(), 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: action.payload ? JSON.stringify(action.payload) : undefined, }) const payload = await response.json().catch(() => ({})) if (!response.ok) { throw new Error(payload?.message || payload?.error || 'Request failed') } if (action.key === 'archive') { trackStudioEvent('studio_item_archived', { surface: studioSurface(), module: filters.module || null, item_module: action.item_module || null, item_id: action.item_id || null, meta: { action: action.key, url: action.url, }, }) } if (action.key === 'restore') { trackStudioEvent('studio_item_restored', { surface: studioSurface(), module: filters.module || null, item_module: action.item_module || null, item_id: action.item_id || null, meta: { action: action.key, url: action.url, }, }) } if (action.redirect_pattern && payload?.data?.id) { window.location.assign(action.redirect_pattern.replace('__ID__', String(payload.data.id))) return } if (payload?.redirect) { window.location.assign(payload.redirect) return } router.reload({ preserveScroll: true, preserveState: true }) } catch (error) { window.alert(error?.message || 'Action failed.') } finally { setBusyKey(null) } } return (
0 ? 'xl:grid-cols-5' : 'xl:grid-cols-4'}`}> {!hideModuleFilter && ( )} {!hideBucketFilter && ( )} {advancedFilters.map((filter) => ( updateQuery({ [key]: value })} /> ))}
{[ { value: 'grid', icon: 'fa-solid fa-table-cells-large', label: 'Grid view' }, { value: 'list', icon: 'fa-solid fa-list', label: 'List view' }, ].map((option) => ( ))}
{quickCreate.map((action) => ( trackStudioEvent('studio_quick_create_used', { surface: studioSurface(), module: action.key, meta: { href: action.url, label: action.label, }, })} className="inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-300/10 px-4 py-2 text-xs font-semibold text-sky-100 transition hover:border-sky-300/35 hover:bg-sky-300/15" > New {action.label} ))}

Showing {items.length} of {Number(meta.total || 0).toLocaleString()} items

Page {meta.current_page || 1} of {meta.last_page || 1}

{items.length > 0 ? ( viewMode === 'grid' ? (
{items.map((item) => )}
) : (
{items.map((item) => )}
) ) : (

{emptyTitle}

{emptyBody}

)}
Creator Studio
) }