/* global React, Icon, Eyebrow, Badge, Button, api */
const { useState: useStateRQ, useEffect: useEffectRQ } = React;
function ReviewQueue({ onChanged }){
const [tab, setTab] = useStateRQ("pending");
const [clips, setClips] = useStateRQ([]);
const [loading, setLoading] = useStateRQ(true);
const [busyId, setBusyId] = useStateRQ(null);
const [viewsDraft, setViewsDraft] = useStateRQ({});
const [reasonDraft, setReasonDraft] = useStateRQ({});
const reload = async () => {
setLoading(true);
const r = tab === "pending" ? await api.listPendingClips() : await api.listAllClips();
setClips(r.error ? [] : r.data);
setLoading(false);
};
useEffectRQ(() => { reload(); }, [tab]);
const setViews = (id, v) => setViewsDraft(d => ({...d, [id]: v}));
const setReason = (id, v) => setReasonDraft(d => ({...d, [id]: v}));
const approve = async (clip) => {
const draft = viewsDraft[clip.id];
const views = draft !== undefined && draft !== "" ? Number(draft) : (clip.views || 0);
if (Number.isNaN(views) || views < 0) return;
setBusyId(clip.id);
await api.reviewClip(clip.id, { status: "approved", views });
setBusyId(null);
await reload();
onChanged && onChanged();
};
const reject = async (clip) => {
const reason = reasonDraft[clip.id] || "Doesn't meet brief";
setBusyId(clip.id);
await api.reviewClip(clip.id, { status: "rejected", rejection_reason: reason });
setBusyId(null);
await reload();
onChanged && onChanged();
};
const updateViewsOnly = async (clip) => {
const draft = viewsDraft[clip.id];
if (draft === undefined || draft === "") return;
const views = Number(draft);
if (Number.isNaN(views) || views < 0) return;
setBusyId(clip.id);
await api.reviewClip(clip.id, { status: clip.status, views });
setBusyId(null);
setViewsDraft(d => { const n = {...d}; delete n[clip.id]; return n; });
await reload();
onChanged && onChanged();
};
return (
REVIEW QUEUE
{tab==="pending" ? "Approve / reject submitted clips" : "All clip submissions"}
{[{k:"pending",l:"Pending"},{k:"all",l:"All"}].map(t => (
))}
{loading ? (
Loading…
) : clips.length === 0 ? (
{tab === "pending" ? "Inbox zero. New submissions will appear here." : "No clips submitted yet."}
) : (
{clips.map(c => {
const camp = c.campaigns || {};
const pr = c.profiles || {};
const tone = c.status === "approved" ? "approved" : c.status === "rejected" ? "rejected" : "pending";
return (
{pr.handle || pr.display_name || "anon"}
·
{camp.name || "—"}
·
{c.platform || "other"}
·
{new Date(c.submitted_at).toLocaleString(undefined, {month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}
{c.notes &&
"{c.notes}"
}
{c.status === "rejected" && c.rejection_reason && (
Rejected: {c.rejection_reason}
)}
{c.status === "pending" && (
<>
REJECT
setReason(c.id, e.target.value)} style={{width:"100%",height:34,padding:"0 10px",marginTop:6,fontFamily:"Geist,sans-serif",fontSize:12,border:"1px solid #FECACA",borderRadius:8,outline:"none"}}/>
>
)}
{c.status !== "pending" && (
)}
{c.earned > 0 &&
Earned ${Number(c.earned).toFixed(2)}
}
);
})}
)}
);
}
window.ReviewQueue = ReviewQueue;