mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 01:02:04 +00:00
Moved resourceDetails with payment flow into it's own component, cleaned up a bit
This commit is contained in:
parent
7808a88258
commit
a85f0505d2
78
src/components/content/resources/ResourceDetails.js
Normal file
78
src/components/content/resources/ResourceDetails.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Tag } from "primereact/tag";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import ResourcePaymentButton from "@/components/bitcoinConnect/ResourcePaymentButton";
|
||||||
|
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
||||||
|
import { useImageProxy } from "@/hooks/useImageProxy";
|
||||||
|
|
||||||
|
const ResourceDetails = ({processedEvent,topics, title, summary, image, price, author, paidResource, decryptedContent, zapAmount, zapsLoading, handlePaymentSuccess, handlePaymentError}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const { slug } = router.query;
|
||||||
|
const { returnImageProxy } = useImageProxy();
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='w-full flex flex-row justify-between max-tab:flex-col max-mob:flex-col'>
|
||||||
|
<i className='pi pi-arrow-left pl-8 cursor-pointer hover:opacity-75 max-tab:pl-2 max-mob:pl-2' onClick={() => router.push('/')} />
|
||||||
|
<div className='w-[75vw] mx-auto flex flex-row items-start justify-between max-tab:flex-col max-mob:flex-col max-tab:w-[95vw] max-mob:w-[95vw]'>
|
||||||
|
<div className='flex flex-col items-start max-w-[45vw] max-tab:max-w-[100vw] max-mob:max-w-[100vw]'>
|
||||||
|
<div className='pt-2 flex flex-row justify-start w-full'>
|
||||||
|
{topics && topics.length > 0 && (
|
||||||
|
topics.map((topic, index) => (
|
||||||
|
<Tag className='mr-2 text-white' key={index} value={topic}></Tag>
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<h1 className='text-4xl mt-6'>{title}</h1>
|
||||||
|
<p className='text-xl mt-6'>{summary}</p>
|
||||||
|
<div className='flex flex-row w-full mt-6 items-center'>
|
||||||
|
<Image
|
||||||
|
alt="avatar image"
|
||||||
|
src={returnImageProxy(author?.avatar, author?.username)}
|
||||||
|
width={50}
|
||||||
|
height={50}
|
||||||
|
className="rounded-full mr-4"
|
||||||
|
/>
|
||||||
|
<p className='text-lg'>
|
||||||
|
Created by{' '}
|
||||||
|
<a rel='noreferrer noopener' target='_blank' className='text-blue-500 hover:underline'>
|
||||||
|
{author?.username}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col max-tab:mt-12 max-mob:mt-12'>
|
||||||
|
{image && (
|
||||||
|
<div className='flex flex-col items-center justify-between rounded-lg h-72 p-4 bg-gray-700 drop-shadow-md'>
|
||||||
|
<Image
|
||||||
|
alt="resource thumbnail"
|
||||||
|
src={returnImageProxy(image)}
|
||||||
|
width={344}
|
||||||
|
height={194}
|
||||||
|
className="w-[344px] h-[194px] object-cover object-top rounded-lg"
|
||||||
|
/>
|
||||||
|
<div className='w-full flex flex-row justify-between'>
|
||||||
|
{paidResource && !decryptedContent && <ResourcePaymentButton
|
||||||
|
lnAddress={'bitcoinplebdev@stacker.news'}
|
||||||
|
amount={price}
|
||||||
|
onSuccess={handlePaymentSuccess}
|
||||||
|
onError={handlePaymentError}
|
||||||
|
resourceId={processedEvent.d}
|
||||||
|
/>}
|
||||||
|
|
||||||
|
{/* if the resource has been paid for show a green paid x sats text */}
|
||||||
|
{paidResource && decryptedContent && <p className='text-green-500'>Paid {processedEvent.price} sats</p>}
|
||||||
|
|
||||||
|
<ZapDisplay zapAmount={zapAmount} event={processedEvent} zapsLoading={zapsLoading} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResourceDetails;
|
@ -2,8 +2,8 @@ import React, { useEffect, useState, useCallback } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { parseEvent, findKind0Fields } from "@/utils/nostr";
|
import { parseEvent, findKind0Fields } from "@/utils/nostr";
|
||||||
import DraftCourseDetails from "@/components/course/DraftCourseDetails";
|
import DraftCourseDetails from "@/components/content/courses/DraftCourseDetails";
|
||||||
import DraftCourseLesson from "@/components/course/DraftCourseLesson";
|
import DraftCourseLesson from "@/components/content/courses/DraftCourseLesson";
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useNDKContext } from "@/context/NDKContext";
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect, useState, useCallback } from "react";
|
import React, { useEffect, useState, useCallback } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { parseCourseEvent, parseEvent, findKind0Fields } from "@/utils/nostr";
|
import { parseCourseEvent, parseEvent, findKind0Fields } from "@/utils/nostr";
|
||||||
import CourseDetails from "@/components/course/CourseDetails";
|
import CourseDetails from "@/components/content/courses/CourseDetails";
|
||||||
import CourseLesson from "@/components/course/CourseLesson";
|
import CourseLesson from "@/components/courses/CourseLesson";
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useNDKContext } from "@/context/NDKContext";
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@ import dynamic from 'next/dynamic';
|
|||||||
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
|
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
import ResourceDetails from '@/components/content/resources/ResourceDetails';
|
||||||
import { useZapsSubscription } from '@/hooks/nostrQueries/zaps/useZapsSubscription';
|
import { useZapsSubscription } from '@/hooks/nostrQueries/zaps/useZapsSubscription';
|
||||||
import { LightningAddress } from "@getalby/lightning-tools";
|
import ResourcePaymentButton from '@/components/bitcoinConnect/ResourcePaymentButton';
|
||||||
import PaymentButton from '@/components/bitcoinConnect/PaymentButton';
|
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
|
|
||||||
const MDDisplay = dynamic(
|
const MDDisplay = dynamic(
|
||||||
@ -26,13 +26,6 @@ const MDDisplay = dynamic(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const BitcoinConnectPayButton = dynamic(
|
|
||||||
() => import('@getalby/bitcoin-connect-react').then((mod) => mod.PayButton),
|
|
||||||
{
|
|
||||||
ssr: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY;
|
const privkey = process.env.NEXT_PUBLIC_APP_PRIV_KEY;
|
||||||
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
|
const pubkey = process.env.NEXT_PUBLIC_APP_PUBLIC_KEY;
|
||||||
|
|
||||||
@ -139,9 +132,10 @@ export default function Details() {
|
|||||||
authors: [pubkey]
|
authors: [pubkey]
|
||||||
}
|
}
|
||||||
|
|
||||||
const author = await ndk.fetchEvent(filter);
|
const author = await ndk.fetchEvent(filter);
|
||||||
if (author) {
|
if (author) {
|
||||||
const fields = await findKind0Fields(JSON.parse(author.content));
|
const fields = await findKind0Fields(JSON.parse(author.content));
|
||||||
|
console.log("fields", fields);
|
||||||
setAuthor(fields);
|
setAuthor(fields);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -206,6 +200,20 @@ export default function Details() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePaymentSuccess = async (response, newResource) => {
|
||||||
|
if (response && response?.preimage) {
|
||||||
|
console.log("newResource", newResource);
|
||||||
|
const updated = await update();
|
||||||
|
console.log("session after update", updated);
|
||||||
|
} else {
|
||||||
|
showToast('error', 'Error', 'Failed to purchase resource. Please try again.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePaymentError = (error) => {
|
||||||
|
showToast('error', 'Payment Error', `Failed to purchase resource. Please try again. Error: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
if (decryptedContent) {
|
if (decryptedContent) {
|
||||||
return <MDDisplay source={decryptedContent} />;
|
return <MDDisplay source={decryptedContent} />;
|
||||||
@ -217,85 +225,25 @@ export default function Details() {
|
|||||||
return <MDDisplay source={processedEvent.content} />;
|
return <MDDisplay source={processedEvent.content} />;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
|
||||||
|
|
||||||
const handlePaymentSuccess = async (response, newResource) => {
|
|
||||||
if (response && response?.preimage) {
|
|
||||||
console.log("newResource", newResource)
|
|
||||||
// Refetch session to get the latest user data
|
|
||||||
const updated = await update();
|
|
||||||
console.log("session after update", updated)
|
|
||||||
// router.reload(); // Optionally, reload the page if necessary
|
|
||||||
} else {
|
|
||||||
showToast('error', 'Error', 'Failed to purchase resource. Please try again.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handlePaymentError = (error) => {
|
|
||||||
showToast('error', 'Payment Error', `Failed to purchase resource. Please try again. Error: ${error}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='w-full px-24 pt-12 mx-auto mt-4 max-tab:px-0 max-mob:px-0 max-tab:pt-2 max-mob:pt-2'>
|
<div className='w-full px-24 pt-12 mx-auto mt-4 max-tab:px-0 max-mob:px-0 max-tab:pt-2 max-mob:pt-2'>
|
||||||
<div className='w-full flex flex-row justify-between max-tab:flex-col max-mob:flex-col'>
|
<ResourceDetails
|
||||||
<i className='pi pi-arrow-left pl-8 cursor-pointer hover:opacity-75 max-tab:pl-2 max-mob:pl-2' onClick={() => router.push('/')} />
|
processedEvent={processedEvent}
|
||||||
<div className='w-[75vw] mx-auto flex flex-row items-start justify-between max-tab:flex-col max-mob:flex-col max-tab:w-[95vw] max-mob:w-[95vw]'>
|
topics={processedEvent.topics}
|
||||||
<div className='flex flex-col items-start max-w-[45vw] max-tab:max-w-[100vw] max-mob:max-w-[100vw]'>
|
title={processedEvent.title}
|
||||||
<div className='pt-2 flex flex-row justify-start w-full'>
|
summary={processedEvent.summary}
|
||||||
{processedEvent && processedEvent.topics && processedEvent.topics.length > 0 && (
|
image={processedEvent.image}
|
||||||
processedEvent.topics.map((topic, index) => (
|
price={processedEvent.price}
|
||||||
<Tag className='mr-2 text-white' key={index} value={topic}></Tag>
|
author={author}
|
||||||
))
|
paidResource={paidResource}
|
||||||
)
|
decryptedContent={decryptedContent}
|
||||||
}
|
zapAmount={zapAmount}
|
||||||
</div>
|
zapsLoading={zapsLoading}
|
||||||
<h1 className='text-4xl mt-6'>{processedEvent?.title}</h1>
|
handlePaymentSuccess={handlePaymentSuccess}
|
||||||
<p className='text-xl mt-6'>{processedEvent?.summary}</p>
|
handlePaymentError={handlePaymentError}
|
||||||
<div className='flex flex-row w-full mt-6 items-center'>
|
/>
|
||||||
<Image
|
|
||||||
alt="avatar image"
|
|
||||||
src={returnImageProxy(author?.avatar, author?.pubkey)}
|
|
||||||
width={50}
|
|
||||||
height={50}
|
|
||||||
className="rounded-full mr-4"
|
|
||||||
/>
|
|
||||||
<p className='text-lg'>
|
|
||||||
Created by{' '}
|
|
||||||
<a rel='noreferrer noopener' target='_blank' className='text-blue-500 hover:underline'>
|
|
||||||
{author?.username}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='flex flex-col max-tab:mt-12 max-mob:mt-12'>
|
|
||||||
{processedEvent && (
|
|
||||||
<div className='flex flex-col items-center justify-between rounded-lg h-72 p-4 bg-gray-700 drop-shadow-md'>
|
|
||||||
<Image
|
|
||||||
alt="resource thumbnail"
|
|
||||||
src={returnImageProxy(processedEvent.image)}
|
|
||||||
width={344}
|
|
||||||
height={194}
|
|
||||||
className="w-[344px] h-[194px] object-cover object-top rounded-lg"
|
|
||||||
/>
|
|
||||||
<div className='w-full flex flex-row justify-between'>
|
|
||||||
{paidResource && !decryptedContent && <PaymentButton
|
|
||||||
lnAddress={'bitcoinplebdev@stacker.news'}
|
|
||||||
amount={processedEvent.price}
|
|
||||||
onSuccess={handlePaymentSuccess}
|
|
||||||
onError={handlePaymentError}
|
|
||||||
resourceId={processedEvent.d}
|
|
||||||
/>}
|
|
||||||
|
|
||||||
{/* if the resource has been paid for show a green paid x sats text */}
|
|
||||||
{paidResource && decryptedContent && <p className='text-green-500'>Paid {processedEvent.price} sats</p>}
|
|
||||||
|
|
||||||
<ZapDisplay zapAmount={zapAmount} event={processedEvent} zapsLoading={zapsLoading} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{authorView && (
|
{authorView && (
|
||||||
<div className='w-[75vw] mx-auto flex flex-row justify-end mt-12'>
|
<div className='w-[75vw] mx-auto flex flex-row justify-end mt-12'>
|
||||||
<div className='w-fit flex flex-row justify-between'>
|
<div className='w-fit flex flex-row justify-between'>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user