Landing page philosophy across ALL dashboard pages
Home: - Empty state: 2-column with 'How it works' 5-step guide - Has data: 7/5 grid — pledges left, education right - Right column: status breakdown, sources, 'What to do next' contextual links, 'What the statuses mean' guide Money: - 8/4 two-column layout: table left, education right - Right column: 'How matching works' 4-step guide, status explainer, collection tips, quick action buttons - No more wasted right margin Reports: - 7/5 two-column layout: downloads left, education right - Right column: 'For your treasurer' 3-step guide, Gift Aid FAQ, 'Understanding your numbers' explainer - Activity log moved to right column Settings: - Removed max-w-2xl constraint, now uses full width - 7/5 two-column: checklist left, education right - Right column: 'What you're setting up' (5 items with Required badges), Privacy & data assurance, Common questions FAQ, 'Need help?' CTA - Every setting explained in human language
This commit is contained in:
@@ -235,10 +235,46 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Has pledges: Stats + Feed ── */}
|
||||
{/* ── Empty state: educational guidance ── */}
|
||||
{isEmpty && !pledgeLink && (
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<div className="border-2 border-dashed border-gray-200 p-8 text-center">
|
||||
<h3 className="text-base font-bold text-[#111827]">Share your pledge link to get started</h3>
|
||||
<p className="text-sm text-gray-500 mt-2 max-w-xs mx-auto">
|
||||
Go to <Link href="/dashboard/collect" className="text-[#1E40AF] font-bold hover:underline">Collect</Link> to
|
||||
create an appeal and get your pledge link.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="border border-gray-200 bg-white">
|
||||
<div className="border-b border-gray-100 px-5 py-3">
|
||||
<h3 className="text-sm font-bold text-[#111827]">How it works</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-50">
|
||||
{[
|
||||
{ n: "01", title: "Create a pledge link", desc: "Give it a name like 'Table 5' or 'Ramadan 2026'. Print the QR or share the link." },
|
||||
{ n: "02", title: "Donors pledge in 60 seconds", desc: "Name, phone, amount, Gift Aid — done. No account, no app download." },
|
||||
{ n: "03", title: "They get your bank details", desc: "Instantly via WhatsApp. With a unique reference so you can match their payment." },
|
||||
{ n: "04", title: "Reminders go out automatically", desc: "Day 2, day 7, day 14. Warm and never pushy. They stop when the donor pays." },
|
||||
{ n: "05", title: "Upload your bank statement", desc: "We match payments to pledges automatically. No spreadsheet cross-referencing." },
|
||||
].map(s => (
|
||||
<div key={s.n} className="px-5 py-3 flex gap-3">
|
||||
<span className="text-lg font-black text-gray-200 shrink-0 w-6">{s.n}</span>
|
||||
<div>
|
||||
<p className="text-xs font-bold text-[#111827]">{s.title}</p>
|
||||
<p className="text-[11px] text-gray-500 leading-relaxed mt-0.5">{s.desc}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* ── Has pledges: Stats + Feed + Education ── */}
|
||||
{!isEmpty && (
|
||||
<>
|
||||
{/* Stats — dark inversion like landing page hero */}
|
||||
{/* Stats — gap-px grid */}
|
||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-px bg-gray-200">
|
||||
{[
|
||||
{ value: String(s.totalPledges), label: "Pledges" },
|
||||
@@ -282,9 +318,9 @@ export default function DashboardPage() {
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<div className="grid lg:grid-cols-5 gap-6">
|
||||
{/* LEFT column */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
<div className="grid lg:grid-cols-12 gap-6">
|
||||
{/* LEFT column: Data */}
|
||||
<div className="lg:col-span-7 space-y-6">
|
||||
{/* Needs attention */}
|
||||
{needsAttention.length > 0 && (
|
||||
<div className="bg-white border border-gray-200">
|
||||
@@ -312,47 +348,7 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* How pledges are doing */}
|
||||
<div className="bg-white border border-gray-200">
|
||||
<div className="border-b border-gray-100 px-5 py-3">
|
||||
<h3 className="text-sm font-bold text-[#111827]">How pledges are doing</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-50">
|
||||
{Object.entries(byStatus).map(([status, count]) => {
|
||||
const sl = STATUS_LABELS[status] || STATUS_LABELS.new
|
||||
return (
|
||||
<div key={status} className="px-5 py-2.5 flex items-center justify-between">
|
||||
<span className={`text-xs font-bold px-2 py-0.5 ${sl.bg} ${sl.color}`}>{sl.label}</span>
|
||||
<span className="text-sm font-black text-[#111827]">{count as number}</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Where pledges come from */}
|
||||
{topSources.length > 0 && (
|
||||
<div className="bg-white border border-gray-200">
|
||||
<div className="border-b border-gray-100 px-5 py-3">
|
||||
<h3 className="text-sm font-bold text-[#111827]">Where pledges come from</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-50">
|
||||
{topSources.slice(0, 5).map((src: { label: string; count: number; amount: number }, i: number) => (
|
||||
<div key={i} className="px-5 py-2.5 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span className="text-xs font-black text-gray-300 w-4">{i + 1}</span>
|
||||
<span className="text-sm text-[#111827]">{src.label}</span>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[#111827]">{formatPence(src.amount)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* RIGHT column: Recent pledges */}
|
||||
<div className="lg:col-span-3">
|
||||
{/* Recent pledges */}
|
||||
<div className="bg-white border border-gray-200">
|
||||
<div className="border-b border-gray-100 px-5 py-3 flex items-center justify-between">
|
||||
<h3 className="text-sm font-bold text-[#111827]">Recent pledges</h3>
|
||||
@@ -396,6 +392,98 @@ export default function DashboardPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* RIGHT column: Status + Sources + Guidance */}
|
||||
<div className="lg:col-span-5 space-y-6">
|
||||
{/* How pledges are doing */}
|
||||
<div className="bg-white border border-gray-200">
|
||||
<div className="border-b border-gray-100 px-5 py-3">
|
||||
<h3 className="text-sm font-bold text-[#111827]">How pledges are doing</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-50">
|
||||
{Object.entries(byStatus).map(([status, count]) => {
|
||||
const sl = STATUS_LABELS[status] || STATUS_LABELS.new
|
||||
return (
|
||||
<div key={status} className="px-5 py-2.5 flex items-center justify-between">
|
||||
<span className={`text-xs font-bold px-2 py-0.5 ${sl.bg} ${sl.color}`}>{sl.label}</span>
|
||||
<span className="text-sm font-black text-[#111827]">{count as number}</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Where pledges come from */}
|
||||
{topSources.length > 0 && (
|
||||
<div className="bg-white border border-gray-200">
|
||||
<div className="border-b border-gray-100 px-5 py-3">
|
||||
<h3 className="text-sm font-bold text-[#111827]">Where pledges come from</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-50">
|
||||
{topSources.slice(0, 5).map((src: { label: string; count: number; amount: number }, i: number) => (
|
||||
<div key={i} className="px-5 py-2.5 flex items-center justify-between">
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span className="text-xs font-black text-gray-300 w-4">{i + 1}</span>
|
||||
<span className="text-sm text-[#111827]">{src.label}</span>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-[#111827]">{formatPence(src.amount)}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* What to do next — contextual guidance */}
|
||||
<div className="border-l-2 border-[#F59E0B] pl-4 space-y-2">
|
||||
<p className="text-xs font-bold text-[#111827]">What to do next</p>
|
||||
<div className="space-y-2">
|
||||
{s.collectionRate < 100 && (byStatus.initiated || 0) > 0 && (
|
||||
<Link href="/dashboard/money" className="flex items-start gap-2 group">
|
||||
<span className="text-[#F59E0B] font-bold text-xs shrink-0 mt-0.5">→</span>
|
||||
<p className="text-xs text-gray-600 group-hover:text-[#111827] transition-colors">
|
||||
<strong>Upload your bank statement</strong> to confirm {byStatus.initiated} {byStatus.initiated === 1 ? "payment" : "payments"} automatically
|
||||
</p>
|
||||
</Link>
|
||||
)}
|
||||
{s.collectionRate < 50 && (
|
||||
<Link href="/dashboard/collect" className="flex items-start gap-2 group">
|
||||
<span className="text-[#F59E0B] font-bold text-xs shrink-0 mt-0.5">→</span>
|
||||
<p className="text-xs text-gray-600 group-hover:text-[#111827] transition-colors">
|
||||
<strong>Share your link more widely</strong> — WhatsApp groups, social media, or print the QR
|
||||
</p>
|
||||
</Link>
|
||||
)}
|
||||
<Link href="/dashboard/automations" className="flex items-start gap-2 group">
|
||||
<span className="text-[#F59E0B] font-bold text-xs shrink-0 mt-0.5">→</span>
|
||||
<p className="text-xs text-gray-600 group-hover:text-[#111827] transition-colors">
|
||||
<strong>Check your messages</strong> — see what donors receive and improve wording
|
||||
</p>
|
||||
</Link>
|
||||
<Link href="/dashboard/reports" className="flex items-start gap-2 group">
|
||||
<span className="text-[#F59E0B] font-bold text-xs shrink-0 mt-0.5">→</span>
|
||||
<p className="text-xs text-gray-600 group-hover:text-[#111827] transition-colors">
|
||||
<strong>Download for your treasurer</strong> — Gift Aid report, full pledge data, HMRC-ready CSV
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Understanding statuses */}
|
||||
<div className="border-l-2 border-[#1E40AF] pl-4 space-y-1.5">
|
||||
<p className="text-xs font-bold text-[#111827]">What the statuses mean</p>
|
||||
{[
|
||||
{ label: "Waiting", desc: "Pledged but hasn't paid yet — reminders are being sent" },
|
||||
{ label: "Said they paid", desc: "Donor replied PAID — upload bank statement to confirm" },
|
||||
{ label: "Received ✓", desc: "Payment confirmed in your bank account" },
|
||||
{ label: "Needs a nudge", desc: "It's been a while — you can send a manual reminder" },
|
||||
].map(s => (
|
||||
<div key={s.label} className="flex items-start gap-2">
|
||||
<span className="w-1.5 h-1.5 bg-[#1E40AF] shrink-0 mt-1.5" />
|
||||
<p className="text-[10px] text-gray-500"><strong className="text-[#111827]">{s.label}</strong> — {s.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user