2023-10-21 09:23:08 -04:00

173 lines
5.7 KiB
TypeScript

import { useState, useEffect } from "react";
import Image from "next/image";
import Link from "next/link";
import dynamic from "next/dynamic";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { cn, log } from "@/lib/utils";
import { NDKEvent, NDKUser, NDKNip07Signer } from "@nostr-dev-kit/ndk";
import { useNDK } from "@/app/_providers/ndk";
import useCurrentUser from "@/lib/hooks/useCurrentUser";
import { toast } from "sonner";
import { getTagValues, getTagsValues } from "@/lib/nostr/utils";
import { sendZap, checkPayment } from "@/lib/actions/zap";
import { btcToSats, formatNumber } from "@/lib/utils";
import { BANNER } from "@/constants";
import { follow } from "@/lib/actions/create";
import { HiOutlineLightningBolt } from "react-icons/hi";
import { formatDate } from "@/lib/utils/dates";
import { useModal } from "@/app/_providers/modal/provider";
const ConfirmModal = dynamic(() => import("@/components/Modals/Confirm"), {
ssr: false,
});
export default function SubscriptionCard({ event }: { event: NDKEvent }) {
const { currentUser } = useCurrentUser();
const { ndk } = useNDK();
const modal = useModal();
const [subscribing, setSubscribing] = useState(false);
const [checkingPayment, setCheckingPayment] = useState(false);
const [hasValidPayment, setHasValidPayment] = useState(false);
const { tags } = event;
const rawEvent = event.rawEvent();
const title = getTagValues("title", tags) ?? getTagValues("name", tags) ?? "";
const image =
getTagValues("image", tags) ?? getTagValues("picture", tags) ?? BANNER;
const description =
getTagValues("description", tags) ?? getTagValues("summary", tags) ?? "";
const delegate = getTagValues("delegate", tags);
const priceInBTC = parseFloat(getTagValues("price", rawEvent.tags) ?? "0");
async function handleSubscribe() {
log("func", "handleSubscribe");
setSubscribing(true);
try {
if (!currentUser || !ndk?.signer) return;
if (delegate) {
await follow(ndk, currentUser, delegate);
log("info", "followed");
}
const result = await sendZap(
ndk!,
btcToSats(priceInBTC),
rawEvent,
`Access payment: ${title}`,
);
toast.success("Payment Sent!");
void handleCheckPayment();
} catch (err) {
console.log("error sending zap", err);
} finally {
setSubscribing(false);
}
}
async function handleCheckPayment() {
if (!event || !currentUser || !ndk) return;
setCheckingPayment(true);
console.log("Checking payment");
try {
const result = await checkPayment(
ndk,
event.tagId(),
currentUser.pubkey,
rawEvent,
);
console.log("Payment result", result);
if (result) {
setHasValidPayment(true);
}
} catch (err) {
console.log("error sending zap", err);
} finally {
setCheckingPayment(false);
}
}
useEffect(() => {
if (!currentUser) return;
if (!checkingPayment && !hasValidPayment) {
void handleCheckPayment();
}
}, [currentUser]);
return (
<Card className="group sm:flex sm:items-stretch">
<div className="max-h-full overflow-hidden max-sm:h-[100px] max-sm:rounded-t-md sm:w-[250px] sm:rounded-l-md">
<Image
width={250}
height={150}
src={image}
alt={title}
unoptimized
className={cn(
"h-full w-full object-cover object-center transition-all group-hover:scale-105 sm:h-full sm:w-auto",
)}
/>
</div>
<div className="h-full flex-1">
<CardHeader className="">
<CardTitle className="line-clamp-2">{title}</CardTitle>
<CardDescription className="line-clamp-3">
{description}
</CardDescription>
</CardHeader>
<CardContent className="items-strech mt-auto flex w-full flex-col items-center gap-2 sm:max-w-md sm:flex-row sm:gap-4">
{hasValidPayment ? (
<Button disabled={true} variant={"ghost"} className="w-full">
Pending sync
</Button>
) : (
<>
<Button
loading={subscribing}
onClick={() =>
modal?.show(
<ConfirmModal
title={`Subscribe to ${title}`}
onConfirm={handleSubscribe}
ctaBody={
<>
<span>Zap to Subscribe</span>
<HiOutlineLightningBolt className="h-4 w-4" />
</>
}
>
<p className="text-muted-forground">
{`Pay ${priceInBTC} BTC (${formatNumber(
btcToSats(priceInBTC),
)} sats) for year long access until ${formatDate(
new Date(
new Date().setFullYear(
new Date().getFullYear() + 1,
),
),
"MMM Do, YYYY",
)}`}
</p>
</ConfirmModal>,
)
}
className="w-full"
>
Subscribe
</Button>
<Link href={`/sub/${event.encode()}`} className="w-full">
<Button variant={"secondary"} className="w-full">
Details
</Button>
</Link>
</>
)}
</CardContent>
</div>
</Card>
);
}