diff --git a/client/src/components/routes/HashtagPage.tsx b/client/src/components/routes/HashtagPage.tsx index c940d53..1037355 100644 --- a/client/src/components/routes/HashtagPage.tsx +++ b/client/src/components/routes/HashtagPage.tsx @@ -4,14 +4,14 @@ import { Event } from "nostr-tools"; import NewNoteCard from "../forms/PostFormCard"; import RepostCard from "../modals/RepostCard"; import { useParams } from "react-router-dom"; -import { useUniqEvents } from "../../hooks/useUniqEvents"; +import { useFetchEvents } from "../../hooks/useFetchEvents"; const DEFAULT_DIFFICULTY = 0; const HashtagPage = () => { const { id } = useParams(); const filterDifficulty = localStorage.getItem("filterHashtagDifficulty") || DEFAULT_DIFFICULTY; - const { noteEvents, metadataEvents } = useUniqEvents(id as string, false); + const { noteEvents, metadataEvents } = useFetchEvents(id as string, false); const postEvents: Event[] = noteEvents .filter((event) => diff --git a/client/src/components/routes/Home.tsx b/client/src/components/routes/Home.tsx index f38bb2b..f853d5d 100644 --- a/client/src/components/routes/Home.tsx +++ b/client/src/components/routes/Home.tsx @@ -3,12 +3,12 @@ import { Event } from "nostr-tools"; import NewNoteCard from "../forms/PostFormCard"; import RepostCard from "../modals/RepostCard"; import { DEFAULT_DIFFICULTY } from "../../config"; -import { useUniqEvents } from "../../hooks/useUniqEvents"; import PostCard from "../modals/PostCard"; +import { useFetchEvents } from "../../hooks/useFetchEvents"; const Home = () => { const filterDifficulty = localStorage.getItem("filterDifficulty") || DEFAULT_DIFFICULTY; - const { noteEvents, metadataEvents } = useUniqEvents(); + const { noteEvents, metadataEvents } = useFetchEvents(); const postEvents: Event[] = noteEvents .filter((event) => diff --git a/client/src/components/routes/Notifications.tsx b/client/src/components/routes/Notifications.tsx index 860c0a1..6fbbafc 100644 --- a/client/src/components/routes/Notifications.tsx +++ b/client/src/components/routes/Notifications.tsx @@ -2,11 +2,11 @@ import { useState, useCallback } from "react"; import PostCard from "../modals/PostCard"; import { Event } from "nostr-tools"; import RepostCard from "../modals/RepostCard"; -import { useUniqEvents } from "../../hooks/useUniqEvents"; +import { useFetchEvents } from "../../hooks/useFetchEvents"; const Notifications = () => { const [notifsView, setNotifsView] = useState(false); - const { noteEvents, metadataEvents } = useUniqEvents(undefined,true); + const { noteEvents, metadataEvents } = useFetchEvents(undefined,true); const storedKeys = JSON.parse(localStorage.getItem('usedKeys') || '[]'); const storedPubkeys = storedKeys.map((key: any[]) => key[1]); diff --git a/client/src/components/routes/Thread.tsx b/client/src/components/routes/Thread.tsx index 2f293ae..9f4652d 100644 --- a/client/src/components/routes/Thread.tsx +++ b/client/src/components/routes/Thread.tsx @@ -1,7 +1,7 @@ import { useParams } from 'react-router-dom'; import { useState } from "react"; import { Event, nip19 } from "nostr-tools" -import { subNote, subNotesOnce } from '../../utils/subscriptions'; +import { subNotesOnce } from '../../utils/subscriptions'; import { useEffect } from 'react'; import { uniqBy } from '../../utils/otherUtils'; import { DocumentTextIcon, FolderPlusIcon, DocumentDuplicateIcon, ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline'; @@ -9,118 +9,56 @@ import Placeholder from '../modals/Placeholder'; import NewNoteCard from '../forms/PostFormCard'; import RepostNote from '../forms/RepostNote'; import PostCard from '../modals/PostCard'; +import { useFetchEvents } from '../../hooks/useFetchEvents'; type PostType = "" | "Reply" | "Quote" | undefined; const Thread = () => { const { id } = useParams(); - const [events, setEvents] = useState([]); // Initialize state - const [OPEvent, setOPEvent] = useState() const [showForm, setShowForm] = useState(false); const [showRepost, setShowRepost] = useState(false); const [postType, setPostType] = useState(""); - const [hasRun, setHasRun] = useState(false); - const [preOPEvents, setPreOPEvents] = useState(['']); + const [prevMentions, setPrevMentions] = useState([]); // const filterDifficulty = useState(localStorage.getItem("filterDifficulty") || "20"); - // Load cached metadataEvents from localStorage - const [cachedMetadataEvents, setCachedMetadataEvents] = useState( - JSON.parse(localStorage.getItem("cachedMetadataEvents") || "[]") - ); - let decodeResult = nip19.decode(id as string); let hexID = decodeResult.data as string; - - // Define your callback function for subGlobalFeed - const onEvent = (event: Event, relay: string) => { - setEvents((prevEvents) => [...prevEvents, event]); - - // If the new event is a metadata event, add it to the cached metadata events - if (event.kind === 0) { - setCachedMetadataEvents((prevMetadataEvents) => { - // Check if the event already exists in the cached metadata events - const existingEvent = prevMetadataEvents.find((e) => e.id === event.id || e.pubkey === event.pubkey) - if (!existingEvent) { - // If the event doesn't exist, add it to the cached metadata events - return [...prevMetadataEvents, event]; - } else if (existingEvent && existingEvent.created_at < event.created_at) { - // Remove any existing metadata event with the same pubkey and id - const updatedMetadataEvents = prevMetadataEvents.filter( - (e) => e.id !== existingEvent.id - ); - // Add the new metadata event - return [...updatedMetadataEvents, event]; - } - // If the event already exists, return the previous cached metadata events - return prevMetadataEvents; - }); - } - }; - - useEffect(() => { - setHasRun(false) - if (decodeResult.type === 'note') { - // Call your subNote function or do whatever you need to do with id_to_hex - subNote(hexID, onEvent); - } - }, [id]); // Empty dependency array means this useEffect runs once when the component mounts - - // Save the cached metadataEvents to localStorage - useEffect(() => { - localStorage.setItem("cachedMetadataEvents", JSON.stringify(cachedMetadataEvents)); - }, [cachedMetadataEvents]); - - const uniqEvents = events.length > 0 ? uniqBy(events, "id") : []; - const metadataEvents = [...cachedMetadataEvents, ...uniqEvents.filter(event => event.kind === 0)]; - - useEffect(() => { - if (!hasRun && events.length > 0) { - let OPEvent = uniqEvents.find(event => event.id === hexID); - setOPEvent(OPEvent); - - console.log(OPEvent) - if (OPEvent && OPEvent.id !== hexID) { - OPEvent = events.find(e => e.id === hexID) as Event; - } - - if (OPEvent) { - setOPEvent(OPEvent); - let OPNoteEvents = OPEvent.tags.filter(tag => tag[0] === 'e').map(tag => tag[1]); - setHasRun(true); - setPreOPEvents(OPNoteEvents) - subNotesOnce(OPNoteEvents, onEvent) - } - } - }, [uniqEvents, hasRun]); + const { noteEvents, metadataEvents } = useFetchEvents(undefined,false,hexID); const countReplies = (event: Event) => { - return uniqEvents.filter(e => e.tags.some(tag => tag[0] === 'e' && tag[1] === event.id)); + return noteEvents.filter(e => e.tags.some(tag => tag[0] === 'e' && tag[1] === event.id)); } const repliedList = (event: Event): Event[] => { - return uniqEvents.filter(e => event.tags.some(tag => tag[0] === 'p' && tag[1] === e.pubkey)); + return noteEvents.filter(e => event.tags.some(tag => tag[0] === 'p' && tag[1] === e.pubkey)); } - const earlierEvents = uniqEvents - .filter(event => - event.kind === 1 && - preOPEvents.includes(event.id) - ).sort((a, b) => (b.created_at as any) - (a.created_at as any)); - const displayedEvents = [...uniqEvents].slice(1) - .filter(event => - event.kind === 1 && - !earlierEvents.map(e => e.id).includes(event.id) && - (OPEvent ? OPEvent.id !== event.id : true) - ).sort((a, b) => a.created_at - b.created_at); + // Define your callback function for subGlobalFeed + const onEvent = (event: Event, relay: string) => { + setPrevMentions((prevEvents) => [...prevEvents, event]); + }; - if (uniqEvents.length === 0) { - return ( - <> - -
{/* This is the white line separator */} - - ); - } + const OPEvent = noteEvents.find(event => event.id === hexID); + useEffect(() => { + if (OPEvent && prevMentions.length == 0) { + const OPMentionIDs = OPEvent.tags.filter(tag => tag[0] === 'e').map(tag => tag[1]); + subNotesOnce(OPMentionIDs, onEvent); + } + }, [OPEvent]); + + if (OPEvent) { + const uniqEvents = uniqBy(prevMentions, "id"); + const earlierEvents = uniqEvents + .filter(e => + e.created_at < OPEvent.created_at + ) + + const replyEvents = [...noteEvents].slice(1) + .filter(event => + !earlierEvents.map(e => e.id).includes(event.id) && + (OPEvent ? OPEvent.id !== event.id : true) + ).sort((a, b) => a.created_at - b.created_at); + return ( <>
@@ -130,7 +68,7 @@ const Thread = () => { .sort((a, b) => a.created_at - b.created_at).map((event, index) => ( e.pubkey === event.pubkey && e.kind === 0) || null} replies={countReplies(event)} /> ))} - {OPEvent && e.pubkey === OPEvent.pubkey && e.kind === 0) || null} replies={countReplies(OPEvent)} type={'OP'}/>} + e.pubkey === OPEvent.pubkey && e.kind === 0) || null} replies={countReplies(OPEvent)} type={'OP'}/>
{
}
{/* This is the white line separator */}
- {displayedEvents.map((event, index) => ( + {replyEvents.map((event, index) => ( e.pubkey === event.pubkey && e.kind === 0) || null} - replies={displayedEvents.filter((e) => e.tags.some((tag) => tag[0] === "e" && tag[1] === event.id))} + replies={replyEvents.filter((e) => e.tags.some((tag) => tag[0] === "e" && tag[1] === event.id))} repliedTo={repliedList(event)} /> ))} @@ -190,6 +128,13 @@ const Thread = () => { ); + } + return ( + <> + +
{/* This is the white line separator */} + + ); }; export default Thread; \ No newline at end of file diff --git a/client/src/hooks/useUniqEvents.ts b/client/src/hooks/useFetchEvents.ts similarity index 90% rename from client/src/hooks/useUniqEvents.ts rename to client/src/hooks/useFetchEvents.ts index 5be3a16..eec2708 100644 --- a/client/src/hooks/useUniqEvents.ts +++ b/client/src/hooks/useFetchEvents.ts @@ -1,10 +1,9 @@ import { useState, useEffect } from "react"; -import { subGlobalFeed, subHashtagFeed, subNotifications } from "../utils/subscriptions"; +import { subGlobalFeed, subHashtagFeed, subNote, subNotifications, subNotesOnce} from "../utils/subscriptions"; import { uniqBy } from "../utils/otherUtils"; import { Event } from "nostr-tools"; -import { } from "../utils/subscriptions"; -export const useUniqEvents = (hashtag?: string, notifications?: boolean) => { +export const useFetchEvents = (hashtag?: string, notifications?: boolean, OP_eventID?: string) => { const [events, setEvents] = useState([]); const age = Number(localStorage.getItem("age")) || 24; @@ -45,6 +44,8 @@ export const useUniqEvents = (hashtag?: string, notifications?: boolean) => { if (hashtag) { // Code from the second function unsubscribe = subHashtagFeed(hashtag, onEvent, age); + } else if (OP_eventID) { + unsubscribe = subNote(OP_eventID, onEvent); } else if (notifications) { // Code from the third function let storedKeys = JSON.parse(localStorage.getItem("usedKeys") || "[]"); diff --git a/client/src/utils/subscriptions.ts b/client/src/utils/subscriptions.ts index 92caefd..95456e2 100644 --- a/client/src/utils/subscriptions.ts +++ b/client/src/utils/subscriptions.ts @@ -236,7 +236,6 @@ export const subNotifications = ( onEvent: SubCallback, ) => { unsubAll(); - sub({ cb: (evt, relay) => { onEvent(evt, relay); diff --git a/client/tsconfig.json b/client/tsconfig.json index be6b2ea..af5e998 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -5,7 +5,7 @@ "allowJs": true, "skipLibCheck": true, "strict": true, - "forceConsistentCasingInFileNames": false, + "forceConsistentCasingInFileNames": true, "noEmit": true, "esModuleInterop": true, "module": "esnext",