/* ════════════════════════════════════════════════
Halaman Donasi — campaign + progress + rekening + form
════════════════════════════════════════════════ */
const NOMINALS = [50000, 100000, 250000, 500000, 1000000, 2500000];
const rpShort = (n) => n >= 1000000 ? (n / 1000000).toFixed(n % 1000000 ? 1 : 0) + ' jt' : n >= 1000 ? (n / 1000) + ' rb' : n;
function DonasiPage({ navigate }) {
const [campaigns, setCampaigns] = useState([]);
const [rekening, setRekening] = useState([]);
const [settings, setSettings] = useState({});
const [stats, setStats] = useState({ total_masuk: 0, total_donatur: 0, total_campaign: 0 });
const [loading, setLoading] = useState(true);
const [nominal, setNominal] = useState(250000);
const [custom, setCustom] = useState('');
const [modal, setModal] = useState(null); // { campaign, amount }
useEffect(() => {
const f = window.__openDonasiForm;
if (f) { window.__openDonasiForm = false; setTimeout(() => setModal({ campaign: (f && f.id) ? f : null, amount: 250000 }), 120); }
}, []);
useEffect(() => {
Promise.all([
api.get('donations.php?action=list_campaigns'),
api.get('donations.php?action=list_rekening'),
api.get('donations.php?action=public_stats'),
api.get('donations.php?action=get_settings'),
]).then(([c, r, s, st]) => {
if (c.ok && c.campaigns) setCampaigns(c.campaigns);
if (r.ok && r.rekening) setRekening(r.rekening);
if (s.ok) setStats({ total_masuk: s.total_masuk || 0, total_donatur: s.total_donatur || 0, total_campaign: s.kampanye_aktif ?? s.total_campaign ?? 0 });
if (st.ok && st.settings) setSettings(st.settings);
}).finally(() => setLoading(false));
}, []);
const finalNominal = custom ? (parseInt(custom) || 0) : nominal;
return (
{/* Statistik */}
{[[fmtRpShort(stats.total_masuk), 'Terkumpul'], [stats.total_donatur, 'Donatur'], [stats.total_campaign, 'Program Donasi']].map(([n, l]) => (
))}
{/* QUICK DONATE */}
Donasi Cepat
{NOMINALS.map(n => {
const active = nominal === n && !custom;
return ;
})}
setCustom(e.target.value.replace(/\D/g, ''))} placeholder="Nominal lain (Rp)" inputMode="numeric"
style={{ flex: 1, minWidth: 160, padding: '13px 16px', borderRadius: 12, border: '1.5px solid var(--border)', fontSize: 14.5, fontFamily: 'inherit', background: 'var(--surface)', color: 'var(--ink-deep)' }} />
{/* CAMPAIGNS */}
{loading ? Memuat…
: (
{campaigns.map(c => {
// Normalisasi: PHP asli pakai nama Indonesia, mock pakai Inggris
const collected = c.terkumpul ?? c.collected ?? 0;
const target = c.target ?? 0;
const desc = c.deskripsi || c.description || '';
const cover = c.cover_url || c.image_url;
const urgent = c.urgensi === 'tinggi' || c.urgent;
const pct = c.percent != null ? c.percent : (target ? Math.min(100, Math.round((collected / target) * 100)) : 0);
const done = c.urgensi === 'selesai' || c.status === 'arsip' || c.status === 'selesai' || pct >= 100;
const cslug = c.slug || (window.slugify ? slugify(c.title) : c.id);
const openCard = (e) => { if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; e.preventDefault(); setModal({ campaign: c, amount: finalNominal }); };
return (
{cover ?

:
}
{urgent ?
MENDESAK : null}
{c.title}
{desc}
{fmtRp(collected)}
dari {fmtRp(target)} · {pct}%
{done ? '✓ Target Tercapai' : <>{IC.heart} Donasi Sekarang>}
);
})}
)}
{/* REKENING */}
{rekening.map((r, i) => )}
{settings.qris_url && (
Scan QRIS
Bayar pakai e-wallet (GoPay, OVO, Dana, ShopeePay) atau m-banking apa pun
)}
{modal &&
setModal(null)} />}
);
}
function RekeningCard({ r }) {
const [copied, setCopied] = useState(false);
const num = r.number || r.nomor || '';
const copy = () => { navigator.clipboard?.writeText(num.replace(/[-\s]/g, '')); setCopied(true); setTimeout(() => setCopied(false), 1600); };
const atasNama = r.atas_nama || r.name || r.nama || '';
return (
{r.bank}
);
}
function DonasiModal({ modal, rekening, settings, onClose }) {
const methods = [...rekening.map(r => r.bank), ...(settings && settings.qris_url ? ['QRIS'] : [])];
const [form, setForm] = useState({ amount: modal.amount || 100000, donor_name: '', donor_phone: '', donor_email: '', metode: methods[0] || 'Transfer', catatan: '' });
const [sending, setSending] = useState(false);
const [done, setDone] = useState(false);
const upd = (k, v) => setForm(f => ({ ...f, [k]: v }));
const waNum = (settings && settings.donasi_wa_konfirmasi) || '628123456789';
const submit = async (e) => {
e.preventDefault();
if (form.amount < 1000 || !form.donor_phone) return;
setSending(true);
try {
await api.post('donations.php?action=submit', { ...form, campaign_id: modal.campaign ? modal.campaign.id : null });
setDone(true);
} finally { setSending(false); }
};
const waConfirm = () => {
const msg = `Assalamu'alaikum, saya ingin konfirmasi donasi:\n\nNama: ${form.donor_name || '-'}\nNominal: ${fmtRp(form.amount)}\nProgram: ${modal.campaign ? modal.campaign.title : 'Donasi Umum'}\nMetode: ${form.metode}`;
window.open('https://wa.me/' + String(waNum).replace(/\D/g, '').replace(/^0/, '62') + '?text=' + encodeURIComponent(msg), '_blank');
};
return (
e.stopPropagation()} style={{ background: 'var(--surface)', borderRadius: 20, width: '100%', maxWidth: 440, maxHeight: '90vh', overflowY: 'auto', boxShadow: '0 30px 80px rgba(0,0,0,.35)' }}>
{done ? (
🤲
Jazakumullah Khairan!
Donasi Anda sebesar {fmtRp(form.amount)} telah dicatat. Mohon transfer & konfirmasi via WhatsApp agar segera kami verifikasi.
) : (
)}
);
}
const inp = { width: '100%', padding: '11px 14px', borderRadius: 10, border: '1.5px solid var(--border)', fontSize: 14, fontFamily: 'inherit', background: 'var(--surface)', color: 'var(--ink-deep)', boxSizing: 'border-box' };
function Field({ label, children }) {
return (
{children}
);
}
Object.assign(window, { DonasiPage, inp, Field });