mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Start on discount code impl, keep it single and hardcoded and simple at first
This commit is contained in:
parent
1392f50261
commit
9e8e355ae8
@ -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);
|
||||||
@ -90,9 +105,56 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
|
|||||||
};
|
};
|
||||||
|
|
||||||
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) => {
|
||||||
|
setDiscountCode(e.target.value);
|
||||||
|
setDiscountApplied(e.target.value === DISCOUNT_CODE);
|
||||||
|
}}
|
||||||
|
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 +195,7 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
|
|||||||
<p>Loading payment details...</p>
|
<p>Loading payment details...</p>
|
||||||
)}
|
)}
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
@ -11,7 +11,7 @@ const appConfig = {
|
|||||||
"wss://purplerelay.com/",
|
"wss://purplerelay.com/",
|
||||||
"wss://relay.devs.tools/"
|
"wss://relay.devs.tools/"
|
||||||
],
|
],
|
||||||
authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345"],
|
authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345", "468f729dd409053dac5e7470622c3996aad88db6ed1de9165cb1921b5ab4fd5e"],
|
||||||
customLightningAddresses: [
|
customLightningAddresses: [
|
||||||
{
|
{
|
||||||
// todo remove need for lowercase
|
// todo remove need for lowercase
|
||||||
|
Loading…
x
Reference in New Issue
Block a user