mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Improvements to progress spinners, fixed resource and course payment buttons to not have to fetch invoice until button is pressed
This commit is contained in:
parent
ff3e907677
commit
a0a9b9fcc8
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,67 +1,78 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { Button } from 'primereact/button';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { Dialog } from 'primereact/dialog'; // Import Dialog component
|
|
||||||
import { initializeBitcoinConnect } from './BitcoinConnect';
|
|
||||||
import { LightningAddress } from '@getalby/lightning-tools';
|
import { LightningAddress } from '@getalby/lightning-tools';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import { useRouter } from 'next/router';
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
|
import axios from 'axios';
|
||||||
import GenericButton from '@/components/buttons/GenericButton';
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
import axios from 'axios'; // Import axios for API calls
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
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 CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }) => {
|
const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }) => {
|
||||||
const [invoice, setInvoice] = useState(null);
|
const [invoice, setInvoice] = useState(null);
|
||||||
const [userId, setUserId] = useState(null);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [dialogVisible, setDialogVisible] = useState(false); // New state for dialog visibility
|
const [dialogVisible, setDialogVisible] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initializeBitcoinConnect();
|
let intervalId;
|
||||||
}, []);
|
if (invoice) {
|
||||||
|
intervalId = setInterval(async () => {
|
||||||
|
const paid = await invoice.verifyPayment();
|
||||||
|
|
||||||
useEffect(() => {
|
if (paid && invoice.preimage) {
|
||||||
if (session && session.user) {
|
clearInterval(intervalId);
|
||||||
setUserId(session.user.id);
|
// handle success
|
||||||
|
handlePaymentSuccess({ paid, preimage: invoice.preimage });
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
console.log('no invoice');
|
||||||
}
|
}
|
||||||
}, [status, session]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
return () => {
|
||||||
const fetchInvoice = async () => {
|
if (intervalId) {
|
||||||
try {
|
clearInterval(intervalId);
|
||||||
const ln = new LightningAddress(lnAddress);
|
|
||||||
await ln.fetch();
|
|
||||||
const invoice = await ln.requestInvoice({ satoshi: amount });
|
|
||||||
setInvoice(invoice);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching invoice:', error);
|
|
||||||
showToast('error', 'Invoice Error', 'Failed to fetch the invoice.');
|
|
||||||
if (onError) onError(error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}, [invoice]);
|
||||||
|
|
||||||
fetchInvoice();
|
const fetchInvoice = async () => {
|
||||||
}, [lnAddress, amount, onError, showToast]);
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
const ln = new LightningAddress(lnAddress);
|
||||||
|
await ln.fetch();
|
||||||
|
const invoice = await ln.requestInvoice({ satoshi: amount });
|
||||||
|
setInvoice(invoice);
|
||||||
|
setDialogVisible(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching invoice:', error);
|
||||||
|
showToast('error', 'Invoice Error', 'Failed to fetch the invoice.');
|
||||||
|
if (onError) onError(error);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('invoice', invoice);
|
||||||
|
}, [invoice]);
|
||||||
|
|
||||||
const handlePaymentSuccess = async (response) => {
|
const handlePaymentSuccess = async (response) => {
|
||||||
try {
|
try {
|
||||||
const purchaseData = {
|
const purchaseData = {
|
||||||
userId: userId,
|
userId: session.user.id,
|
||||||
courseId: courseId,
|
courseId: courseId,
|
||||||
amountPaid: parseInt(amount, 10)
|
amountPaid: parseInt(amount, 10)
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('purchaseData', purchaseData);
|
|
||||||
|
|
||||||
const result = await axios.post('/api/purchase/course', purchaseData);
|
const result = await axios.post('/api/purchase/course', purchaseData);
|
||||||
|
|
||||||
if (result.status === 200) {
|
if (result.status === 200) {
|
||||||
@ -75,27 +86,36 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
|
|||||||
showToast('error', 'Purchase Update Failed', 'Payment was successful, but failed to update user purchases.');
|
showToast('error', 'Purchase Update Failed', 'Payment was successful, but failed to update user purchases.');
|
||||||
if (onError) onError(error);
|
if (onError) onError(error);
|
||||||
}
|
}
|
||||||
setDialogVisible(false); // Close the dialog on successful payment
|
setDialogVisible(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<GenericButton
|
<GenericButton
|
||||||
label={`${amount} sats`}
|
label={`${amount} sats`}
|
||||||
|
icon="pi pi-wallet"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (status === 'unauthenticated') {
|
if (status === 'unauthenticated') {
|
||||||
console.log('unauthenticated');
|
console.log('unauthenticated');
|
||||||
router.push('/auth/signin');
|
router.push('/auth/signin');
|
||||||
} else {
|
} else {
|
||||||
setDialogVisible(true);
|
fetchInvoice();
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
disabled={!invoice}
|
disabled={isLoading}
|
||||||
severity='primary'
|
severity='primary'
|
||||||
rounded
|
rounded
|
||||||
icon='pi pi-wallet'
|
className={`text-[#f8f8ff] text-sm ${isLoading ? 'hidden' : ''}`}
|
||||||
className='text-[#f8f8ff] text-sm'
|
|
||||||
/>
|
/>
|
||||||
|
{isLoading && (
|
||||||
|
<div className='w-full h-full flex items-center justify-center'>
|
||||||
|
<ProgressSpinner
|
||||||
|
style={{ width: '30px', height: '30px' }}
|
||||||
|
strokeWidth="8"
|
||||||
|
animationDuration=".5s"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<Dialog
|
<Dialog
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
onHide={() => setDialogVisible(false)}
|
onHide={() => setDialogVisible(false)}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { Dialog } from 'primereact/dialog';
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { initializeBitcoinConnect } from './BitcoinConnect';
|
|
||||||
import { LightningAddress } from '@getalby/lightning-tools';
|
import { LightningAddress } from '@getalby/lightning-tools';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
@ -17,43 +16,56 @@ const Payment = dynamic(
|
|||||||
|
|
||||||
const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resourceId }) => {
|
const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resourceId }) => {
|
||||||
const [invoice, setInvoice] = useState(null);
|
const [invoice, setInvoice] = useState(null);
|
||||||
const [userId, setUserId] = useState(null);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [dialogVisible, setDialogVisible] = useState(false);
|
const [dialogVisible, setDialogVisible] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
initializeBitcoinConnect();
|
let intervalId;
|
||||||
}, []);
|
if (invoice) {
|
||||||
|
intervalId = setInterval(async () => {
|
||||||
|
const paid = await invoice.verifyPayment();
|
||||||
|
|
||||||
useEffect(() => {
|
if (paid && invoice.preimage) {
|
||||||
if (session && session.user) {
|
clearInterval(intervalId);
|
||||||
setUserId(session.user.id);
|
// handle success
|
||||||
|
handlePaymentSuccess({ paid, preimage: invoice.preimage });
|
||||||
|
}
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
console.log('no invoice');
|
||||||
}
|
}
|
||||||
}, [status, session]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
return () => {
|
||||||
const fetchInvoice = async () => {
|
if (intervalId) {
|
||||||
try {
|
clearInterval(intervalId);
|
||||||
const ln = new LightningAddress(lnAddress);
|
}
|
||||||
await ln.fetch();
|
|
||||||
const invoice = await ln.requestInvoice({ satoshi: amount });
|
|
||||||
setInvoice(invoice);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching invoice:', error);
|
|
||||||
showToast('error', 'Invoice Error', 'Failed to fetch the invoice.');
|
|
||||||
if (onError) onError(error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}, [invoice]);
|
||||||
|
|
||||||
fetchInvoice();
|
const fetchInvoice = async () => {
|
||||||
}, [lnAddress, amount, onError, showToast]);
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
const ln = new LightningAddress(lnAddress);
|
||||||
|
await ln.fetch();
|
||||||
|
const invoice = await ln.requestInvoice({ satoshi: amount });
|
||||||
|
setInvoice(invoice);
|
||||||
|
setDialogVisible(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching invoice:', error);
|
||||||
|
showToast('error', 'Invoice Error', 'Failed to fetch the invoice.');
|
||||||
|
if (onError) onError(error);
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
const handlePaymentSuccess = async (response) => {
|
const handlePaymentSuccess = async (response) => {
|
||||||
|
console.log('handlePaymentSuccess', response);
|
||||||
try {
|
try {
|
||||||
const purchaseData = {
|
const purchaseData = {
|
||||||
userId: userId,
|
userId: session.user.id,
|
||||||
resourceId: resourceId,
|
resourceId: resourceId,
|
||||||
amountPaid: parseInt(amount, 10)
|
amountPaid: parseInt(amount, 10)
|
||||||
};
|
};
|
||||||
@ -76,31 +88,31 @@ const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resource
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{
|
<GenericButton
|
||||||
invoice ? (
|
label={`${amount} sats`}
|
||||||
<GenericButton
|
icon="pi pi-wallet"
|
||||||
label={`${amount} sats`}
|
onClick={() => {
|
||||||
icon="pi pi-wallet"
|
if (status === 'unauthenticated') {
|
||||||
onClick={() => {
|
console.log('unauthenticated');
|
||||||
if (status === 'unauthenticated') {
|
router.push('/auth/signin');
|
||||||
console.log('unauthenticated');
|
} else {
|
||||||
router.push('/auth/signin');
|
fetchInvoice();
|
||||||
} else {
|
}
|
||||||
setDialogVisible(true);
|
}}
|
||||||
}
|
disabled={isLoading}
|
||||||
}}
|
severity='primary'
|
||||||
disabled={!invoice}
|
rounded
|
||||||
severity='primary'
|
className={`text-[#f8f8ff] text-sm ${isLoading ? 'hidden' : ''}`}
|
||||||
rounded
|
/>
|
||||||
className="text-[#f8f8ff] text-sm"
|
{isLoading && (
|
||||||
/>
|
<div className='w-full h-full flex items-center justify-center'>
|
||||||
) : (
|
|
||||||
<ProgressSpinner
|
<ProgressSpinner
|
||||||
style={{ width: '30px', height: '30px' }}
|
style={{ width: '30px', height: '30px' }}
|
||||||
strokeWidth="8"
|
strokeWidth="8"
|
||||||
animationDuration=".5s"
|
animationDuration=".5s"
|
||||||
/>
|
/>
|
||||||
)}
|
</div>
|
||||||
|
)}
|
||||||
<Dialog
|
<Dialog
|
||||||
visible={dialogVisible}
|
visible={dialogVisible}
|
||||||
onHide={() => setDialogVisible(false)}
|
onHide={() => setDialogVisible(false)}
|
||||||
|
@ -47,7 +47,7 @@ export function CourseTemplate({ course }) {
|
|||||||
}
|
}
|
||||||
}, [course]);
|
}, [course]);
|
||||||
|
|
||||||
if (!nAddress) return <ProgressSpinner />;
|
if (!nAddress) return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
|
|
||||||
if (zapsError) return <div>Error: {zapsError}</div>;
|
if (zapsError) return <div>Error: {zapsError}</div>;
|
||||||
|
|
||||||
|
@ -116,9 +116,7 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec
|
|||||||
|
|
||||||
if (!processedEvent || !author) {
|
if (!processedEvent || !author) {
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center items-center h-screen">
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<ProgressSpinner />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ import useWindowWidth from "@/hooks/useWindowWidth";
|
|||||||
import { useNDKContext } from "@/context/NDKContext";
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
import { findKind0Fields } from '@/utils/nostr';
|
import { findKind0Fields } from '@/utils/nostr';
|
||||||
import { defaultRelayUrls } from "@/context/NDKContext";
|
import { defaultRelayUrls } from "@/context/NDKContext";
|
||||||
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
|
|
||||||
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
|
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ export default function CourseDetailsNew({ processedEvent, paidCourse, lessons,
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!processedEvent || !author) {
|
if (!processedEvent || !author) {
|
||||||
return <div>Loading...</div>;
|
return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import CommunityMessage from "@/components/feeds/messages/CommunityMessage";
|
import CommunityMessage from "@/components/feeds/messages/CommunityMessage";
|
||||||
import { parseMessageEvent, findKind0Fields } from "@/utils/nostr";
|
import { parseMessageEvent, findKind0Fields } from "@/utils/nostr";
|
||||||
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
import { useNDKContext } from "@/context/NDKContext";
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
|
|
||||||
const MessageDropdownItem = ({ message, onSelect }) => {
|
const MessageDropdownItem = ({ message, onSelect }) => {
|
||||||
@ -79,7 +80,7 @@ const MessageDropdownItem = ({ message, onSelect }) => {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full border-t-2 border-gray-700 py-4">
|
<div className="w-full border-t-2 border-gray-700 py-4">
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<div>Loading...</div>
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
) : (
|
) : (
|
||||||
<CommunityMessage message={messageWithAuthor ? messageWithAuthor : message} platform={platform} />
|
<CommunityMessage message={messageWithAuthor ? messageWithAuthor : message} platform={platform} />
|
||||||
)}
|
)}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { ProgressSpinner } from 'primereact/progressspinner';
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
import { useDiscordQuery } from '@/hooks/communityQueries/useDiscordQuery';
|
import { useDiscordQuery } from '@/hooks/communityQueries/useDiscordQuery';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { highlightText } from '@/utils/text';
|
|
||||||
import CommunityMessage from '@/components/feeds/messages/CommunityMessage';
|
import CommunityMessage from '@/components/feeds/messages/CommunityMessage';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
@ -11,6 +10,14 @@ const DiscordFeed = ({ searchQuery }) => {
|
|||||||
const { data, error, isLoading } = useDiscordQuery({page: router.query.page});
|
const { data, error, isLoading } = useDiscordQuery({page: router.query.page});
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
|
|
||||||
|
// Memoize the filtered data
|
||||||
|
const filteredData = useMemo(() => {
|
||||||
|
if (!data) return [];
|
||||||
|
return data.filter(message =>
|
||||||
|
message.content.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
}, [data, searchQuery]);
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="h-[100vh] min-bottom-bar:w-[86vw] max-sidebar:w-[100vw]">
|
<div className="h-[100vh] min-bottom-bar:w-[86vw] max-sidebar:w-[100vw]">
|
||||||
@ -23,14 +30,10 @@ const DiscordFeed = ({ searchQuery }) => {
|
|||||||
return <div className="text-red-500 text-center p-4">Failed to load messages. Please try again later.</div>;
|
return <div className="text-red-500 text-center p-4">Failed to load messages. Please try again later.</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredData = data.filter(message =>
|
|
||||||
message.content.toLowerCase().includes(searchQuery.toLowerCase())
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-900 h-full w-full min-bottom-bar:w-[86vw]">
|
<div className="bg-gray-900 h-full w-full min-bottom-bar:w-[86vw]">
|
||||||
<div className="mx-4">
|
<div className="mx-4">
|
||||||
{filteredData && filteredData.length > 0 ? (
|
{filteredData.length > 0 ? (
|
||||||
filteredData.map(message => (
|
filteredData.map(message => (
|
||||||
<CommunityMessage
|
<CommunityMessage
|
||||||
key={message.id}
|
key={message.id}
|
||||||
|
@ -165,7 +165,7 @@ const CourseForm = ({ draft = null }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (documentsLoading || videosLoading || draftsLoading) {
|
if (documentsLoading || videosLoading || draftsLoading) {
|
||||||
return <ProgressSpinner />;
|
return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -142,7 +142,7 @@ const UserContent = () => {
|
|||||||
<div className="w-full mx-auto my-8">
|
<div className="w-full mx-auto my-8">
|
||||||
<div className="w-full mx-auto px-8 max-tab:px-0">
|
<div className="w-full mx-auto px-8 max-tab:px-0">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<ProgressSpinner className="w-full mx-auto" />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
) : isError ? (
|
) : isError ? (
|
||||||
<p>Error loading content.</p>
|
<p>Error loading content.</p>
|
||||||
) : content.length > 0 ? (
|
) : content.length > 0 ? (
|
||||||
|
@ -89,7 +89,7 @@ const UserProfile = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!session || !session?.user || !ndk ? (
|
{!session || !session?.user || !ndk ? (
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
) : (
|
) : (
|
||||||
<DataTable
|
<DataTable
|
||||||
emptyMessage="No purchases"
|
emptyMessage="No purchases"
|
||||||
|
@ -173,7 +173,7 @@ const UserSettings = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{!session || !session?.user || !ndk ? (
|
{!session || !session?.user || !ndk ? (
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Panel
|
<Panel
|
||||||
|
@ -157,7 +157,7 @@ const SubscribeModal = ({ user }) => {
|
|||||||
>
|
>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<span className="ml-2">Processing subscription...</span>
|
<span className="ml-2">Processing subscription...</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -146,7 +146,7 @@ const UserSubscription = ({ user }) => {
|
|||||||
<Card title="Subscribe to PlebDevs" className="mb-6">
|
<Card title="Subscribe to PlebDevs" className="mb-6">
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<span className="ml-2">Processing subscription...</span>
|
<span className="ml-2">Processing subscription...</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
17
src/config/appConfig.js
Normal file
17
src/config/appConfig.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
const appConfig = {
|
||||||
|
defaultRelayUrls: [
|
||||||
|
"wss://nos.lol/",
|
||||||
|
"wss://relay.damus.io/",
|
||||||
|
"wss://relay.snort.social/",
|
||||||
|
"wss://relay.nostr.band/",
|
||||||
|
"wss://relay.mutinywallet.com/",
|
||||||
|
"wss://relay.primal.net/",
|
||||||
|
"wss://nostr21.com/",
|
||||||
|
"wss://nostrue.com/",
|
||||||
|
"wss://purplerelay.com/",
|
||||||
|
// "wss://relay.devs.tools/"
|
||||||
|
],
|
||||||
|
authorPubkeys: ["8cb60e215678879cda0bef4d5b3fc1a5c5925d2adb5d8c4fa7b7d03b5f2deaea"]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default appConfig;
|
@ -7,6 +7,8 @@ import DraftCourseLesson from "@/components/content/courses/DraftCourseLesson";
|
|||||||
import { useNDKContext } from "@/context/NDKContext";
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useIsAdmin } from "@/hooks/useIsAdmin";
|
import { useIsAdmin } from "@/hooks/useIsAdmin";
|
||||||
|
import { ProgressSpinner } from 'primereact/progressspinner';
|
||||||
|
|
||||||
const DraftCourse = () => {
|
const DraftCourse = () => {
|
||||||
const { data: session, status } = useSession();
|
const { data: session, status } = useSession();
|
||||||
const [course, setCourse] = useState(null);
|
const [course, setCourse] = useState(null);
|
||||||
@ -94,7 +96,7 @@ const DraftCourse = () => {
|
|||||||
}, [lessons, ndk, fetchAuthor, session, status]);
|
}, [lessons, ndk, fetchAuthor, session, status]);
|
||||||
|
|
||||||
if (status === "loading") {
|
if (status === "loading") {
|
||||||
return <div>Loading...</div>;
|
return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -194,9 +194,7 @@ const Course = () => {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-center items-center h-screen">
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<ProgressSpinner />
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ const Create = () => {
|
|||||||
|
|
||||||
if (!isAdmin) return null;
|
if (!isAdmin) return null;
|
||||||
|
|
||||||
if (isLoading) return <ProgressSpinner />;
|
if (isLoading) return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full min-bottom-bar:w-[86vw] max-sidebar:w-[100vw] px-8 mx-auto my-8 flex flex-col justify-center">
|
<div className="w-full min-bottom-bar:w-[86vw] max-sidebar:w-[100vw] px-8 mx-auto my-8 flex flex-col justify-center">
|
||||||
|
@ -192,9 +192,7 @@ export default function Details() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div className="mx-auto">
|
return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<ProgressSpinner />
|
|
||||||
</div>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -41,7 +41,7 @@ const Profile = () => {
|
|||||||
|
|
||||||
if (status === 'loading' || isLoading) {
|
if (status === 'loading' || isLoading) {
|
||||||
return (
|
return (
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ const Subscribe = () => {
|
|||||||
<Card title="Subscribe to PlebDevs" className="mb-6">
|
<Card title="Subscribe to PlebDevs" className="mb-6">
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
<div className="w-full flex flex-col mx-auto justify-center items-center mt-4">
|
||||||
<ProgressSpinner />
|
<div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>
|
||||||
<span className="ml-2">Processing subscription...</span>
|
<span className="ml-2">Processing subscription...</span>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
Loading…
x
Reference in New Issue
Block a user