naddress slugs for all published details pages, also view nostr note buttons on all content

This commit is contained in:
austinkelsay 2024-09-14 17:05:05 -05:00
parent 3b077b542a
commit 8b782ffc60
8 changed files with 74 additions and 18 deletions

View File

@ -1,22 +1,34 @@
import { useState, useEffect } from "react";
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
import ZapDisplay from "@/components/zaps/ZapDisplay";
import { FileText } from "lucide-react"
import Image from "next/image"
import { useZapsSubscription } from "@/hooks/nostrQueries/zaps/useZapsSubscription";
import { getTotalFromZaps } from "@/utils/lightning";
import { useImageProxy } from "@/hooks/useImageProxy";
import { useRouter } from "next/router";
import { formatTimestampToHowLongAgo } from "@/utils/time";
import { nip19 } from "nostr-tools";
import { Tag } from "primereact/tag";
import GenericButton from "@/components/buttons/GenericButton";
export function DocumentTemplate({ document }) {
const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: document });
const [nAddress, setNAddress] = useState(null);
const [zapAmount, setZapAmount] = useState(0);
const router = useRouter();
const { returnImageProxy } = useImageProxy();
useEffect(() => {
if (document && document?.id) {
const nAddress = nip19.naddrEncode({
pubkey: document.pubkey,
kind: document.kind,
identifier: document.id,
});
setNAddress(nAddress);
}
}, [document]);
useEffect(() => {
if (zaps.length > 0) {
const total = getTotalFromZaps(zaps, document);
@ -73,7 +85,7 @@ export function DocumentTemplate({ document }) {
) : (
formatTimestampToHowLongAgo(document.created_at)
)}</p>
<GenericButton onClick={() => router.push(`/details/${document.id}`)} size="small" label="Read" icon="pi pi-chevron-right" iconPos="right" outlined className="items-center py-2" />
<GenericButton onClick={() => router.push(`/details/${nAddress}`)} size="small" label="Read" icon="pi pi-chevron-right" iconPos="right" outlined className="items-center py-2" />
</CardFooter>
</Card>
)

View File

@ -7,6 +7,7 @@ import { useZapsSubscription } from "@/hooks/nostrQueries/zaps/useZapsSubscripti
import { getTotalFromZaps } from "@/utils/lightning";
import { useImageProxy } from "@/hooks/useImageProxy";
import { useRouter } from "next/router";
import { nip19 } from "nostr-tools";
import { formatTimestampToHowLongAgo } from "@/utils/time";
import { Tag } from "primereact/tag";
import GenericButton from "@/components/buttons/GenericButton";
@ -14,9 +15,19 @@ import GenericButton from "@/components/buttons/GenericButton";
export function VideoTemplate({ video }) {
const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: video });
const [zapAmount, setZapAmount] = useState(0);
const [nAddress, setNAddress] = useState(null);
const router = useRouter();
const { returnImageProxy } = useImageProxy();
useEffect(() => {
const addr = nip19.naddrEncode({
pubkey: video.pubkey,
kind: video.kind,
identifier: video.id
})
setNAddress(addr);
}, [video]);
useEffect(() => {
if (zaps.length > 0) {
const total = getTotalFromZaps(zaps, video);
@ -73,7 +84,7 @@ export function VideoTemplate({ video }) {
) : (
formatTimestampToHowLongAgo(video.created_at)
)}</p>
<GenericButton onClick={() => router.push(`/details/${video.id}`)} size="small" label="Watch" icon="pi pi-chevron-right" iconPos="right" outlined className="items-center py-2" />
<GenericButton onClick={() => router.push(`/details/${nAddress}`)} size="small" label="Watch" icon="pi pi-chevron-right" iconPos="right" outlined className="items-center py-2" />
</CardFooter>
</Card>
)

View File

@ -164,9 +164,7 @@ export default function CourseDetailsNew({ processedEvent, paidCourse, lessons,
</div>
)}
{nAddress && (
<div className='w-full flex flex-row justify-end'>
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: 'left' }} />
</div>
<GenericButton outlined icon="pi pi-external-link" onClick={() => window.open(`https://nostr.band/${nAddress}`, '_blank')} tooltip="View Nostr Event" tooltipOptions={{ position: paidCourse ? 'left' : 'right' }} />
)}
</div>
</div>

View File

