From 9e8e355ae8af22d7e8075be6189b0a73cb2a9f72 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Mon, 18 Nov 2024 13:34:46 -0600 Subject: [PATCH 1/3] Start on discount code impl, keep it single and hardcoded and simple at first --- .../bitcoinConnect/CoursePaymentButton.js | 72 +++++++++++++++++-- .../content/courses/CourseDetails.js | 2 +- .../content/documents/DocumentDetails.js | 4 +- src/config/appConfig.js | 2 +- 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/components/bitcoinConnect/CoursePaymentButton.js b/src/components/bitcoinConnect/CoursePaymentButton.js index a8040d3..f20754c 100644 --- a/src/components/bitcoinConnect/CoursePaymentButton.js +++ b/src/components/bitcoinConnect/CoursePaymentButton.js @@ -10,12 +10,15 @@ import axios from 'axios'; import GenericButton from '@/components/buttons/GenericButton'; import { useRouter } from 'next/router'; import useWindowWidth from '@/hooks/useWindowWidth'; +import { InputText } from 'primereact/inputtext'; const Payment = dynamic( () => import('@getalby/bitcoin-connect-react').then((mod) => mod.Payment), { ssr: false } ); +const DISCOUNT_CODE = process.env.NEXT_PUBLIC_DISCOUNT_CODE; + const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }) => { const [invoice, setInvoice] = useState(null); const [isLoading, setIsLoading] = useState(false); @@ -25,6 +28,9 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } const router = useRouter(); const windowWidth = useWindowWidth(); const isMobile = windowWidth < 768; + const [discountCode, setDiscountCode] = useState(''); + const [discountApplied, setDiscountApplied] = useState(false); + const [showDiscountInput, setShowDiscountInput] = useState(false); useEffect(() => { let intervalId; @@ -49,12 +55,21 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } }; }, [invoice]); + const calculateDiscount = (originalAmount) => { + if (discountCode === DISCOUNT_CODE) { + const discountedAmount = 21000; + const savedPercentage = Math.round(((originalAmount - discountedAmount) / originalAmount) * 100); + return { discountedAmount, savedPercentage }; + } + return { discountedAmount: originalAmount, savedPercentage: 0 }; + }; + const fetchInvoice = async () => { setIsLoading(true); try { const ln = new LightningAddress(lnAddress); await ln.fetch(); - const invoice = await ln.requestInvoice({ satoshi: amount }); + const invoice = await ln.requestInvoice({ satoshi: discountApplied ? calculateDiscount(amount).discountedAmount : amount }); setInvoice(invoice); setDialogVisible(true); } catch (error) { @@ -70,7 +85,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } const purchaseData = { userId: session.user.id, courseId: courseId, - amountPaid: parseInt(amount, 10) + amountPaid: discountApplied ? calculateDiscount(amount).discountedAmount : parseInt(amount, 10) }; const result = await axios.post('/api/purchase/course', purchaseData); @@ -90,9 +105,56 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } }; return ( - <> +
+ {!showDiscountInput ? ( + + ) : ( +
+
+
+ { + setDiscountCode(e.target.value); + setDiscountApplied(e.target.value === DISCOUNT_CODE); + }} + placeholder="Enter discount code" + className="text-sm w-full p-2" + /> + +
+ {discountApplied && ( + + + {calculateDiscount(amount).savedPercentage}% off! + + )} +
+ {discountApplied && ( +
+ {amount} sats + → {calculateDiscount(amount).discountedAmount} sats +
+ )} +
+ )} { if (status === 'unauthenticated') { @@ -133,7 +195,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }

Loading payment details...

)} - +
); }; diff --git a/src/components/content/courses/CourseDetails.js b/src/components/content/courses/CourseDetails.js index 31df945..fee1b5c 100644 --- a/src/components/content/courses/CourseDetails.js +++ b/src/components/content/courses/CourseDetails.js @@ -91,7 +91,7 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec } if (paidCourse && decryptionPerformed && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed) { - return + return } if (paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey) { diff --git a/src/components/content/documents/DocumentDetails.js b/src/components/content/documents/DocumentDetails.js index 661ef26..0f6e9af 100644 --- a/src/components/content/documents/DocumentDetails.js +++ b/src/components/content/documents/DocumentDetails.js @@ -77,11 +77,11 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price, // if the user paid for the course that this lesson is in, show a message that says you have this lesson through the course and show how much you paid for the course if (isLesson && course && session?.user?.purchased?.some(purchase => purchase.courseId === course)) { - return purchase.courseId === course)?.course?.price} sats for the course.`} icon="pi pi-check" label={`Paid ${session?.user?.purchased?.find(purchase => purchase.courseId === course)?.course?.price} sats`} severity="success" outlined size="small" className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" /> + return purchase.courseId === course)?.course?.price} sats for the course.`} icon="pi pi-check" label={`Paid`} severity="success" outlined size="small" className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" /> } if (paidResource && decryptedContent && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed) { - return + return } if (paidResource && author && processedEvent?.pubkey === session?.user?.pubkey) { diff --git a/src/config/appConfig.js b/src/config/appConfig.js index 30556e0..44155e5 100644 --- a/src/config/appConfig.js +++ b/src/config/appConfig.js @@ -11,7 +11,7 @@ const appConfig = { "wss://purplerelay.com/", "wss://relay.devs.tools/" ], - authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345"], + authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345", "468f729dd409053dac5e7470622c3996aad88db6ed1de9165cb1921b5ab4fd5e"], customLightningAddresses: [ { // todo remove need for lowercase From 93d0dc9b3115e4c1e7f20f25ee44fa6d51120c02 Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Tue, 26 Nov 2024 15:44:12 -0600 Subject: [PATCH 2/3] Clean up test again, it seems to work --- .../bitcoinConnect/CoursePaymentButton.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/bitcoinConnect/CoursePaymentButton.js b/src/components/bitcoinConnect/CoursePaymentButton.js index f20754c..fdef804 100644 --- a/src/components/bitcoinConnect/CoursePaymentButton.js +++ b/src/components/bitcoinConnect/CoursePaymentButton.js @@ -104,6 +104,16 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId } setDialogVisible(false); }; + const handleDiscountCode = (value) => { + setDiscountCode(value); + if (value.toLowerCase() === DISCOUNT_CODE.toLowerCase()) { + setDiscountApplied(true); + showToast('success', 'Discount Applied', `${calculateDiscount(amount).savedPercentage}% discount applied!`); + } else if (value && value.toLowerCase() !== DISCOUNT_CODE.toLowerCase()) { + setDiscountApplied(false); + } + }; + return (
{!showDiscountInput ? ( @@ -120,10 +130,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
{ - setDiscountCode(e.target.value); - setDiscountApplied(e.target.value === DISCOUNT_CODE); - }} + onChange={(e) => handleDiscountCode(e.target.value)} placeholder="Enter discount code" className="text-sm w-full p-2" /> From b7ede13cab5345b9a6ddfa39f2cffae6948fa76d Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Tue, 26 Nov 2024 15:47:24 -0600 Subject: [PATCH 3/3] Revert app config --- src/config/appConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/appConfig.js b/src/config/appConfig.js index 44155e5..30556e0 100644 --- a/src/config/appConfig.js +++ b/src/config/appConfig.js @@ -11,7 +11,7 @@ const appConfig = { "wss://purplerelay.com/", "wss://relay.devs.tools/" ], - authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345", "468f729dd409053dac5e7470622c3996aad88db6ed1de9165cb1921b5ab4fd5e"], + authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345"], customLightningAddresses: [ { // todo remove need for lowercase