2024-04-23 18:52:55 -05:00
|
|
|
import { useState, useEffect, useCallback, useContext, useRef } from 'react';
|
2024-04-20 16:16:22 -05:00
|
|
|
import axios from 'axios';
|
2024-04-22 19:09:46 -05:00
|
|
|
import { nip57, nip19 } from 'nostr-tools';
|
2024-04-20 17:42:00 -05:00
|
|
|
import { NostrContext } from '@/context/NostrContext';
|
2024-04-22 19:09:46 -05:00
|
|
|
import { lnurlEncode } from '@/utils/lnurl';
|
2024-03-19 17:47:16 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const defaultRelays = [
|
2024-03-19 17:47:16 -05:00
|
|
|
"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/"
|
2024-04-22 19:09:46 -05:00
|
|
|
];
|
2024-02-11 00:00:27 -06:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
export function useNostr() {
|
2024-04-20 17:42:00 -05:00
|
|
|
const pool = useContext(NostrContext);
|
2024-04-23 18:52:55 -05:00
|
|
|
const subscriptionQueue = useRef([]);
|
|
|
|
const lastSubscriptionTime = useRef(0);
|
|
|
|
const throttleDelay = 2000;
|
|
|
|
|
|
|
|
const processSubscriptionQueue = useCallback(() => {
|
|
|
|
if (subscriptionQueue.current.length === 0) return;
|
|
|
|
|
|
|
|
const currentTime = Date.now();
|
|
|
|
if (currentTime - lastSubscriptionTime.current < throttleDelay) {
|
|
|
|
setTimeout(processSubscriptionQueue, throttleDelay);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const subscription = subscriptionQueue.current.shift();
|
|
|
|
subscription();
|
|
|
|
|
|
|
|
lastSubscriptionTime.current = currentTime;
|
|
|
|
setTimeout(processSubscriptionQueue, throttleDelay);
|
|
|
|
}, [throttleDelay]);
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const subscribe = useCallback(
|
|
|
|
(filters, opts) => {
|
2024-04-22 19:09:46 -05:00
|
|
|
if (!pool) return;
|
|
|
|
|
2024-04-23 18:52:55 -05:00
|
|
|
const subscriptionFn = () => {
|
|
|
|
return pool.subscribeMany(defaultRelays, filters, opts);
|
|
|
|
};
|
|
|
|
|
|
|
|
subscriptionQueue.current.push(subscriptionFn);
|
|
|
|
processSubscriptionQueue();
|
2024-04-20 16:16:22 -05:00
|
|
|
},
|
2024-04-23 18:52:55 -05:00
|
|
|
[pool, processSubscriptionQueue]
|
2024-04-22 19:09:46 -05:00
|
|
|
);
|
2024-04-20 16:16:22 -05:00
|
|
|
|
|
|
|
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 {
|
2024-04-23 18:52:55 -05:00
|
|
|
const event = await new Promise((resolve, reject) => {
|
|
|
|
subscribe(
|
|
|
|
[{ ids: [id] }],
|
|
|
|
{
|
|
|
|
onevent: (event) => {
|
|
|
|
resolve(event);
|
|
|
|
},
|
|
|
|
onerror: (error) => {
|
|
|
|
reject(error);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
2024-03-27 18:12:17 -05:00
|
|
|
});
|
2024-04-20 16:16:22 -05:00
|
|
|
return event;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch event:', error);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
},
|
2024-04-23 18:52:55 -05:00
|
|
|
[subscribe]
|
|
|
|
);
|
|
|
|
|
|
|
|
const querySyncQueue = useRef([]);
|
|
|
|
const lastQuerySyncTime = useRef(0);
|
|
|
|
|
|
|
|
const processQuerySyncQueue = useCallback(() => {
|
|
|
|
if (querySyncQueue.current.length === 0) return;
|
|
|
|
|
|
|
|
const currentTime = Date.now();
|
|
|
|
if (currentTime - lastQuerySyncTime.current < throttleDelay) {
|
|
|
|
setTimeout(processQuerySyncQueue, throttleDelay);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const querySync = querySyncQueue.current.shift();
|
|
|
|
querySync();
|
|
|
|
|
|
|
|
lastQuerySyncTime.current = currentTime;
|
|
|
|
setTimeout(processQuerySyncQueue, throttleDelay);
|
|
|
|
}, [throttleDelay]);
|
|
|
|
|
|
|
|
const fetchZapsForParamaterizedEvent = useCallback(
|
|
|
|
async (kind, id, d) => {
|
|
|
|
try {
|
|
|
|
const filters = { kinds: [9735], '#a': [`${kind}:${id}:${d}`] };
|
|
|
|
const zaps = await pool.querySync(defaultRelays, filters);
|
|
|
|
return zaps;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch zaps for event:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
},
|
2024-04-20 16:16:22 -05:00
|
|
|
[pool]
|
|
|
|
);
|
|
|
|
|
2024-04-23 18:52:55 -05:00
|
|
|
const fetchZapsForNonParameterizedEvent = useCallback(
|
|
|
|
async (id) => {
|
2024-04-20 16:16:22 -05:00
|
|
|
try {
|
2024-04-23 18:52:55 -05:00
|
|
|
const filters = { kinds: [9735], '#e': [id] };
|
|
|
|
const zaps = await pool.querySync(defaultRelays, filters);
|
2024-04-20 16:16:22 -05:00
|
|
|
return zaps;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch zaps for event:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[pool]
|
|
|
|
);
|
|
|
|
|
2024-04-23 18:52:55 -05:00
|
|
|
const fetchZapsForEvent = useCallback(
|
|
|
|
async (event) => {
|
|
|
|
const querySyncFn = async () => {
|
|
|
|
try {
|
|
|
|
const parameterizedZaps = await fetchZapsForParamaterizedEvent(event.kind, event.id, event.d);
|
|
|
|
const nonParameterizedZaps = await fetchZapsForNonParameterizedEvent(event.id);
|
|
|
|
return [...parameterizedZaps, ...nonParameterizedZaps];
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch zaps for event:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
querySyncQueue.current.push(async () => {
|
|
|
|
const zaps = await querySyncFn();
|
|
|
|
resolve(zaps);
|
|
|
|
});
|
|
|
|
processQuerySyncQueue();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
[fetchZapsForParamaterizedEvent, fetchZapsForNonParameterizedEvent, processQuerySyncQueue]
|
|
|
|
);
|
|
|
|
|
|
|
|
const fetchZapsForEvents = useCallback(
|
|
|
|
async (events) => {
|
|
|
|
const querySyncFn = async () => {
|
|
|
|
try {
|
|
|
|
// Collect all #a and #e tag values from the list of events
|
|
|
|
let aTags = [];
|
2024-04-24 14:30:40 -05:00
|
|
|
let aTagsAlt = [];
|
2024-04-23 18:52:55 -05:00
|
|
|
let eTags = [];
|
|
|
|
events.forEach(event => {
|
|
|
|
aTags.push(`${event.kind}:${event.id}:${event.d}`);
|
2024-04-24 14:30:40 -05:00
|
|
|
aTagsAlt.push(`${event.kind}:${event.pubkey}:${event.d}`);
|
2024-04-23 18:52:55 -05:00
|
|
|
eTags.push(event.id);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Create filters for batch querying
|
|
|
|
const filterA = { kinds: [9735], '#a': aTags };
|
|
|
|
const filterE = { kinds: [9735], '#e': eTags };
|
2024-04-24 14:30:40 -05:00
|
|
|
const filterAAlt = { kinds: [9735], '#a': aTagsAlt };
|
2024-04-23 18:52:55 -05:00
|
|
|
|
|
|
|
// Perform batch queries
|
2024-04-24 14:30:40 -05:00
|
|
|
// const [zapsA, zapsE] = await Promise.all([
|
|
|
|
// pool.querySync(defaultRelays, filterA),
|
|
|
|
// pool.querySync(defaultRelays, filterE)
|
|
|
|
// ]);
|
|
|
|
let allZaps = []
|
|
|
|
|
|
|
|
await new Promise((resolve) => pool.subscribeMany(defaultRelays, [filterA, filterE, filterAAlt], {
|
|
|
|
onerror: (error) => {
|
|
|
|
console.error('Failed to fetch zaps for events:', error);
|
|
|
|
resolve([]);
|
|
|
|
},
|
|
|
|
onevent: (event) => {
|
|
|
|
allZaps.push(event);
|
|
|
|
},
|
|
|
|
oneose: () => {
|
|
|
|
resolve(allZaps);
|
2024-04-23 18:52:55 -05:00
|
|
|
}
|
2024-04-24 14:30:40 -05:00
|
|
|
}))
|
|
|
|
|
|
|
|
// remove any duplicates
|
|
|
|
allZaps = allZaps.filter((zap, index, self) => index === self.findIndex((t) => (
|
|
|
|
t.id === zap.id
|
|
|
|
)))
|
|
|
|
|
|
|
|
return allZaps;
|
2024-04-23 18:52:55 -05:00
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch zaps for events:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return new Promise((resolve) => {
|
|
|
|
querySyncQueue.current.push(async () => {
|
|
|
|
const zaps = await querySyncFn();
|
|
|
|
resolve(zaps);
|
|
|
|
});
|
|
|
|
processQuerySyncQueue();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
[pool, processQuerySyncQueue]
|
|
|
|
);
|
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const fetchKind0 = useCallback(
|
|
|
|
async (publicKey) => {
|
|
|
|
try {
|
2024-04-23 18:52:55 -05:00
|
|
|
const kind0 = await new Promise((resolve, reject) => {
|
|
|
|
subscribe(
|
|
|
|
[{ authors: [publicKey], kinds: [0] }],
|
|
|
|
{
|
|
|
|
onevent: (event) => {
|
|
|
|
resolve(JSON.parse(event.content));
|
|
|
|
},
|
|
|
|
onerror: (error) => {
|
|
|
|
reject(error);
|
|
|
|
},
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
return kind0;
|
2024-04-20 16:16:22 -05:00
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to fetch kind 0 for event:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
},
|
2024-04-23 18:52:55 -05:00
|
|
|
[subscribe]
|
2024-04-20 16:16:22 -05:00
|
|
|
);
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const zapEvent = useCallback(
|
2024-04-22 19:09:46 -05:00
|
|
|
async (event, amount, comment) => {
|
2024-04-20 16:16:22 -05:00
|
|
|
const kind0 = await fetchKind0(event.pubkey);
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
if (kind0.length === 0) {
|
|
|
|
console.error('Error fetching kind0');
|
|
|
|
return;
|
|
|
|
}
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-04-22 11:59:20 -05:00
|
|
|
if (kind0.lud16) {
|
|
|
|
const lud16Username = kind0.lud16.split('@')[0];
|
|
|
|
const lud16Domain = kind0.lud16.split('@')[1];
|
2024-04-20 16:16:22 -05:00
|
|
|
const lud16Url = `https://${lud16Domain}/.well-known/lnurlp/${lud16Username}`;
|
|
|
|
|
|
|
|
try {
|
|
|
|
const response = await axios.get(lud16Url);
|
|
|
|
|
|
|
|
if (response.data.allowsNostr) {
|
2024-04-23 18:52:55 -05:00
|
|
|
// const zapReq = nip57.makeZapRequest({
|
|
|
|
// profile: event.pubkey,
|
|
|
|
// event: event.id,
|
|
|
|
// amount: amount,
|
|
|
|
// relays: defaultRelays,
|
|
|
|
// comment: comment ? comment : 'Plebdevs Zap',
|
|
|
|
// });
|
2024-04-20 16:16:22 -05:00
|
|
|
|
2024-04-22 19:09:46 -05:00
|
|
|
const user = window.localStorage.getItem('user');
|
|
|
|
|
|
|
|
const pubkey = JSON.parse(user).pubkey;
|
|
|
|
|
|
|
|
const lnurl = lnurlEncode(lud16Url)
|
|
|
|
|
|
|
|
console.log('lnurl:', lnurl);
|
|
|
|
|
|
|
|
console.log('pubkey:', pubkey);
|
|
|
|
|
2024-04-23 18:52:55 -05:00
|
|
|
const zapReq = {
|
|
|
|
kind: 9734,
|
|
|
|
content: "",
|
|
|
|
tags: [
|
2024-04-24 14:30:40 -05:00
|
|
|
["relays", defaultRelays.join(",")],
|
2024-04-23 18:52:55 -05:00
|
|
|
["amount", amount.toString()],
|
|
|
|
// ["lnurl", lnurl],
|
|
|
|
["e", event.id],
|
|
|
|
["p", event.pubkey],
|
2024-04-24 14:30:40 -05:00
|
|
|
["a", `${event.kind}:${event.pubkey}:${event.d}`],
|
2024-04-23 18:52:55 -05:00
|
|
|
],
|
|
|
|
created_at: Math.floor(Date.now() / 1000)
|
|
|
|
}
|
2024-04-22 19:09:46 -05:00
|
|
|
|
|
|
|
console.log('zapRequest:', zapReq);
|
2024-04-20 16:16:22 -05:00
|
|
|
|
|
|
|
const signedEvent = await window?.nostr?.signEvent(zapReq);
|
2024-04-22 19:09:46 -05:00
|
|
|
console.log('signedEvent:', signedEvent);
|
2024-04-20 16:16:22 -05:00
|
|
|
const callbackUrl = response.data.callback;
|
2024-04-22 19:09:46 -05:00
|
|
|
const zapRequestAPICall = `${callbackUrl}?amount=${amount}&nostr=${encodeURI(
|
2024-04-20 16:16:22 -05:00
|
|
|
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);
|
2024-03-27 18:12:17 -05:00
|
|
|
}
|
2024-04-20 16:16:22 -05:00
|
|
|
} else if (profile.lud06) {
|
|
|
|
// handle lnurlpay
|
|
|
|
} else {
|
2024-04-23 18:52:55 -05:00
|
|
|
showToast('error', 'Error', 'User has no Lightning Address or LNURL');
|
2024-03-27 18:12:17 -05:00
|
|
|
}
|
2024-04-20 16:16:22 -05:00
|
|
|
},
|
|
|
|
[fetchKind0]
|
|
|
|
);
|
2024-03-27 18:12:17 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const fetchResources = useCallback(async () => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
2024-04-20 16:16:22 -05:00
|
|
|
const hasRequiredTags = (eventData) => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
|
|
|
const hasResource = eventData.some(([tag, value]) => tag === "t" && value === "resource");
|
2024-04-20 16:16:22 -05:00
|
|
|
return hasPlebDevs && hasResource;
|
2024-03-27 14:44:54 -05:00
|
|
|
};
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let resources = [];
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
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
|
|
|
|
);
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
setTimeout(() => {
|
|
|
|
subscription?.close();
|
|
|
|
resolve(resources);
|
|
|
|
}, 2000); // Adjust the timeout value as needed
|
|
|
|
});
|
|
|
|
}, [subscribe]);
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const fetchWorkshops = useCallback(async () => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
2024-04-20 16:16:22 -05:00
|
|
|
const hasRequiredTags = (eventData) => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
|
|
|
const hasWorkshop = eventData.some(([tag, value]) => tag === "t" && value === "workshop");
|
2024-04-20 16:16:22 -05:00
|
|
|
return hasPlebDevs && hasWorkshop;
|
2024-03-27 14:44:54 -05:00
|
|
|
};
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let workshops = [];
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
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
|
|
|
|
);
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
setTimeout(() => {
|
|
|
|
subscription?.close();
|
|
|
|
resolve(workshops);
|
|
|
|
}, 2000); // Adjust the timeout value as needed
|
|
|
|
});
|
|
|
|
}, [subscribe]);
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
const fetchCourses = useCallback(async () => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const filter = [{ kinds: [30023], authors: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741"] }];
|
2024-04-20 16:16:22 -05:00
|
|
|
const hasRequiredTags = (eventData) => {
|
2024-03-27 14:44:54 -05:00
|
|
|
const hasPlebDevs = eventData.some(([tag, value]) => tag === "t" && value === "plebdevs");
|
|
|
|
const hasCourse = eventData.some(([tag, value]) => tag === "t" && value === "course");
|
2024-04-20 16:16:22 -05:00
|
|
|
return hasPlebDevs && hasCourse;
|
2024-03-27 14:44:54 -05:00
|
|
|
};
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-02-11 00:00:27 -06:00
|
|
|
return new Promise((resolve, reject) => {
|
2024-04-20 16:16:22 -05:00
|
|
|
let courses = [];
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-04-20 16:16:22 -05:00
|
|
|
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);
|
|
|
|
},
|
2024-02-11 00:00:27 -06:00
|
|
|
},
|
2024-04-20 16:16:22 -05:00
|
|
|
2000 // Adjust the timeout value as needed
|
|
|
|
);
|
2024-04-22 19:09:46 -05:00
|
|
|
|
2024-02-11 00:00:27 -06:00
|
|
|
setTimeout(() => {
|
2024-04-20 16:16:22 -05:00
|
|
|
subscription?.close();
|
|
|
|
resolve(courses);
|
|
|
|
}, 2000); // Adjust the timeout value as needed
|
2024-02-11 00:00:27 -06:00
|
|
|
});
|
2024-04-20 16:16:22 -05:00
|
|
|
}, [subscribe]);
|
2024-02-11 00:00:27 -06:00
|
|
|
|
2024-04-23 18:52:55 -05:00
|
|
|
return { subscribe, publish, fetchSingleEvent, fetchZapsForEvent, fetchKind0, fetchResources, fetchWorkshops, fetchCourses, zapEvent, fetchZapsForEvents };
|
2024-04-20 16:16:22 -05:00
|
|
|
}
|