feat: add zap button to goal renderers

Show a 'Zap this Goal' button in both feed and detail views
when the goal is still open (not past its closed_at deadline).
This commit is contained in:
Claude
2026-01-20 15:56:05 +00:00
parent 316908196d
commit 5b9713f0ae
2 changed files with 36 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
import { useMemo } from "react";
import { NostrEvent } from "@/types/nostr";
import { Zap } from "lucide-react";
import { useTimeline } from "@/hooks/useTimeline";
import {
getGoalAmount,
@@ -14,6 +15,7 @@ import { getZapAmount, getZapSender } from "applesauce-common/helpers/zap";
import { formatTimestamp } from "@/hooks/useLocale";
import { useGrimoire } from "@/core/state";
import { Progress } from "@/components/ui/progress";
import { Button } from "@/components/ui/button";
import { UserName } from "../UserName";
import { Skeleton } from "@/components/ui/skeleton";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
@@ -29,7 +31,7 @@ interface Contributor {
* Shows full goal info with sorted contributor breakdown
*/
export function GoalDetailRenderer({ event }: { event: NostrEvent }) {
const { locale } = useGrimoire();
const { locale, addWindow } = useGrimoire();
// Get goal metadata
const targetAmount = getGoalAmount(event);
@@ -109,6 +111,13 @@ export function GoalDetailRenderer({ event }: { event: NostrEvent }) {
? formatTimestamp(closedAt, "absolute", locale.locale)
: null;
const handleZap = () => {
addWindow("zap", {
recipientPubkey: event.pubkey,
eventPointer: { id: event.id },
});
};
return (
<div className="flex flex-col gap-6 p-6 max-w-2xl mx-auto">
{/* Header */}
@@ -153,6 +162,14 @@ export function GoalDetailRenderer({ event }: { event: NostrEvent }) {
</div>
)}
{/* Zap Button */}
{!closed && (
<Button variant="outline" onClick={handleZap} className="w-fit">
<Zap className="size-4 text-zap" />
Zap this Goal
</Button>
)}
{/* Beneficiaries */}
{beneficiaries.length > 0 && (
<div className="flex flex-col gap-2">

View File

@@ -4,6 +4,7 @@ import {
BaseEventContainer,
ClickableEventTitle,
} from "./BaseEventRenderer";
import { Zap } from "lucide-react";
import { useTimeline } from "@/hooks/useTimeline";
import {
getGoalAmount,
@@ -17,6 +18,7 @@ import { getZapAmount } from "applesauce-common/helpers/zap";
import { formatTimestamp } from "@/hooks/useLocale";
import { useGrimoire } from "@/core/state";
import { Progress } from "@/components/ui/progress";
import { Button } from "@/components/ui/button";
import { AGGREGATOR_RELAYS } from "@/services/loaders";
/**
@@ -24,7 +26,7 @@ import { AGGREGATOR_RELAYS } from "@/services/loaders";
* Shows goal title, description, and funding progress
*/
export function GoalRenderer({ event }: BaseEventProps) {
const { locale } = useGrimoire();
const { locale, addWindow } = useGrimoire();
// Get goal metadata
const targetAmount = getGoalAmount(event);
@@ -77,6 +79,13 @@ export function GoalRenderer({ event }: BaseEventProps) {
? formatTimestamp(closedAt, "absolute", locale.locale)
: null;
const handleZap = () => {
addWindow("zap", {
recipientPubkey: event.pubkey,
eventPointer: { id: event.id },
});
};
return (
<BaseEventContainer event={event}>
<div className="flex flex-col gap-3">
@@ -130,6 +139,14 @@ export function GoalRenderer({ event }: BaseEventProps) {
)}
</div>
)}
{/* Zap Button */}
{!closed && (
<Button variant="outline" size="sm" onClick={handleZap}>
<Zap className="size-4 text-zap" />
Zap this Goal
</Button>
)}
</div>
</BaseEventContainer>
);