Good stuff

This commit is contained in:
austinkelsay 2024-09-15 15:53:27 -05:00
parent cb3f124c3a
commit 5bb89c4c35
14 changed files with 99 additions and 43 deletions

View File

@ -6,6 +6,7 @@ import { initializeBitcoinConnect } 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 GenericButton from '@/components/buttons/GenericButton';
import axios from 'axios'; // Import axios for API calls
@ -20,19 +21,20 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
const [invoice, setInvoice] = useState(null);
const [userId, setUserId] = useState(null);
const { showToast } = useToast();
const { data: session } = useSession();
const { data: session, status } = useSession();
const [dialogVisible, setDialogVisible] = useState(false); // New state for dialog visibility
useEffect(() => {
if (session?.user) {
setUserId(session.user.id);
}
}, [session]);
const router = useRouter();
useEffect(() => {
initializeBitcoinConnect();
}, []);
useEffect(() => {
if (session && session.user) {
setUserId(session.user.id);
}
}, [status, session]);
useEffect(() => {
const fetchInvoice = async () => {
try {
@ -78,17 +80,24 @@ const CoursePaymentButton = ({ lnAddress, amount, onSuccess, onError, courseId }
return (
<>
<GenericButton
label={`${amount} sats`}
onClick={() => setDialogVisible(true)}
<GenericButton
label={`${amount} sats`}
onClick={() => {
if (status === 'unauthenticated') {
console.log('unauthenticated');
router.push('/auth/signin');
} else {
setDialogVisible(true);
}
}}
disabled={!invoice}
severity='primary'
rounded
icon='pi pi-wallet'
className='text-[#f8f8ff] text-sm'
/>
<Dialog
visible={dialogVisible}
<Dialog
visible={dialogVisible}
onHide={() => setDialogVisible(false)}
header="Make Payment"
style={{ width: '50vw' }}

View File

@ -8,6 +8,7 @@ import { useSession } from 'next-auth/react';
import { ProgressSpinner } from 'primereact/progressspinner';
import axios from 'axios';
import GenericButton from '@/components/buttons/GenericButton';
import { useRouter } from 'next/router';
const Payment = dynamic(
() => import('@getalby/bitcoin-connect-react').then((mod) => mod.Payment),
@ -18,19 +19,20 @@ const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resource
const [invoice, setInvoice] = useState(null);
const [userId, setUserId] = useState(null);
const { showToast } = useToast();
const { data: session } = useSession();
const { data: session, status } = useSession();
const [dialogVisible, setDialogVisible] = useState(false);
useEffect(() => {
if (session?.user) {
setUserId(session.user.id);
}
}, [session]);
const router = useRouter();
useEffect(() => {
initializeBitcoinConnect();
}, []);
useEffect(() => {
if (session && session.user) {
setUserId(session.user.id);
}
}, [status, session]);
useEffect(() => {
const fetchInvoice = async () => {
try {
@ -79,7 +81,14 @@ const ResourcePaymentButton = ({ lnAddress, amount, onSuccess, onError, resource
<GenericButton
label={`${amount} sats`}
icon="pi pi-wallet"
onClick={() => setDialogVisible(true)}
onClick={() => {
if (status === 'unauthenticated') {
console.log('unauthenticated');
router.push('/auth/signin');
} else {
setDialogVisible(true);
}
}}
disabled={!invoice}
severity='primary'
rounded

View File

@ -24,7 +24,8 @@ const SubscriptionPaymentButtons = ({ onSuccess, onError, onRecurringSubscriptio
const [showRecurringOptions, setShowRecurringOptions] = useState(false);
const [nwcInput, setNwcInput] = useState('');
const { showToast } = useToast();
const { data: session } = useSession();
const { data: session, status } = useSession();
const router = useRouter();
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
const amount = 25;
@ -211,8 +212,13 @@ const SubscriptionPaymentButtons = ({ onSuccess, onError, onRecurringSubscriptio
label="Pay as you go"
icon="pi pi-bolt"
onClick={async () => {
const invoice = await fetchInvoice();
setInvoice(invoice);
if (status === 'unauthenticated') {
console.log('unauthenticated');
router.push('/auth/signin');
} else {
const invoice = await fetchInvoice();
setInvoice(invoice);
}
}}
severity='primary'
className="w-fit mt-4 text-[#f8f8ff]"
@ -232,7 +238,14 @@ const SubscriptionPaymentButtons = ({ onSuccess, onError, onRecurringSubscriptio
}
severity='help'
className="w-fit mt-4 text-[#f8f8ff] bg-purple-600"
onClick={() => setShowRecurringOptions(!showRecurringOptions)}
onClick={() => {
if (status === 'unauthenticated') {
console.log('unauthenticated');
router.push('/auth/signin');
} else {
setShowRecurringOptions(!showRecurringOptions);
}
}}
/>
)}
</div>

View File

@ -17,6 +17,7 @@ import 'primeicons/primeicons.css';
import CoursePaymentButton from "@/components/bitcoinConnect/CoursePaymentButton";
import { ProgressSpinner } from 'primereact/progressspinner';
import { defaultRelayUrls } from "@/context/NDKContext";
import useWindowWidth from '@/hooks/useWindowWidth';
const MDDisplay = dynamic(
() => import("@uiw/react-markdown-preview"),
@ -35,6 +36,8 @@ export default function CourseDetails({ processedEvent, paidCourse, lessons, dec
const { data: session, status } = useSession();
const router = useRouter();
const {ndk, addSigner} = useNDKContext();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;

View File

@ -29,6 +29,7 @@ export default function CourseDetailsNew({ processedEvent, paidCourse, lessons,
const { data: session, status } = useSession();
const { showToast } = useToast();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
const { ndk } = useNDKContext();
const fetchAuthor = useCallback(async (pubkey) => {
@ -134,7 +135,14 @@ export default function CourseDetailsNew({ processedEvent, paidCourse, lessons,
)}
</div>
</div>
<p className='text-xl text-gray-200 mb-4 mt-4'>{processedEvent.description}</p>
<p className='text-xl text-gray-200 mb-4 mt-4'>{processedEvent.description && (
<div className='mt-4'>
{processedEvent.description.split('\n').map((line, index) => (
<p key={index}>{line}</p>
))}
</div>
)}
</p>
<div className='flex items-center justify-between'>
<div className='flex items-center'>
<Image
@ -163,11 +171,11 @@ export default function CourseDetailsNew({ processedEvent, paidCourse, lessons,
<div className='flex space-x-2 mt-4 sm:mt-0'>
<GenericButton onClick={() => router.push(`/details/${processedEvent.id}/edit`)} label="Edit" severity='warning' outlined />
<GenericButton onClick={handleDelete} label="Delete" severity='danger' outlined />
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: 'right' }} />
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip={ isMobileView ? null : "View Nostr Event" } tooltipOptions={{ position: paidCourse ? 'left' : 'right' }} />
</div>
) : (
<div className='flex space-x-2 mt-4 sm:mt-0'>
<GenericButton className='my-2' outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: paidCourse ? 'left' : 'right' }} />
<GenericButton className='my-2' outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip={ isMobileView ? null : "View Nostr Event" } tooltipOptions={{ position: paidCourse ? 'left' : 'right' }} />
</div>
)}
</div>

View File

@ -9,6 +9,7 @@ import { nip19 } from "nostr-tools";
import { Divider } from "primereact/divider";
import { getTotalFromZaps } from "@/utils/lightning";
import dynamic from "next/dynamic";
import useWindowWidth from "@/hooks/useWindowWidth";
import { defaultRelayUrls } from "@/context/NDKContext";
const MDDisplay = dynamic(
@ -23,6 +24,8 @@ const DocumentLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
const [nAddress, setNAddress] = useState(null);
const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: lesson, type: "lesson" });
const { returnImageProxy } = useImageProxy();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
useEffect(() => {
if (!zaps || zapsLoading || zapsError) return;
@ -119,7 +122,7 @@ const DocumentLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
</div>
<div className="w-full flex flex-row justify-end">
<GenericButton
tooltip={`View Nostr Note`}
tooltip={isMobileView ? null : "View Nostr Note"}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined

View File

@ -270,7 +270,7 @@ export default function DraftCourseDetails({ processedEvent, draftId, lessons })
...draft.topics.map(topic => ['t', topic]),
['published_at', Math.floor(Date.now() / 1000).toString()],
...(draft?.price ? [['price', draft.price.toString()], ['location', `https://plebdevs.com/details/${draft.id}`]] : []),
...(draft?.additionalLinks ? draft.additionalLinks.map(link => ['r', link]) : []),
...(draft?.additionalLinks ? draft.additionalLinks.filter(link => link !== 'https://plebdevs.com').map(link => ['r', link]) : []),
];
type = 'document';
@ -293,7 +293,7 @@ export default function DraftCourseDetails({ processedEvent, draftId, lessons })
...draft.topics.map(topic => ['t', topic]),
['published_at', Math.floor(Date.now() / 1000).toString()],
...(draft?.price ? [['price', draft.price.toString()], ['location', `https://plebdevs.com/details/${draft.id}`]] : []),
...(draft?.additionalLinks ? draft.additionalLinks.map(link => ['r', link]) : []),
...(draft?.additionalLinks ? draft.additionalLinks.filter(link => link !== 'https://plebdevs.com').map(link => ['r', link]) : []),
];
type = 'video';

View File

@ -10,6 +10,7 @@ import { getTotalFromZaps } from "@/utils/lightning";
import dynamic from "next/dynamic";
import { Divider } from "primereact/divider";
import { defaultRelayUrls } from "@/context/NDKContext";
import useWindowWidth from "@/hooks/useWindowWidth";
const MDDisplay = dynamic(
() => import("@uiw/react-markdown-preview"),
@ -23,6 +24,8 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
const [nAddress, setNAddress] = useState(null);
const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: lesson, type: "lesson" });
const { returnImageProxy } = useImageProxy();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
useEffect(() => {
if (!zaps || zapsLoading || zapsError) return;
@ -130,7 +133,7 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
</p>
</div>
<GenericButton
tooltip={`View Nostr Note`}
tooltip={isMobileView ? null : "View Nostr Note"}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined

View File

@ -31,6 +31,7 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price,
const { data: session, status } = useSession();
const { showToast } = useToast();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
useEffect(() => {
if (zaps.length > 0) {
@ -172,7 +173,7 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price,
<GenericButton onClick={() => router.push(`/details/${nAddress}/edit`)} label="Edit" severity='warning' outlined />
<GenericButton onClick={handleDelete} label="Delete" severity='danger' outlined />
<GenericButton
tooltip={`View Nostr Note`}
tooltip={isMobileView ? null : "View Nostr Note"}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined
@ -184,7 +185,7 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price,
) : (
<div className="w-full flex flex-row justify-end">
<GenericButton
tooltip={`View Nostr Note`}
tooltip={isMobileView ? null : "View Nostr Note"}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined

View File

@ -31,6 +31,7 @@ const VideoDetails = ({ processedEvent, topics, title, summary, image, price, au
const { data: session, status } = useSession();
const { showToast } = useToast();
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
useEffect(() => {
if (zaps.length > 0) {
@ -165,11 +166,11 @@ const VideoDetails = ({ processedEvent, topics, title, summary, image, price, au
<div className='flex flex-row justify-center items-center space-x-2'>
<GenericButton onClick={() => router.push(`/details/${nAddress}/edit`)} label="Edit" severity='warning' outlined />
<GenericButton onClick={handleDelete} label="Delete" severity='danger' outlined />
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: 'right' }} />
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip={ isMobileView ? null : "View Nostr Event" } tooltipOptions={{ position: 'right' }} />
</div>
) : (
<div className='flex flex-row justify-center items-center space-x-2'>
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: paidResource ? 'left' : 'right' }} />
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip={ isMobileView ? null : "View Nostr Event" } tooltipOptions={{ position: paidResource ? 'left' : 'right' }} />
</div>
)}
</div>

View File

@ -10,6 +10,7 @@ import NostrIcon from '../../../../public/images/nostr.png';
import Image from 'next/image';
import { nip19 } from 'nostr-tools';
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
import useWindowWidth from '@/hooks/useWindowWidth';
const StackerNewsIconComponent = () => (
<svg width="16" height="16" className='mr-2' viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
@ -21,7 +22,7 @@ const StackerNewsIconComponent = () => (
const headerTemplate = (options, windowWidth, platform, id) => {
return (
<div className="flex flex-row justify-between items-end mb-2">
<GenericButton outlined severity="primary" size="small" className="py-0" onClick={options.onTogglerClick} icon={options.collapsed ? 'pi pi-chevron-down' : 'pi pi-chevron-up'} tooltip={'comments'} tooltipOptions={{ position: 'right' }} />
<GenericButton outlined severity="primary" size="small" className="py-0" onClick={options.onTogglerClick} icon={options.collapsed ? 'pi pi-chevron-down' : 'pi pi-chevron-up'} tooltip={windowWidth <= 768 ? null : 'comments'} tooltipOptions={{ position: 'right' }} />
<GenericButton
label={windowWidth > 768 ? `View in ${platform}` : null}
icon="pi pi-external-link"
@ -39,6 +40,7 @@ const CommunityMessage = ({ message, searchQuery, windowWidth, platform }) => {
const [npub, setNpub] = useState(null);
const [collapsed, setCollapsed] = useState(true);
const { data: session } = useSession();
const isMobileView = windowWidth <= 768;
useEffect(() => {
if (session?.user?.pubkey) {

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
import { InputText } from 'primereact/inputtext';
import { InputTextarea } from 'primereact/inputtextarea';
import { InputNumber } from 'primereact/inputnumber';
import { InputSwitch } from 'primereact/inputswitch';
import GenericButton from '@/components/buttons/GenericButton';
@ -173,7 +174,7 @@ const CourseForm = ({ draft = null }) => {
<InputText value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Title" />
</div>
<div className="p-inputgroup flex-1 mt-4">
<InputText value={summary} onChange={(e) => setSummary(e.target.value)} placeholder="Summary" />
<InputTextarea value={summary} onChange={(e) => setSummary(e.target.value)} placeholder="Summary" rows={5} cols={30} />
</div>
<div className="p-inputgroup flex-1 mt-4">
<InputText value={coverImage} onChange={(e) => setCoverImage(e.target.value)} placeholder="Cover Image URL" />

View File

@ -3,9 +3,12 @@ import Image from 'next/image';
import NostrIcon from '../../public/images/nostr.png';
import { Tooltip } from 'primereact/tooltip';
import { useToast } from "@/hooks/useToast"
import useWindowWidth from "@/hooks/useWindowWidth";
const AboutPage = () => {
const {showToast} = useToast()
const windowWidth = useWindowWidth();
const isMobileView = windowWidth <= 768;
const copyToClipboard = async (text) => {
try {
@ -77,19 +80,19 @@ const AboutPage = () => {
<div className="mt-12 bg-gray-700 rounded-lg p-6">
<div className="flex items-center justify-center space-x-16">
<Tooltip target=".pi-github" content="GitHub" position="bottom" />
<Tooltip target=".pi-github" content={isMobileView ? null : "GitHub"} position="bottom" />
<a href="https://github.com/pleb-devs" target="_blank" rel="noopener noreferrer">
<i className="pi pi-github text-white text-5xl"></i>
</a>
<Tooltip target=".pi-twitter" content="X.com" position="bottom" />
<Tooltip target=".pi-twitter" content={isMobileView ? null : "X.com"} position="bottom" />
<a href="https://x.com/pleb_devs" target="_blank" rel="noopener noreferrer">
<i className="pi pi-twitter text-black text-5xl"></i>
</a>
<Tooltip target=".nostr-icon" content="Nostr" position="bottom" />
<Tooltip target=".nostr-icon" content={isMobileView ? null : "Nostr"} position="bottom" />
<a href="https://nostr.com/plebdevs@plebdevs.com" target="_blank" rel="noopener noreferrer">
<Image src={NostrIcon} alt="Nostr" width={44} height={44} className='nostr-icon' />
</a>
<Tooltip target=".pi-bolt" content="Donate" position="bottom" />
<Tooltip target=".pi-bolt" content={isMobileView ? null : "Donate"} position="bottom" />
<p onClick={() => copyToClipboard("austin@bitcoinpleb.dev")} className='cursor-pointer'>
<i className="pi pi-bolt text-yellow-500 text-5xl"></i>
</p>

View File

@ -206,7 +206,7 @@ export default function Draft() {
...draft.topics.map(topic => ['t', topic]),
['published_at', Math.floor(Date.now() / 1000).toString()],
...(draft?.price ? [['price', draft.price.toString()], ['location', `https://plebdevs.com/details/${draft.id}`]] : []),
...(draft?.additionalLinks ? draft.additionalLinks.map(link => ['r', link]) : []),
...(draft?.additionalLinks ? draft.additionalLinks.filter(link => link !== 'https://plebdevs.com').map(link => ['r', link]) : []),
];
type = 'document';
@ -243,7 +243,7 @@ export default function Draft() {
...draft.topics.map(topic => ['t', topic]),
['published_at', Math.floor(Date.now() / 1000).toString()],
...(draft?.price ? [['price', draft.price.toString()], ['location', `https://plebdevs.com/details/${draft.id}`]] : []),
...(draft?.additionalLinks ? draft.additionalLinks.map(link => ['r', link]) : []),
...(draft?.additionalLinks ? draft.additionalLinks.filter(link => link !== 'https://plebdevs.com').map(link => ['r', link]) : []),
];
type = 'video';