Fixed zaps, keeping open subscription

This commit is contained in:
austinkelsay 2024-08-04 19:00:26 -05:00
parent 829d974675
commit c5eb71e4b8
6 changed files with 143 additions and 113 deletions

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState, useMemo } from "react"; import React, { useEffect, useState } from "react";
import Image from "next/image"; 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";
@ -11,7 +11,7 @@ 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 }) const { zaps, zapsLoading, zapsError } = useCoursesZapsQuery({ event: course });
useEffect(() => { useEffect(() => {
if (!zaps || zapsLoading || zapsError) return; if (!zaps || zapsLoading || zapsError) return;
@ -63,8 +63,7 @@ const CourseTemplate = ({ course }) => {
formatTimestampToHowLongAgo(course.published_at) formatTimestampToHowLongAgo(course.published_at)
) : ( ) : (
formatTimestampToHowLongAgo(course.created_at) formatTimestampToHowLongAgo(course.created_at)
) )}
}
</p> </p>
<ZapDisplay zapAmount={zapAmount} event={course} /> <ZapDisplay zapAmount={zapAmount} event={course} />
</div> </div>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState, useMemo } from "react"; import React, { useEffect, useState } from "react";
import Image from "next/image"; 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";
@ -9,7 +9,7 @@ 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 { zaps, zapsLoading, zapsError } = useResourceZapsQuery({ event: resource });
const router = useRouter(); const router = useRouter();
const { returnImageProxy } = useImageProxy(); const { returnImageProxy } = useImageProxy();
@ -33,7 +33,7 @@ const ResourceTemplate = ({ resource }) => {
}, [resource, zaps, zapsLoading, zapsError]); }, [resource, zaps, zapsLoading, zapsError]);
if (zapsLoading) return <div>Loading...</div>; if (zapsLoading) return <div>Loading...</div>;
if (zapsError) return <div>Error: {zapsError}</div>; if (zapsError) return <div>Error: {zapsError}</div>;
return ( return (
<div <div

View File

@ -1,17 +1,17 @@
import React, { useEffect, useState, useMemo } from "react"; import React, { useEffect, useState } from "react";
import Image from "next/image"; 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 { useWorkshopsZapsQuery } from "@/hooks/nostrQueries/useWorkshopsZapsQuery" 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";
const WorkshopTemplate = ({workshop}) => { 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 } = useWorkshopsZapsQuery({event: workshop}); const { zaps, zapsLoading, zapsError } = useWorkshopsZapsQuery({ event: workshop });
useEffect(() => { useEffect(() => {
if (!zaps || zapsLoading || zapsError) return; if (!zaps || zapsLoading || zapsError) return;
@ -22,9 +22,9 @@ const WorkshopTemplate = ({workshop}) => {
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}`)) { 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}`)) {
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;
} }
} }
}); });
@ -35,9 +35,7 @@ const WorkshopTemplate = ({workshop}) => {
if (zapsError) return <div>Error: {zapsError}</div>; if (zapsError) return <div>Error: {zapsError}</div>;
return ( return (
<div <div className="flex flex-col items-center mx-auto px-4 mt-8 rounded-md">
className="flex flex-col items-center mx-auto px-4 mt-8 rounded-md"
>
<div <div
onClick={() => router.push(`/details/${workshop.id}`)} onClick={() => router.push(`/details/${workshop.id}`)}
className="relative w-full h-0 hover:opacity-80 transition-opacity duration-300 cursor-pointer" className="relative w-full h-0 hover:opacity-80 transition-opacity duration-300 cursor-pointer"

View File

@ -1,51 +1,62 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useNDKContext } from '@/context/NDKContext'; import { useNDKContext } from '@/context/NDKContext';
export function useCoursesZapsQuery({ event }) { export function useCoursesZapsQuery({ event }) {
const [isClient, setIsClient] = useState(false); const [isClient, setIsClient] = useState(false);
const [zaps, setZaps] = useState([]);
const [zapsLoading, setZapsLoading] = useState(true);
const [zapsError, setZapsError] = useState(null);
const ndk = useNDKContext(); const ndk = useNDKContext();
useEffect(() => { useEffect(() => {
setIsClient(true); setIsClient(true);
}, []); }, []);
const fetchZapsFromNDK = async (event) => { useEffect(() => {
if (!ndk) { if (!isClient || !ndk || !event) return;
console.error('NDK instance is null');
return [];
}
if (!event) { let subscription = null;
console.error('No event provided'); let isSubscribed = true;
return [];
}
try { const fetchZapsFromNDK = async () => {
await ndk.connect(); try {
let zaps = []; await ndk.connect();
const uniqueEvents = new Set();
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }]; const filters = [
{ kinds: [9735], "#e": [event.id] },
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
];
for (const filter of filters) { subscription = ndk.subscribe(filters);
const zapEvents = await ndk.fetchEvents(filter);
zapEvents.forEach(zap => zaps.push(zap)); subscription.on('event', (zap) => {
if (isSubscribed) {
uniqueEvents.add(zap);
setZaps(Array.from(uniqueEvents));
}
});
subscription.on('eose', () => {
setZaps(Array.from(uniqueEvents));
setZapsLoading(false);
});
} catch (error) {
setZapsError('Error fetching zaps from NDK: ' + error);
setZapsLoading(false);
} }
};
return zaps; fetchZapsFromNDK();
} catch (error) {
console.error('Error fetching zaps from NDK:', error);
return [];
}
};
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({ return () => {
queryKey: ['coursesZaps', isClient, event], isSubscribed = false;
queryFn: () => fetchZapsFromNDK(event), if (subscription) {
staleTime: 1000 * 60 * 3, // 3 minutes subscription.stop();
cacheTime: 1000 * 60 * 60, // 1 hour }
enabled: isClient, };
}); }, [isClient, ndk, event]);
return { zaps, zapsLoading, zapsError, refetchZaps } return { zaps, zapsLoading, zapsError };
} }

View File

@ -1,51 +1,62 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useNDKContext } from '@/context/NDKContext'; import { useNDKContext } from '@/context/NDKContext';
export function useResourceZapsQuery({ event }) { export function useResourceZapsQuery({ event }) {
const [isClient, setIsClient] = useState(false); const [isClient, setIsClient] = useState(false);
const [zaps, setZaps] = useState([]);
const [zapsLoading, setZapsLoading] = useState(true);
const [zapsError, setZapsError] = useState(null);
const ndk = useNDKContext(); const ndk = useNDKContext();
useEffect(() => { useEffect(() => {
setIsClient(true); setIsClient(true);
}, []); }, []);
const fetchZapsFromNDK = async (event) => { useEffect(() => {
if (!ndk) { if (!isClient || !ndk || !event) return;
console.error('NDK instance is null');
return [];
}
if (!event) { let subscription = null;
console.error('No event provided'); let isSubscribed = true;
return [];
}
try { const fetchZapsFromNDK = async () => {
await ndk.connect(); try {
let zaps = []; await ndk.connect();
const uniqueEvents = new Set();
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }]; const filters = [
{ kinds: [9735], "#e": [event.id] },
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
];
for (const filter of filters) { subscription = ndk.subscribe(filters);
const zapEvents = await ndk.fetchEvents(filter);
zapEvents.forEach(zap => zaps.push(zap)); subscription.on('event', (zap) => {
if (isSubscribed) {
uniqueEvents.add(zap);
setZaps(Array.from(uniqueEvents));
}
});
subscription.on('eose', () => {
setZaps(Array.from(uniqueEvents));
setZapsLoading(false);
});
} catch (error) {
setZapsError('Error fetching zaps from NDK: ' + error);
setZapsLoading(false);
} }
};
return zaps; fetchZapsFromNDK();
} catch (error) {
console.error('Error fetching zaps from NDK:', error);
return [];
}
};
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({ return () => {
queryKey: ['resourceZaps', isClient, event], isSubscribed = false;
queryFn: () => fetchZapsFromNDK(event), if (subscription) {
staleTime: 1000 * 60 * 3, // 3 minutes subscription.stop();
cacheTime: 1000 * 60 * 60, // 1 hour }
enabled: isClient, };
}); }, [isClient, ndk, event]);
return { zaps, zapsLoading, zapsError, refetchZaps } return { zaps, zapsLoading, zapsError };
} }

