From 3c3336383eb6909efd60c3d6817c77dad747f288 Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Thu, 5 Mar 2026 03:03:55 +0800 Subject: [PATCH] Platform overhaul: every dashboard page feels like a landing page - Layout: Midnight header, white background, editorial sidebar - Home: Brand photography hero with contextual state (empty/active/collected) - Automations: ALL tech-speak stripped (no GPT model names, no cost per message, no 'AI optimisation' labels). Hero is about outcomes not engine. 'Current'/'New' labels replace 'Yours'/'AI'. - Collect: Brand photography hero with event context - Money: Dark hero with key financials + photography - Reports: Landing page compliance-style financial hero - Settings: Dark progress header with brand treatment Brand DNA applied across all pages: - Image + dark panel hero sections - border-l-2 section labels - gap-px grids for data - Sharp edges, no rounded corners - Human language throughout - 60-30-10 color rule enforced --- .../src/app/dashboard/automations/page.tsx | 79 +++++---- .../src/app/dashboard/collect/page.tsx | 30 +++- .../src/app/dashboard/exports/page.tsx | 33 +++- .../src/app/dashboard/layout.tsx | 63 ++++--- .../src/app/dashboard/page.tsx | 166 +++++++++++------- .../src/app/dashboard/pledges/page.tsx | 29 ++- .../src/app/dashboard/settings/page.tsx | 26 +-- 7 files changed, 263 insertions(+), 163 deletions(-) diff --git a/pledge-now-pay-later/src/app/dashboard/automations/page.tsx b/pledge-now-pay-later/src/app/dashboard/automations/page.tsx index f745fd4..9329ad5 100644 --- a/pledge-now-pay-later/src/app/dashboard/automations/page.tsx +++ b/pledge-now-pay-later/src/app/dashboard/automations/page.tsx @@ -3,7 +3,7 @@ import { useState, useEffect, useCallback, useRef } from "react" import Image from "next/image" import { - Loader2, Check, Send, Sparkles, Trophy, CheckCheck, + Loader2, Check, Send, Trophy, CheckCheck, ChevronDown, Clock, MessageCircle, RefreshCw, Calendar } from "lucide-react" import Link from "next/link" @@ -152,7 +152,7 @@ export default function AutomationsPage() { {/* ── Header ── */}
-

Automations

+

Donor journey

What your donors receive @@ -169,73 +169,74 @@ export default function AutomationsPage() {

)} - {/* ━━ AI HERO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */} + {/* ━━ HERO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + No tech-speak. No model names. No cost breakdowns. + This is about what happens for the DONOR, not the engine. + ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */} {neverOptimised ? ( + /* ── Never tested: invite them to start ── */
Young man at a London bus stop smiling at his phone — the moment a gentle WhatsApp reminder lands
-
- -

AI optimisation

-

- Let AI improve your messages + Messages that improve themselves

- AI writes a different version of each message and tests both with real donors. - The better version wins automatically. Your messages get better over time — without you doing anything. + We test different versions of each message with your real donors. + The one that collects more pledges wins. Automatically. You don't do anything — they just get better over time.

-

Uses GPT-4.1 nano · Costs less than 1p per message

) : testsRunning > 0 ? ( + /* ── Tests running: quiet confidence ── */
- - +
+
-

AI is testing {testsRunning} experiment{testsRunning > 1 ? "s" : ""}

-

Each message has two versions. The better one wins automatically.

+

Testing {testsRunning} new version{testsRunning > 1 ? "s" : ""}

+

The version that converts more donors wins automatically.

{stepsWithoutTest > 0 && ( )}
) : ( + /* ── All optimised: show results ── */
- +
-

Messages optimised

+

Your messages are tuned

- {stats && stats.total > 0 ? `${stats.total} sent this week · ${stats.deliveryRate}% delivered` : "Winning versions are live."} + {stats && stats.total > 0 ? `${stats.total} sent · ${stats.deliveryRate}% delivered` : "Best-performing versions are live."}

)} {/* ━━ THE CONVERSATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - Full messages always visible. No truncation. No eclipse. - A/B tests stack vertically — Yours on top, AI below. + Full messages always visible. No truncation. + A/B tests stack vertically — Current on top, New below. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */}
@@ -313,25 +314,25 @@ export default function AutomationsPage() {
) : b ? ( - /* ── A/B TEST — FULL MESSAGES, STACKED VERTICALLY ── */ + /* ── A/B TEST — Two versions, stacked ── */
{/* Header bar */}
- - AI is testing +
+ Testing two versions {hasEnoughData && winner && ( - {winner === "B" ? "AI" : "Yours"} winning + {winner === "B" ? "New" : "Current"} winning )} {!hasEnoughData && {progress}%}
- {/* Variant A — Yours (full message) */} + {/* Variant A — Current (full message) */} - {/* Variant B — AI (full message) */} + {/* Variant B — New (full message) */}
- - AI + + New {b.sentCount > 0 && ( @@ -361,7 +362,7 @@ export default function AutomationsPage() { {/* Regenerate */}
@@ -373,8 +374,8 @@ export default function AutomationsPage() {

{hasEnoughData - ? winner ? `${winner === "B" ? "AI" : "Your"} version converts ${Math.abs(rateB - rateA)}% better` : "Too close to call — need more data" - : `${totalSent} of ${MIN_SAMPLE * 2} sends needed for a verdict`} + ? winner ? `${winner === "B" ? "New" : "Current"} version converts ${Math.abs(rateB - rateA)}% better` : "Too close to call — need more data" + : `${totalSent} of ${MIN_SAMPLE * 2} sends needed`}

@@ -422,7 +423,7 @@ export default function AutomationsPage() { className="w-full bg-[#111827] text-white py-3 text-sm font-bold flex items-center justify-center gap-2 hover:bg-gray-800 transition-colors disabled:opacity-50"> {aiWorking ? <> Picking winners… - : <> Pick winners & start new round} + : <> Pick the best & test new ones}
)} diff --git a/pledge-now-pay-later/src/app/dashboard/collect/page.tsx b/pledge-now-pay-later/src/app/dashboard/collect/page.tsx index e9c9e85..aad40ab 100644 --- a/pledge-now-pay-later/src/app/dashboard/collect/page.tsx +++ b/pledge-now-pay-later/src/app/dashboard/collect/page.tsx @@ -7,6 +7,7 @@ import { Download, ExternalLink, Users, Trophy, ChevronDown, Link2, ArrowRight, QrCode as QrCodeIcon } from "lucide-react" +import Image from "next/image" import Link from "next/link" import { QRCodeCanvas } from "@/components/qr-code" @@ -222,13 +223,34 @@ export default function CollectPage() { return (
- {/* ── Header: Appeal context (quiet for single, selector for multi) ── */} + {/* ━━ HERO — Brand photography + context ━━━━━━━━━━━━━━━━━━━ */} +
+
+ Guest scanning a QR code at a fundraising event +
+
+
+

Collect

+
+

+ Share your link, collect pledges +

+

+ {activeEvent ? `${sources.length} link${sources.length !== 1 ? "s" : ""} · ${activeEvent.pledgeCount} pledges · ${formatPence(activeEvent.totalPledged)} raised` : "Create an appeal and start collecting"} +

+
+
+ + {/* ── Appeal context (quiet for single, selector for multi) ── */}
-

Collect

- {events.length === 1 ? ( -

{activeEvent?.name}

+

{activeEvent?.name}

) : (
- - )} {session && ( -
-
-

No pledges yet — share your link and they'll appear here

-
-
Create more pledge links → @@ -185,10 +235,10 @@ export default function DashboardPage() {
)} - {/* ── State 3+: Has pledges → stats + feed ── */} + {/* ── Has pledges: Stats + Feed ── */} {!isEmpty && ( <> - {/* Big numbers */} + {/* Stats — dark inversion like landing page hero */}
{[ { value: String(s.totalPledges), label: "Pledges" }, @@ -214,13 +264,13 @@ export default function DashboardPage() {
{formatPence(s.totalCollectedPence)} received - {formatPence(s.totalPledgedPence - s.totalCollectedPence)} still to come + {formatPence(outstanding)} still to come
- {/* ── Contextual prompt: "said they paid" → upload bank statement ── */} + {/* ── "Said they paid" prompt ── */} {hasSaidPaid && ( - +
@@ -237,7 +287,7 @@ export default function DashboardPage() {
{/* Needs attention */} {needsAttention.length > 0 && ( -
+

Needs attention

{needsAttention.length} @@ -263,7 +313,7 @@ export default function DashboardPage() { )} {/* How pledges are doing */} -
+

How pledges are doing

@@ -280,9 +330,9 @@ export default function DashboardPage() {
- {/* Top sources */} + {/* Where pledges come from */} {topSources.length > 0 && ( -
+

Where pledges come from

@@ -303,7 +353,7 @@ export default function DashboardPage() { {/* RIGHT column: Recent pledges */}
-
+

Recent pledges

View all @@ -349,14 +399,6 @@ export default function DashboardPage() {
)} - - {/* ── State: all paid → celebration ── */} - {!isEmpty && s.collectionRate === 100 && ( -
-

Every pledge collected

-

{formatPence(s.totalCollectedPence)} received from {s.totalPledges} donors

-
- )}
) } diff --git a/pledge-now-pay-later/src/app/dashboard/pledges/page.tsx b/pledge-now-pay-later/src/app/dashboard/pledges/page.tsx index 5026a65..12f9846 100644 --- a/pledge-now-pay-later/src/app/dashboard/pledges/page.tsx +++ b/pledge-now-pay-later/src/app/dashboard/pledges/page.tsx @@ -8,6 +8,7 @@ import { ChevronLeft, ChevronRight, Loader2, Upload, AlertTriangle, Clock, HelpCircle, AlertCircle, FileUp, X } from "lucide-react" +import Image from "next/image" import { formatPence } from "@/lib/utils" /** @@ -259,12 +260,28 @@ export default function MoneyPage() { return (
- {/* ── Header ── */} -
-

Money

-

- {formatPence(stats.totalCollected)} received of {formatPence(stats.totalPledged)} promised -

+ {/* ━━ HERO — Dark stats panel like landing page ━━━━━━━━━━━━ */} +
+
+ Charity treasurer counting donations after an event +
+
+
+

Money

+
+

+ {formatPence(stats.totalCollected)} + of {formatPence(stats.totalPledged)} +

+

+ {collectionRate}% collected · {stats.total} pledges +

+
{/* ── Stats bar (clickable filters) ── */} diff --git a/pledge-now-pay-later/src/app/dashboard/settings/page.tsx b/pledge-now-pay-later/src/app/dashboard/settings/page.tsx index eabc851..d3a2e6c 100644 --- a/pledge-now-pay-later/src/app/dashboard/settings/page.tsx +++ b/pledge-now-pay-later/src/app/dashboard/settings/page.tsx @@ -188,24 +188,24 @@ export default function SettingsPage() { return (
- {/* ── Header ── */} -
-

{settings.name}

-

Settings

-
- - {/* ── Progress — human sentence, not a grid ── */} -
-
-
+ {/* ── Header — human progress, not a form page ── */} +
+
+

Settings

+
+

+ {settings.name} +

+

{headerMsg}

+
+
- {doneCount}/{totalCount} + {doneCount}/{totalCount}
-

{headerMsg}

{error &&
{error}
}