import React, { useEffect, useState } from 'react' import { router, usePage } from '@inertiajs/react' import StudioLayout from '../../Layouts/StudioLayout' import { studioSurface, trackStudioEvent } from '../../utils/studioEvents' import { formatReleaseCountdown, formatScheduledDate } from '../../utils/scheduleCountdown' async function requestJson(url, method = 'POST') { 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', }, }) const payload = await response.json().catch(() => ({})) if (!response.ok) throw new Error(payload?.message || 'Request failed') return payload } export default function StudioCalendar() { const { props } = usePage() const calendar = props.calendar || {} const filters = calendar.filters || {} const summary = calendar.summary || {} const [busyKey, setBusyKey] = useState(null) const [nowMs, setNowMs] = useState(() => Date.now()) const updateFilters = (patch) => { const next = { ...filters, ...patch } trackStudioEvent('studio_scheduled_opened', { surface: studioSurface(), module: next.module, meta: patch, }) router.get(window.location.pathname, next, { preserveScroll: true, preserveState: true, replace: true, }) } const runAction = async (pattern, item, key) => { const url = String(pattern || '').replace('__MODULE__', item.module).replace('__ID__', String(item.numeric_id)) setBusyKey(`${key}:${item.id}`) try { await requestJson(url) router.reload({ preserveScroll: true, preserveState: true }) } catch (error) { window.alert(error?.message || 'Unable to update schedule.') } finally { setBusyKey(null) } } useEffect(() => { const hasTimedEntries = Boolean(summary.next_publish_at) || (calendar.scheduled_items || []).some((item) => Boolean(item.scheduled_at)) if (!hasTimedEntries) return undefined const timer = window.setInterval(() => { setNowMs(Date.now()) }, 1000) return () => window.clearInterval(timer) }, [calendar.scheduled_items, summary.next_publish_at]) return (
Scheduled
{Number(summary.scheduled_total || 0).toLocaleString()}
Unscheduled
{Number(summary.unscheduled_total || 0).toLocaleString()}
Overloaded days
{Number(summary.overloaded_days || 0).toLocaleString()}
Next publish
{formatReleaseCountdown(summary.next_publish_at, nowMs)}
{summary.next_publish_at &&
{formatScheduledDate(summary.next_publish_at)}
}
{filters.view === 'week' ? ( <>

{calendar.week?.label}

{(calendar.week?.days || []).map((day) => (
{day.label}
{day.items.length > 0 ? day.items.map((item) => {item.title}) :
No scheduled items
}
))}
) : filters.view === 'agenda' ? ( <>

Agenda

{(calendar.agenda || []).map((group) =>
{group.label}
{group.count} items
)}
) : ( <>

{calendar.month?.label}

{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map((label) =>
{label}
)}
{(calendar.month?.days || []).map((day) =>
{day.day}{day.count}
{day.items.map((item) => {item.title})}
)}
)}
) }