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:
BIN
pledge-now-pay-later/screenshots/pledge-form-amount.png
Normal file
BIN
pledge-now-pay-later/screenshots/pledge-form-amount.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
pledge-now-pay-later/screenshots/pledge-match-expanded.png
Normal file
BIN
pledge-now-pay-later/screenshots/pledge-match-expanded.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
pledge-now-pay-later/screenshots/pledge-match-funding.png
Normal file
BIN
pledge-now-pay-later/screenshots/pledge-match-funding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
BIN
pledge-now-pay-later/screenshots/pledge-match-options.png
Normal file
BIN
pledge-now-pay-later/screenshots/pledge-match-options.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
pledge-now-pay-later/screenshots/pledge-match-toggle.png
Normal file
BIN
pledge-now-pay-later/screenshots/pledge-match-toggle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
@@ -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,24 +589,53 @@ export default function CollectPage() {
|
||||
|
||||
{/* Quick add link inline */}
|
||||
{showQuickAdd && (
|
||||
<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 "{activeEvent?.name}"
|
||||
</label>
|
||||
<input
|
||||
value={quickLinkName} onChange={e => setQuickLinkName(e.target.value)}
|
||||
placeholder="e.g. Table 5, Imam Yusuf, WhatsApp group"
|
||||
autoFocus onKeyDown={e => e.key === "Enter" && handleQuickAdd()}
|
||||
className="w-full h-10 px-3 border-2 border-gray-200 text-sm focus:border-[#1E40AF] outline-none"
|
||||
/>
|
||||
<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">
|
||||
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)}
|
||||
placeholder="e.g. Table 5, Imam Yusuf, WhatsApp group"
|
||||
autoFocus onKeyDown={e => e.key === "Enter" && handleQuickAdd()}
|
||||
className="w-full h-10 px-3 border-2 border-gray-200 text-sm focus:border-[#1E40AF] outline-none"
|
||||
/>
|
||||
</div>
|
||||
<button onClick={handleQuickAdd} disabled={quickCreating || !quickLinkName.trim()}
|
||||
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>
|
||||
</div>
|
||||
<button onClick={handleQuickAdd} disabled={quickCreating || !quickLinkName.trim()}
|
||||
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>
|
||||
)}
|
||||
|
||||
|
||||
@@ -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't send</p>
|
||||
<p className="text-xs text-gray-600 mt-0.5">
|
||||
Connect your WhatsApp so donors automatically get payment reminders.
|
||||
</p>
|
||||
<div className="flex items-center gap-3 mt-2.5">
|
||||
<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>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user