/* global React, Icon, Badge, Button, Eyebrow, api */
const { useState: useStateBD, useEffect: useEffectBD, useRef: useRefBD } = React;
function BriefDetail({ campaign, profile, onBack, onSubmit }){
const [c, setC] = useStateBD(campaign || null);
const [loading, setLoading] = useStateBD(!campaign);
const [myClips, setMyClips] = useStateBD([]);
const [recent, setRecent] = useStateBD([]);
const [adminStats, setAdminStats] = useStateBD(null);
const [playerOpen, setPlayerOpen] = useStateBD(null); // {url}
const isAdmin = !!(profile && profile.is_admin);
useEffectBD(() => {
let mounted = true;
(async () => {
let camp = campaign;
if (!camp) {
const r = await api.getCampaignBySlug("rizz");
camp = r.data;
}
if (!mounted) return;
setC(camp);
setLoading(false);
const [mc, rec] = await Promise.all([api.listMyClips(), api.listRecentPaidPayouts(5)]);
if (!mounted) return;
setMyClips((mc.error ? [] : mc.data).filter(x => camp && x.campaign_id === camp.id));
setRecent(rec.error ? [] : rec.data);
if (isAdmin && camp) {
const s = await api.getCampaignStats(camp.id);
if (mounted && !s.error) setAdminStats(s.data);
}
})();
return () => { mounted = false; };
}, [campaign, isAdmin]);
if (loading) return
Loading…
;
if (!c) return Campaign not found.
;
const myViews = myClips.reduce((s,x) => s + (x.views||0), 0);
const myEarned = myClips.filter(x => x.status==="approved").reduce((s,x) => s + Number(x.earned||0), 0);
const examples = Array.isArray(c.examples) ? c.examples : [];
const dos = Array.isArray(c.dos) ? c.dos : [];
const donts = Array.isArray(c.donts) ? c.donts : [];
const tint = c.tint || "#6366f1";
return (
{playerOpen &&
setPlayerOpen(null)}/>}
← Back
🔥 LIVE CAMPAIGN
{(c.tag||"").toUpperCase()}
{c.name}
} onClick={onSubmit}>Submit clip
{isAdmin && (
)}
{c.description || "Short-form clips for this campaign. See do's/don'ts below."}
{c.brief_md && {c.brief_md}
}
{["TikTok","Instagram Reels","YouTube Shorts"].map(p => (
{p}
))}
{examples.length > 0 && (
setPlayerOpen({url})}/>
· Replicate the structure + hook, not the exact words. Duplicates get flagged.
)}
{(Array.isArray(c.assets) && c.assets.length > 0) && (
{c.assets.map((a,i) =>
)}
)}
{(dos.length > 0 || donts.length > 0) && (
{dos.length > 0 && (
)}
{donts.length > 0 && (
{donts.map((d,i) => {d} )}
)}
)}
Worked example: a clip that hits 50,000 views = ${(50 * Number(c.rpm)).toFixed(2)}. Five clips like that in a month = ${(250 * Number(c.rpm)).toFixed(2)}, paid weekly in batches.
YOUR PROGRESS
${myEarned.toFixed(2)}
{myClips.length} clip{myClips.length===1?"":"s"} · {myViews.toLocaleString()} views
}>Submit a clip
{c.discord_url && (
SUPPORT
Questions on the brief? Drop a message in the Discord. Replies usually within 1–2 hours.
Open Discord
)}
{recent.length > 0 && (
RECENT PAYOUTS
{recent.map((p,i) => {
const pr = p.profiles || {};
return (
{pr.handle || pr.display_name || "anon"}
${Number(p.amount).toFixed(2)}
);
})}
)}
);
}
function BriefStat({label,value,sub}){
return (
);
}
function Section({title, eyebrow, children, tone}){
const tones = {
success: {border:"1px solid #BBF7D0", bg:"#F0FDF4"},
warning: {border:"1px solid #FECACA", bg:"#FEF2F2"},
default: {border:"1px solid #E8E6DF", bg:"#fff"},
};
const t = tones[tone] || tones.default;
return (
{eyebrow}
{title}
{children}
);
}
function AdminStat({label, value}){
return (
);
}
function ExamplesCarousel({ examples, onPlay }){
const railRef = useRefBD(null);
const scroll = (dir) => {
if (!railRef.current) return;
const w = railRef.current.clientWidth;
railRef.current.scrollBy({ left: dir * Math.max(220, w * 0.6), behavior: "smooth" });
};
return (
{examples.map((e, i) => )}
scroll(-1)}/>
scroll( 1)}/>
);
}
function CarouselArrow({ dir, onClick }){
const isLeft = dir < 0;
return (
›
);
}
function ExampleCard({ ex, onPlay }){
const url = ex && ex.url;
const ytId = url ? api.youtubeId(url) : null;
const isYt = !!ytId;
const [imgOk, setImgOk] = useStateBD(true);
const thumbUrl = isYt ? api.youtubeThumb(ytId) : null;
const handleClick = (e) => {
if (!url) return;
if (isYt) { e.preventDefault(); onPlay && onPlay(url); }
};
return (
{isYt && imgOk && thumbUrl ? (
setImgOk(false)}
style={{position:"absolute",inset:0,width:"100%",height:"100%",objectFit:"cover"}}/>
) : (
)}
{ex.views && (
{ex.views}
)}
{isYt && (
{api.isYoutubeShorts(url) ? "SHORTS" : "YT"}
)}
{url && (
▶
)}
{ex.hook &&
{ex.hook}
}
{ex.handle &&
{ex.handle}
}
);
}
function YoutubePlayerModal({ url, onClose }){
if (!url) return null;
const id = api.youtubeId(url);
const isShorts = api.isYoutubeShorts(url);
const src = api.youtubeEmbed(id, { autoplay: true, mute: false });
if (!id) return null;
return (
e.stopPropagation()} style={{
position:"relative",
width: isShorts ? "min(380px, 100%)" : "min(960px, 100%)",
aspectRatio: isShorts ? "9/16" : "16/9",
borderRadius:14, overflow:"hidden", background:"#000",
boxShadow:"0 30px 80px rgba(0,0,0,0.6)",
}}>
×
);
}
function AssetRow({icon,label,sub,cta,url}){
const inner = (
<>
{cta}
>
);
return url
? {inner}
: {inner}
;
}
function PayoutStepCard({n,title,body}){
return (
);
}
window.BriefDetail = BriefDetail;