View File

@ -1,51 +1,62 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { useNDKContext } from '@/context/NDKContext'; import { useNDKContext } from '@/context/NDKContext';
export function useWorkshopsZapsQuery({ event }) { export function useWorkshopsZapsQuery({ event }) {
const [isClient, setIsClient] = useState(false); const [isClient, setIsClient] = useState(false);
const [zaps, setZaps] = useState([]);
const [zapsLoading, setZapsLoading] = useState(true);
const [zapsError, setZapsError] = useState(null);
const ndk = useNDKContext(); const ndk = useNDKContext();
useEffect(() => { useEffect(() => {
setIsClient(true); setIsClient(true);
}, []); }, []);
const fetchZapsFromNDK = async (event) => { useEffect(() => {
if (!ndk) { if (!isClient || !ndk || !event) return;
console.error('NDK instance is null');
return [];
}
if (!event) { let subscription = null;
console.error('No event provided'); let isSubscribed = true;
return [];
}
try { const fetchZapsFromNDK = async () => {
await ndk.connect(); try {
let zaps = []; await ndk.connect();
const uniqueEvents = new Set();
const filters = [{ kinds: [9735], "#e": [event.id] }, { kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }]; const filters = [
{ kinds: [9735], "#e": [event.id] },
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
];
for (const filter of filters) { subscription = ndk.subscribe(filters);
const zapEvents = await ndk.fetchEvents(filter);
zapEvents.forEach(zap => zaps.push(zap)); subscription.on('event', (zap) => {
if (isSubscribed) {
uniqueEvents.add(zap);
setZaps(Array.from(uniqueEvents));
}
});
subscription.on('eose', () => {
setZaps(Array.from(uniqueEvents));
setZapsLoading(false);
});
} catch (error) {
setZapsError('Error fetching zaps from NDK: ' + error);
setZapsLoading(false);
} }
};
return zaps; fetchZapsFromNDK();
} catch (error) {
console.error('Error fetching zaps from NDK:', error);
return [];
}
};
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({ return () => {
queryKey: ['workshopsZaps', isClient, event], isSubscribed = false;
queryFn: () => fetchZapsFromNDK(event), if (subscription) {
staleTime: 1000 * 60 * 3, // 3 minutes subscription.stop();
cacheTime: 1000 * 60 * 60, // 1 hour }
enabled: isClient, };
}); }, [isClient, ndk, event]);
return { zaps, zapsLoading, zapsError, refetchZaps } return { zaps, zapsLoading, zapsError };
} }