From aaedada2ca6adfe5dafe1c75365ca66e88a85265 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Thu, 12 Sep 2024 09:17:22 -0500 Subject: [PATCH] Standardized and improved payment messages on paid courses and resources --- .../bitcoinConnect/CoursePaymentButton.js | 2 + .../content/courses/CourseDetails.js | 71 +++++++++---------- .../content/courses/CourseLesson.js | 16 ++--- .../content/resources/ResourceDetails.js | 23 ++++-- src/pages/course/[slug]/index.js | 9 ++- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/src/components/bitcoinConnect/CoursePaymentButton.js b/src/components/bitcoinConnect/CoursePaymentButton.js index cec2000..463c3e4 100644 --- a/src/components/bitcoinConnect/CoursePaymentButton.js +++ b/src/components/bitcoinConnect/CoursePaymentButton.js @@ -58,6 +58,8 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } amountPaid: parseInt(amount, 10) }; + console.log('purchaseData', purchaseData); + const result = await axios.post('/api/purchase/course', purchaseData); if (result.status === 200) { diff --git a/src/components/content/courses/CourseDetails.js b/src/components/content/courses/CourseDetails.js index f04c2c1..6bf2347 100644 --- a/src/components/content/courses/CourseDetails.js +++ b/src/components/content/courses/CourseDetails.js @@ -4,8 +4,9 @@ import { useImageProxy } from '@/hooks/useImageProxy'; import ZapDisplay from '@/components/zaps/ZapDisplay'; import { getTotalFromZaps } from '@/utils/lightning'; import { Tag } from 'primereact/tag'; -import { nip19, nip04 } from 'nostr-tools'; +import { nip19 } from 'nostr-tools'; import { useSession } from 'next-auth/react'; +import GenericButton from '@/components/buttons/GenericButton'; import Image from 'next/image'; import dynamic from 'next/dynamic'; import ZapThreadsWrapper from '@/components/ZapThreadsWrapper'; @@ -36,26 +37,6 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS; - useEffect(() => { - console.log("processedEvent", processedEvent); - }, [processedEvent]); - - useEffect(() => { - console.log("lessons", lessons); - }, [lessons]); - - useEffect(() => { - console.log("zaps", zaps); - }, [zaps]); - - useEffect(() => { - console.log("paidCourse", paidCourse); - }, [paidCourse]); - - useEffect(() => { - console.log("decryptionPerformed", decryptionPerformed); - }, [decryptionPerformed]); - useEffect(() => { if (session) { setUser(session.user); @@ -96,6 +77,38 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec } }, [zaps, processedEvent]); + const renderPaymentMessage = () => { + if (paidCourse && !decryptionPerformed) { + return ( + + ); + } + + const coursePurchased = session?.user?.purchased?.some(purchase => + purchase?.courseId === processedEvent.d + ); + + if (paidCourse && decryptionPerformed && author && session?.user?.role?.subscribed && processedEvent?.pubkey !== session?.user?.pubkey) { + return + } + + if (paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey) { + return + } + + if (paidCourse && decryptionPerformed && author && coursePurchased) { + return + } + + return null; + }; + if (!processedEvent || !author) { return (
@@ -146,21 +159,7 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec className="w-[344px] h-[194px] object-cover object-top rounded-lg" />
- {paidCourse && !decryptionPerformed && ( - - )} - {paidCourse && decryptionPerformed && author && processedEvent?.pubkey !== session?.user?.pubkey && ( -

Paid {processedEvent.price} sats

- )} - {paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey && ( -

Price {processedEvent.price} sats

- )} + {renderPaymentMessage()} { +const CourseLesson = ({ lesson, course, decryptionPerformed, isPaid }) => { const [zapAmount, setZapAmount] = useState(0); - const [paidResource, setPaidResource] = useState(false); - const [decryptedContent, setDecryptedContent] = useState(false); const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: lesson, type: "lesson" }); const { returnImageProxy } = useImageProxy(); - useEffect(() => { - if (course.price) { - setPaidResource(true); - } - }, [course]); - useEffect(() => { if (!zaps || zapsLoading || zapsError) return; @@ -36,10 +28,10 @@ const CourseLesson = ({ lesson, course }) => { }, [zaps, zapsLoading, zapsError, lesson]); const renderContent = () => { - if (decryptedContent) { - return ; + if (isPaid && decryptionPerformed) { + return ; } - if (paidResource && !decryptedContent) { + if (isPaid && !decryptionPerformed) { return

This content is paid and needs to be purchased before viewing.

; } if (lesson?.content) { diff --git a/src/components/content/resources/ResourceDetails.js b/src/components/content/resources/ResourceDetails.js index 15525d9..e39af99 100644 --- a/src/components/content/resources/ResourceDetails.js +++ b/src/components/content/resources/ResourceDetails.js @@ -4,6 +4,7 @@ import Image from "next/image"; import { useRouter } from "next/router"; import ResourcePaymentButton from "@/components/bitcoinConnect/ResourcePaymentButton"; import ZapDisplay from "@/components/zaps/ZapDisplay"; +import GenericButton from "@/components/buttons/GenericButton"; import { useImageProxy } from "@/hooks/useImageProxy"; import { useZapsSubscription } from "@/hooks/nostrQueries/zaps/useZapsSubscription"; import { getTotalFromZaps } from "@/utils/lightning"; @@ -26,6 +27,22 @@ const ResourceDetails = ({processedEvent, topics, title, summary, image, price, } }, [zaps, processedEvent]); + const renderPaymentMessage = () => { + if (session?.user && session.user?.role?.subscribed && decryptedContent) { + return + } + + if (paidResource && decryptedContent && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed) { + return + } + + if (paidResource && author && processedEvent?.pubkey === session?.user?.pubkey) { + return + } + + return null; + }; + return (
router.push('/')} /> @@ -76,11 +93,7 @@ const ResourceDetails = ({processedEvent, topics, title, summary, image, price, resourceId={processedEvent.d} />} - {/* if the resource has been paid for show a green paid x sats text */} - {paidResource && decryptedContent && author && !processedEvent?.pubkey === session?.user?.pubkey &&

Paid {processedEvent.price} sats

} - - {/* if this is the author of the resource show a zap button */} - {paidResource && author && processedEvent?.pubkey === session?.user?.pubkey &&

Price {processedEvent.price} sats

} + {renderPaymentMessage()} { session.user?.role?.subscribed || session.user?.pubkey === course?.pubkey; + console.log('canAccess', canAccess); + if (canAccess && lessons.length > 0) { try { const decryptedLessons = await Promise.all(lessons.map(async (lesson) => { @@ -154,11 +156,12 @@ const Course = () => { } }, [course, lessons, paidCourse, decryptionPerformed]); - const handlePaymentSuccess = async (response, newCourse) => { + const handlePaymentSuccess = async (response) => { if (response && response?.preimage) { - console.log("newCourse", newCourse); const updated = await update(); console.log("session after update", updated); + showToast('success', 'Payment Success', 'You have successfully purchased this course'); + router.reload(); } else { showToast('error', 'Error', 'Failed to purchase course. Please try again.'); } @@ -187,7 +190,7 @@ const Course = () => { handlePaymentError={handlePaymentError} /> {lessons.length > 0 && lessons.map((lesson, index) => ( - + ))}
{course?.content && }