import React, { useState, useEffect } from 'react'; import { track } from '@vercel/analytics'; import { initializeBitcoinConnect, getSDK } from './BitcoinConnect'; import { LightningAddress } from '@getalby/lightning-tools'; import { useToast } from '@/hooks/useToast'; import { useSession } from 'next-auth/react'; import { useRouter } from 'next/router'; import { Divider } from 'primereact/divider'; import dynamic from 'next/dynamic'; import AlbyButton from '@/components/buttons/AlbyButton'; import GenericButton from '@/components/buttons/GenericButton'; import axios from 'axios'; import Image from 'next/image'; const PaymentModal = dynamic( () => import('@getalby/bitcoin-connect-react').then(mod => mod.Payment), { ssr: false } ); const SubscriptionPaymentButtons = ({ onSuccess, onError, onRecurringSubscriptionSuccess, setIsProcessing, oneTime = false, recurring = false, layout = 'row', subscriptionType = 'monthly', }) => { const [invoice, setInvoice] = useState(null); const [showRecurringOptions, setShowRecurringOptions] = useState(false); const [nwcInput, setNwcInput] = useState(''); const { showToast } = useToast(); const { data: session, status } = useSession(); const router = useRouter(); const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS; // Calculate the amount based on the subscription type const getAmount = () => { return subscriptionType === 'yearly' ? 500000 : 50000; }; const amount = getAmount(); useEffect(() => { // Initialize Bitcoin Connect as early as possible initializeBitcoinConnect().catch(err => { console.error("Error initializing Bitcoin Connect:", err); }); }, []); useEffect(() => { let intervalId; if (invoice) { intervalId = setInterval(async () => { try { const paid = await invoice.verifyPayment(); if (paid) { clearInterval(intervalId); // handle success onSuccess(); } } catch (error) { console.error("Error verifying payment:", error); clearInterval(intervalId); } }, 1000); } return () => { if (intervalId) { clearInterval(intervalId); } }; }, [invoice, onSuccess]); const fetchInvoice = async () => { try { const ln = new LightningAddress(lnAddress); await ln.fetch(); const newInvoice = await ln.requestInvoice({ satoshi: amount, comment: `${subscriptionType.charAt(0).toUpperCase() + subscriptionType.slice(1)} Subscription Purchase. User: ${session?.user?.id}`, }); return newInvoice; } catch (error) { console.error('Error fetching invoice:', error); showToast('error', 'Invoice Error', `Failed to fetch the invoice: ${error.message}`); if (onError) onError(error); return null; } }; const handlePaymentSuccess = async response => { track('Subscription Payment', { method: 'pay_as_you_go', type: subscriptionType, userId: session?.user?.id }); showToast('success', 'Payment Successful', 'Your payment has been processed successfully.'); if (onSuccess) onSuccess(response); }; const handlePaymentError = async error => { console.error('Payment error', error); showToast('error', 'Payment Failed', `An error occurred during payment: ${error.message}`); if (onError) onError(error); }; const handleRecurringSubscription = async () => { if (!setIsProcessing) { console.warn("setIsProcessing is not defined"); } else { setIsProcessing(true); } try { // Get SDK directly to avoid client issues const sdk = await getSDK(); // Create NWC client const newNwc = sdk.nwc.NWCClient.withNewSecret(); const yearFromNow = new Date(); yearFromNow.setFullYear(yearFromNow.getFullYear() + 1); const initNwcOptions = { name: 'plebdevs.com', requestMethods: ['pay_invoice'], maxAmount: amount, editable: false, budgetRenewal: subscriptionType === 'yearly' ? 'yearly' : 'monthly', expiresAt: yearFromNow, }; console.log("Initializing NWC with options:", initNwcOptions); // Initialize NWC await newNwc.initNWC(initNwcOptions); showToast('info', 'Alby', 'Alby connection window opened.'); // Get NWC URL const newNWCUrl = newNwc.getNostrWalletConnectUrl(); if (newNWCUrl) { const nwcProvider = new sdk.webln.NostrWebLNProvider({ nostrWalletConnectUrl: newNWCUrl, }); await nwcProvider.enable(); console.log("NWC provider enabled"); const invoice = await fetchInvoice(); console.log("Invoice fetched for recurring payment:", !!invoice); if (!invoice || !invoice.paymentRequest) { showToast('error', 'NWC', `Failed to fetch invoice from ${lnAddress}`); if (setIsProcessing) setIsProcessing(false); return; } console.log("Sending payment with NWC provider"); const paymentResponse = await nwcProvider.sendPayment(invoice.paymentRequest); console.log("Payment response:", paymentResponse?.preimage); if (!paymentResponse || !paymentResponse?.preimage) { showToast('error', 'NWC', 'Payment failed'); if (setIsProcessing) setIsProcessing(false); return; } console.log("Updating subscription in API"); const subscriptionResponse = await axios.put('/api/users/subscription', { userId: session.user.id, isSubscribed: true, nwc: newNWCUrl, subscriptionType: subscriptionType, }); if (subscriptionResponse.status === 200) { track('Subscription Payment', { method: 'recurring', type: subscriptionType, userId: session?.user?.id }); showToast('success', 'Subscription Setup', 'Recurring subscription setup successful!'); if (onRecurringSubscriptionSuccess) onRecurringSubscriptionSuccess(); } else { throw new Error(`Unexpected response status: ${subscriptionResponse.status}`); } } else { throw new Error('Failed to generate NWC URL'); } } catch (error) { console.error('Error initializing NWC:', error); showToast('error', 'Subscription Setup Failed', `Error: ${error.message}`); if (onError) onError(error); } finally { if (setIsProcessing) setIsProcessing(false); } }; const handleManualNwcSubmit = async () => { if (!nwcInput) { showToast('error', 'NWC', 'Please enter a valid NWC URL'); return; } if (setIsProcessing) setIsProcessing(true); try { const sdk = await getSDK(); const nwc = new sdk.webln.NostrWebLNProvider({ nostrWalletConnectUrl: nwcInput, }); await nwc.enable(); console.log("Manual NWC provider enabled"); const invoice = await fetchInvoice(); console.log("Invoice fetched for manual NWC:", !!invoice); if (!invoice || !invoice.paymentRequest) { showToast('error', 'NWC', `Failed to fetch invoice from ${lnAddress}`); if (setIsProcessing) setIsProcessing(false); return; } console.log("Sending payment with manual NWC"); const payResponse = await nwc.sendPayment(invoice.paymentRequest); console.log("Payment response:", payResponse?.preimage); if (!payResponse || !payResponse.preimage) { showToast('error', 'NWC', 'Payment failed'); if (setIsProcessing) setIsProcessing(false); return; } showToast('success', 'NWC', 'Payment successful!'); try { console.log("Updating subscription in API (manual)"); const subscriptionResponse = await axios.put('/api/users/subscription', { userId: session.user.id, isSubscribed: true, nwc: nwcInput, subscriptionType: subscriptionType, }); if (subscriptionResponse.status === 200) { track('Subscription Payment', { method: 'recurring-manual', type: subscriptionType, userId: session?.user?.id }); showToast('success', 'NWC', 'Subscription setup successful!'); if (onRecurringSubscriptionSuccess) onRecurringSubscriptionSuccess(); } else { throw new Error('Unexpected response status'); } } catch (error) { console.error('Subscription setup error:', error); showToast('error', 'NWC', 'Subscription setup failed. Please contact support.'); if (onError) onError(error); } } catch (error) { console.error('NWC error:', error); showToast('error', 'NWC', `An error occurred: ${error.message}`); if (onError) onError(error); } finally { if (setIsProcessing) setIsProcessing(false); } }; return ( <> {!invoice && (
{(oneTime || (!oneTime && !recurring)) && ( { if (status === 'unauthenticated') { console.log('unauthenticated'); router.push('/auth/signin'); } else { const invoice = await fetchInvoice(); setInvoice(invoice); } }} severity="primary" className={`mt-4 text-[#f8f8ff] ${layout === 'col' ? 'w-full max-w-md' : 'w-fit'}`} /> )} {(recurring || (!oneTime && !recurring)) && ( } severity="help" className={`mt-4 text-[#f8f8ff] bg-purple-600 ${layout === 'col' ? 'w-full max-w-md' : 'w-fit'}`} onClick={() => { if (status === 'unauthenticated') { console.log('unauthenticated'); router.push('/auth/signin'); } else { setShowRecurringOptions(!showRecurringOptions); } }} /> )}
)} {showRecurringOptions && ( <>
or

Manually enter NWC URL

*make sure you set a budget of at least {(amount).toLocaleString()} sats and set budget renewal to {subscriptionType} setNwcInput(e.target.value)} placeholder="Enter NWC URL" className="w-full p-2 mb-4 border rounded" />
)} {invoice && invoice.paymentRequest && (
)} ); }; export default SubscriptionPaymentButtons;