"use client" import { useState, useEffect } from "react" import { formatPence } from "@/lib/utils" import { Plus, Copy, Check, Loader2, MessageCircle, Share2, Mail, Download, Trophy, Link2, ArrowRight, QrCode as QrCodeIcon, Code2, Building2, CreditCard, Globe } from "lucide-react" import Image from "next/image" import Link from "next/link" import { QRCodeCanvas } from "@/components/qr-code" /** * /dashboard/collect — "I want to share my link" * * FUNDAMENTAL REDESIGN: * * The primary object is the LINK. Not the appeal. * * Creating a link = one flow that handles: * 1. What you're raising for (appeal — created behind the scenes) * 2. How donors pay (bank / external platform / card) * 3. Link name * * Every link card shows: * - Payment method badge (so the user always knows how THIS link works) * - 3 sharing tabs: Link, QR Code, Website Widget * - Stats * * The widget is NOT a separate concept — it's just another way to share * the same link. Copy the embed code, paste on your website. */ interface EventSummary { id: string; name: string; slug: string; eventDate: string | null location: string | null; goalAmount: number | null; status: string pledgeCount: number; qrSourceCount: number; totalPledged: number; totalCollected: number paymentMode?: string; externalPlatform?: string; externalUrl?: string } interface SourceInfo { id: string; label: string; code: string volunteerName: string | null; tableName: string | null scanCount: number; pledgeCount: number; totalPledged: number; totalCollected?: number } const PLATFORM_LABELS: Record = { justgiving: "JustGiving", launchgood: "LaunchGood", gofundme: "GoFundMe", enthuse: "Enthuse", other: "External link" } export default function CollectPage() { const [events, setEvents] = useState([]) const [sources, setSources] = useState([]) const [loading, setLoading] = useState(true) const [copiedCode, setCopiedCode] = useState(null) const [copiedEmbed, setCopiedEmbed] = useState(null) const [expandedLink, setExpandedLink] = useState(null) const [shareTab, setShareTab] = useState>({}) // Unified creation flow const [showCreate, setShowCreate] = useState(false) const [createStep, setCreateStep] = useState<"name" | "payment" | "link">("name") const [newAppealName, setNewAppealName] = useState("") const [newPaymentMode, setNewPaymentMode] = useState<"bank" | "external" | "card">("bank") const [newPlatform, setNewPlatform] = useState("") const [newExternalUrl, setNewExternalUrl] = useState("") const [newLinkName, setNewLinkName] = useState("Main link") const [creating, setCreating] = useState(false) // Quick add link (to existing appeal) const [showQuickAdd, setShowQuickAdd] = useState(false) const [quickLinkName, setQuickLinkName] = useState("") const [quickCreating, setQuickCreating] = useState(false) const [hasStripe, setHasStripe] = useState(false) const baseUrl = typeof window !== "undefined" ? window.location.origin : "" // Load everything useEffect(() => { Promise.all([ fetch("/api/events").then(r => r.json()), fetch("/api/settings").then(r => r.json()).catch(() => ({})), ]).then(([evData, settingsData]) => { if (Array.isArray(evData)) { setEvents(evData) // Load sources for all events const allSourcePromises = evData.map((ev: EventSummary) => fetch(`/api/events/${ev.id}/qr`).then(r => r.json()).catch(() => []) ) Promise.all(allSourcePromises).then(results => { const allSources: (SourceInfo & { _eventId: string; _eventName: string; _paymentMode: string; _externalPlatform: string | null })[] = [] results.forEach((srcs, i) => { if (Array.isArray(srcs)) { srcs.forEach((s: SourceInfo) => { allSources.push({ ...s, _eventId: evData[i].id, _eventName: evData[i].name, _paymentMode: evData[i].paymentMode || "self", _externalPlatform: evData[i].externalPlatform || null, }) }) } }) setSources(allSources) }) } if (settingsData.stripeSecretKey) setHasStripe(true) }).catch(() => {}).finally(() => setLoading(false)) }, []) // Quick-add: which appeal does the new link belong to? // Single appeal → auto-select. Multiple → user picks. const [quickAddEventId, setQuickAddEventId] = useState(null) const activeEvent = events.length === 1 ? events[0] : events.find(e => e.id === quickAddEventId) || events[0] // ── Actions ── const copyLink = async (code: string) => { await navigator.clipboard.writeText(`${baseUrl}/p/${code}`) setCopiedCode(code); setTimeout(() => setCopiedCode(null), 2000) } const copyEmbed = async (code: string) => { const snippet = `\n