flockstr/lib/hooks/useEvents.ts

168 lines
4.2 KiB
TypeScript
Raw Normal View History

2023-10-15 22:15:49 -04:00
"use client";
import { useState, useEffect } from "react";
import { useNDK } from "@/app/_providers/ndk";
import {
NDKEvent,
type NDKFilter,
type NDKSubscription,
} from "@nostr-dev-kit/ndk";
import { log } from "@/lib/utils";
import { uniqBy } from "ramda";
import { Event as NostrEvent } from "nostr-tools";
const debug = true;
type OnEventFunc = (event: NostrEvent) => void;
type OnDoneFunc = () => void;
type OnSubscribeFunc = (sub: NDKSubscription) => void;
type UseEventsProps = {
filter: NDKFilter;
enabled?: boolean;
eventFilter?: (e: NDKEvent) => boolean;
};
export default function useEvents({
filter,
enabled = true,
eventFilter = () => true,
}: UseEventsProps) {
const [isLoading, setIsLoading] = useState(true);
const [sub, setSub] = useState<NDKSubscription | undefined>(undefined);
const [events, setEvents] = useState<NDKEvent[]>([]);
const [eventIds, setEventIds] = useState<Set<string>>(new Set());
let onEventCallback: null | OnEventFunc = null;
let onSubscribeCallback: null | OnSubscribeFunc = null;
let onDoneCallback: null | OnDoneFunc = null;
const { ndk } = useNDK();
useEffect(() => {
if (!enabled || !ndk) return;
void init();
return () => {
console.log("STOPPING", sub);
if (sub) {
sub.stop();
}
};
}, [enabled, ndk]);
async function init() {
console.log("Running init");
setIsLoading(true);
try {
const sub = ndk!.subscribe(
{ limit: 50, ...filter },
{ closeOnEose: false },
);
setSub(sub);
onSubscribeCallback?.(sub);
sub.on("event", (e, r) => {
if (eventIds.has(e.id)) {
return;
}
if (eventFilter(e)) {
setEvents((prevEvents) => {
const events = uniqBy((a) => a.id, [...prevEvents, e]);
return events.sort((a, b) => b.created_at - a.created_at);
});
setEventIds((prev) => prev.add(e.id));
}
});
} catch (err) {
2023-10-18 21:55:45 -04:00
log("error", `❌ nostr (${err})`);
} finally {
setIsLoading(false);
}
}
return {
isLoading,
events,
onEvent: (_onEventCallback: OnEventFunc) => {
if (_onEventCallback) {
onEventCallback = _onEventCallback;
}
},
onDone: (_onDoneCallback: OnDoneFunc) => {
if (_onDoneCallback) {
onDoneCallback = _onDoneCallback;
}
},
onSubscribe: (_onSubscribeCallback: OnSubscribeFunc) => {
if (_onSubscribeCallback) {
onSubscribeCallback = _onSubscribeCallback;
}
},
};
}
2023-10-28 11:07:50 -04:00
export function useEvent({
filter,
enabled = true,
eventFilter = () => true,
}: UseEventsProps) {
const [isLoading, setIsLoading] = useState(true);
const [sub, setSub] = useState<NDKSubscription | undefined>(undefined);
const [event, setEvent] = useState<NDKEvent>();
const [eventId, setEventId] = useState<string>();
let onEventCallback: null | OnEventFunc = null;
let onSubscribeCallback: null | OnSubscribeFunc = null;
let onDoneCallback: null | OnDoneFunc = null;
const { ndk } = useNDK();
useEffect(() => {
if (!enabled || !ndk) return;
void init();
return () => {
console.log("STOPPING", sub);
if (sub) {
sub.stop();
}
};
}, [enabled, ndk]);
async function init() {
setIsLoading(true);
try {
const sub = ndk!.subscribe(
{ limit: 1, ...filter },
{ closeOnEose: false },
);
setSub(sub);
onSubscribeCallback?.(sub);
sub.on("event", (e, r) => {
if (eventId === e.id) {
return;
}
if (eventFilter(e)) {
setEvent(e);
setEventId(e.id);
}
});
} catch (err) {
log("error", `❌ nostr (${err})`);
} finally {
setIsLoading(false);
}
}
return {
isLoading,
event,
onEvent: (_onEventCallback: OnEventFunc) => {
if (_onEventCallback) {
onEventCallback = _onEventCallback;
}
},
onDone: (_onDoneCallback: OnDoneFunc) => {
if (_onDoneCallback) {
onDoneCallback = _onDoneCallback;
}
},
onSubscribe: (_onSubscribeCallback: OnSubscribeFunc) => {
if (_onSubscribeCallback) {
onSubscribeCallback = _onSubscribeCallback;
}
},
};
}