diff --git a/src/App.tsx b/src/App.tsx
index a8773e0..076f30a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -267,21 +267,26 @@ export default function App() {
{store.isLoggedIn && (
{jim.recommendedByUsers.map((user) => (
-
)}
diff --git a/src/store.ts b/src/store.ts
index 6e86da0..504915f 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -4,6 +4,7 @@ import NDK, {
NDKKind,
NDKNip07Signer,
NDKSigner,
+ NDKSubscription,
NDKUser,
} from "@nostr-dev-kit/ndk";
import { create } from "zustand";
@@ -51,19 +52,48 @@ type Jim = {
};
type Store = {
+ readonly _jims: Partial
[];
readonly jims: Jim[];
readonly isLoggedIn: boolean;
readonly hasLoaded: boolean;
- setJims(jims: Jim[]): void;
+ updateJim(jim: Partial): void;
setLoaded(hasLoaded: boolean): void;
login(): Promise;
};
export const useStore = create((set, get) => ({
isLoggedIn: false,
+ _jims: [],
jims: [],
hasLoaded: false,
- setJims: (jims) => set({ jims }),
+ updateJim: (jim: Partial) => {
+ const currentJims = get()._jims;
+ const currentJim: Partial =
+ currentJims.find((current) => current.eventId === jim.eventId) || {};
+
+ const updatedJim: Partial = {
+ ...currentJim,
+ ...jim,
+ recommendedByUsers: [
+ ...(currentJim.recommendedByUsers || []),
+ ...(jim.recommendedByUsers || []),
+ ].filter(
+ (v, i, a) =>
+ a.findIndex((current) => current.user.npub === v.user.npub) === i,
+ ),
+ };
+
+ const _jims = [
+ ...currentJims.filter((current) => current.eventId !== jim.eventId),
+ updatedJim,
+ ];
+ const jims = _jims.filter((jim) => !!jim.info) as Jim[];
+ jims.sort(
+ (a, b) => b.recommendedByUsers.length - a.recommendedByUsers.length,
+ );
+
+ set({ _jims, jims });
+ },
setLoaded: (hasLoaded) => set({ hasLoaded }),
login: async () => {
if (get().isLoggedIn || !get().hasLoaded) {
@@ -83,19 +113,36 @@ export const useStore = create((set, get) => ({
}));
(async () => {
- await ndk.connect();
+ console.log("Connecting to relays");
+ await ndk.connect(5000);
+ console.log("Loading Jims");
await loadJims();
useStore.getState().setLoaded(true);
})();
+let jimInstanceEventsSub: NDKSubscription | undefined;
async function loadJims() {
- const jimInstanceEvents = await ndk.fetchEvents({
+ if (jimInstanceEventsSub) {
+ jimInstanceEventsSub.stop();
+ }
+ console.log("Fetching jim instance events");
+ jimInstanceEventsSub = ndk.subscribe({
kinds: [JIM_INSTANCE_KIND as NDKKind],
});
- const jims: Jim[] = [];
- console.log("jim instance events", jimInstanceEvents);
- for (const event of jimInstanceEvents) {
+ jimInstanceEventsSub.on("event", async (event) => {
+ if (
+ useStore
+ .getState()
+ .jims.some((existing) => existing.eventId === event.id && existing.info)
+ ) {
+ // only update the event
+ useStore.getState().updateJim({
+ event,
+ eventId: event.id,
+ });
+ }
+
const url = event.dTag;
if (url && !url.endsWith("/")) {
let info: Jim["info"];
@@ -107,7 +154,7 @@ async function loadJims() {
info = await response.json();
} catch (error) {
console.error("failed to fetch jim info", url, error);
- continue;
+ return;
}
let reserves: Jim["reserves"];
try {
@@ -118,39 +165,39 @@ async function loadJims() {
reserves = await response.json();
} catch (error) {
console.error("failed to fetch jim reserves", url, error);
- continue;
+ return;
}
- jims.push({
+ const jim: Partial = {
eventId: event.id,
url,
- recommendedByUsers: [],
event,
info,
reserves,
- });
- useStore.getState().setJims(jims);
+ };
+ useStore.getState().updateJim(jim);
}
- }
+ });
// load recommendations
- const jimRecommendationEvents = await ndk.fetchEvents({
+ const jimRecommendationSub = ndk.subscribe({
kinds: [38000],
"#k": [JIM_INSTANCE_KIND.toString()],
});
- console.log("jim recommendation events", jimRecommendationEvents);
- for (const recommendationEvent of jimRecommendationEvents) {
- const jim = jims.find((j) => j.eventId === recommendationEvent.dTag);
- if (jim) {
- jim.recommendedByUsers.push({
- user: recommendationEvent.author,
- mutual: false,
- });
- }
- }
- useStore.getState().setJims(jims);
+ jimRecommendationSub.on("event", (recommendationEvent: NDKEvent) => {
+ const jimEventId = recommendationEvent.dTag;
+ useStore.getState().updateJim({
+ eventId: jimEventId,
+ recommendedByUsers: [
+ {
+ user: recommendationEvent.author,
+ mutual: false,
+ },
+ ],
+ });
+ });
}
async function loadMutualRecommendations(signer: NDKSigner) {
@@ -170,10 +217,11 @@ async function loadMutualRecommendations(signer: NDKSigner) {
await recommendedByUser.user.fetchProfile();
}
}
+ useStore.getState().updateJim({
+ eventId: jim.eventId,
+ recommendedByUsers: jim.recommendedByUsers,
+ });
}
- useStore.getState().setJims(jims);
-
- // TODO: sort jims
useStore.getState().setLoaded(true);
}