/* global React, Icon, Badge, Button, Eyebrow, api */ const { useState: useStatePA, useEffect: useEffectPA } = React; function PayoutsAdmin({ onChanged }){ const [tab, setTab] = useStatePA("pending"); const [rows, setRows] = useStatePA([]); const [loading, setLoading] = useStatePA(true); const [busyId, setBusyId] = useStatePA(null); const [txnDraft, setTxnDraft] = useStatePA({}); const reload = async () => { setLoading(true); const r = tab === "pending" ? await api.listPendingPayouts() : await api.listAllPayouts(); setRows(r.error ? [] : r.data); setLoading(false); }; useEffectPA(() => { reload(); }, [tab]); const setTxn = (id,v) => setTxnDraft(d => ({...d, [id]: v})); const markPaid = async (p) => { const txn = txnDraft[p.id] || null; setBusyId(p.id); await api.processPayout(p.id, { status: "paid", txn_ref: txn }); setBusyId(null); await reload(); onChanged && onChanged(); }; const markProcessing = async (p) => { setBusyId(p.id); await api.processPayout(p.id, { status: "processing" }); setBusyId(null); await reload(); }; const markFailed = async (p) => { setBusyId(p.id); await api.processPayout(p.id, { status: "failed" }); setBusyId(null); await reload(); }; const totalPending = rows.filter(r => r.status === "pending" || r.status === "processing").reduce((s,r) => s + Number(r.amount||0), 0); return (
PAYOUTS
Process clipper payouts
{[{k:"pending",l:`Pending${totalPending>0?` · $${totalPending.toFixed(2)}`:""}`},{k:"all",l:"All"}].map(t => ( ))}
Process flow: 1. Send the PayPal / bank transfer manually using the destination shown. 2. Paste your txn reference. 3. Click "Mark paid" — clipper sees it instantly and balance drops accordingly.
{loading ? (
Loading…
) : rows.length === 0 ? (
{tab === "pending" ? "No payout requests pending." : "No payouts yet."}
) : (
{["CLIPPER","AMOUNT","METHOD","DESTINATION","REQUESTED","STATUS","TXN / ACTION"].map(h => ( ))} {rows.map((p,i) => { const last = i === rows.length - 1; const pr = p.profiles || {}; const tone = p.status === "paid" ? "paid" : p.status === "failed" ? "rejected" : p.status === "processing" ? "pending" : "pending"; const dest = p.method === "paypal" ? (pr.paypal_email || p.destination || "—") : (p.destination || "Bank details on file"); return ( ); })}
{h}
{pr.display_name || pr.handle || "anon"}
{pr.handle || ""}
${Number(p.amount).toFixed(2)} {p.method === "paypal" ? "PayPal" : "Bank"} {dest} {new Date(p.requested_at).toLocaleString(undefined, {month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})} {p.status} {p.status === "paid" || p.status === "failed" ? ( {p.txn_ref || "—"} ) : (
setTxn(p.id, e.target.value)} style={{height:30,padding:"0 8px",fontFamily:"Geist Mono,monospace",fontSize:12,border:"1px solid #E8E6DF",borderRadius:6,outline:"none",width:120}}/> {p.status === "pending" && }
)}
)}
); } window.PayoutsAdmin = PayoutsAdmin;