import { useEffect, useMemo, useRef, useState } from 'react'; import { useCollection, exportCSV, renderChart, share } from '@deplixo/sdk'; import { ProgressBar } from './components/ProgressBar.jsx'; import { Stats } from './components/Stats.jsx'; import { DonationForm } from './components/DonationForm.jsx'; import { DonorWall } from './components/DonorWall.jsx'; const FUNDRAISING_GOAL = 10000; function App() { const { items, loading, add } = useCollection('donations', { personal: true }); const [showForm, setShowForm] = useState(false); const [activeTab, setActiveTab] = useState('overview'); const [shareOpen, setShareOpen] = useState(false); const [copyStatus, setCopyStatus] = useState('idle'); const totalRaised = items.reduce((sum, item) => sum + (Number(item.value.amount) || 0), 0); const percentage = Math.min((totalRaised / FUNDRAISING_GOAL) * 100, 100); const campaignUrl = useMemo(() => { if (typeof window === 'undefined') return ''; return window.location.href; }, []); const shareText = useMemo(() => { return `Support our fundraising campaign! Every contribution helps us reach our goal. ${campaignUrl}`; }, [campaignUrl]); const handleDonate = async (donation) => { await add({ name: donation.name, amount: Number(donation.amount), message: donation.message || '', date: new Date().toISOString() }); setShowForm(false); }; const handleCopyLink = async () => { try { await navigator.clipboard.writeText(campaignUrl); setCopyStatus('copied'); setTimeout(() => setCopyStatus('idle'), 2000); } catch (error) { setCopyStatus('failed'); setTimeout(() => setCopyStatus('idle'), 2000); } }; const handleNativeShare = async () => { if (navigator.share) { try { await navigator.share({ title: 'Donation Tracker Campaign', text: shareText, url: campaignUrl }); setShareOpen(false); } catch (error) { // User cancelled or share failed; keep menu open for other options. } } }; const handleExportCSV = () => { exportCSV( items.map((i) => i.value), { filename: 'donations.csv', columns: ['name', 'amount', 'message', 'date'] } ); }; return (
🔥

Donation Tracker

Every contribution fuels the fire

Share the campaign

Copy the link or use a share option to invite more supporters.

{shareOpen && (
{navigator.share && ( )} Share by email Share on X
)}
{showForm && setShowForm(false)} />} {activeTab === 'overview' && (
)} {activeTab === 'charts' && (
)} {activeTab === 'donors' && (
)}
); } function FundraisingCharts({ items, loading }) { const lineData = []; const dailyTotals = {}; items.forEach((item) => { const rawDate = item && item.value ? item.value.date : null; const amount = Number(item && item.value ? item.value.amount : 0) || 0; const dateKey = rawDate ? new Date(rawDate).toISOString().slice(0, 10) : null; if (!dateKey) return; dailyTotals[dateKey] = (dailyTotals[dateKey] || 0) + amount; }); Object.keys(dailyTotals) .sort() .forEach((dateKey) => { lineData.push({ label: dateKey, value: dailyTotals[dateKey] }); }); const donorTotals = {}; items.forEach((item) => { const donorName = item && item.value ? item.value.name || 'Anonymous' : 'Anonymous'; const amount = Number(item && item.value ? item.value.amount : 0) || 0; donorTotals[donorName] = (donorTotals[donorName] || 0) + amount; }); const topDonors = Object.keys(donorTotals) .map((name) => ({ label: name, value: donorTotals[name] })) .sort((a, b) => b.value - a.value) .slice(0, 5); return (

Donations Over Time

Daily totals update automatically as new donations arrive.

{loading ? (
Loading chart data...
) : lineData.length > 0 ? ( ) : (
No donation history yet.
)}

Top Donors

Ranked by total contribution amount.

{loading ? (
Loading chart data...
) : topDonors.length > 0 ? ( ) : (
No donors to display yet.
)}
); } function SalesChart({ data }) { const canvasRef = useRef(null); const chartType = data && data.length > 0 && data[0] && typeof data[0].label === 'string' && data[0].label.length === 10 ? 'line' : 'bar'; useEffect(() => { if (canvasRef.current && data.length > 0) { renderChart(canvasRef.current, { type: chartType, data: { labels: data.map((d) => d.label), datasets: [{ label: chartType === 'line' ? 'Donations' : 'Top Donors', data: data.map((d) => d.value) }] } }); } }, [data, chartType]); return ; } ReactDOM.createRoot(document.getElementById('root')).render();