import { useState, useEffect, useCallback, useContext } from 'react'; import axios from 'axios'; import { nip57 } from 'nostr-tools'; import { NostrContext } from '@/context/NostrContext'; const defaultRelays = [ "wss://nos.lol/", "wss://relay.damus.io/", "wss://relay.snort.social/", "wss://relay.nostr.band/", "wss://nostr.mutinywallet.com/", "wss://relay.mutinywallet.com/", "wss://relay.primal.net/" ]; export function useNostr() { const pool = useContext(NostrContext); const subscribe = useCallback( (filters, opts) => { if (!pool) return; return pool.subscribeMany(defaultRelays, filters, opts); }, [pool] ); const publish = useCallback( async (event) => { if (!pool) return; try { await Promise.any(pool.publish(defaultRelays, event)); console.log('Published event to at least one relay'); } catch (error) { console.error('Failed to publish event:', error); } }, [pool] ); const fetchSingleEvent = useCallback( async (id) => { try { const event = await pool.get(defaultRelays, { ids: [id], }); return event; } catch (error) { console.error('Failed to fetch event:', error); return null; } }, [pool] ); const fetchZapsForEvent = useCallback( async (id) => { try { const filter = { kinds: [9735], '#e': [id] }; const zaps = await pool.querySync(defaultRelays, filter); console.log('zaps:', zaps); return zaps; } catch (error) { console.error('Failed to fetch zaps for event:', error); return []; } }, [pool] ); const fetchKind0 = useCallback( async (publicKey) => { try { const filter = { authors: [publicKey], kinds: [0] }; const kind0 = await pool.querySync(defaultRelays, filter); return JSON.parse(kind0[0].content); } catch (error) { console.error('Failed to fetch kind 0 for event:', error); return []; } }, [pool] ); const zapEvent = useCallback( async (event) => { const kind0 = await fetchKind0(event.pubkey); if (kind0.length === 0) { console.error('Error fetching kind0'); return; } if (kind0.lud16) { const lud16Username = kind0.lud16.split('@')[0]; const lud16Domain = kind0.lud16.split('@')[1]; const lud16Url = `https://${lud16Domain}/.well-known/lnurlp/${lud16Username}`; try { const response = await axios.get(lud16Url); if (response.data.allowsNostr) { const zapReq = nip57.makeZapRequest({ profile: event.pubkey, event: event.id, amount: 1000, relays: defaultRelays, comment: 'Plebdevs Zap', }); console.log('zapReq:', zapReq); const signedEvent = await window?.nostr?.signEvent(zapReq); const callbackUrl = response.data.callback; const zapRequestAPICall = `${callbackUrl}?amount=${1000}&nostr=${encodeURI( JSON.stringify(signedEvent) )}`; const invoiceResponse = await axios.get(zapRequestAPICall); if (invoiceResponse?.data?.pr) { const invoice = invoiceResponse.data.pr; const enabled = await window?.webln?.enable(); console.log('webln enabled:', enabled); const payInvoiceResponse = await window?.webln?.sendPayment(invoice); console.log('payInvoiceResponse:', payInvoiceResponse); } else { console.error('Error fetching invoice'); // showToast('error', 'Error', 'Error fetching invoice'); } } } catch (error) { console.error('Error fetching lud16 data:', error); } } else if (profile.lud06) { // handle lnurlpay } else { // showToast('error', 'Error', 'User has no Lightning Address or LNURL'); } }, [fetchKind0] ); const fetchResources = useCallback(async () => { const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }]; const hasRequiredTags = (eventData) => { const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs"); const hasResource = eventData.some(([tag, value]) => tag === "t" && value === "resource"); return hasPlebDevs && hasResource; }; return new Promise((resolve, reject) => { let resources = []; const subscription = subscribe( filter, { onevent: (event) => { if (hasRequiredTags(event.tags)) { resources.push(event); } }, onerror: (error) => { console.error('Error fetching resources:', error); subscription?.close(); resolve(resources); }, onclose: () => { resolve(resources); }, }, 2000 // Adjust the timeout value as needed ); setTimeout(() => { subscription?.close(); resolve(resources); }, 2000); // Adjust the timeout value as needed }); }, [subscribe]); const fetchWorkshops = useCallback(async () => { const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }]; const hasRequiredTags = (eventData) => { const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs"); const hasWorkshop = eventData.some(([tag, value]) => tag === "t" && value === "workshop"); return hasPlebDevs && hasWorkshop; }; return new Promise((resolve, reject) => { let workshops = []; const subscription = subscribe( filter, { onevent: (event) => { if (hasRequiredTags(event.tags)) { workshops.push(event); } }, onerror: (error) => { console.error('Error fetching workshops:', error); subscription?.close(); resolve(workshops); }, onclose: () => { resolve(workshops); }, }, 2000 // Adjust the timeout value as needed ); setTimeout(() => { subscription?.close(); resolve(workshops); }, 2000); // Adjust the timeout value as needed }); }, [subscribe]); const fetchCourses = useCallback(async () => { const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }]; const hasRequiredTags = (eventData) => { const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs"); const hasCourse = eventData.some(([tag, value]) => tag === "t" && value === "course"); return hasPlebDevs && hasCourse; }; return new Promise((resolve, reject) => { let courses = []; const subscription = subscribe( filter, { onevent: (event) => { if (hasRequiredTags(event.tags)) { courses.push(event); } }, onerror: (error) => { console.error('Error fetching courses:', error); subscription?.close(); resolve(courses); }, onclose: () => { resolve(courses); }, }, 2000 // Adjust the timeout value as needed ); setTimeout(() => { subscription?.close(); resolve(courses); }, 2000); // Adjust the timeout value as needed }); }, [subscribe]); return { subscribe, publish, fetchSingleEvent, fetchZapsForEvent, fetchKind0, fetchResources, fetchWorkshops, fetchCourses, zapEvent }; }