mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-23 16:05:24 +00:00
Zaps are implemented but still fickle, added to details page
This commit is contained in:
parent
4b0476c509
commit
eaad977677
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect, use } from 'react';
|
import React, { useState, useEffect, use } from 'react';
|
||||||
import { Carousel } from 'primereact/carousel';
|
import { Carousel } from 'primereact/carousel';
|
||||||
import { parseCourseEvent } from '@/utils/nostr';
|
import { parseCourseEvent } from '@/utils/nostr';
|
||||||
import { useZapsQuery } from '@/hooks/nostrQueries/useZapsQuery';
|
|
||||||
import CourseTemplate from '@/components/content/carousels/templates/CourseTemplate';
|
import CourseTemplate from '@/components/content/carousels/templates/CourseTemplate';
|
||||||
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
||||||
import { useCoursesQuery } from '@/hooks/nostrQueries/useCoursesQuery';
|
import { useCoursesQuery } from '@/hooks/nostrQueries/useCoursesQuery';
|
||||||
@ -27,29 +26,14 @@ const responsiveOptions = [
|
|||||||
export default function CoursesCarousel() {
|
export default function CoursesCarousel() {
|
||||||
const [processedCourses, setProcessedCourses] = useState([]);
|
const [processedCourses, setProcessedCourses] = useState([]);
|
||||||
const { courses, coursesLoading, coursesError, refetchCourses } = useCoursesQuery()
|
const { courses, coursesLoading, coursesError, refetchCourses } = useCoursesQuery()
|
||||||
const { zaps, zapsLoading, zapsError, refetchZaps } = useZapsQuery({ events: courses })
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refetchZaps(courses)
|
|
||||||
}, [courses, refetchZaps]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
try {
|
try {
|
||||||
if (courses && courses.length > 0 && zaps) {
|
if (courses && courses.length > 0) {
|
||||||
const processedCourses = courses.map(course => parseCourseEvent(course));
|
const processedCourses = courses.map(course => parseCourseEvent(course));
|
||||||
|
|
||||||
let coursesWithZaps = processedCourses.map(course => {
|
setProcessedCourses(processedCourses);
|
||||||
let collectedZaps = []
|
|
||||||
zaps.forEach(zap => {
|
|
||||||
if (zap.tags.find(tag => tag[0] === "e" && tag[1] === course.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${course.kind}:${course.id}:${course.d}`)) {
|
|
||||||
collectedZaps.push(zap)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return { ...course, zaps: collectedZaps }
|
|
||||||
})
|
|
||||||
|
|
||||||
setProcessedCourses(coursesWithZaps);
|
|
||||||
} else {
|
} else {
|
||||||
console.log('No courses fetched or empty array returned');
|
console.log('No courses fetched or empty array returned');
|
||||||
}
|
}
|
||||||
@ -58,7 +42,7 @@ export default function CoursesCarousel() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetch();
|
fetch();
|
||||||
}, [courses, zaps]);
|
}, [courses]);
|
||||||
|
|
||||||
if (coursesError) {
|
if (coursesError) {
|
||||||
return <div>Error: {coursesError.message}</div>
|
return <div>Error: {coursesError.message}</div>
|
||||||
|
@ -4,7 +4,6 @@ import { parseEvent } from '@/utils/nostr';
|
|||||||
import ResourceTemplate from '@/components/content/carousels/templates/ResourceTemplate';
|
import ResourceTemplate from '@/components/content/carousels/templates/ResourceTemplate';
|
||||||
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
||||||
import { useResourcesQuery } from '@/hooks/nostrQueries/useResourcesQuery';
|
import { useResourcesQuery } from '@/hooks/nostrQueries/useResourcesQuery';
|
||||||
import { useZapsQuery } from '@/hooks/nostrQueries/useZapsQuery';
|
|
||||||
|
|
||||||
const responsiveOptions = [
|
const responsiveOptions = [
|
||||||
{
|
{
|
||||||
@ -27,31 +26,14 @@ const responsiveOptions = [
|
|||||||
export default function ResourcesCarousel() {
|
export default function ResourcesCarousel() {
|
||||||
const [processedResources, setProcessedResources] = useState([]);
|
const [processedResources, setProcessedResources] = useState([]);
|
||||||
const { resources, resourcesLoading, resourcesError, refetchResources } = useResourcesQuery()
|
const { resources, resourcesLoading, resourcesError, refetchResources } = useResourcesQuery()
|
||||||
const { zaps, zapsLoading, zapsError, refetchZaps } = useZapsQuery({ events: resources })
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (resources && resources.length > 0) {
|
|
||||||
refetchZaps(resources)
|
|
||||||
}
|
|
||||||
}, [resources, refetchZaps]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
try {
|
try {
|
||||||
if (resources && resources.length > 0 && zaps) {
|
if (resources && resources.length > 0) {
|
||||||
const processedResources = resources.map(resource => parseEvent(resource));
|
const processedResources = resources.map(resource => parseEvent(resource));
|
||||||
|
|
||||||
let resourcesWithZaps = processedResources.map(resource => {
|
setProcessedResources(processedResources);
|
||||||
let collectedZaps = []
|
|
||||||
zaps.forEach(zap => {
|
|
||||||
if (zap.tags.find(tag => tag[0] === "e" && tag[1] === resource.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${resource.kind}:${resource.id}:${resource.d}`)) {
|
|
||||||
collectedZaps.push(zap)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return { ...resource, zaps: collectedZaps }
|
|
||||||
})
|
|
||||||
|
|
||||||
setProcessedResources(resourcesWithZaps);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching resources:', error);
|
console.error('Error fetching resources:', error);
|
||||||
|
@ -4,7 +4,6 @@ import { parseEvent } from '@/utils/nostr';
|
|||||||
import WorkshopTemplate from '@/components/content/carousels/templates/WorkshopTemplate';
|
import WorkshopTemplate from '@/components/content/carousels/templates/WorkshopTemplate';
|
||||||
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
import TemplateSkeleton from '@/components/content/carousels/skeletons/TemplateSkeleton';
|
||||||
import { useWorkshopsQuery } from '@/hooks/nostrQueries/useWorkshopsQuery';
|
import { useWorkshopsQuery } from '@/hooks/nostrQueries/useWorkshopsQuery';
|
||||||
import { useZapsQuery } from '@/hooks/nostrQueries/useZapsQuery';
|
|
||||||
|
|
||||||
const responsiveOptions = [
|
const responsiveOptions = [
|
||||||
{
|
{
|
||||||
@ -27,30 +26,14 @@ const responsiveOptions = [
|
|||||||
export default function WorkshopsCarousel() {
|
export default function WorkshopsCarousel() {
|
||||||
const [processedWorkshops, setProcessedWorkshops] = useState([])
|
const [processedWorkshops, setProcessedWorkshops] = useState([])
|
||||||
const { workshops, workshopsLoading, workshopsError, refetchWorkshops } = useWorkshopsQuery()
|
const { workshops, workshopsLoading, workshopsError, refetchWorkshops } = useWorkshopsQuery()
|
||||||
const { zaps, zapsLoading, zapsError, refetchZaps } = useZapsQuery({ events: workshops })
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
refetchZaps(workshops)
|
|
||||||
}, [workshops, refetchZaps]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetch = async () => {
|
const fetch = async () => {
|
||||||
try {
|
try {
|
||||||
console.debug('workshops', workshops);
|
if (workshops && workshops.length > 0) {
|
||||||
if (workshops && workshops.length > 0 && zaps) {
|
|
||||||
const processedWorkshops = workshops.map(workshop => parseEvent(workshop));
|
const processedWorkshops = workshops.map(workshop => parseEvent(workshop));
|
||||||
|
|
||||||
let workshopsWithZaps = processedWorkshops.map(workshop => {
|
setProcessedWorkshops(processedWorkshops);
|
||||||
let collectedZaps = []
|
|
||||||
zaps.forEach(zap => {
|
|
||||||
if (zap.tags.find(tag => tag[0] === "e" && tag[1] === workshop.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${workshop.kind}:${workshop.id}:${workshop.d}`)) {
|
|
||||||
collectedZaps.push(zap)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return { ...workshop, zaps: collectedZaps }
|
|
||||||
})
|
|
||||||
|
|
||||||
setProcessedWorkshops(workshopsWithZaps);
|
|
||||||
} else {
|
} else {
|
||||||
console.log('No workshops fetched or empty array returned');
|
console.log('No workshops fetched or empty array returned');
|
||||||
}
|
}
|
||||||
@ -59,7 +42,7 @@ export default function WorkshopsCarousel() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
fetch();
|
fetch();
|
||||||
}, [workshops, zaps]);
|
}, [workshops]);
|
||||||
|
|
||||||
if (workshopsLoading) return <div>Loading...</div>;
|
if (workshopsLoading) return <div>Loading...</div>;
|
||||||
if (workshopsError) return <div>Error: {workshopsError}</div>;
|
if (workshopsError) return <div>Error: {workshopsError}</div>;
|
||||||
|
@ -5,27 +5,31 @@ import { formatTimestampToHowLongAgo } from "@/utils/time";
|
|||||||
import { useImageProxy } from "@/hooks/useImageProxy";
|
import { useImageProxy } from "@/hooks/useImageProxy";
|
||||||
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
||||||
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
||||||
|
import { useCoursesZapsQuery } from "@/hooks/nostrQueries/useCoursesZapsQuery";
|
||||||
|
|
||||||
const CourseTemplate = ({ course }) => {
|
const CourseTemplate = ({ course }) => {
|
||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(0);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
|
const { zaps, zapsLoading, zapsError, refetchZaps } = useCoursesZapsQuery({ event: course })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!course?.zaps || !course?.zaps.length > 0) return;
|
if (!zaps || !zaps.length > 0) return;
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
course.zaps.forEach((zap) => {
|
zaps.forEach((zap) => {
|
||||||
// If the zap matches the event or the parameterized event, then add the zap to the total
|
// If the zap matches the event or the parameterized event, then add the zap to the total
|
||||||
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
if (zap.tags.find(tag => tag[0] === "e" && tag[1] === course.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${course.kind}:${course.id}:${course.d}`)) {
|
||||||
const invoice = bolt11Tag ? bolt11Tag[1] : null;
|
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
||||||
if (invoice) {
|
const invoice = bolt11Tag ? bolt11Tag[1] : null;
|
||||||
const amount = getSatAmountFromInvoice(invoice);
|
if (invoice) {
|
||||||
total += amount;
|
const amount = getSatAmountFromInvoice(invoice);
|
||||||
|
total += amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setZapAmount(total);
|
setZapAmount(total);
|
||||||
}, [course]);
|
}, [course, zaps]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -3,31 +3,34 @@ import Image from "next/image";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { formatTimestampToHowLongAgo } from "@/utils/time";
|
import { formatTimestampToHowLongAgo } from "@/utils/time";
|
||||||
import { useImageProxy } from "@/hooks/useImageProxy";
|
import { useImageProxy } from "@/hooks/useImageProxy";
|
||||||
import { useZapsQuery } from "@/hooks/nostrQueries/useZapsQuery";
|
import { useResourceZapsQuery } from "@/hooks/nostrQueries/useResourceZapsQuery";
|
||||||
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
||||||
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
||||||
|
|
||||||
const ResourceTemplate = ({ resource }) => {
|
const ResourceTemplate = ({ resource }) => {
|
||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(0);
|
||||||
|
const { zaps, zapsLoading, zapsError, refetchZaps } = useResourceZapsQuery({ event: resource })
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!resource?.zaps || !resource?.zaps.length > 0) return;
|
if (!zaps || !zaps.length > 0) return;
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
resource.zaps.forEach((zap) => {
|
zaps.forEach((zap) => {
|
||||||
// If the zap matches the event or the parameterized event, then add the zap to the total
|
// If the zap matches the event or the parameterized event, then add the zap to the total
|
||||||
|
if (zap.tags.find(tag => tag[0] === "e" && tag[1] === resource.id) || zap.tags.find(tag => tag[0] === "a" && tag[1] === `${resource.kind}:${resource.id}:${resource.d}`)) {
|
||||||
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
||||||
const invoice = bolt11Tag ? bolt11Tag[1] : null;
|
const invoice = bolt11Tag ? bolt11Tag[1] : null;
|
||||||
if (invoice) {
|
if (invoice) {
|
||||||
const amount = getSatAmountFromInvoice(invoice);
|
const amount = getSatAmountFromInvoice(invoice);
|
||||||
total += amount;
|
total += amount;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
setZapAmount(total);
|
setZapAmount(total);
|
||||||
}, [resource]);
|
}, [resource, zaps]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -3,7 +3,7 @@ import Image from "next/image";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { formatTimestampToHowLongAgo } from "@/utils/time";
|
import { formatTimestampToHowLongAgo } from "@/utils/time";
|
||||||
import { useImageProxy } from "@/hooks/useImageProxy";
|
import { useImageProxy } from "@/hooks/useImageProxy";
|
||||||
import { useZapsQuery } from "@/hooks/nostrQueries/useZapsQuery";
|
import { useWorkshopsZapsQuery } from "@/hooks/nostrQueries/useWorkshopsZapsQuery"
|
||||||
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
import { getSatAmountFromInvoice } from "@/utils/lightning";
|
||||||
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
import ZapDisplay from "@/components/zaps/ZapDisplay";
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ const WorkshopTemplate = ({workshop}) => {
|
|||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(0);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { zaps, zapsLoading, zapsError, refetchZaps } = useZapsQuery({event: workshop});
|
const { zaps, zapsLoading, zapsError, refetchZaps } = useWorkshopsZapsQuery({event: workshop});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!zaps || !zaps.length > 0) return;
|
if (!zaps || !zaps.length > 0) return;
|
||||||
|
@ -3,14 +3,6 @@ import NDK from "@nostr-dev-kit/ndk";
|
|||||||
|
|
||||||
const NDKContext = createContext(null);
|
const NDKContext = createContext(null);
|
||||||
|
|
||||||
// Define the public key of the author whose events we want to fetch.
|
|
||||||
const AUTHOR_PUBKEY = process.env.NEXT_PUBLIC_AUTHOR_PUBKEY;
|
|
||||||
|
|
||||||
// Ensure AUTHOR_PUBKEY is defined
|
|
||||||
if (!AUTHOR_PUBKEY) {
|
|
||||||
throw new Error("NEXT_PUBLIC_AUTHOR_PUBKEY is not defined in the environment variables");
|
|
||||||
}
|
|
||||||
|
|
||||||
const relayUrls = [
|
const relayUrls = [
|
||||||
"wss://nos.lol/",
|
"wss://nos.lol/",
|
||||||
"wss://relay.damus.io/",
|
"wss://relay.damus.io/",
|
||||||
|
@ -2,7 +2,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
|
||||||
export function useZapsQuery({ events }) {
|
export function useCoursesZapsQuery({ event }) {
|
||||||
const [isClient, setIsClient] = useState(false);
|
const [isClient, setIsClient] = useState(false);
|
||||||
const ndk = useNDKContext();
|
const ndk = useNDKContext();
|
||||||
|
|
||||||
@ -10,24 +10,28 @@ export function useZapsQuery({ events }) {
|
|||||||
setIsClient(true);
|
setIsClient(true);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchZapsFromNDK = async (events) => {
|
const fetchZapsFromNDK = async (event) => {
|
||||||
|
if (!ndk) {
|
||||||
|
console.error('NDK instance is null');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
console.error('No event provided');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ndk.connect();
|
await ndk.connect();
|
||||||
|
|
||||||
let zaps = [];
|
let zaps = [];
|
||||||
|
|
||||||
for (const event of events) {
|
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }];
|
||||||
const uniqueEvents = new Set();
|
|
||||||
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }];
|
|
||||||
|
|
||||||
for (const filter of filters) {
|
for (const filter of filters) {
|
||||||
const zapEvents = await ndk.fetchEvents(filter);
|
const zapEvents = await ndk.fetchEvents(filter);
|
||||||
zapEvents.forEach(zap => uniqueEvents.add(zap));
|
zapEvents.forEach(zap => zaps.push(zap));
|
||||||
}
|
|
||||||
|
|
||||||
zaps = [...zaps, ...Array.from(uniqueEvents)];
|
|
||||||
}
|
}
|
||||||
console.log('Zaps fetched:', zaps);
|
|
||||||
return zaps;
|
return zaps;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching zaps from NDK:', error);
|
console.error('Error fetching zaps from NDK:', error);
|
||||||
@ -36,12 +40,12 @@ export function useZapsQuery({ events }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({
|
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({
|
||||||
queryKey: ['zaps', isClient],
|
queryKey: ['coursesZaps', isClient, event],
|
||||||
queryFn: () => fetchZapsFromNDK(events),
|
queryFn: () => fetchZapsFromNDK(event),
|
||||||
staleTime: 1000 * 60 * 3, // 3 minutes
|
staleTime: 1000 * 60 * 3, // 3 minutes
|
||||||
cacheTime: 1000 * 60 * 60, // 1 hour
|
cacheTime: 1000 * 60 * 60, // 1 hour
|
||||||
enabled: isClient,
|
enabled: isClient,
|
||||||
})
|
});
|
||||||
|
|
||||||
return { zaps, zapsLoading, zapsError, refetchZaps }
|
return { zaps, zapsLoading, zapsError, refetchZaps }
|
||||||
}
|
}
|
51
src/hooks/nostrQueries/useResourceZapsQuery.js
Normal file
51
src/hooks/nostrQueries/useResourceZapsQuery.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
|
||||||
|
export function useResourceZapsQuery({ event }) {
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
const ndk = useNDKContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchZapsFromNDK = async (event) => {
|
||||||
|
if (!ndk) {
|
||||||
|
console.error('NDK instance is null');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
console.error('No event provided');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ndk.connect();
|
||||||
|
let zaps = [];
|
||||||
|
|
||||||
|
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }];
|
||||||
|
|
||||||
|
for (const filter of filters) {
|
||||||
|
const zapEvents = await ndk.fetchEvents(filter);
|
||||||
|
zapEvents.forEach(zap => zaps.push(zap));
|
||||||
|
}
|
||||||
|
|
||||||
|
return zaps;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching zaps from NDK:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({
|
||||||
|
queryKey: ['resourceZaps', isClient, event],
|
||||||
|
queryFn: () => fetchZapsFromNDK(event),
|
||||||
|
staleTime: 1000 * 60 * 3, // 3 minutes
|
||||||
|
cacheTime: 1000 * 60 * 60, // 1 hour
|
||||||
|
enabled: isClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { zaps, zapsLoading, zapsError, refetchZaps }
|
||||||
|
}
|
51
src/hooks/nostrQueries/useWorkshopsZapsQuery.js
Normal file
51
src/hooks/nostrQueries/useWorkshopsZapsQuery.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
|
||||||
|
export function useWorkshopsZapsQuery({ event }) {
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
const ndk = useNDKContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchZapsFromNDK = async (event) => {
|
||||||
|
if (!ndk) {
|
||||||
|
console.error('NDK instance is null');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
console.error('No event provided');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ndk.connect();
|
||||||
|
let zaps = [];
|
||||||
|
|
||||||
|
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }];
|
||||||
|
|
||||||
|
for (const filter of filters) {
|
||||||
|
const zapEvents = await ndk.fetchEvents(filter);
|
||||||
|
zapEvents.forEach(zap => zaps.push(zap));
|
||||||
|
}
|
||||||
|
|
||||||
|
return zaps;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching zaps from NDK:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({
|
||||||
|
queryKey: ['workshopsZaps', isClient, event],
|
||||||
|
queryFn: () => fetchZapsFromNDK(event),
|
||||||
|
staleTime: 1000 * 60 * 3, // 3 minutes
|
||||||
|
cacheTime: 1000 * 60 * 60, // 1 hour
|
||||||
|
enabled: isClient,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { zaps, zapsLoading, zapsError, refetchZaps }
|
||||||
|
}
|
@ -1,7 +1,5 @@
|
|||||||
"use client";
|
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import { useNostr } from '@/hooks/useNostr';
|
|
||||||
import { parseEvent, findKind0Fields, hexToNpub } from '@/utils/nostr';
|
import { parseEvent, findKind0Fields, hexToNpub } from '@/utils/nostr';
|
||||||
import { useImageProxy } from '@/hooks/useImageProxy';
|
import { useImageProxy } from '@/hooks/useImageProxy';
|
||||||
import { getSatAmountFromInvoice } from '@/utils/lightning';
|
import { getSatAmountFromInvoice } from '@/utils/lightning';
|
||||||
@ -12,6 +10,7 @@ import { useLocalStorageWithEffect } from '@/hooks/useLocalStorage';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
|
import ZapThreadsWrapper from '@/components/ZapThreadsWrapper';
|
||||||
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
const MDDisplay = dynamic(
|
const MDDisplay = dynamic(
|
||||||
() => import("@uiw/react-markdown-preview"),
|
() => import("@uiw/react-markdown-preview"),
|
||||||
@ -35,21 +34,13 @@ export default function Details() {
|
|||||||
const [nAddress, setNAddress] = useState(null);
|
const [nAddress, setNAddress] = useState(null);
|
||||||
const [zaps, setZaps] = useState([]);
|
const [zaps, setZaps] = useState([]);
|
||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(0);
|
||||||
|
|
||||||
|
const ndk = useNDKContext();
|
||||||
const [user] = useLocalStorageWithEffect('user', {});
|
const [user] = useLocalStorageWithEffect('user', {});
|
||||||
console.log('user:', user);
|
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { fetchSingleEvent, fetchKind0, zapEvent, fetchZapsForEvent } = useNostr();
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const handleZapEvent = async () => {
|
|
||||||
if (!event) return;
|
|
||||||
|
|
||||||
const response = await zapEvent(event);
|
|
||||||
|
|
||||||
console.log('zap response:', response);
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof window === 'undefined') return;
|
if (typeof window === 'undefined') return;
|
||||||
|
|
||||||
@ -65,31 +56,51 @@ export default function Details() {
|
|||||||
const { slug } = router.query;
|
const { slug } = router.query;
|
||||||
|
|
||||||
const fetchEvent = async (slug) => {
|
const fetchEvent = async (slug) => {
|
||||||
console.log('slug:', slug);
|
try {
|
||||||
const event = await fetchSingleEvent(slug);
|
await ndk.connect();
|
||||||
console.log('event:', event);
|
|
||||||
if (event) {
|
const filter = {
|
||||||
setEvent(event);
|
ids: [slug]
|
||||||
|
}
|
||||||
|
|
||||||
|
const event = await ndk.fetchEvent(filter);
|
||||||
|
|
||||||
|
if (event) {
|
||||||
|
setEvent(event);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching event:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (ndk) {
|
||||||
fetchEvent(slug);
|
fetchEvent(slug);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [router.isReady, router.query]);
|
}, [router.isReady, router.query, ndk]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchAuthor = async (pubkey) => {
|
const fetchAuthor = async (pubkey) => {
|
||||||
const author = await fetchKind0(pubkey);
|
try {
|
||||||
const fields = await findKind0Fields(author);
|
await ndk.connect();
|
||||||
console.log('fields:', fields);
|
|
||||||
if (fields) {
|
const filter = {
|
||||||
setAuthor(fields);
|
kinds: [0],
|
||||||
|
authors: [pubkey]
|
||||||
|
}
|
||||||
|
|
||||||
|
const author = await ndk.fetchEvent(filter);
|
||||||
|
if (author) {
|
||||||
|
const fields = await findKind0Fields(JSON.parse(author.content));
|
||||||
|
setAuthor(fields);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching author:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (event) {
|
if (event && ndk) {
|
||||||
fetchAuthor(event.pubkey);
|
fetchAuthor(event.pubkey);
|
||||||
}
|
}
|
||||||
}, [fetchKind0, event]);
|
}, [ndk, event]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (event) {
|
if (event) {
|
||||||
@ -105,14 +116,13 @@ export default function Details() {
|
|||||||
kind: processedEvent.kind,
|
kind: processedEvent.kind,
|
||||||
identifier: processedEvent.d,
|
identifier: processedEvent.d,
|
||||||
});
|
});
|
||||||
console.log('naddr:', naddr);
|
|
||||||
setNAddress(naddr);
|
setNAddress(naddr);
|
||||||
}
|
}
|
||||||
}, [processedEvent]);
|
}, [processedEvent]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!zaps || zaps.length === 0) return;
|
if (!zaps || zaps.length === 0) return;
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
zaps.forEach((zap) => {
|
zaps.forEach((zap) => {
|
||||||
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
const bolt11Tag = zap.tags.find(tag => tag[0] === "bolt11");
|
||||||
@ -127,13 +137,31 @@ export default function Details() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchZaps = async () => {
|
const fetchZaps = async () => {
|
||||||
if (event) {
|
try {
|
||||||
const zaps = await fetchZapsForEvent(event);
|
const processed = parseEvent(event);
|
||||||
|
await ndk.connect();
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
{
|
||||||
|
kinds: [9735],
|
||||||
|
"#e": [processed.id]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
kinds: [9734],
|
||||||
|
"#a": [`${processed.kind}:${processed.id}:${processed.d}`]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const zaps = await ndk.fetchEvents(filters);
|
||||||
setZaps(zaps);
|
setZaps(zaps);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching zaps:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fetchZaps();
|
if (event && ndk) {
|
||||||
}, [fetchZapsForEvent, event]);
|
fetchZaps();
|
||||||
|
}
|
||||||
|
}, [ndk, event]);
|
||||||
|
|
||||||
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'>
|
||||||
|
@ -18,8 +18,8 @@ export default function Home() {
|
|||||||
<main>
|
<main>
|
||||||
<HeroBanner />
|
<HeroBanner />
|
||||||
<CoursesCarousel />
|
<CoursesCarousel />
|
||||||
{/* <WorkshopsCarousel />
|
<WorkshopsCarousel />
|
||||||
<ResourcesCarousel /> */}
|
<ResourcesCarousel />
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user