fix: WhatsApp banner → thin midnight strip + Collect quick-add appeal picker

WhatsApp notice:
- Was: Ugly amber warning box with margins, breaking layout flow
- Now: Thin edge-to-edge midnight strip below header, same design
  language as the header itself. Green WhatsApp icon, 'Set up →' link,
  subtle × dismiss. Zero layout disruption.

Collect quick-add:
- Was: 'New link' always added to events[0] with no choice
- Now: Multi-appeal orgs see appeal picker buttons. Single-appeal orgs
  see appeal name as subtle label. Quick-add panel has blue border
  treatment matching brand.
- Removed unused AlertTriangle import
This commit is contained in:
2026-03-05 17:58:33 +08:00
parent 50d449e2b7
commit 5c615ad35e
7 changed files with 80 additions and 34 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -113,7 +113,12 @@ export default function CollectPage() {
}).catch(() => {}).finally(() => setLoading(false))
}, [])
const activeEvent = events[0] // Most orgs have one appeal
// Quick-add: which appeal does the new link belong to?
// Single appeal → auto-select. Multiple → user picks.
const [quickAddEventId, setQuickAddEventId] = useState<string | null>(null)
const activeEvent = events.length === 1
? events[0]
: events.find(e => e.id === quickAddEventId) || events[0]
// ── Actions ──
const copyLink = async (code: string) => {
@@ -584,10 +589,40 @@ export default function CollectPage() {
{/* Quick add link inline */}
{showQuickAdd && (
<div className="border-2 border-[#1E40AF] bg-[#1E40AF]/[0.02] p-4 space-y-3">
<div className="flex items-center justify-between">
<p className="text-sm font-bold text-[#111827]">Create a new pledge link</p>
<button onClick={() => { setShowQuickAdd(false); setQuickLinkName(""); setQuickAddEventId(null) }}
className="text-xs text-gray-400 hover:text-gray-600">Cancel</button>
</div>
{/* Appeal picker — only shows when there are multiple appeals */}
{events.length > 1 && (
<div>
<label className="text-[10px] font-bold text-gray-500 block mb-1.5">Which appeal is this for?</label>
<div className="flex flex-wrap gap-2">
{events.map(ev => (
<button key={ev.id}
onClick={() => setQuickAddEventId(ev.id)}
className={`px-3 py-1.5 text-xs font-bold border-2 transition-colors ${
activeEvent?.id === ev.id
? "border-[#1E40AF] bg-[#1E40AF]/5 text-[#1E40AF]"
: "border-gray-200 text-gray-500 hover:border-gray-300"
}`}>
{ev.name}
</button>
))}
</div>
</div>
)}
<div className="flex gap-2 items-end">
<div className="flex-1">
<label className="text-[10px] font-bold text-gray-500 block mb-1">
New link for &quot;{activeEvent?.name}&quot;
Link name
{events.length === 1 && activeEvent && (
<span className="text-gray-400 font-normal"> · {activeEvent.name}</span>
)}
</label>
<input
value={quickLinkName} onChange={e => setQuickLinkName(e.target.value)}
@@ -600,8 +635,7 @@ export default function CollectPage() {
className="h-10 bg-[#1E40AF] px-4 text-xs font-bold text-white disabled:opacity-40">
{quickCreating ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : "Create"}
</button>
<button onClick={() => { setShowQuickAdd(false); setQuickLinkName("") }}
className="h-10 px-3 text-xs text-gray-400 hover:text-gray-600">Cancel</button>
</div>
</div>
)}

View File

@@ -4,7 +4,7 @@ import Link from "next/link"
import { usePathname } from "next/navigation"
import { useSession, signOut } from "next-auth/react"
import { useState, useEffect } from "react"
import { Home, Megaphone, Banknote, FileText, Settings, LogOut, Shield, AlertTriangle, MessageCircle, Users, Zap } from "lucide-react"
import { Home, Megaphone, Banknote, FileText, Settings, LogOut, Shield, MessageCircle, Users, Zap } from "lucide-react"
import { cn } from "@/lib/utils"
/**
@@ -157,7 +157,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
{/* Main content — white background, generous padding */}
<main className="flex-1 pb-20 md:pb-8 overflow-hidden">
<WhatsAppBanner />
<WhatsAppNotice />
{children}
</main>
</div>
@@ -165,8 +165,12 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
)
}
/** WhatsApp connection banner — shows until connected */
function WhatsAppBanner() {
/**
* WhatsApp connection notice — thin, edge-to-edge, midnight-brand.
* Sits flush below the header. Not a warning — just a next step.
* Same design language as the header itself.
*/
function WhatsAppNotice() {
const [status, setStatus] = useState<string | null>(null)
const [dismissed, setDismissed] = useState(false)
const pathname = usePathname()
@@ -182,22 +186,30 @@ function WhatsAppBanner() {
if (status === "CONNECTED" || status === "skip" || status === null || dismissed) return null
return (
<div className="mx-4 md:mx-6 lg:mx-8 mt-4 md:mt-6 lg:mt-8 border-l-2 border-[#F59E0B] bg-[#F59E0B]/5 p-4 flex items-start gap-3">
<AlertTriangle className="h-5 w-5 text-[#F59E0B] shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
<p className="text-sm font-bold text-[#111827]">WhatsApp not connected reminders won&apos;t send</p>
<p className="text-xs text-gray-600 mt-0.5">
Connect your WhatsApp so donors automatically get payment reminders.
<div className="bg-[#111827] border-b border-gray-800">
<div className="flex items-center justify-between px-4 md:px-6 lg:px-8 py-2.5">
<div className="flex items-center gap-2.5 min-w-0">
<div className="h-5 w-5 bg-[#25D366] flex items-center justify-center shrink-0">
<MessageCircle className="h-3 w-3 text-white" />
</div>
<p className="text-xs text-gray-400 truncate">
<span className="text-white font-bold">Connect WhatsApp</span>
{" "}to send automatic payment reminders
</p>
<div className="flex items-center gap-3 mt-2.5">
</div>
<div className="flex items-center gap-3 shrink-0 ml-4">
<Link
href="/dashboard/settings"
className="inline-flex items-center gap-1.5 bg-[#25D366] px-3 py-1.5 text-xs font-bold text-white hover:bg-[#25D366]/90 transition-colors"
className="text-xs font-bold text-[#25D366] hover:text-[#25D366]/80 transition-colors"
>
<MessageCircle className="h-3.5 w-3.5" /> Connect WhatsApp
Set up
</Link>
<button onClick={() => setDismissed(true)} className="text-xs text-gray-400 hover:text-gray-600">
Dismiss
<button
onClick={() => setDismissed(true)}
className="text-gray-600 hover:text-gray-400 transition-colors"
aria-label="Dismiss"
>
<svg className="h-3.5 w-3.5" viewBox="0 0 14 14" fill="none"><path d="M1 1l12 12M13 1L1 13" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>
</button>
</div>
</div>