fundraiser mode: external platforms, role-aware onboarding, show-don't-gate
SCHEMA: - Organization.orgType: 'charity' | 'fundraiser' - Organization.whatsappConnected: boolean - Event.paymentMode: 'self' (bank transfer) | 'external' (redirect to URL) - Event.externalUrl: fundraising page URL - Event.externalPlatform: launchgood, enthuse, justgiving, gofundme, other ONBOARDING (role-aware): - Dashboard shows getting-started banner AT TOP, not full-page blocker - First-time users see role picker: 'Charity/Mosque' vs 'Personal Fundraiser' - POST /api/onboarding sets orgType - Charity checklist: bank details → WhatsApp → create fundraiser → share link - Fundraiser checklist: add fundraising page → WhatsApp → share pledge link → first pledge - WhatsApp is now a core onboarding step for both types - Banner is dismissable via X button - Dashboard always shows stats (with zeros), progress bar, empty-state card SHOW DON'T GATE: - Stats cards show immediately (with zeros, slightly faded) - Collection progress bar always visible - Empty-state card says 'Your pledge data will appear here' - Getting started is a guidance banner, not a lock screen EXTERNAL PAYMENT FLOW: - Events can be paymentMode='external' with externalUrl - Pledge flow: amount → identity → 'Donate on LaunchGood' redirect (skips schedule + payment method) - ExternalRedirectStep: branded per platform (LaunchGood green, Enthuse purple, etc.) - Marks pledge as 'initiated' when donor clicks through - WhatsApp sends donation link instead of bank details - Share button shares the external URL EVENT CREATION: - Payment mode toggle: 'Bank transfer' vs 'External page' - External shows URL input + platform dropdown - Fundraiser orgs default to external mode - Platform badge on event cards PLATFORMS SUPPORTED: 🌙 LaunchGood, 💜 Enthuse, 💛 JustGiving, 💚 GoFundMe, 🔗 Other/Custom
This commit is contained in:
@@ -8,6 +8,7 @@ import { PaymentStep } from "./steps/payment-step"
|
||||
import { IdentityStep } from "./steps/identity-step"
|
||||
import { ConfirmationStep } from "./steps/confirmation-step"
|
||||
import { BankInstructionsStep } from "./steps/bank-instructions-step"
|
||||
import { ExternalRedirectStep } from "./steps/external-redirect-step"
|
||||
import { CardPaymentStep } from "./steps/card-payment-step"
|
||||
import { DirectDebitStep } from "./steps/direct-debit-step"
|
||||
|
||||
@@ -33,6 +34,9 @@ interface EventInfo {
|
||||
organizationName: string
|
||||
qrSourceId: string | null
|
||||
qrSourceLabel: string | null
|
||||
paymentMode: "self" | "external"
|
||||
externalUrl: string | null
|
||||
externalPlatform: string | null
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -85,13 +89,21 @@ export default function PledgePage() {
|
||||
}).catch(() => {})
|
||||
}, [token])
|
||||
|
||||
const isExternal = eventInfo?.paymentMode === "external" && eventInfo?.externalUrl
|
||||
|
||||
// Step 0: Amount selected
|
||||
const handleAmountSelected = (amountPence: number) => {
|
||||
setPledgeData((d) => ({ ...d, amountPence }))
|
||||
setStep(1) // → Schedule step
|
||||
if (isExternal) {
|
||||
// External events: amount → identity → redirect (skip schedule + payment method)
|
||||
setPledgeData((d) => ({ ...d, amountPence, rail: "bank", scheduleMode: "now" }))
|
||||
setStep(3) // → Identity
|
||||
} else {
|
||||
setStep(1) // → Schedule step
|
||||
}
|
||||
}
|
||||
|
||||
// Step 1: Schedule selected
|
||||
// Step 1: Schedule selected (self-payment events only)
|
||||
const handleScheduleSelected = (schedule: {
|
||||
mode: "now" | "date" | "installments"
|
||||
dueDate?: string
|
||||
@@ -110,16 +122,15 @@ export default function PledgePage() {
|
||||
setStep(2) // → Payment method selection
|
||||
} else {
|
||||
// Deferred or installments: skip payment method, go to identity
|
||||
// Payment method will be chosen when the due date arrives
|
||||
setPledgeData((d) => ({ ...d, rail: "bank" })) // default to bank for deferred
|
||||
setPledgeData((d) => ({ ...d, rail: "bank" }))
|
||||
setStep(3) // → Identity
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Payment method selected (only for "now" mode)
|
||||
// Step 2: Payment method selected (only for "now" self-payment mode)
|
||||
const handleRailSelected = (rail: Rail) => {
|
||||
setPledgeData((d) => ({ ...d, rail }))
|
||||
setStep(rail === "bank" ? 3 : rail === "card" ? 6 : 8) // identity or card/DD
|
||||
setStep(rail === "bank" ? 3 : rail === "card" ? 6 : 8)
|
||||
}
|
||||
|
||||
// Submit pledge (from identity step, or card/DD steps)
|
||||
@@ -142,7 +153,9 @@ export default function PledgePage() {
|
||||
setPledgeResult(result)
|
||||
|
||||
// Where to go after pledge is created:
|
||||
if (finalData.scheduleMode === "now" && finalData.rail === "bank") {
|
||||
if (isExternal) {
|
||||
setStep(7) // External redirect
|
||||
} else if (finalData.scheduleMode === "now" && finalData.rail === "bank") {
|
||||
setStep(4) // Bank instructions
|
||||
} else {
|
||||
setStep(5) // Confirmation
|
||||
@@ -209,6 +222,7 @@ export default function PledgePage() {
|
||||
/>
|
||||
),
|
||||
6: <CardPaymentStep amount={pledgeData.amountPence} eventName={eventInfo?.name || ""} eventId={eventInfo?.id || ""} qrSourceId={eventInfo?.qrSourceId || null} onComplete={submitPledge} />,
|
||||
7: pledgeResult && <ExternalRedirectStep pledge={pledgeResult} amount={pledgeData.amountPence} eventName={eventInfo?.name || ""} externalUrl={eventInfo?.externalUrl || ""} externalPlatform={eventInfo?.externalPlatform} donorPhone={pledgeData.donorPhone} />,
|
||||
8: <DirectDebitStep amount={pledgeData.amountPence} eventName={eventInfo?.name || ""} organizationName={eventInfo?.organizationName || ""} eventId={eventInfo?.id || ""} qrSourceId={eventInfo?.qrSourceId || null} onComplete={submitPledge} />,
|
||||
}
|
||||
|
||||
@@ -220,7 +234,7 @@ export default function PledgePage() {
|
||||
return s - 1
|
||||
}
|
||||
|
||||
const progressMap: Record<number, number> = { 0: 8, 1: 25, 2: 40, 3: 60, 4: 100, 5: 100, 6: 60, 8: 60 }
|
||||
const progressMap: Record<number, number> = { 0: 8, 1: 25, 2: 40, 3: 60, 4: 100, 5: 100, 6: 60, 7: 100, 8: 60 }
|
||||
const progressPercent = progressMap[step] || 10
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user