mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Queries are near perfect, also quality of life improvements
This commit is contained in:
parent
e2181722e3
commit
e265d1ea88
45
package-lock.json
generated
45
package-lock.json
generated
@ -30,6 +30,7 @@
|
|||||||
"zapthreads": "^0.5.2"
|
"zapthreads": "^0.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
@ -1275,6 +1276,36 @@
|
|||||||
"tslib": "^2.4.0"
|
"tslib": "^2.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/typography": {
|
||||||
|
"version": "0.5.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz",
|
||||||
|
"integrity": "sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.castarray": "^4.4.0",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.merge": "^4.6.2",
|
||||||
|
"postcss-selector-parser": "6.0.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": ">=3.0.0 || insiders"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
|
||||||
|
"version": "6.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz",
|
||||||
|
"integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"util-deprecate": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.51.21",
|
"version": "5.51.21",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.21.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.51.21.tgz",
|
||||||
@ -7249,6 +7280,20 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.castarray": {
|
||||||
|
"version": "4.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz",
|
||||||
|
"integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
"zapthreads": "^0.5.2"
|
"zapthreads": "^0.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@tailwindcss/typography": "^0.5.13",
|
||||||
"eslint": "^8",
|
"eslint": "^8",
|
||||||
"eslint-config-next": "14.2.5",
|
"eslint-config-next": "14.2.5",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
@ -5,13 +5,13 @@ 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/zaps/useCoursesZapsQuery";
|
import { useZapsQuery } from "@/hooks/nostrQueries/zaps/useZapsQuery";
|
||||||
|
|
||||||
const CourseTemplate = ({ course }) => {
|
const CourseTemplate = ({ course }) => {
|
||||||
const [zapAmount, setZapAmount] = useState(0);
|
const [zapAmount, setZapAmount] = useState(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { zaps, zapsLoading, zapsError } = useCoursesZapsQuery({ event: course });
|
const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: course, type: "course" });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!zaps || zapsLoading || zapsError) return;
|
if (!zaps || zapsLoading || zapsError) return;
|
||||||
@ -37,6 +37,7 @@ const CourseTemplate = ({ course }) => {
|
|||||||
<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"
|
||||||
>
|
>
|
||||||
|
{/* Wrap the image in a div with a relative class with a padding-bottom of 56.25% representing the aspect ratio of 16:9 */}
|
||||||
<div
|
<div
|
||||||
onClick={() => router.push(`/course/${course.id}`)}
|
onClick={() => router.push(`/course/${course.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"
|
||||||
|
@ -3,13 +3,13 @@ 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 { useResourceZapsQuery } from "@/hooks/nostrQueries/zaps/useResourceZapsQuery";
|
import { useZapsQuery } from "@/hooks/nostrQueries/zaps/useZapsQuery";
|
||||||
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(null);
|
||||||
const { zaps, zapsLoading, zapsError } = useResourceZapsQuery({ event: resource });
|
const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: resource, type: "resource" });
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
|
@ -3,18 +3,18 @@ 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/zaps/useWorkshopsZapsQuery";
|
import { useZapsQuery } from "@/hooks/nostrQueries/zaps/useZapsQuery";
|
||||||
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(null);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { zaps, zapsLoading, zapsError } = useWorkshopsZapsQuery({ event: workshop });
|
const { zaps, zapsLoading, zapsError } = useZapsQuery({ event: workshop, type: "workshop" });
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!zaps || zapsLoading || zapsError) return;
|
if (zapsLoading || !zaps) return;
|
||||||
|
|
||||||
let total = 0;
|
let total = 0;
|
||||||
zaps.forEach((zap) => {
|
zaps.forEach((zap) => {
|
||||||
@ -28,6 +28,7 @@ const WorkshopTemplate = ({ workshop }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setZapAmount(total);
|
setZapAmount(total);
|
||||||
}, [zaps, workshop, zapsLoading, zapsError]);
|
}, [zaps, workshop, zapsLoading, zapsError]);
|
||||||
|
|
||||||
@ -35,6 +36,7 @@ const WorkshopTemplate = ({ workshop }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center mx-auto px-4 mt-8 rounded-md">
|
<div className="flex flex-col items-center mx-auto px-4 mt-8 rounded-md">
|
||||||
|
{/* Wrap the image in a div with a relative class with a padding-bottom of 56.25% representing the aspect ratio of 16:9 */}
|
||||||
<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"
|
||||||
|
@ -41,12 +41,12 @@ const WorkshopForm = ({ draft = null }) => {
|
|||||||
// Check if it's a YouTube video
|
// Check if it's a YouTube video
|
||||||
if (videoUrl.includes('youtube.com') || videoUrl.includes('youtu.be')) {
|
if (videoUrl.includes('youtube.com') || videoUrl.includes('youtu.be')) {
|
||||||
const videoId = videoUrl.split('v=')[1] || videoUrl.split('/').pop();
|
const videoId = videoUrl.split('v=')[1] || videoUrl.split('/').pop();
|
||||||
embedCode = `<iframe width="560" height="315" src="https://www.youtube.com/embed/${videoId}" frameborder="0" allowfullscreen></iframe>`;
|
embedCode = `<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;max-width:100%;"><iframe src="https://www.youtube.com/embed/${videoId}" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allowfullscreen></iframe></div>`;
|
||||||
}
|
}
|
||||||
// Check if it's a Vimeo video
|
// Check if it's a Vimeo video
|
||||||
else if (videoUrl.includes('vimeo.com')) {
|
else if (videoUrl.includes('vimeo.com')) {
|
||||||
const videoId = videoUrl.split('/').pop();
|
const videoId = videoUrl.split('/').pop();
|
||||||
embedCode = `<iframe width="560" height="315" src="https://player.vimeo.com/video/${videoId}" frameborder="0" allowfullscreen></iframe>`;
|
embedCode = `<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;max-width:100%;"><iframe src="https://player.vimeo.com/video/${videoId}" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allowfullscreen></iframe></div>`;
|
||||||
}
|
}
|
||||||
// Add more conditions here for other video services
|
// Add more conditions here for other video services
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ const ZapDisplay = ({ zapAmount, event, zapsLoading }) => {
|
|||||||
{zapsLoading ? (
|
{zapsLoading ? (
|
||||||
<ProgressSpinner style={{width: '20px', height: '20px'}} strokeWidth="8" animationDuration=".5s" />
|
<ProgressSpinner style={{width: '20px', height: '20px'}} strokeWidth="8" animationDuration=".5s" />
|
||||||
) : (
|
) : (
|
||||||
zapAmount
|
zapAmount !== null ? zapAmount : <ProgressSpinner style={{width: '20px', height: '20px'}} strokeWidth="8" animationDuration=".5s" />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<OverlayPanel className='w-[40%] h-[40%]' ref={op}>
|
<OverlayPanel className='w-[40%] h-[40%]' ref={op}>
|
||||||
|
@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
const ZapForm = ({ event }) => {
|
const ZapForm = ({ event }) => {
|
||||||
|
console.log('event', event);
|
||||||
const nAddress = nip19.naddrEncode({
|
const nAddress = nip19.naddrEncode({
|
||||||
kind: event?.kind,
|
kind: event?.kind,
|
||||||
pubkey: event?.pubkey,
|
pubkey: event?.pubkey,
|
||||||
|
@ -38,7 +38,7 @@ const { data: courses, isLoading: coursesLoading, error: coursesError, refetch:
|
|||||||
queryKey: ['courses', isClient],
|
queryKey: ['courses', isClient],
|
||||||
queryFn: fetchCoursesFromNDK,
|
queryFn: fetchCoursesFromNDK,
|
||||||
staleTime: 1000 * 60 * 30, // 30 minutes
|
staleTime: 1000 * 60 * 30, // 30 minutes
|
||||||
cacheTime: 1000 * 60 * 60, // 1 hour
|
refetchInterval: 1000 * 60 * 30, // 30 minutes
|
||||||
enabled: isClient,
|
enabled: isClient,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const { data: resources, isLoading: resourcesLoading, error: resourcesError, ref
|
|||||||
queryKey: ['resources', isClient],
|
queryKey: ['resources', isClient],
|
||||||
queryFn: fetchResourcesFromNDK,
|
queryFn: fetchResourcesFromNDK,
|
||||||
staleTime: 1000 * 60 * 30, // 30 minutes
|
staleTime: 1000 * 60 * 30, // 30 minutes
|
||||||
cacheTime: 1000 * 60 * 60, // 1 hour
|
refetchInterval: 1000 * 60 * 30, // 30 minutes
|
||||||
enabled: isClient,
|
enabled: isClient,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ const { data: workshops, isLoading: workshopsLoading, error: workshopsError, ref
|
|||||||
queryKey: ['workshops', isClient],
|
queryKey: ['workshops', isClient],
|
||||||
queryFn: fetchWorkshopsFromNDK,
|
queryFn: fetchWorkshopsFromNDK,
|
||||||
staleTime: 1000 * 60 * 30, // 30 minutes
|
staleTime: 1000 * 60 * 30, // 30 minutes
|
||||||
cacheTime: 1000 * 60 * 60, // 1 hour
|
refetchInterval: 1000 * 60 * 30, // 30 minutes
|
||||||
enabled: isClient,
|
enabled: isClient,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
|
||||||
|
|
||||||
export function useCoursesZapsQuery({ event }) {
|
|
||||||
const [isClient, setIsClient] = useState(false);
|
|
||||||
const [zaps, setZaps] = useState([]);
|
|
||||||
const [zapsLoading, setZapsLoading] = useState(true);
|
|
||||||
const [zapsError, setZapsError] = useState(null);
|
|
||||||
const ndk = useNDKContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isClient || !ndk || !event) return;
|
|
||||||
|
|
||||||
let subscription = null;
|
|
||||||
let isSubscribed = true;
|
|
||||||
|
|
||||||
const fetchZapsFromNDK = async () => {
|
|
||||||
try {
|
|
||||||
await ndk.connect();
|
|
||||||
const uniqueEvents = new Set();
|
|
||||||
|
|
||||||
const filters = [
|
|
||||||
{ kinds: [9735], "#e": [event.id] },
|
|
||||||
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
|
|
||||||
];
|
|
||||||
|
|
||||||
subscription = ndk.subscribe(filters);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchZapsFromNDK();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isSubscribed = false;
|
|
||||||
if (subscription) {
|
|
||||||
subscription.stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [isClient, ndk, event]);
|
|
||||||
|
|
||||||
return { zaps, zapsLoading, zapsError };
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
|
||||||
|
|
||||||
export function useResourceZapsQuery({ event }) {
|
|
||||||
const [isClient, setIsClient] = useState(false);
|
|
||||||
const [zaps, setZaps] = useState([]);
|
|
||||||
const [zapsLoading, setZapsLoading] = useState(true);
|
|
||||||
const [zapsError, setZapsError] = useState(null);
|
|
||||||
const ndk = useNDKContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isClient || !ndk || !event) return;
|
|
||||||
|
|
||||||
let subscription = null;
|
|
||||||
let isSubscribed = true;
|
|
||||||
|
|
||||||
const fetchZapsFromNDK = async () => {
|
|
||||||
try {
|
|
||||||
await ndk.connect();
|
|
||||||
const uniqueEvents = new Set();
|
|
||||||
|
|
||||||
const filters = [
|
|
||||||
{ kinds: [9735], "#e": [event.id] },
|
|
||||||
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
|
|
||||||
];
|
|
||||||
|
|
||||||
subscription = ndk.subscribe(filters);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchZapsFromNDK();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isSubscribed = false;
|
|
||||||
if (subscription) {
|
|
||||||
subscription.stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [isClient, ndk, event]);
|
|
||||||
|
|
||||||
return { zaps, zapsLoading, zapsError };
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import { useState, useEffect } from 'react';
|
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
|
||||||
|
|
||||||
export function useWorkshopsZapsQuery({ event }) {
|
|
||||||
const [isClient, setIsClient] = useState(false);
|
|
||||||
const [zaps, setZaps] = useState([]);
|
|
||||||
const [zapsLoading, setZapsLoading] = useState(true);
|
|
||||||
const [zapsError, setZapsError] = useState(null);
|
|
||||||
const ndk = useNDKContext();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsClient(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isClient || !ndk || !event) return;
|
|
||||||
|
|
||||||
let subscription = null;
|
|
||||||
let isSubscribed = true;
|
|
||||||
|
|
||||||
const fetchZapsFromNDK = async () => {
|
|
||||||
try {
|
|
||||||
await ndk.connect();
|
|
||||||
const uniqueEvents = new Set();
|
|
||||||
|
|
||||||
const filters = [
|
|
||||||
{ kinds: [9735], "#e": [event.id] },
|
|
||||||
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
|
|
||||||
];
|
|
||||||
|
|
||||||
subscription = ndk.subscribe(filters);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
fetchZapsFromNDK();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isSubscribed = false;
|
|
||||||
if (subscription) {
|
|
||||||
subscription.stop();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, [isClient, ndk, event]);
|
|
||||||
|
|
||||||
return { zaps, zapsLoading, zapsError };
|
|
||||||
}
|
|
39
src/hooks/nostrQueries/zaps/useZapsQuery.js
Normal file
39
src/hooks/nostrQueries/zaps/useZapsQuery.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useNDKContext } from '@/context/NDKContext';
|
||||||
|
|
||||||
|
export function useZapsQuery({ event, type }) {
|
||||||
|
const [isClient, setIsClient] = useState(false);
|
||||||
|
const ndk = useNDKContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsClient(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const fetchZaps = async (event) => {
|
||||||
|
try {
|
||||||
|
await ndk.connect();
|
||||||
|
|
||||||
|
const filters = [
|
||||||
|
{ kinds: [9735], "#e": [event.id] },
|
||||||
|
{ kinds: [9735], "#a": [`${event.kind}:${event.id}:${event.d}`] }
|
||||||
|
];
|
||||||
|
|
||||||
|
const events = await ndk.fetchEvents(filters, { closeOnEose: true });
|
||||||
|
return events;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching zaps from NDK:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: zaps, isLoading: zapsLoading, error: zapsError, refetch: refetchZaps } = useQuery({
|
||||||
|
queryKey: ['zaps', isClient, event, type],
|
||||||
|
queryFn: () => fetchZaps(event),
|
||||||
|
staleTime: 10000, // 10 seconds
|
||||||
|
refetchInterval: 10000, // 10 seconds
|
||||||
|
enabled: isClient,
|
||||||
|
})
|
||||||
|
|
||||||
|
return { zaps, zapsLoading, zapsError, refetchZaps }
|
||||||
|
}
|
@ -34,6 +34,7 @@ export function useZapsSubscription({ event }) {
|
|||||||
if (isSubscribed) {
|
if (isSubscribed) {
|
||||||
uniqueEvents.add(zap);
|
uniqueEvents.add(zap);
|
||||||
setZaps(Array.from(uniqueEvents));
|
setZaps(Array.from(uniqueEvents));
|
||||||
|
setZapsLoading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ export default function Details() {
|
|||||||
const ndk = useNDKContext();
|
const ndk = useNDKContext();
|
||||||
const [user] = useLocalStorageWithEffect('user', {});
|
const [user] = useLocalStorageWithEffect('user', {});
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const { zaps, zapsError } = useZapsSubscription({ event: processedEvent });
|
const { zaps, zapsLoading, zapsError } = useZapsSubscription({ event: processedEvent });
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@ -105,8 +105,8 @@ export default function Details() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (event) {
|
if (event) {
|
||||||
const { id, pubkey, content, title, summary, image, published_at, d, topics } = parseEvent(event);
|
const parsedEvent = parseEvent(event);
|
||||||
setProcessedEvent({ id, pubkey, content, title, summary, image, published_at, d, topics });
|
setProcessedEvent(parsedEvent);
|
||||||
}
|
}
|
||||||
}, [event]);
|
}, [event]);
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ export default function Details() {
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-full flex justify-end">
|
<div className="w-full flex justify-end">
|
||||||
<ZapDisplay zapAmount={zapAmount} event={processedEvent} />
|
<ZapDisplay zapAmount={zapAmount} event={processedEvent} zapsLoading={zapsLoading} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -29,5 +29,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [
|
||||||
|
require('@tailwindcss/typography'),
|
||||||
|
// ...
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user