added confirm modal and fixed some subscribing bugs
This commit is contained in:
parent
675e0c4507
commit
7a478f9efe
@ -4,8 +4,7 @@ import Image from "next/image";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import useProfile from "@/lib/hooks/useProfile";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import useEvents from "@/lib/hooks/useEvents";
|
||||
import { HiOutlineLightningBolt } from "react-icons/hi";
|
||||
import Spinner from "@/components/spinner";
|
||||
import { getTagValues, getTagsValues } from "@/lib/nostr/utils";
|
||||
import ProfileInfo from "./ProfileInfo";
|
||||
@ -19,19 +18,22 @@ import {
|
||||
} from "@/lib/actions/zap";
|
||||
import { useModal } from "@/app/_providers/modal/provider";
|
||||
import { type NDKEvent } from "@nostr-dev-kit/ndk";
|
||||
|
||||
import { btcToSats, formatNumber } from "@/lib/utils";
|
||||
import { formatDate } from "@/lib/utils/dates";
|
||||
const EditListModal = dynamic(() => import("@/components/Modals/EditList"), {
|
||||
ssr: false,
|
||||
});
|
||||
const CreateEventModal = dynamic(() => import("@/components/Modals/NewEvent"), {
|
||||
ssr: false,
|
||||
});
|
||||
const ConfirmModal = dynamic(() => import("@/components/Modals/Confirm"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
export default function Header({ event }: { event: NDKEvent }) {
|
||||
const { currentUser } = useCurrentUser();
|
||||
const modal = useModal();
|
||||
const { ndk } = useNDK();
|
||||
const [sendingZap, setSendingZap] = useState(false);
|
||||
const [checkingPayment, setCheckingPayment] = useState(false);
|
||||
const [hasValidPayment, setHasValidPayment] = useState(false);
|
||||
const [syncingUsers, setSyncingUsers] = useState(false);
|
||||
@ -39,7 +41,6 @@ export default function Header({ event }: { event: NDKEvent }) {
|
||||
const { profile } = useProfile(pubkey);
|
||||
|
||||
const noteIds = getTagsValues("e", event.tags).filter(Boolean);
|
||||
console.log("notes", event.tags);
|
||||
const title =
|
||||
getTagValues("title", event.tags) ??
|
||||
getTagValues("name", event.tags) ??
|
||||
@ -53,7 +54,7 @@ export default function Header({ event }: { event: NDKEvent }) {
|
||||
const description = getTagValues("description", event.tags);
|
||||
const rawEvent = event.rawEvent();
|
||||
const subscriptionsEnabled = !!getTagValues("subscriptions", rawEvent.tags);
|
||||
const priceInBTC = getTagValues("price", rawEvent.tags);
|
||||
const priceInBTC = parseFloat(getTagValues("price", rawEvent.tags) ?? "0");
|
||||
const isMember =
|
||||
currentUser &&
|
||||
getTagsValues("p", rawEvent.tags).includes(currentUser.pubkey);
|
||||
@ -99,6 +100,21 @@ export default function Header({ event }: { event: NDKEvent }) {
|
||||
setSyncingUsers(false);
|
||||
}
|
||||
}
|
||||
async function handleSendZap() {
|
||||
try {
|
||||
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 {
|
||||
}
|
||||
}
|
||||
if (!event) {
|
||||
return (
|
||||
<div className="center pt-20 text-primary">
|
||||
@ -155,7 +171,39 @@ export default function Header({ event }: { event: NDKEvent }) {
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{subscriptionsEnabled && !isMember && <Button>Subscribe</Button>}
|
||||
{subscriptionsEnabled && !isMember && (
|
||||
<Button
|
||||
onClick={() =>
|
||||
modal?.show(
|
||||
<ConfirmModal
|
||||
title={`Subscribe to ${title}`}
|
||||
onConfirm={handleSendZap}
|
||||
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>,
|
||||
)
|
||||
}
|
||||
>
|
||||
Subscribe
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
56
components/Modals/Confirm.tsx
Normal file
56
components/Modals/Confirm.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
"use client";
|
||||
import { useState, type ReactNode } from "react";
|
||||
import Template from "./Template";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useModal } from "@/app/_providers/modal/provider";
|
||||
import { nip19 } from "nostr-tools";
|
||||
// import { useKeys } from "@/app/_providers/keysProvider";
|
||||
import { useNDK } from "@/app/_providers/ndk";
|
||||
import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
||||
import { HiOutlineLightningBolt } from "react-icons/hi";
|
||||
import { RiSubtractFill, RiAddFill } from "react-icons/ri";
|
||||
import { formatCount } from "@/lib/utils";
|
||||
|
||||
type ConfirmModalProps = {
|
||||
title?: string;
|
||||
children: ReactNode;
|
||||
ctaBody?: ReactNode;
|
||||
onConfirm: () => Promise<void>;
|
||||
};
|
||||
|
||||
export default function ConfirmModal({
|
||||
title = "Confirm",
|
||||
children,
|
||||
ctaBody = "Confirm",
|
||||
onConfirm,
|
||||
}: ConfirmModalProps) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const modal = useModal();
|
||||
|
||||
async function handleSubmit() {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await onConfirm();
|
||||
} catch (err) {
|
||||
console.log("Error", err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
modal?.hide();
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Template title={title} className="md:max-w-[400px]">
|
||||
<div className="flex flex-col gap-y-5">
|
||||
<div className="pb-2">{children}</div>
|
||||
<Button
|
||||
onClick={() => void handleSubmit()}
|
||||
loading={isLoading}
|
||||
className="w-full gap-x-1"
|
||||
>
|
||||
{ctaBody}
|
||||
</Button>
|
||||
</div>
|
||||
</Template>
|
||||
);
|
||||
}
|
@ -114,6 +114,7 @@ export default function FormModal<TSchema extends FieldValues>({
|
||||
if (!condition) {
|
||||
return (
|
||||
<FormField
|
||||
key={slug}
|
||||
control={form.control}
|
||||
name={slug as Path<TSchema>}
|
||||
render={({ field }) => (
|
||||
@ -187,6 +188,7 @@ export default function FormModal<TSchema extends FieldValues>({
|
||||
if (!state) return;
|
||||
return (
|
||||
<FormField
|
||||
key={slug}
|
||||
control={form.control}
|
||||
name={slug as Path<TSchema>}
|
||||
render={({ field }) => (
|
||||
|
@ -103,10 +103,11 @@ export async function updateListUsersFromZaps(
|
||||
event: NostrEvent,
|
||||
) {
|
||||
const SECONDS_IN_MONTH = 2_628_000;
|
||||
const SECONDS_IN_YEAR = SECONDS_IN_MONTH * 365;
|
||||
const paymentEvents = await ndk.fetchEvents({
|
||||
kinds: [9735],
|
||||
["#a"]: [tagId],
|
||||
since: unixTimeNowInSeconds() - SECONDS_IN_MONTH,
|
||||
since: unixTimeNowInSeconds() - SECONDS_IN_YEAR,
|
||||
});
|
||||
const paymentInvoices = Array.from(paymentEvents).map((paymentEvent) =>
|
||||
zapInvoiceFromEvent(paymentEvent),
|
||||
@ -137,7 +138,7 @@ export async function updateListUsersFromZaps(
|
||||
paymentInvoice.zappee,
|
||||
"",
|
||||
"",
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_MONTH).toString(),
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_YEAR).toString(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -152,14 +153,14 @@ export async function updateListUsersFromZaps(
|
||||
event.pubkey,
|
||||
"",
|
||||
"self",
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_MONTH).toString(),
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_YEAR).toString(),
|
||||
];
|
||||
} else {
|
||||
validUsers.push([
|
||||
event.pubkey,
|
||||
"",
|
||||
"self",
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_MONTH).toString(),
|
||||
(unixTimeNowInSeconds() + SECONDS_IN_YEAR).toString(),
|
||||
]);
|
||||
}
|
||||
console.log("Valid users", validUsers);
|
||||
|
Loading…
x
Reference in New Issue
Block a user