import { Head, Link, router } from '@inertiajs/react'; import { Ban, Radio, Shield, StopCircle, Undo2, Users } from 'lucide-react'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { dashboard as adminDashboard } from '@/routes/admin'; import { stop as stopBroadcast } from '@/routes/admin/broadcasts'; import { restore, suspend } from '@/routes/admin/channels'; import { show as showChannel } from '@/routes/channels'; type LiveBroadcast = { id: number; title: string; started_at: string | null; channel: { id: number; slug: string; display_name: string; thumbnail_url: string | null; owner: string; }; }; type AdminChannel = { id: number; slug: string; display_name: string; avatar_url: string | null; thumbnail_url: string | null; is_live: boolean; suspended_at: string | null; owner: { id: number; name: string; }; }; type Props = { stats: { users: number; channels: number; live_channels: number; vods: number; }; liveBroadcasts: LiveBroadcast[]; channels: AdminChannel[]; }; type ModerationAction = | { kind: 'stop'; broadcast: LiveBroadcast } | { kind: 'suspend'; channel: AdminChannel } | { kind: 'restore'; channel: AdminChannel } | null; export default function AdminDashboard({ stats, liveBroadcasts, channels, }: Props) { const [action, setAction] = useState(null); function confirmAction() { if (!action) { return; } if (action.kind === 'stop') { router.post(stopBroadcast(action.broadcast.id), undefined, { onFinish: () => setAction(null), }); return; } router.post( action.kind === 'suspend' ? suspend(action.channel.slug) : restore(action.channel.slug), undefined, { onFinish: () => setAction(null) }, ); } return ( <>

Moderation console

Review live streams, suspended states, users, and recordings.

{liveBroadcasts.length} active broadcasts

Live broadcasts

{liveBroadcasts.length} rows
{liveBroadcasts.map((broadcast) => (
{broadcast.title}
{broadcast.channel.display_name} by{' '} {broadcast.channel.owner}
LIVE
))} {liveBroadcasts.length === 0 && ( )}

Recent channels

{channels.length} rows
{channels.map((channel) => (
{channel.display_name}
@{channel.slug} owned by{' '} {channel.owner.name}
{channel.is_live && ( LIVE )} {channel.suspended_at && ( SUSPENDED )}
{channel.suspended_at ? ( ) : ( )}
))}
!open && setAction(null)} > {dialogTitle(action)} {dialogDescription(action)} ); } AdminDashboard.layout = { breadcrumbs: [ { title: 'Admin', href: adminDashboard(), }, ], }; function Stat({ icon: Icon, label, value, live = false, }: { icon: typeof Radio; label: string; value: number; live?: boolean; }) { return (
{label}
{value}
); } function Thumb({ url }: { url: string | null }) { return (
{url ? ( ) : (
)}
); } function Avatar({ channel }: { channel: AdminChannel }) { return (
{channel.avatar_url ? ( ) : ( )}
); } function EmptyState({ text }: { text: string }) { return (
{text}
); } function dialogTitle(action: ModerationAction): string { if (action?.kind === 'stop') { return 'Stop live broadcast?'; } if (action?.kind === 'restore') { return 'Restore channel?'; } return 'Suspend channel?'; } function dialogDescription(action: ModerationAction): string { if (action?.kind === 'stop') { return 'The live session will end immediately and the channel will move offline.'; } if (action?.kind === 'restore') { return 'The channel will be visible again if the owning account is active.'; } return 'The channel will be hidden from public browsing and watch pages.'; }