mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-23 16:05:24 +00:00
refactor(modals): migrate blur effects to Tailwind
- Replace CSS modules with Tailwind classes for blur effects - Remove moreinfo.module.css and subscribemodal.module.css - Standardize blur implementation across MoreInfo and SubscribeModal - Maintain consistent blur behavior with filter and transition classes - Keep navigation clear while content is blurred
This commit is contained in:
parent
6d2b782045
commit
14e85ca7ae
@ -1,7 +1,7 @@
|
|||||||
// datasource db {
|
// datasource db {
|
||||||
// provider = "postgresql"
|
// provider = "postgresql"
|
||||||
// url = env("DATABASE_URL")
|
// url = env("DATABASE_URL")
|
||||||
// }
|
//}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "postgresql"
|
provider = "postgresql"
|
||||||
|
@ -2,21 +2,31 @@ import React, { useState, useEffect } from "react";
|
|||||||
import { Dialog } from "primereact/dialog";
|
import { Dialog } from "primereact/dialog";
|
||||||
import { Tooltip } from "primereact/tooltip";
|
import { Tooltip } from "primereact/tooltip";
|
||||||
import useWindowWidth from "@/hooks/useWindowWidth";
|
import useWindowWidth from "@/hooks/useWindowWidth";
|
||||||
import styles from "./moreinfo.module.css";
|
|
||||||
|
|
||||||
const MoreInfo = ({ tooltip, modalTitle, modalBody, className = "" }) => {
|
const MoreInfo = ({ tooltip, modalTitle, modalBody, className = "" }) => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
const isMobile = windowWidth < 768;
|
const isMobile = windowWidth < 768;
|
||||||
|
|
||||||
// Add blur effect when modal is visible
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const mainContent = document.querySelector(".main-content");
|
const mainContent = document.querySelector(".main-content");
|
||||||
if (mainContent) {
|
if (mainContent) {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
mainContent.classList.add(styles.blurredContent);
|
mainContent.classList.add(
|
||||||
|
"filter",
|
||||||
|
"blur-md",
|
||||||
|
"transition-all",
|
||||||
|
"duration-200",
|
||||||
|
"ease-in-out"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
mainContent.classList.remove(styles.blurredContent);
|
mainContent.classList.remove(
|
||||||
|
"filter",
|
||||||
|
"blur-md",
|
||||||
|
"transition-all",
|
||||||
|
"duration-200",
|
||||||
|
"ease-in-out"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [visible]);
|
}, [visible]);
|
||||||
@ -43,11 +53,11 @@ const MoreInfo = ({ tooltip, modalTitle, modalBody, className = "" }) => {
|
|||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
className="max-w-3xl"
|
className="max-w-3xl"
|
||||||
modal
|
modal
|
||||||
dismissableMask // This enables click-outside-to-close
|
dismissableMask
|
||||||
closeOnEscape // This enables closing with Escape key
|
closeOnEscape
|
||||||
breakpoints={{ "960px": "75vw", "641px": "90vw" }}
|
breakpoints={{ "960px": "75vw", "641px": "90vw" }}
|
||||||
pt={{
|
pt={{
|
||||||
mask: { className: "backdrop-blur-none" }, // Ensures the Dialog's mask doesn't add its own blur
|
mask: { className: "backdrop-blur-none" },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{typeof modalBody === "string" ? (
|
{typeof modalBody === "string" ? (
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
.blurredContent {
|
|
||||||
filter: blur(8px);
|
|
||||||
transition: filter 0.2s ease-in-out;
|
|
||||||
}
|
|
@ -1,258 +1,349 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from "primereact/dialog";
|
||||||
import { ProgressSpinner } from 'primereact/progressspinner';
|
import { ProgressSpinner } from "primereact/progressspinner";
|
||||||
import SubscriptionPaymentButtons from '@/components/bitcoinConnect/SubscriptionPaymentButton';
|
import SubscriptionPaymentButtons from "@/components/bitcoinConnect/SubscriptionPaymentButton";
|
||||||
import axios from 'axios';
|
import axios from "axios";
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from "next-auth/react";
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from "next/router";
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from "@/hooks/useToast";
|
||||||
import { Card } from 'primereact/card';
|
import { Card } from "primereact/card";
|
||||||
import GenericButton from '@/components/buttons/GenericButton';
|
import GenericButton from "@/components/buttons/GenericButton";
|
||||||
import { Menu } from "primereact/menu";
|
import { Menu } from "primereact/menu";
|
||||||
import { Message } from "primereact/message";
|
import { Message } from "primereact/message";
|
||||||
import CancelSubscription from '@/components/profile/subscription/CancelSubscription';
|
import CancelSubscription from "@/components/profile/subscription/CancelSubscription";
|
||||||
import CalendlyEmbed from '@/components/profile/subscription/CalendlyEmbed';
|
import CalendlyEmbed from "@/components/profile/subscription/CalendlyEmbed";
|
||||||
import Nip05Form from '@/components/profile/subscription/Nip05Form';
|
import Nip05Form from "@/components/profile/subscription/Nip05Form";
|
||||||
import LightningAddressForm from '@/components/profile/subscription/LightningAddressForm';
|
import LightningAddressForm from "@/components/profile/subscription/LightningAddressForm";
|
||||||
import NostrIcon from '../../../../public/images/nostr.png';
|
import NostrIcon from "../../../../public/images/nostr.png";
|
||||||
import Image from 'next/image';
|
import Image from "next/image";
|
||||||
import RenewSubscription from '@/components/profile/subscription/RenewSubscription';
|
import RenewSubscription from "@/components/profile/subscription/RenewSubscription";
|
||||||
|
|
||||||
const SubscribeModal = ({ user }) => {
|
const SubscribeModal = ({ user }) => {
|
||||||
const { data: session, update } = useSession();
|
const { data: session, update } = useSession();
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const menu = useRef(null);
|
const menu = useRef(null);
|
||||||
const [isProcessing, setIsProcessing] = useState(false);
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const [subscribed, setSubscribed] = useState(false);
|
const [subscribed, setSubscribed] = useState(false);
|
||||||
const [subscribedUntil, setSubscribedUntil] = useState(null);
|
const [subscribedUntil, setSubscribedUntil] = useState(null);
|
||||||
const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null);
|
const [subscriptionExpiredAt, setSubscriptionExpiredAt] = useState(null);
|
||||||
const [calendlyVisible, setCalendlyVisible] = useState(false);
|
const [calendlyVisible, setCalendlyVisible] = useState(false);
|
||||||
const [lightningAddressVisible, setLightningAddressVisible] = useState(false);
|
const [lightningAddressVisible, setLightningAddressVisible] = useState(false);
|
||||||
const [nip05Visible, setNip05Visible] = useState(false);
|
const [nip05Visible, setNip05Visible] = useState(false);
|
||||||
const [cancelSubscriptionVisible, setCancelSubscriptionVisible] = useState(false);
|
const [cancelSubscriptionVisible, setCancelSubscriptionVisible] =
|
||||||
const [renewSubscriptionVisible, setRenewSubscriptionVisible] = useState(false);
|
useState(false);
|
||||||
|
const [renewSubscriptionVisible, setRenewSubscriptionVisible] =
|
||||||
|
useState(false);
|
||||||
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (user && user.role) {
|
if (user && user.role) {
|
||||||
setSubscribed(user.role.subscribed);
|
setSubscribed(user.role.subscribed);
|
||||||
const subscribedAt = new Date(user.role.lastPaymentAt);
|
const subscribedAt = new Date(user.role.lastPaymentAt);
|
||||||
const subscribedUntil = new Date(subscribedAt.getTime() + 31 * 24 * 60 * 60 * 1000);
|
const subscribedUntil = new Date(
|
||||||
setSubscribedUntil(subscribedUntil);
|
subscribedAt.getTime() + 31 * 24 * 60 * 60 * 1000
|
||||||
if (user.role.subscriptionExpiredAt) {
|
);
|
||||||
const expiredAt = new Date(user.role.subscriptionExpiredAt)
|
setSubscribedUntil(subscribedUntil);
|
||||||
setSubscriptionExpiredAt(expiredAt);
|
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.');
|
|
||||||
onHide();
|
|
||||||
} 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.');
|
|
||||||
onHide();
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Session update error:', error);
|
|
||||||
showToast('error', 'Session Update Failed', `Error: ${error.message}`);
|
|
||||||
} finally {
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onHide = () => {
|
|
||||||
setVisible(false);
|
|
||||||
setIsProcessing(false);
|
|
||||||
}
|
}
|
||||||
|
}, [user]);
|
||||||
|
|
||||||
const menuItems = [
|
useEffect(() => {
|
||||||
{
|
const mainContent = document.querySelector(".main-content");
|
||||||
label: "Schedule 1:1",
|
if (mainContent) {
|
||||||
icon: "pi pi-calendar",
|
if (isModalVisible) {
|
||||||
command: () => {
|
mainContent.classList.add(
|
||||||
setCalendlyVisible(true);
|
"filter",
|
||||||
},
|
"blur-md",
|
||||||
},
|
"transition-all",
|
||||||
{
|
"duration-200",
|
||||||
label: session?.user?.platformLightningAddress ? "Update PlebDevs Lightning Address" : "Claim PlebDevs Lightning Address",
|
"ease-in-out"
|
||||||
icon: "pi pi-bolt",
|
);
|
||||||
command: () => {
|
} else {
|
||||||
setLightningAddressVisible(true);
|
mainContent.classList.remove(
|
||||||
},
|
"filter",
|
||||||
},
|
"blur-md",
|
||||||
{
|
"transition-all",
|
||||||
label: session?.user?.platformNip05?.name ? "Update PlebDevs Nostr NIP-05" : "Claim PlebDevs Nostr NIP-05",
|
"duration-200",
|
||||||
icon: "pi pi-at",
|
"ease-in-out"
|
||||||
command: () => {
|
);
|
||||||
setNip05Visible(true);
|
}
|
||||||
},
|
}
|
||||||
},
|
}, [isModalVisible]);
|
||||||
{
|
|
||||||
label: "Renew Subscription",
|
|
||||||
icon: "pi pi-sync",
|
|
||||||
command: () => {
|
|
||||||
setRenewSubscriptionVisible(true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Cancel Subscription",
|
|
||||||
icon: "pi pi-trash",
|
|
||||||
command: () => {
|
|
||||||
setCancelSubscriptionVisible(true);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const subscriptionCardTitle = (
|
const handleSubscriptionSuccess = async (response) => {
|
||||||
<div className="w-full flex flex-row justify-between items-center">
|
setIsProcessing(true);
|
||||||
<span className="text-xl text-900 font-bold text-white">Plebdevs Subscription</span>
|
try {
|
||||||
{subscribed && (
|
const apiResponse = await axios.put("/api/users/subscription", {
|
||||||
<i
|
userId: session.user.id,
|
||||||
className="pi pi-ellipsis-h text-2xl cursor-pointer hover:opacity-75"
|
isSubscribed: true,
|
||||||
onClick={(e) => menu.current.toggle(e)}
|
});
|
||||||
></i>
|
if (apiResponse.data) {
|
||||||
)}
|
await update();
|
||||||
<Menu model={menuItems} popup ref={menu} className="w-fit" />
|
showToast(
|
||||||
</div>
|
"success",
|
||||||
|
"Subscription Successful",
|
||||||
|
"Your subscription has been activated."
|
||||||
|
);
|
||||||
|
onHide();
|
||||||
|
} 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);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
const handleRecurringSubscriptionSuccess = async () => {
|
||||||
<>
|
setIsProcessing(true);
|
||||||
<Card title={subscriptionCardTitle} className="w-full m-2 mx-auto border border-gray-700">
|
try {
|
||||||
{subscribed && !user?.role?.nwc && (
|
await update();
|
||||||
<div className="flex flex-col">
|
showToast(
|
||||||
<Message className="w-fit" severity="success" text="Subscribed!" />
|
"success",
|
||||||
<p className="mt-3">Thank you for your support 🎉</p>
|
"Recurring Subscription Activated",
|
||||||
<p className="text-sm text-gray-400">Pay-as-you-go subscription will renew on {subscribedUntil.toLocaleDateString()}</p>
|
"Your recurring subscription has been set up successfully."
|
||||||
</div>
|
);
|
||||||
)}
|
onHide();
|
||||||
{subscribed && user?.role?.nwc && (
|
} catch (error) {
|
||||||
<div className="flex flex-col">
|
console.error("Session update error:", error);
|
||||||
<Message className="w-fit" severity="success" text="Subscribed!" />
|
showToast("error", "Session Update Failed", `Error: ${error.message}`);
|
||||||
<p className="mt-3">Thank you for your support 🎉</p>
|
} finally {
|
||||||
<p className="text-sm text-gray-400">Recurring subscription will AUTO renew on {subscribedUntil.toLocaleDateString()}</p>
|
setIsProcessing(false);
|
||||||
</div>
|
}
|
||||||
)}
|
};
|
||||||
{(!subscribed && !subscriptionExpiredAt) && (
|
|
||||||
<div className="flex flex-col">
|
const onHide = () => {
|
||||||
<Message className="w-fit" severity="info" text="You currently have no active subscription" />
|
setIsModalVisible(false);
|
||||||
<GenericButton
|
setIsProcessing(false);
|
||||||
label="Subscribe"
|
};
|
||||||
className="w-auto mt-3 text-[#f8f8ff]"
|
|
||||||
onClick={() => setVisible(true)}
|
const menuItems = [
|
||||||
/>
|
{
|
||||||
</div>
|
label: "Schedule 1:1",
|
||||||
)}
|
icon: "pi pi-calendar",
|
||||||
{subscriptionExpiredAt && (
|
command: () => {
|
||||||
<div className="flex flex-col">
|
setCalendlyVisible(true);
|
||||||
<Message className="w-fit" severity="warn" text={`Your subscription expired on ${subscriptionExpiredAt.toLocaleDateString()}`} />
|
},
|
||||||
<GenericButton
|
},
|
||||||
label="Subscribe"
|
{
|
||||||
className="w-auto mt-4 text-[#f8f8ff]"
|
label: session?.user?.platformLightningAddress
|
||||||
onClick={() => setVisible(true)}
|
? "Update PlebDevs Lightning Address"
|
||||||
/>
|
: "Claim PlebDevs Lightning Address",
|
||||||
</div>
|
icon: "pi pi-bolt",
|
||||||
)}
|
command: () => {
|
||||||
</Card>
|
setLightningAddressVisible(true);
|
||||||
<Dialog
|
},
|
||||||
header="Subscribe to PlebDevs"
|
},
|
||||||
visible={visible}
|
{
|
||||||
onHide={onHide}
|
label: session?.user?.platformNip05?.name
|
||||||
className="p-fluid pb-0 w-fit"
|
? "Update PlebDevs Nostr NIP-05"
|
||||||
>
|
: "Claim PlebDevs Nostr NIP-05",
|
||||||
{isProcessing ? (
|
icon: "pi pi-at",
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
command: () => {
|
||||||
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
setNip05Visible(true);
|
||||||
<span className="ml-2">Processing subscription...</span>
|
},
|
||||||
</div>
|
},
|
||||||
) : (
|
{
|
||||||
<Card className="shadow-lg">
|
label: "Renew Subscription",
|
||||||
<div className="text-center mb-4">
|
icon: "pi pi-sync",
|
||||||
<h2 className="text-2xl font-bold text-primary">Unlock Premium Benefits</h2>
|
command: () => {
|
||||||
<p className="text-gray-400">Subscribe now and elevate your development journey!</p>
|
setRenewSubscriptionVisible(true);
|
||||||
</div>
|
},
|
||||||
<div className="flex flex-col gap-4 mb-4 w-[60%] mx-auto">
|
},
|
||||||
<div className="flex items-center">
|
{
|
||||||
<i className="pi pi-book text-2xl text-primary mr-2 text-blue-400"></i>
|
label: "Cancel Subscription",
|
||||||
<span>Access ALL current and future PlebDevs content</span>
|
icon: "pi pi-trash",
|
||||||
</div>
|
command: () => {
|
||||||
<div className="flex items-center">
|
setCancelSubscriptionVisible(true);
|
||||||
<i className="pi pi-calendar text-2xl text-primary mr-2 text-red-400"></i>
|
},
|
||||||
<span>Personal mentorship & guidance and access to exclusive 1:1 booking calendar</span>
|
},
|
||||||
</div>
|
];
|
||||||
<div className="flex items-center">
|
|
||||||
<i className="pi pi-bolt text-2xl text-primary mr-2 text-yellow-500"></i>
|
const subscriptionCardTitle = (
|
||||||
<span>Claim your own personal plebdevs.com Lightning Address</span>
|
<div className="w-full flex flex-row justify-between items-center">
|
||||||
</div>
|
<span className="text-xl text-900 font-bold text-white">
|
||||||
<div className="flex items-center">
|
Plebdevs Subscription
|
||||||
<Image src={NostrIcon} alt="Nostr" width={26} height={26} className='mr-2' />
|
</span>
|
||||||
<span>Claim your own personal plebdevs.com Nostr NIP-05 identity</span>
|
{subscribed && (
|
||||||
</div>
|
<i
|
||||||
</div>
|
className="pi pi-ellipsis-h text-2xl cursor-pointer hover:opacity-75"
|
||||||
<SubscriptionPaymentButtons
|
onClick={(e) => menu.current.toggle(e)}
|
||||||
onSuccess={handleSubscriptionSuccess}
|
></i>
|
||||||
onRecurringSubscriptionSuccess={handleRecurringSubscriptionSuccess}
|
)}
|
||||||
onError={handleSubscriptionError}
|
<Menu model={menuItems} popup ref={menu} className="w-fit" />
|
||||||
setIsProcessing={setIsProcessing}
|
</div>
|
||||||
/>
|
);
|
||||||
</Card>
|
|
||||||
)}
|
return (
|
||||||
</Dialog>
|
<>
|
||||||
<CalendlyEmbed
|
<Card
|
||||||
visible={calendlyVisible}
|
title={subscriptionCardTitle}
|
||||||
onHide={() => setCalendlyVisible(false)}
|
className="w-full m-2 mx-auto border border-gray-700"
|
||||||
userId={session?.user?.id}
|
>
|
||||||
userName={session?.user?.username || user?.kind0?.username}
|
{subscribed && !user?.role?.nwc && (
|
||||||
userEmail={session?.user?.email}
|
<div className="flex flex-col">
|
||||||
|
<Message className="w-fit" severity="success" text="Subscribed!" />
|
||||||
|
<p className="mt-3">Thank you for your support 🎉</p>
|
||||||
|
<p className="text-sm text-gray-400">
|
||||||
|
Pay-as-you-go subscription will renew on{" "}
|
||||||
|
{subscribedUntil.toLocaleDateString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{subscribed && user?.role?.nwc && (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Message className="w-fit" severity="success" text="Subscribed!" />
|
||||||
|
<p className="mt-3">Thank you for your support 🎉</p>
|
||||||
|
<p className="text-sm text-gray-400">
|
||||||
|
Recurring subscription will AUTO renew on{" "}
|
||||||
|
{subscribedUntil.toLocaleDateString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!subscribed && !subscriptionExpiredAt && (
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<Message
|
||||||
|
className="w-fit"
|
||||||
|
severity="info"
|
||||||
|
text="You currently have no active subscription"
|
||||||
/>
|
/>
|
||||||
<CancelSubscription
|
<GenericButton
|
||||||
visible={cancelSubscriptionVisible}
|
label="Subscribe"
|
||||||
onHide={() => setCancelSubscriptionVisible(false)}
|
className="w-auto mt-3 text-[#f8f8ff]"
|
||||||
|
onClick={() => setIsModalVisible(true)}
|
||||||
/>
|
/>
|
||||||
<RenewSubscription
|
</div>
|
||||||
visible={renewSubscriptionVisible}
|
)}
|
||||||
onHide={() => setRenewSubscriptionVisible(false)}
|
{subscriptionExpiredAt && (
|
||||||
subscribedUntil={subscribedUntil}
|
<div className="flex flex-col">
|
||||||
|
<Message
|
||||||
|
className="w-fit"
|
||||||
|
severity="warn"
|
||||||
|
text={`Your subscription expired on ${subscriptionExpiredAt.toLocaleDateString()}`}
|
||||||
/>
|
/>
|
||||||
<Nip05Form
|
<GenericButton
|
||||||
visible={nip05Visible}
|
label="Subscribe"
|
||||||
onHide={() => setNip05Visible(false)}
|
className="w-auto mt-4 text-[#f8f8ff]"
|
||||||
|
onClick={() => setIsModalVisible(true)}
|
||||||
/>
|
/>
|
||||||
<LightningAddressForm
|
</div>
|
||||||
visible={lightningAddressVisible}
|
)}
|
||||||
onHide={() => setLightningAddressVisible(false)}
|
</Card>
|
||||||
|
<Dialog
|
||||||
|
header="Subscribe to PlebDevs"
|
||||||
|
visible={isModalVisible}
|
||||||
|
onHide={onHide}
|
||||||
|
className="p-fluid pb-0 w-fit"
|
||||||
|
modal
|
||||||
|
dismissableMask
|
||||||
|
closeOnEscape
|
||||||
|
pt={{
|
||||||
|
mask: { className: "backdrop-blur-none" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isProcessing ? (
|
||||||
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
|
<div className="w-full h-full flex items-center justify-center">
|
||||||
|
<ProgressSpinner />
|
||||||
|
</div>
|
||||||
|
<span className="ml-2">Processing subscription...</span>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Card className="shadow-lg">
|
||||||
|
<div className="text-center mb-4">
|
||||||
|
<h2 className="text-2xl font-bold text-primary">
|
||||||
|
Unlock Premium Benefits
|
||||||
|
</h2>
|
||||||
|
<p className="text-gray-400">
|
||||||
|
Subscribe now and elevate your development journey!
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-4 mb-4 w-[60%] mx-auto">
|
||||||
|
<div className="flex items-center">
|
||||||
|
<i className="pi pi-book text-2xl text-primary mr-2 text-blue-400"></i>
|
||||||
|
<span>Access ALL current and future PlebDevs content</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<i className="pi pi-calendar text-2xl text-primary mr-2 text-red-400"></i>
|
||||||
|
<span>
|
||||||
|
Personal mentorship & guidance and access to exclusive 1:1
|
||||||
|
booking calendar
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<i className="pi pi-bolt text-2xl text-primary mr-2 text-yellow-500"></i>
|
||||||
|
<span>
|
||||||
|
Claim your own personal plebdevs.com Lightning Address
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center">
|
||||||
|
<Image
|
||||||
|
src={NostrIcon}
|
||||||
|
alt="Nostr"
|
||||||
|
width={26}
|
||||||
|
height={26}
|
||||||
|
className="mr-2"
|
||||||
|
/>
|
||||||
|
<span>
|
||||||
|
Claim your own personal plebdevs.com Nostr NIP-05 identity
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<SubscriptionPaymentButtons
|
||||||
|
onSuccess={handleSubscriptionSuccess}
|
||||||
|
onRecurringSubscriptionSuccess={
|
||||||
|
handleRecurringSubscriptionSuccess
|
||||||
|
}
|
||||||
|
onError={handleSubscriptionError}
|
||||||
|
setIsProcessing={setIsProcessing}
|
||||||
/>
|
/>
|
||||||
</>
|
</Card>
|
||||||
);
|
)}
|
||||||
|
</Dialog>
|
||||||
|
<CalendlyEmbed
|
||||||
|
visible={calendlyVisible}
|
||||||
|
onHide={() => setCalendlyVisible(false)}
|
||||||
|
userId={session?.user?.id}
|
||||||
|
userName={session?.user?.username || user?.kind0?.username}
|
||||||
|
userEmail={session?.user?.email}
|
||||||
|
/>
|
||||||
|
<CancelSubscription
|
||||||
|
visible={cancelSubscriptionVisible}
|
||||||
|
onHide={() => setCancelSubscriptionVisible(false)}
|
||||||
|
/>
|
||||||
|
<RenewSubscription
|
||||||
|
visible={renewSubscriptionVisible}
|
||||||
|
onHide={() => setRenewSubscriptionVisible(false)}
|
||||||
|
subscribedUntil={subscribedUntil}
|
||||||
|
/>
|
||||||
|
<Nip05Form visible={nip05Visible} onHide={() => setNip05Visible(false)} />
|
||||||
|
<LightningAddressForm
|
||||||
|
visible={lightningAddressVisible}
|
||||||
|
onHide={() => setLightningAddressVisible(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SubscribeModal;
|
export default SubscribeModal;
|
||||||
|
@ -18,7 +18,7 @@ import RenewSubscription from "@/components/profile/subscription/RenewSubscripti
|
|||||||
import Nip05Form from "@/components/profile/subscription/Nip05Form";
|
import Nip05Form from "@/components/profile/subscription/Nip05Form";
|
||||||
import LightningAddressForm from "@/components/profile/subscription/LightningAddressForm";
|
import LightningAddressForm from "@/components/profile/subscription/LightningAddressForm";
|
||||||
|
|
||||||
import MoreInfo from '@/components/MoreInfo';
|
import MoreInfo from "@/components/MoreInfo";
|
||||||
|
|
||||||
const Subscribe = () => {
|
const Subscribe = () => {
|
||||||
const { data: session, update } = useSession();
|
const { data: session, update } = useSession();
|
||||||
@ -212,22 +212,26 @@ const Subscribe = () => {
|
|||||||
/>
|
/>
|
||||||
{/* Test MoreInfo modal blur here */}
|
{/* Test MoreInfo modal blur here */}
|
||||||
{/* <div className="flex items-center gap-2">
|
{/* <div className="flex items-center gap-2">
|
||||||
<Message className="w-fit" severity="info" text="Login to manage your subscription" />
|
<Message
|
||||||
<MoreInfo
|
className="w-fit"
|
||||||
tooltip="About Subscriptions"
|
severity="info"
|
||||||
modalTitle="Subscription Information"
|
text="Login to manage your subscription"
|
||||||
modalBody={
|
/>
|
||||||
<div className="space-y-3">
|
<MoreInfo
|
||||||
<p>As a PlebDevs subscriber, you get access to:</p>
|
tooltip="About Subscriptions"
|
||||||
<ul className="list-disc pl-4">
|
modalTitle="Subscription Information"
|
||||||
<li>Full access to all courses and content</li>
|
modalBody={
|
||||||
<li>Exclusive developer resources</li>
|
<div className="space-y-3">
|
||||||
<li>Priority support</li>
|
<p>As a PlebDevs subscriber, you get access to:</p>
|
||||||
<li>Community features</li>
|
<ul className="list-disc pl-4">
|
||||||
</ul>
|
<li>Full access to all courses and content</li>
|
||||||
</div>
|
<li>Exclusive developer resources</li>
|
||||||
}
|
<li>Priority support</li>
|
||||||
/>
|
<li>Community features</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</div> */}
|
</div> */}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user