import React, { useMemo, useState } from 'react' import { router, usePage } from '@inertiajs/react' import StudioLayout from '../../Layouts/StudioLayout' import { studioSurface, trackStudioEvent } from '../../utils/studioEvents' const reportReasons = [ { value: 'spam', label: 'Spam or scam' }, { value: 'harassment', label: 'Harassment' }, { value: 'abuse', label: 'Abusive content' }, { value: 'stolen', label: 'Stolen or impersonation' }, { value: 'other', label: 'Other' }, ] function formatDate(value) { if (!value) return 'Unknown' const date = new Date(value) if (Number.isNaN(date.getTime())) return 'Unknown' return date.toLocaleString() } async function requestJson(url, method, body) { const response = await 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, }) const payload = await response.json().catch(() => ({})) if (!response.ok) { throw new Error(payload?.message || payload?.error || 'Request failed') } return payload } export default function StudioComments() { const { props } = usePage() const listing = props.listing || {} const filters = listing.filters || {} const items = listing.items || [] const meta = listing.meta || {} const moduleOptions = listing.module_options || [] const endpoints = props.endpoints || {} const [busyKey, setBusyKey] = useState(null) const [replyFor, setReplyFor] = useState(null) const [replyText, setReplyText] = useState('') const [reportFor, setReportFor] = useState(null) const [reportReason, setReportReason] = useState('spam') const [reportDetails, setReportDetails] = useState('') const visibleSummary = useMemo(() => { return moduleOptions .filter((option) => option.value !== 'all') .map((option) => ({ ...option, count: items.filter((item) => item.module === option.value).length, })) }, [items, moduleOptions]) const updateFilters = (patch) => { const next = { ...filters, ...patch, } if (patch.page == null) { next.page = 1 } trackStudioEvent('studio_filter_used', { surface: studioSurface(), module: 'comments', meta: patch, }) router.get(window.location.pathname, next, { preserveScroll: true, preserveState: true, replace: true, }) } const buildUrl = (pattern, comment) => pattern .replace('__MODULE__', comment.module) .replace('__COMMENT__', String(comment.comment_id)) const submitReply = async (comment) => { if (!replyText.trim()) { window.alert('Reply cannot be empty.') return } const key = `reply:${comment.id}` setBusyKey(key) try { await requestJson(buildUrl(endpoints.replyPattern, comment), 'POST', { content: replyText.trim(), }) trackStudioEvent('studio_comment_replied', { surface: studioSurface(), module: comment.module, item_module: comment.module, item_id: comment.item_id, }) setReplyFor(null) setReplyText('') router.reload({ preserveScroll: true, preserveState: true }) } catch (error) { window.alert(error?.message || 'Unable to send reply.') } finally { setBusyKey(null) } } const moderateComment = async (comment) => { if (!window.confirm('Remove this comment from the conversation stream?')) { return } const key = `moderate:${comment.id}` setBusyKey(key) try { await requestJson(buildUrl(endpoints.moderatePattern, comment), 'DELETE') trackStudioEvent('studio_comment_moderated', { surface: studioSurface(), module: comment.module, item_module: comment.module, item_id: comment.item_id, }) router.reload({ preserveScroll: true, preserveState: true }) } catch (error) { window.alert(error?.message || 'Unable to remove comment.') } finally { setBusyKey(null) } } const submitReport = async (comment) => { const key = `report:${comment.id}` setBusyKey(key) try { await requestJson(buildUrl(endpoints.reportPattern, comment), 'POST', { reason: reportReason, details: reportDetails.trim() || null, }) trackStudioEvent('studio_comment_reported', { surface: studioSurface(), module: comment.module, item_module: comment.module, item_id: comment.item_id, }) setReportFor(null) setReportReason('spam') setReportDetails('') window.alert('Report sent.') } catch (error) { window.alert(error?.message || 'Unable to report comment.') } finally { setBusyKey(null) } } return (

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

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

{items.length > 0 ? items.map((comment) => { const replyBusy = busyKey === `reply:${comment.id}` const moderateBusy = busyKey === `moderate:${comment.id}` const reportBusy = busyKey === `report:${comment.id}` return (
{comment.author_avatar_url ? ( {comment.author_name} ) : (
)}
{comment.module_label} {comment.time_ago || formatDate(comment.created_at)}

{comment.author_name} {' '}on{' '} {comment.item_title || 'Untitled item'}

{comment.body}

{comment.preview_url && ( Preview )} Context {comment.reply_supported && ( )} {comment.moderate_supported && ( )} {comment.report_supported && ( )}
{replyFor === comment.id && (