simplify: zakat yes/no per campaign, remove 5 fund types, add I've Donated button for external pledges
- Event.zakatEligible (boolean) replaces Organization.zakatEnabled + 5 fund types - Pledge.isZakat (boolean) replaces Pledge.fundType enum - Removed fundAllocation from Event (campaign IS the allocation) - Identity step: simple checkbox instead of 5-option grid - Campaign creation: Zakat toggle + optional external URL for self-payment - External redirect step: 'I've Donated' button calls /api/pledges/[id]/mark-initiated - Landing page: simplified Zakat section (toggle preview, not 5 fund descriptions) - Settings: removed org-level Zakat toggle (it's per campaign now) - Migration: ALTER TABLE adds zakatEligible/isZakat, drops fundAllocation
This commit is contained in:
@@ -53,7 +53,7 @@ export default function EventsPage() {
|
||||
}, [])
|
||||
const [creating, setCreating] = useState(false)
|
||||
const [orgType, setOrgType] = useState<string | null>(null)
|
||||
const [form, setForm] = useState({ name: "", description: "", location: "", eventDate: "", goalAmount: "", paymentMode: "self" as "self" | "external", externalUrl: "", externalPlatform: "", fundAllocation: "" })
|
||||
const [form, setForm] = useState({ name: "", description: "", location: "", eventDate: "", goalAmount: "", paymentMode: "self" as "self" | "external", externalUrl: "", externalPlatform: "", zakatEligible: false })
|
||||
|
||||
// Fetch org type to customize the form
|
||||
useEffect(() => {
|
||||
@@ -79,14 +79,14 @@ export default function EventsPage() {
|
||||
paymentMode: form.paymentMode,
|
||||
externalUrl: form.externalUrl || undefined,
|
||||
externalPlatform: form.paymentMode === "external" ? (form.externalPlatform || "other") : undefined,
|
||||
fundAllocation: form.fundAllocation || undefined,
|
||||
zakatEligible: form.zakatEligible,
|
||||
}),
|
||||
})
|
||||
if (res.ok) {
|
||||
const event = await res.json()
|
||||
setEvents((prev) => [{ ...event, pledgeCount: 0, qrSourceCount: 0, totalPledged: 0, totalCollected: 0 }, ...prev])
|
||||
setShowCreate(false)
|
||||
setForm({ name: "", description: "", location: "", eventDate: "", goalAmount: "", paymentMode: orgType === "fundraiser" ? "external" : "self", externalUrl: "", externalPlatform: "", fundAllocation: "" })
|
||||
setForm({ name: "", description: "", location: "", eventDate: "", goalAmount: "", paymentMode: orgType === "fundraiser" ? "external" : "self", externalUrl: "", externalPlatform: "", zakatEligible: false })
|
||||
}
|
||||
} catch {
|
||||
// handle error
|
||||
@@ -298,29 +298,37 @@ export default function EventsPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Fund allocation — for charities tracking which fund this goes to */}
|
||||
{/* Zakat eligible toggle */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setForm(f => ({ ...f, zakatEligible: !f.zakatEligible }))}
|
||||
className={`w-full flex items-center justify-between rounded-xl border-2 p-3 text-left transition-all ${
|
||||
form.zakatEligible ? "border-trust-blue bg-trust-blue/5" : "border-gray-200"
|
||||
}`}
|
||||
>
|
||||
<div>
|
||||
<p className="text-sm font-bold">🌙 Zakat eligible</p>
|
||||
<p className="text-xs text-muted-foreground">Let donors mark their pledge as Zakat</p>
|
||||
</div>
|
||||
<div className={`w-5 h-5 rounded border-2 flex items-center justify-center ${form.zakatEligible ? "bg-trust-blue border-trust-blue" : "border-gray-300"}`}>
|
||||
{form.zakatEligible && <span className="text-white text-xs font-bold">✓</span>}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* External URL for self-payment campaigns (for reference/allocation) */}
|
||||
{form.paymentMode === "self" && (
|
||||
<div className="space-y-2">
|
||||
<Label>Fund allocation <span className="text-muted-foreground font-normal">(optional)</span></Label>
|
||||
<Input
|
||||
placeholder="e.g. Mosque Building Fund, Orphan Sponsorship"
|
||||
value={form.fundAllocation}
|
||||
onChange={(e) => setForm(f => ({ ...f, fundAllocation: e.target.value }))}
|
||||
/>
|
||||
<p className="text-[10px] text-muted-foreground">Track which fund this event raises for. Shows on pledge receipts & reports.</p>
|
||||
<div className="space-y-2">
|
||||
<Label>External fundraising page <span className="text-muted-foreground font-normal">(optional)</span></Label>
|
||||
<div className="relative">
|
||||
<ExternalLink className="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="https://launchgood.com/mosque-building"
|
||||
value={form.externalUrl}
|
||||
onChange={(e) => setForm(f => ({ ...f, externalUrl: e.target.value }))}
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-muted-foreground">Link an external campaign page for reference & allocation tracking.</p>
|
||||
<Label>External fundraising page <span className="text-muted-foreground font-normal">(optional)</span></Label>
|
||||
<div className="relative">
|
||||
<ExternalLink className="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
placeholder="https://launchgood.com/my-campaign"
|
||||
value={form.externalUrl}
|
||||
onChange={(e) => setForm(f => ({ ...f, externalUrl: e.target.value }))}
|
||||
className="pl-9"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[10px] text-muted-foreground">Link an external page for reference. Payments still go via your bank.</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ interface OrgSettings {
|
||||
gcAccessToken: string
|
||||
gcEnvironment: string
|
||||
orgType: string
|
||||
zakatEnabled: boolean
|
||||
}
|
||||
|
||||
export default function SettingsPage() {
|
||||
@@ -118,42 +117,6 @@ export default function SettingsPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Zakat & Fund Types */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base flex items-center gap-2">☪️ Zakat & Fund Types</CardTitle>
|
||||
<CardDescription className="text-xs">Let donors specify their donation type (Zakat, Sadaqah, Lillah, Fitrana)</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<button
|
||||
onClick={() => {
|
||||
setSettings(s => s ? { ...s, zakatEnabled: !s.zakatEnabled } : s)
|
||||
fetch("/api/settings", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ zakatEnabled: !settings.zakatEnabled }) }).then(() => { setSaved("zakat"); setTimeout(() => setSaved(null), 2000) }).catch(() => {})
|
||||
}}
|
||||
className={`w-full flex items-center justify-between rounded-xl border-2 p-4 transition-all ${
|
||||
settings.zakatEnabled ? "border-trust-blue bg-trust-blue/5" : "border-gray-200"
|
||||
}`}
|
||||
>
|
||||
<div className="text-left">
|
||||
<p className="text-sm font-bold">{settings.zakatEnabled ? "Fund types enabled" : "Enable fund types"}</p>
|
||||
<p className="text-xs text-muted-foreground mt-0.5">Donors can choose: Zakat · Sadaqah · Lillah · Fitrana · General</p>
|
||||
</div>
|
||||
<div className={`w-11 h-6 rounded-full transition-colors ${settings.zakatEnabled ? "bg-trust-blue" : "bg-gray-200"}`}>
|
||||
<div className={`w-5 h-5 bg-white rounded-full shadow-sm mt-0.5 transition-transform ${settings.zakatEnabled ? "translate-x-5.5 ml-[22px]" : "translate-x-0.5 ml-[2px]"}`} />
|
||||
</div>
|
||||
</button>
|
||||
{settings.zakatEnabled && (
|
||||
<div className="rounded-xl bg-trust-blue/5 border border-trust-blue/10 p-3 space-y-1.5 text-xs text-muted-foreground animate-fade-in">
|
||||
<p>🌙 <strong>Zakat</strong> — Obligatory 2.5% annual charity</p>
|
||||
<p>🤲 <strong>Sadaqah / General</strong> — Voluntary donations</p>
|
||||
<p>🌱 <strong>Sadaqah Jariyah</strong> — Ongoing charity (buildings, wells)</p>
|
||||
<p>🕌 <strong>Lillah</strong> — For the mosque / institution</p>
|
||||
<p>🍽️ <strong>Fitrana</strong> — Zakat al-Fitr (before Eid)</p>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Branding */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user