'use client'; import AdminShell from '@/components/AdminShell'; import { api } from '@/lib/api'; import { formatDate } from '@/lib/utils'; import { useEffect, useState } from 'react'; import { RefreshCw, Wrench, Play, CheckCircle } from 'lucide-react'; export default function QuipsPage() { const [quips, setQuips] = useState([]); const [loading, setLoading] = useState(true); const [repairing, setRepairing] = useState>(new Set()); const [repaired, setRepaired] = useState>(new Set()); const fetchQuips = () => { setLoading(true); api.getBrokenQuips() .then((data) => setQuips(data.quips ?? [])) .catch(() => {}) .finally(() => setLoading(false)); }; useEffect(() => { fetchQuips(); }, []); const repairQuip = async (quip: any) => { setRepairing((prev) => new Set(prev).add(quip.id)); try { await api.repairQuip(quip.id); setRepaired((prev) => new Set(prev).add(quip.id)); setQuips((prev) => prev.filter((q) => q.id !== quip.id)); } catch (e: any) { alert(`Repair failed: ${e.message}`); } finally { setRepairing((prev) => { const s = new Set(prev); s.delete(quip.id); return s; }); } }; const repairAll = async () => { const list = [...quips]; for (const q of list) { await repairQuip(q); } }; return (

Quip Repair

Videos missing thumbnails — server extracts frames via FFmpeg and uploads to R2.

{quips.length > 0 && ( )}
{repaired.size > 0 && (
{repaired.size} quip{repaired.size !== 1 ? 's' : ''} repaired this session.
)}
{loading ? (
Loading…
) : quips.length === 0 ? (
{repaired.size > 0 ? '✓ All quips repaired!' : 'No broken quips found.'}
) : ( {quips.map((q) => ( ))}
Post ID Video URL Created Action
{q.id.slice(0, 8)}… {q.video_url} {formatDate(q.created_at)}
)}
); }