Files
democratic-money/src/app/raised/page.tsx
root a3f08242fe first commit
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 19:20:03 +00:00

90 lines
4.0 KiB
TypeScript

import { prisma } from "@/lib/prisma";
import Link from "next/link";
import { appTitle } from "@/lib/public-env";
export const metadata = {
title: `Dollars raised — ${appTitle()}`,
description: "Live totals from confirmed Stripe donations in this deployment.",
};
export default async function RaisedPage() {
const [agg, donorRows] = await Promise.all([
prisma.donation.aggregate({
_sum: { amountUsdCents: true },
_count: true,
}),
prisma.donation.groupBy({
by: ["userId"],
_count: true,
}),
]);
const raisedUsd = (agg._sum.amountUsdCents ?? 0) / 100;
const donationCount = agg._count;
const uniqueDonors = donorRows.length;
const goalUsd = parseFloat(process.env.PUBLIC_CAMPAIGN_GOAL_USD ?? "250000");
const pct = goalUsd > 0 ? Math.min(100, Math.round((raisedUsd / goalUsd) * 100)) : 0;
const formatted = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(raisedUsd);
return (
<main className="min-h-[70vh] border-b border-white/10 py-16">
<div className="mx-auto max-w-3xl px-4 sm:px-6">
<p className="text-xs uppercase tracking-[0.32em] text-sky-200/80">Transparency</p>
<h1 className="mt-4 text-4xl font-semibold text-white sm:text-5xl">Total dollars raised</h1>
<p className="mt-4 text-lg text-slate-400">
Sum of successful donations processed through Stripe for this app ({appTitle()}). Updates as webhooks confirm
payments.
</p>
<div className="mt-12 rounded-[28px] border border-white/10 bg-gradient-to-br from-sky-500/15 via-indigo-900/40 to-fuchsia-900/30 p-8 shadow-[0_0_100px_rgba(56,189,248,0.12)]">
<p className="text-sm uppercase tracking-[0.2em] text-slate-400">Confirmed via Stripe</p>
<p className="mt-4 font-mono text-5xl font-semibold tracking-tight text-white sm:text-6xl">{formatted}</p>
<p className="mt-6 flex flex-wrap gap-6 text-sm text-slate-300">
<span>
<strong className="text-white">{donationCount}</strong> donation{donationCount === 1 ? "" : "s"}
</span>
<span>
<strong className="text-white">{uniqueDonors}</strong> supporter{uniqueDonors === 1 ? "" : "s"}
</span>
</p>
</div>
<div className="mt-10">
<div className="flex justify-between text-xs text-slate-500">
<span>$0</span>
<span>
Goal {new Intl.NumberFormat("en-US", { style: "currency", currency: "USD", maximumFractionDigits: 0 }).format(goalUsd)}{" "}
<span className="text-slate-600">(PUBLIC_CAMPAIGN_GOAL_USD)</span>
</span>
</div>
<div className="mt-2 h-3 overflow-hidden rounded-full border border-white/10 bg-black/40">
<div
className="h-full rounded-full bg-gradient-to-r from-sky-400 via-indigo-400 to-fuchsia-400 transition-[width]"
style={{ width: `${pct}%` }}
/>
</div>
<p className="mt-2 text-center text-xs text-slate-500">{pct}% of demo goal</p>
</div>
<div className="mt-12 rounded-2xl border border-white/10 bg-white/5 p-6 text-sm text-slate-400">
<p className="font-medium text-white">Note</p>
<p className="mt-2 leading-relaxed">
This total reflects <code className="rounded bg-black/30 px-1">Donation</code> rows created by the Stripe webhook
onlyonly processed charges count. Configure committee reporting separately for compliance.
</p>
</div>
<div className="mt-10 flex flex-wrap gap-4">
<Link href="/#donate" className="rounded-full bg-gradient-to-r from-sky-500 to-indigo-500 px-6 py-3 text-sm font-semibold text-white">
Donate
</Link>
<Link href="/" className="rounded-full border border-white/15 px-6 py-3 text-sm font-semibold text-white hover:bg-white/5">
Back home
</Link>
</div>
</div>
</main>
);
}