Merge pull request #3 from AustinKelsay/feature/discount-code-hardcoded

Discount code single
This commit is contained in:
Austin Kelsay 2024-11-26 15:52:06 -06:00 committed by GitHub
commit 8e68214972
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 77 additions and 8 deletions

View File

@ -10,12 +10,15 @@ import axios from 'axios';
import GenericButton from '@/components/buttons/GenericButton'; import GenericButton from '@/components/buttons/GenericButton';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import useWindowWidth from '@/hooks/useWindowWidth'; import useWindowWidth from '@/hooks/useWindowWidth';
import { InputText } from 'primereact/inputtext';
const Payment = dynamic( const Payment = dynamic(
() => import('@getalby/bitcoin-connect-react').then((mod) => mod.Payment), () => import('@getalby/bitcoin-connect-react').then((mod) => mod.Payment),
{ ssr: false } { ssr: false }
); );
const DISCOUNT_CODE = process.env.NEXT_PUBLIC_DISCOUNT_CODE;
const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }) => { const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }) => {
const [invoice, setInvoice] = useState(null); const [invoice, setInvoice] = useState(null);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@ -25,6 +28,9 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
const router = useRouter(); const router = useRouter();
const windowWidth = useWindowWidth(); const windowWidth = useWindowWidth();
const isMobile = windowWidth < 768; const isMobile = windowWidth < 768;
const [discountCode, setDiscountCode] = useState('');
const [discountApplied, setDiscountApplied] = useState(false);
const [showDiscountInput, setShowDiscountInput] = useState(false);
useEffect(() => { useEffect(() => {
let intervalId; let intervalId;
@ -49,12 +55,21 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
}; };
}, [invoice]); }, [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 () => { const fetchInvoice = async () => {
setIsLoading(true); setIsLoading(true);
try { try {
const ln = new LightningAddress(lnAddress); const ln = new LightningAddress(lnAddress);
await ln.fetch(); await ln.fetch();
const invoice = await ln.requestInvoice({ satoshi: amount }); const invoice = await ln.requestInvoice({ satoshi: discountApplied ? calculateDiscount(amount).discountedAmount : amount });
setInvoice(invoice); setInvoice(invoice);
setDialogVisible(true); setDialogVisible(true);
} catch (error) { } catch (error) {
@ -70,7 +85,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
const purchaseData = { const purchaseData = {
userId: session.user.id, userId: session.user.id,
courseId: courseId, courseId: courseId,
amountPaid: parseInt(amount, 10) amountPaid: discountApplied ? calculateDiscount(amount).discountedAmount : parseInt(amount, 10)
}; };
const result = await axios.post('/api/purchase/course', purchaseData); const result = await axios.post('/api/purchase/course', purchaseData);
@ -89,10 +104,64 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
setDialogVisible(false); 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 ( return (
<> <div className="flex flex-col gap-2">
{!showDiscountInput ? (
<button
onClick={() => setShowDiscountInput(true)}
className="text-sm text-blue-500 hover:text-blue-700 underline self-start flex items-center gap-1"
>
<i className="pi pi-tag text-xs"></i>
Have a discount code?
</button>
) : (
<div className="flex flex-col gap-2 w-full">
<div className="flex gap-2 items-center">
<div className="relative flex-1">
<InputText
value={discountCode}
onChange={(e) => handleDiscountCode(e.target.value)}
placeholder="Enter discount code"
className="text-sm w-full p-2"
/>
<button
onClick={() => {
setShowDiscountInput(false);
setDiscountCode('');
setDiscountApplied(false);
}}
className="absolute right-2 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600"
>
<i className="pi pi-times text-xs"></i>
</button>
</div>
{discountApplied && (
<span className="text-green-500 text-sm whitespace-nowrap flex items-center gap-1">
<i className="pi pi-check-circle"></i>
{calculateDiscount(amount).savedPercentage}% off!
</span>
)}
</div>
{discountApplied && (
<div className="text-xs text-gray-500 flex items-center gap-1">
<span className="line-through">{amount} sats</span>
<span className="text-green-500 font-semibold"> {calculateDiscount(amount).discountedAmount} sats</span>
</div>
)}
</div>
)}
<GenericButton <GenericButton
label={`${amount} sats`} label={`${discountApplied ? calculateDiscount(amount).discountedAmount : amount} sats`}
icon="pi pi-wallet" icon="pi pi-wallet"
onClick={() => { onClick={() => {
if (status === 'unauthenticated') { if (status === 'unauthenticated') {
@ -133,7 +202,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
<p>Loading payment details...</p> <p>Loading payment details...</p>
)} )}
</Dialog> </Dialog>
</> </div>
); );
}; };

View File

@ -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) { if (paidCourse && decryptionPerformed && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed) {
return <GenericButton icon="pi pi-check" label={`Paid ${processedEvent.price} sats`} severity="success" outlined size="small" className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" /> return <GenericButton icon="pi pi-check" label={`Paid`} severity="success" outlined size="small" tooltip={`You paid ${processedEvent.price} sats to access this course (or potentially less if a discount was applied)`} tooltipOptions={{ position: 'top' }} className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" />
} }
if (paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey) { if (paidCourse && author && processedEvent?.pubkey === session?.user?.pubkey) {

View File

@ -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 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)) { if (isLesson && course && session?.user?.purchased?.some(purchase => purchase.courseId === course)) {
return <GenericButton tooltipOptions={{ position: 'top' }} tooltip={`You have this lesson through purchasing the course it belongs to. You paid ${session?.user?.purchased?.find(purchase => 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 <GenericButton tooltipOptions={{ position: 'top' }} tooltip={`You have this lesson through purchasing the course it belongs to. You paid ${session?.user?.purchased?.find(purchase => 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) { if (paidResource && decryptedContent && author && processedEvent?.pubkey !== session?.user?.pubkey && !session?.user?.role?.subscribed) {
return <GenericButton icon="pi pi-check" label={`Paid ${processedEvent.price} sats`} severity="success" outlined size="small" className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" /> return <GenericButton icon="pi pi-check" label={`Paid`} severity="success" outlined size="small" tooltip={`You paid ${processedEvent.price} sats to access this content (or potentially less if a discount was applied)`} tooltipOptions={{ position: 'top' }} className="cursor-default hover:opacity-100 hover:bg-transparent focus:ring-0" />
} }
if (paidResource && author && processedEvent?.pubkey === session?.user?.pubkey) { if (paidResource && author && processedEvent?.pubkey === session?.user?.pubkey) {