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
Open
setAction({
kind: 'stop',
broadcast,
})
}
>
Stop
))}
{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
)}
Open
{channel.suspended_at ? (
setAction({
kind: 'restore',
channel,
})
}
>
Restore
) : (
setAction({
kind: 'suspend',
channel,
})
}
>
Suspend
)}
))}
!open && setAction(null)}
>
{dialogTitle(action)}
{dialogDescription(action)}
setAction(null)}
>
Cancel
Confirm
>
);
}
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 (
);
}
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.';
}