diff --git a/src/components/course/CourseDetails.js b/src/components/course/CourseDetails.js
index 2bbb294..9cfa11e 100644
--- a/src/components/course/CourseDetails.js
+++ b/src/components/course/CourseDetails.js
@@ -1,8 +1,5 @@
-"use client";
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, useCallback } from 'react';
import { useRouter } from 'next/router';
-import { useNostr } from '@/hooks/useNostr';
-import { findKind0Fields } from '@/utils/nostr';
import { useImageProxy } from '@/hooks/useImageProxy';
import ZapDisplay from '@/components/zaps/ZapDisplay';
import { getSatAmountFromInvoice } from '@/utils/lightning';
@@ -12,7 +9,11 @@ import { useLocalStorageWithEffect } from '@/hooks/useLocalStorage';
import Image from 'next/image';
import dynamic from 'next/dynamic';
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
+import { useNDKContext } from "@/context/NDKContext";
+import { useZapsSubscription } from '@/hooks/nostrQueries/zaps/useZapsSubscription';
+import { findKind0Fields } from '@/utils/nostr';
import 'primeicons/primeicons.css';
+
const MDDisplay = dynamic(
() => import("@uiw/react-markdown-preview"),
{
@@ -27,25 +28,36 @@ const BitcoinConnectPayButton = dynamic(
}
);
-export default function CourseDetails({processedEvent}) {
+export default function CourseDetails({ processedEvent }) {
const [author, setAuthor] = useState(null);
const [bitcoinConnect, setBitcoinConnect] = useState(false);
- const [nAddress, setNAddress] = useState(null);
- const [user] = useLocalStorageWithEffect('user', {});
- const [zaps, setZaps] = useState([]);
+ const [nAddress, setNAddress] = useState(null);
const [zapAmount, setZapAmount] = useState(0);
- const { returnImageProxy } = useImageProxy();
- const { fetchKind0, zapEvent, fetchZapsForEvent } = useNostr();
+ const [user] = useLocalStorageWithEffect('user', {});
+ const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: processedEvent });
+ const { returnImageProxy } = useImageProxy();
const router = useRouter();
+ const ndk = useNDKContext();
const handleZapEvent = async () => {
if (!processedEvent) return;
+ // Update zap event logic if necessary for NDK
const response = await zapEvent(processedEvent);
console.log('zap response:', response);
- }
+ };
+
+ const fetchAuthor = useCallback(async (pubkey) => {
+ const author = await ndk.getUser({ pubkey });
+ const profile = await author.fetchProfile();
+ const fields = await findKind0Fields(profile);
+ console.log('fields:', fields);
+ if (fields) {
+ setAuthor(fields);
+ }
+ }, [ndk]);
useEffect(() => {
if (typeof window === 'undefined') return;
@@ -58,18 +70,10 @@ export default function CourseDetails({processedEvent}) {
}, []);
useEffect(() => {
- const fetchAuthor = async (pubkey) => {
- const author = await fetchKind0(pubkey);
- const fields = await findKind0Fields(author);
- console.log('fields:', fields);
- if (fields) {
- setAuthor(fields);
- }
- }
if (processedEvent) {
fetchAuthor(processedEvent.pubkey);
}
- }, [fetchKind0, processedEvent]);
+ }, [fetchAuthor, processedEvent]);
useEffect(() => {
if (processedEvent?.d) {
@@ -84,7 +88,7 @@ export default function CourseDetails({processedEvent}) {
useEffect(() => {
if (!zaps || zaps.length === 0) return;
-
+
let total = 0;
zaps.forEach((zap) => {
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
@@ -97,16 +101,6 @@ export default function CourseDetails({processedEvent}) {
setZapAmount(total);
}, [zaps]);
- useEffect(() => {
- const fetchZaps = async () => {
- if (processedEvent) {
- const zaps = await fetchZapsForEvent(processedEvent);
- setZaps(zaps);
- }
- }
- fetchZaps();
- }, [fetchZapsForEvent, processedEvent]);
-
return (
@@ -155,7 +148,7 @@ export default function CourseDetails({processedEvent}) {
) : (
-
+
)}
@@ -180,4 +173,4 @@ export default function CourseDetails({processedEvent}) {
);
-}
\ No newline at end of file
+}
diff --git a/src/components/course/CourseLesson.js b/src/components/course/CourseLesson.js
index 2de807f..d1d045d 100644
--- a/src/components/course/CourseLesson.js
+++ b/src/components/course/CourseLesson.js
@@ -2,12 +2,10 @@ import React, { useEffect, useState } from "react";
import { Tag } from "primereact/tag";
import Image from "next/image";
import { useImageProxy } from "@/hooks/useImageProxy";
-import { useNostr } from "@/hooks/useNostr";
import { getSatAmountFromInvoice } from "@/utils/lightning";
-import { parseEvent } from "@/utils/nostr";
-import { useLocalStorageWithEffect } from "@/hooks/useLocalStorage";
import ZapDisplay from "@/components/zaps/ZapDisplay";
import dynamic from "next/dynamic";
+import { useZapsQuery } from "@/hooks/nostrQueries/zaps/useZapsQuery";
const BitcoinConnectPayButton = dynamic(
() => import('@getalby/bitcoin-connect-react').then((mod) => mod.PayButton),
@@ -25,10 +23,9 @@ const MDDisplay = dynamic(
const CourseLesson = ({ lesson, course }) => {
const [bitcoinConnect, setBitcoinConnect] = useState(false);
- const [zaps, setZaps] = useState([]);
const [zapAmount, setZapAmount] = useState(0);
- const { fetchZapsForEvent } = useNostr();
+ const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: lesson, type: "lesson" });
const { returnImageProxy } = useImageProxy();
useEffect(() => {
@@ -46,29 +43,22 @@ const CourseLesson = ({ lesson, course }) => {
}
useEffect(() => {
- if (!zaps || zaps.length === 0) return;
-
+ if (!zaps || zapsLoading || zapsError) return;
+
let total = 0;
zaps.forEach((zap) => {
- const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
- const invoice = bolt11Tag ? bolt11Tag[1] : null;
- if (invoice) {
- const amount = getSatAmountFromInvoice(invoice);
- total += amount;
+ if (zap.tags.find(tag => tag[0] === "e" && tag[1] === lesson.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${lesson.kind}:${lesson.id}:${lesson.d}`)) {
+ const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
+ const invoice = bolt11Tag ? bolt11Tag[1] : null;
+ if (invoice) {
+ const amount = getSatAmountFromInvoice(invoice);
+ total += amount;
+ }
}
});
setZapAmount(total);
- }, [zaps]);
+ }, [zaps, zapsLoading, zapsError]);
- useEffect(() => {
- const fetchZaps = async () => {
- if (lesson) {
- const zaps = await fetchZapsForEvent(lesson);
- setZaps(zaps);
- }
- }
- fetchZaps();
- }, [fetchZapsForEvent, lesson]);
return (
@@ -116,7 +105,7 @@ const CourseLesson = ({ lesson, course }) => {
) : (
-
+
)}
@@ -133,4 +122,4 @@ const CourseLesson = ({ lesson, course }) => {
)
}
-export default CourseLesson;
\ No newline at end of file
+export default CourseLesson;
diff --git a/src/hooks/nostrQueries/zaps/useZapsQuery.js b/src/hooks/nostrQueries/zaps/useZapsQuery.js
index c23bced..d7aad8b 100644
--- a/src/hooks/nostrQueries/zaps/useZapsQuery.js
+++ b/src/hooks/nostrQueries/zaps/useZapsQuery.js
@@ -20,9 +20,6 @@ export function useZapsQuery({ event, type }) {
];
const events = await ndk.fetchEvents(filters, { closeOnEose: true });
- if (event.id === "f679183f0e66878142186cf7d0ae44ab137dabed1dfcb28a609472afbb7c8d51") {
- console.log('events', events);
- }
return events;
} catch (error) {
console.error('Error fetching zaps from NDK:', error);
diff --git a/src/pages/course/[slug].js b/src/pages/course/[slug].js
index 16365d0..eee777c 100644
--- a/src/pages/course/[slug].js
+++ b/src/pages/course/[slug].js
@@ -1,10 +1,11 @@
-import React, { useEffect, useState } from "react";
+import React, { useEffect, useState, useCallback } from "react";
import { useRouter } from "next/router";
-import { useNostr } from "@/hooks/useNostr";
import { parseCourseEvent, parseEvent, findKind0Fields } from "@/utils/nostr";
import CourseDetails from "@/components/course/CourseDetails";
import CourseLesson from "@/components/course/CourseLesson";
import dynamic from 'next/dynamic';
+import { useNDKContext } from "@/context/NDKContext";
+
const MDDisplay = dynamic(
() => import("@uiw/react-markdown-preview"),
{
@@ -18,58 +19,81 @@ const Course = () => {
const [lessons, setLessons] = useState([]);
const router = useRouter();
- const { fetchSingleEvent, fetchSingleNaddrEvent, fetchKind0 } = useNostr();
+ const ndk = useNDKContext();
- const { slug } = router.query;
-
- const fetchAuthor = async (pubkey) => {
- const author = await fetchKind0(pubkey);
- const fields = await findKind0Fields(author);
+ const fetchAuthor = useCallback(async (pubkey) => {
+ const author = await ndk.getUser({ pubkey });
+ const profile = await author.fetchProfile();
+ const fields = await findKind0Fields(profile);
if (fields) {
return fields;
}
- }
+ }, [ndk]);
useEffect(() => {
- const getCourse = async () => {
- if (slug) {
- const fetchedCourse = await fetchSingleEvent(slug);
- const formattedCourse = parseCourseEvent(fetchedCourse);
- const aTags = formattedCourse.tags.filter(tag => tag[0] === 'a');
- setCourse(formattedCourse);
- if (aTags.length > 0) {
- const lessonIds = aTags.map(tag => tag[1]);
- setLessonIds(lessonIds);
- }
- }
- };
+ if (router.isReady) {
+ const { slug } = router.query;
- if (slug && !course) {
- getCourse();
+ const fetchCourse = async (slug) => {
+ try {
+ await ndk.connect();
+
+ const filter = {
+ ids: [slug]
+ }
+
+ const event = await ndk.fetchEvent(filter);
+
+ if (event) {
+ const author = await fetchAuthor(event.pubkey);
+ const aTags = event.tags.filter(tag => tag[0] === 'a');
+ const lessonIds = aTags.map(tag => tag[1].split(':')[2]);
+ setLessonIds(lessonIds);
+ const parsedCourse = {
+ ...parseCourseEvent(event),
+ author
+ };
+ setCourse(parsedCourse);
+ }
+ } catch (error) {
+ console.error('Error fetching event:', error);
+ }
+ };
+ if (ndk) {
+ fetchCourse(slug);
+ }
}
- }, [slug]);
+ }, [router.isReady, router.query, ndk, fetchAuthor]);
useEffect(() => {
if (lessonIds.length > 0) {
const fetchLesson = async (lessonId) => {
try {
- const l = await fetchSingleNaddrEvent(lessonId.split(':')[2]);
- const author = await fetchAuthor(l.pubkey);
- const parsedLesson = parseEvent(l);
- const lessonObj = {
- ...parsedLesson,
- author
+ await ndk.connect();
+
+ const filter = {
+ "#d": [lessonId]
+ }
+
+ const event = await ndk.fetchEvent(filter);
+
+ if (event) {
+ const author = await fetchAuthor(event.pubkey);
+ const parsedLesson = {
+ ...parseEvent(event),
+ author
+ };
+ setLessons(prev => [...prev, parsedLesson]);
}
- setLessons(prev => [...prev, lessonObj]);
} catch (error) {
- console.error('Error fetching lesson:', error);
+ console.error('Error fetching event:', error);
}
- }
+ };
lessonIds.forEach(lessonId => fetchLesson(lessonId));
}
- }, [lessonIds]);
+ }, [lessonIds, ndk, fetchAuthor]);
return (
<>
diff --git a/src/pages/details/[slug].js b/src/pages/details/[slug].js
index b0cfd1a..13464e3 100644
--- a/src/pages/details/[slug].js
+++ b/src/pages/details/[slug].js
@@ -38,7 +38,6 @@ export default function Details() {
const [zapAmount, setZapAmount] = useState(null);
const [paidResource, setPaidResource] = useState(false);
const [decryptedContent, setDecryptedContent] = useState(null);
- // const [user, setUser] = useState(null);
const ndk = useNDKContext();
const [user] = useLocalStorageWithEffect('user', {});
@@ -78,7 +77,7 @@ export default function Details() {
}
}
decryptContent();
- }, [user, paidResource]);
+ }, [user, paidResource, processedEvent]);
useEffect(() => {
if (router.isReady) {