feat: add improved pi agent with observatory, dashboard, and pledge-now-pay-later

This commit is contained in:
Azreen Jamal
2026-03-01 23:41:24 +08:00
parent ae242436c9
commit f832b913d5
99 changed files with 20949 additions and 74 deletions

View File

@@ -0,0 +1,97 @@
"use client"
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
const PRESETS = [1000, 2000, 5000, 10000, 25000, 50000] // pence
interface Props {
onSelect: (amountPence: number) => void
eventName: string
}
export function AmountStep({ onSelect, eventName }: Props) {
const [custom, setCustom] = useState("")
const [selected, setSelected] = useState<number | null>(null)
const handlePreset = (amount: number) => {
setSelected(amount)
setCustom("")
}
const handleCustomChange = (value: string) => {
const clean = value.replace(/[^0-9.]/g, "")
setCustom(clean)
setSelected(null)
}
const handleContinue = () => {
const amount = selected || Math.round(parseFloat(custom) * 100)
if (amount >= 100) onSelect(amount)
}
const isValid = selected || (custom && parseFloat(custom) >= 1)
return (
<div className="max-w-md mx-auto pt-4 space-y-8">
<div className="text-center space-y-2">
<h1 className="text-3xl font-extrabold text-gray-900">
Make a Pledge
</h1>
<p className="text-muted-foreground">
for <span className="font-semibold text-foreground">{eventName}</span>
</p>
</div>
{/* Presets */}
<div className="grid grid-cols-3 gap-3">
{PRESETS.map((amount) => (
<button
key={amount}
onClick={() => handlePreset(amount)}
className={`
tap-target rounded-2xl border-2 py-4 text-center font-bold text-lg transition-all
${selected === amount
? "border-trust-blue bg-trust-blue text-white shadow-lg shadow-trust-blue/25 scale-[1.02]"
: "border-gray-200 bg-white text-gray-900 hover:border-trust-blue/50 active:scale-[0.98]"
}
`}
>
£{amount / 100}
</button>
))}
</div>
{/* Custom */}
<div className="space-y-2">
<label className="text-sm font-medium text-muted-foreground">Or enter a custom amount</label>
<div className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-2xl font-bold text-gray-400">£</span>
<Input
type="text"
inputMode="decimal"
placeholder="0.00"
value={custom}
onChange={(e) => handleCustomChange(e.target.value)}
className="pl-10 h-16 text-2xl font-bold text-center rounded-2xl"
/>
</div>
</div>
{/* Continue */}
<Button
size="xl"
className="w-full"
disabled={!isValid}
onClick={handleContinue}
>
Continue
</Button>
<p className="text-center text-xs text-muted-foreground">
You won&apos;t be charged now. Choose how to pay next.
</p>
</div>
)
}