@ -86,7 +86,7 @@ const VideoLesson = ({ lesson, course, decryptionPerformed, isPaid }) => {
<Divider />
<div className="bg-gray-800/90 rounded-lg p-4 m-4">
<div className="w-full flex flex-col items-start justify-start mt-2 px-2">
<div className="flex flex-row items-center justify-between w-full">
<div className="flex flex-row items-center gap-2 w-full">
<h1 className='text-3xl text-white'>{lesson.title}</h1>
{lesson.topics && lesson.topics.length > 0 && (
lesson.topics.map((topic, index) => (

View File

@ -23,7 +23,7 @@ const MDDisplay = dynamic(
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
const DocumentDetails = ({ processedEvent, topics, title, summary, image, price, author, paidResource, decryptedContent, handlePaymentSuccess, handlePaymentError, authorView }) => {
const DocumentDetails = ({ processedEvent, topics, title, summary, image, price, author, paidResource, decryptedContent, nAddress, handlePaymentSuccess, handlePaymentError, authorView }) => {
const [zapAmount, setZapAmount] = useState(0);
const router = useRouter();
const { returnImageProxy } = useImageProxy();
@ -151,6 +151,17 @@ const DocumentDetails = ({ processedEvent, topics, title, summary, image, price,
zapsLoading={zapsLoading && zapAmount === 0}
/>
</div>
<div className="w-full flex flex-row justify-end">
<GenericButton
tooltip={`View Nostr Note`}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined
onClick={() => {
window.open(`https://nostr.com/${nAddress}`, '_blank');
}}
/>
</div>
</div>
</div>
{renderContent()}

View File

@ -23,7 +23,7 @@ const MDDisplay = dynamic(
const lnAddress = process.env.NEXT_PUBLIC_LIGHTNING_ADDRESS;
const VideoDetails = ({ processedEvent, topics, title, summary, image, price, author, paidResource, decryptedContent, handlePaymentSuccess, handlePaymentError, authorView }) => {
const VideoDetails = ({ processedEvent, topics, title, summary, image, price, author, paidResource, decryptedContent, nAddress, handlePaymentSuccess, handlePaymentError, authorView }) => {
const [zapAmount, setZapAmount] = useState(0);
const router = useRouter();
const { returnImageProxy } = useImageProxy();
@ -119,7 +119,7 @@ const VideoDetails = ({ processedEvent, topics, title, summary, image, price, au
{renderContent()}
<div className="bg-gray-800/90 rounded-lg p-4 m-4">
<div className="w-full flex flex-col items-start justify-start mt-2 px-2">
<div className="flex flex-row items-center justify-between w-full">
<div className="flex flex-row items-center gap-2 w-full">
<h1 className='text-4xl'>{title}</h1>
{topics && topics.length > 0 && (
topics.map((topic, index) => (
@ -154,6 +154,15 @@ const VideoDetails = ({ processedEvent, topics, title, summary, image, price, au
</a>
</p>
</div>
<GenericButton
tooltip={`View Nostr Note`}
tooltipOptions={{ position: 'left' }}
icon="pi pi-external-link"
outlined
onClick={() => {
window.open(`https://nostr.com/${nAddress}`, '_blank');
}}
/>
{authorView && (
<div className='flex flex-row justify-center items-center space-x-2'>
<GenericButton onClick={() => router.push(`/details/${processedEvent.id}/edit`)} label="Edit" severity='warning' outlined />

View File

@ -40,7 +40,7 @@ const Sidebar = ({ course = false }) => {
if (router.isReady) {
const { slug } = router.query;
if (slug) {
if (slug && course) {
const { data } = nip19.decode(slug)
if (!data) {

View File

@ -68,14 +68,27 @@ export default function Details() {
if (router.isReady) {
const { slug } = router.query;
const fetchEvent = async (slug, retryCount = 0) => {
if (!slug) {
return;
}
const { data } = nip19.decode(slug)
if (!data) {
showToast('error', 'Error', 'Resource not found');
return;
}
const id = data?.identifier;
const fetchEvent = async (id, retryCount = 0) => {
setLoading(true);
setError(null);
try {
await ndk.connect();
const filter = {
ids: [slug]
ids: [id]
}
const event = await ndk.fetchEvent(filter);
@ -93,7 +106,7 @@ export default function Details() {
if (retryCount < 1) {
// Wait for 2 seconds before retrying
await new Promise(resolve => setTimeout(resolve, 3000));
return fetchEvent(slug, retryCount + 1);
return fetchEvent(id, retryCount + 1);
} else {
setError("Event not found");
}
@ -103,7 +116,7 @@ export default function Details() {
if (retryCount < 1) {
// Wait for 2 seconds before retrying
await new Promise(resolve => setTimeout(resolve, 3000));
return fetchEvent(slug, retryCount + 1);
return fetchEvent(id, retryCount + 1);
} else {
setError("Failed to fetch event. Please try again.");
}
@ -112,8 +125,8 @@ export default function Details() {
}
};
if (ndk) {
fetchEvent(slug);
if (ndk && id) {
fetchEvent(id);
}
}
}, [router.isReady, router.query, ndk, user]);
@ -200,6 +213,7 @@ export default function Details() {
price={processedEvent.price}
author={author}
paidResource={paidResource}
nAddress={nAddress}
decryptedContent={decryptedContent}
handlePaymentSuccess={handlePaymentSuccess}
handlePaymentError={handlePaymentError}
@ -216,13 +230,14 @@ export default function Details() {
author={author}
paidResource={paidResource}
decryptedContent={decryptedContent}
nAddress={nAddress}
handlePaymentSuccess={handlePaymentSuccess}
handlePaymentError={handlePaymentError}
authorView={authorView}
/>
)}
{typeof window !== 'undefined' && nAddress !== null && (
<div className='max-tab:px-4'>
<div className='px-4'>
<ZapThreadsWrapper
anchor={nAddress}
user={user?.pubkey || null}