dvijaykrishnan's picture
feat: Implement admin moderation history, audit logging for detection actions, and a new admin navigation and opportunity hub.
5480d48
Raw
History Blame Contribute Delete
7.67 kB
import { getAnalysisQueue } from "@/features/admin/actions/analysis";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Video, Clock, CheckCircle2, AlertCircle, Play, ArrowRight } from "lucide-react";
import Link from "next/link";
import { formatDistanceToNow } from "date-fns";
export const metadata = {
title: "Video Hub | Vault Admin",
};
export default async function AnalysisQueuePage(props: {
searchParams: Promise<{ status?: string }>;
}) {
const searchParams = await props.searchParams;
const status = searchParams.status;
const queue = await getAnalysisQueue(status);
const getStatusColor = (status: string) => {
switch (status) {
case 'pending_analysis': return 'bg-amber-500/10 text-amber-500 border-amber-500/20';
case 'in_progress': return 'bg-blue-500/10 text-blue-500 border-blue-500/20';
case 'awaiting_approval': return 'bg-emerald-500/10 text-emerald-500 border-emerald-500/20';
default: return 'bg-slate-500/10 text-slate-500 border-slate-500/20';
}
};
const getStatusLabel = (status: string) => {
switch (status) {
case 'pending_analysis': return 'In Intake';
case 'in_progress': return 'In Pipeline';
case 'awaiting_approval': return 'Ready for Review';
default: return status;
}
};
return (
<div className="space-y-6">
<div className="flex flex-col gap-2">
<div className="flex items-center gap-2 text-xs text-muted-foreground mb-1">
<Link href="/admin/dashboard" className="hover:text-primary transition-colors">Dashboard</Link>
<span>/</span>
<span className="text-foreground font-medium">Video Hub</span>
</div>
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold tracking-tight">Video Hub</h1>
<p className="text-muted-foreground">Manage video content submitted for AI product discovery.</p>
</div>
{status && (
<Badge variant="outline" className="h-8 gap-2">
<span className="w-2 h-2 rounded-full bg-primary animate-pulse" />
Filtering by: {getStatusLabel(status)}
<Button variant="ghost" size="icon" className="h-4 w-4 ml-2 p-0" asChild>
<Link href="/admin/analysis-queue">×</Link>
</Button>
</Badge>
)}
</div>
</div>
<div className="grid gap-4">
{queue.length === 0 ? (
<Card className="flex flex-col items-center justify-center py-12 text-center">
<CheckCircle2 className="h-12 w-12 text-muted-foreground mb-4 opacity-20" />
<CardTitle>Queue is empty</CardTitle>
<CardDescription>No videos currently require analysis review.</CardDescription>
</Card>
) : (
queue.map((video) => (
<Card key={video.id} className="overflow-hidden bg-card/40 backdrop-blur-md border-border/40 hover:border-primary/50 transition-colors">
<div className="flex flex-col md:flex-row">
<div className="relative w-full md:w-48 aspect-video md:aspect-auto">
<img
src={video.thumbnailUrl || ''}
alt={video.title}
className="absolute inset-0 w-full h-full object-cover"
/>
{video.scanStatus === 'in_progress' && (
<div className="absolute inset-0 bg-background/60 backdrop-blur-sm flex items-center justify-center">
<div className="flex flex-col items-center gap-2">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-primary"></div>
<span className="text-xs font-medium">Analyzing...</span>
</div>
</div>
)}
</div>
<div className="flex-1 p-6 flex flex-col gap-4">
<div className="flex flex-col gap-1">
<div className="flex items-center justify-between gap-4">
<h3 className="font-semibold text-lg line-clamp-1">{video.title}</h3>
<Badge variant="outline" className={getStatusColor(video.scanStatus)}>
{getStatusLabel(video.scanStatus)}
</Badge>
</div>
<div className="flex items-center gap-2 text-sm text-muted-foreground">
<span>{video.channel?.channelName}</span>
<span></span>
<span>{formatDistanceToNow(new Date(video.createdAt))} ago</span>
</div>
</div>
<div className="mt-auto flex items-center justify-between gap-4">
<div className="flex items-center gap-4 text-xs">
<div className="flex items-center gap-1.5">
<Video className="h-3.5 w-3.5 opacity-50" />
<span>{video.platform}</span>
</div>
{video.scanStatus === 'awaiting_approval' && (
<div className="flex items-center gap-1.5 text-emerald-500 font-medium">
<AlertCircle className="h-3.5 w-3.5" />
<span>Ready for Approval</span>
</div>
)}
</div>
<Button size="sm" asChild>
<Link href={`/admin/analysis/${video.id}`}>
{video.scanStatus === 'awaiting_approval' ? 'Review Results' : 'Start Review'}
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</Button>
</div>
</div>
</div>
</Card>
))
)}
</div>
</div>
);
}