import React, { useState, useRef, useEffect } from 'react'; import { useSession } from 'next-auth/react'; import { useRouter } from 'next/router'; import { useToast } from '@/hooks/useToast'; import axios from 'axios'; import { Card } from 'primereact/card'; import { Message } from 'primereact/message'; import useWindowWidth from '@/hooks/useWindowWidth'; import { Menu } from "primereact/menu"; import GenericButton from '@/components/buttons/GenericButton'; import { ProgressSpinner } from 'primereact/progressspinner'; import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton'; import Image from 'next/image'; import NostrIcon from '../../public/images/nostr.png'; import CalendlyEmbed from '@/components/profile/subscription/CalendlyEmbed'; import CancelSubscription from '@/components/profile/subscription/CancelSubscription'; import RenewSubscription from '@/components/profile/subscription/RenewSubscription'; import Nip05Form from '@/components/profile/subscription/Nip05Form'; import LightningAddressForm from '@/components/profile/subscription/LightningAddressForm'; const Subscribe = () => { const { data: session, update } = useSession(); const { showToast } = useToast(); const router = useRouter(); const menu = useRef(null); const windowWidth = useWindowWidth(); const [user, setUser] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [subscribed, setSubscribed] = useState(false); const [subscribedUntil, setSubscribedUntil] = useState(null); const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null); const [calendlyVisible, setCalendlyVisible] = useState(false); const [lightningAddressVisible, setLightningAddressVisible] = useState(false); const [nip05Visible, setNip05Visible] = useState(false); const [cancelSubscriptionVisible, setCancelSubscriptionVisible] = useState(false); const [renewSubscriptionVisible, setRenewSubscriptionVisible] = useState(false); useEffect(() => { if (session && session?.user) { setUser(session.user); } }, [session]) useEffect(() => { if (user && user.role) { setSubscribed(user.role.subscribed); const subscribedAt = new Date(user.role.lastPaymentAt); const subscribedUntil = new Date(subscribedAt.getTime() + 31 * 24 * 60 * 60 * 1000); setSubscribedUntil(subscribedUntil); if (user.role.subscriptionExpiredAt) { const expiredAt = new Date(user.role.subscriptionExpiredAt) setSubscriptionExpiredAt(expiredAt); } } }, [user]); const handleSubscriptionSuccess = async (response) => { setIsProcessing(true); try { const apiResponse = await axios.put('/api/users/subscription', { userId: session.user.id, isSubscribed: true, }); if (apiResponse.data) { await update(); showToast('success', 'Subscription Successful', 'Your subscription has been activated.'); } else { throw new Error('Failed to update subscription status'); } } catch (error) { console.error('Subscription update error:', error); showToast('error', 'Subscription Update Failed', `Error: ${error.message}`); } finally { setIsProcessing(false); } }; const handleSubscriptionError = (error) => { console.error('Subscription error:', error); showToast('error', 'Subscription Failed', `An error occurred: ${error.message}`); setIsProcessing(false); }; const handleRecurringSubscriptionSuccess = async () => { setIsProcessing(true); try { await update(); showToast('success', 'Recurring Subscription Activated', 'Your recurring subscription has been set up successfully.'); } catch (error) { console.error('Session update error:', error); showToast('error', 'Session Update Failed', `Error: ${error.message}`); } finally { setIsProcessing(false); } }; const menuItems = [ { label: "Schedule 1:1", icon: "pi pi-calendar", command: () => setCalendlyVisible(true), }, { label: session?.user?.lightningAddress ? "Update PlebDevs Lightning Address" : "Claim PlebDevs Lightning Address", icon: "pi pi-bolt", command: () => setLightningAddressVisible(true), }, { label: session?.user?.nip05 ? "Update PlebDevs Nostr NIP-05" : "Claim PlebDevs Nostr NIP-05", icon: "pi pi-at", command: () => setNip05Visible(true), }, { label: "Renew Subscription", icon: "pi pi-sync", command: () => setRenewSubscriptionVisible(true), }, { label: "Cancel Subscription", icon: "pi pi-trash", command: () => setCancelSubscriptionVisible(true), }, ]; const subscriptionCardTitleAndButton = (
Thank you for your support 🎉
Pay-as-you-go subscription will renew on {subscribedUntil.toLocaleDateString()}
The PlebDevs subscription unlocks all paid content, grants access to our 1:1 calendar for tutoring, support, and mentorship, and grants you your own personal plebdevs.com Lightning Address and Nostr NIP-05 identity.
Subscribe monthly with a pay-as-you-go option or set up an auto-recurring subscription using Nostr Wallet Connect.
Login to start your subscription!
Subscribe now and elevate your development journey!
Think of the subscriptions as a Patreon-type model. You pay a monthly fee and in return you get access to premium features and all of the paid content. You can cancel at any time.
The pay as you go subscription is a one-time payment that gives you access to all of the premium features for one month. You will need to manually renew your subscription every month.
The recurring subscription option allows you to submit a Nostr Wallet Connect URI that will be used to automatically send the subscription fee every month. You can cancel at any time.
Yes, you can cancel your subscription at any time. Your access will remain active until the end of the current billing period.
If you don't renew your subscription, your access to 1:1 calendar and paid content will be removed. However, you will still have access to your PlebDevs Lightning Address, NIP-05, and any content that you paid for.