diff --git a/client/src/components/Home.tsx b/client/src/components/Home.tsx index 0967d8d..fbff3fb 100644 --- a/client/src/components/Home.tsx +++ b/client/src/components/Home.tsx @@ -3,48 +3,54 @@ import PostCard from './PostCard/PostCard'; import NewThreadCard from './PostCard/NewThreadCard'; import { getPow } from '../utils/mine'; import { relayInit, Event } from 'nostr-tools'; -import { subGlobalFeed, simpleSub24hFeed } from '../utils/subscriptions'; +import { subGlobalFeed } from '../utils/subscriptions'; import { uniqBy } from '../utils/utils'; const Home = () => { - const [events, setEvents] = useState([]); // Initialize state + const [events, setEvents] = useState([]); - // Define your callback function for subGlobalFeed - const onEvent = (event: Event, relay: string) => { + const onEvent = (event: Event) => { setEvents((prevEvents) => [...prevEvents, event]); - console.log(event.id + ' ' + event.kind + ' ' + event.tags); + console.log(`${event.id} ${event.kind} ${event.tags}`); }; useEffect(() => { - // Subscribe to global feed when the component mounts subGlobalFeed(onEvent); - - // Optionally, return a cleanup function to unsubscribe when the component unmounts - return () => { - // Your cleanup code here - }; - }, []); // Empty dependency array means this useEffect runs once when the component mounts + // If you eventually need a cleanup function, put it here + }, []); const uniqEvents = events.length > 0 ? uniqBy(events, "id") : []; - const filteredEvents1 = uniqEvents.filter(event => getPow(event.id) > 3); - const filteredEvents2 = filteredEvents1.filter(event => event.kind == 1); - const filteredEvents3 = filteredEvents2.filter(event => - !event.tags.some(tag => tag[0] === 'p') - ); - const sortedEvents = filteredEvents3.sort((a, b) => (b.created_at as any) - (a.created_at as any)); + + const filteredAndSortedEvents = uniqEvents + .filter(event => + getPow(event.id) > 3 && + event.kind === 1 && + !event.tags.some(tag => tag[0] === 'p') + ) + .sort((a, b) => (b.created_at as any) - (a.created_at as any)); + + + const getMetadataEvent = (event: Event) => { + const metadataEvent = uniqEvents.find(e => e.pubkey === event.pubkey && e.kind === 0); + if (metadataEvent) { + return metadataEvent; + } + return null; + } + + const countReplies = (event: Event) => { + return uniqEvents.filter(e => e.tags.some(tag => tag[0] === 'e' && tag[1] === event.id)).length; + } return ( - <>
- {sortedEvents.sort((a, b) => b.created_at - a.created_at).map((event, index) => ( - + {filteredAndSortedEvents.map((event, index) => ( + ))}
- {/*
*/} - ); }; diff --git a/client/src/components/PostCard/OPPostCard.tsx b/client/src/components/PostCard/OPPostCard.tsx deleted file mode 100644 index 6763820..0000000 --- a/client/src/components/PostCard/OPPostCard.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import CardContainer from './CardContainer'; -import { FolderIcon } from '@heroicons/react/24/outline'; -import { parseContent } from '../../utils/content'; -import { Event } from 'nostr-tools'; - -const colorCombos = [ - 'from-red-400 to-yellow-500', - 'from-green-400 to-blue-500', - 'from-purple-400 to-pink-500', - 'from-yellow-400 to-orange-500', - 'from-indigo-400 to-purple-500', - 'from-pink-400 to-red-500', - 'from-blue-400 to-indigo-500', - 'from-orange-400 to-red-500', - 'from-teal-400 to-green-500', - 'from-cyan-400 to-teal-500', - 'from-lime-400 to-green-500', - 'from-amber-400 to-orange-500', - 'from-rose-400 to-pink-500', - 'from-violet-400 to-purple-500', - 'from-sky-400 to-cyan-500' -]; - -const getColorFromHash = (id: string, colors: string[]): string => { - // Create a simple hash from the event.id - let hash = 0; - for (let i = 0; i < id.length; i++) { - hash = (hash << 5) - hash + id.charCodeAt(i); - } - - // Use the hash to pick a color from the colors array - const index = Math.abs(hash) % colors.length; - return colors[index]; -}; - -const timeAgo = (unixTime: number) => { - const seconds = Math.floor((new Date().getTime() / 1000) - unixTime); - - if (seconds < 60) return `now`; - - const minutes = Math.floor(seconds / 60); - if (minutes < 60) return `${minutes}m`; - - const hours = Math.floor(minutes / 60); - if (hours < 24) return `${hours}h`; - - const days = Math.floor(hours / 24); - return `${days} days ago`; -}; - -const PostCard = ({ event}: { event: Event }) => { - // Replace 10 with the actual number of comments for each post - const numberOfComments = 10; - - const { comment, file } = parseContent(event); - - // const replyList = await relay.list([ - // { - // kinds: [1], - // limit: 200, - // }, - // ]); - const colorCombo = getColorFromHash(event.pubkey, colorCombos); - - return ( - <> - -
-
-
-
-
Anonymous
-
-
-
{timeAgo(event.created_at)}
- - {numberOfComments} -
-
-
- {comment} -
- {file !== "" && ( -
- -
- )} -
- - - ); -}; - -export default PostCard; \ No newline at end of file diff --git a/client/src/components/PostCard/PostCard.tsx b/client/src/components/PostCard/PostCard.tsx index afaaaed..9359629 100644 --- a/client/src/components/PostCard/PostCard.tsx +++ b/client/src/components/PostCard/PostCard.tsx @@ -3,6 +3,9 @@ import { FolderIcon } from '@heroicons/react/24/outline'; import { parseContent } from '../../utils/content'; import { Event } from 'nostr-tools'; import { nip19 } from 'nostr-tools'; +import { useEffect, useState } from 'react'; +import { subNote } from '../../utils/subscriptions'; +import { getMetadata, uniqBy } from '../../utils/utils'; const colorCombos = [ 'from-red-400 to-yellow-500', @@ -46,23 +49,23 @@ const timeAgo = (unixTime: number) => { if (hours < 24) return `${hours}h`; const days = Math.floor(hours / 24); - return `${days} days ago`; + if (days < 7) return `${days}d`; + + const weeks = Math.floor(days / 7); + return `${weeks}w`; }; -const PostCard = ({ event}: { event: Event }) => { +const PostCard = ({ event, metadata, replyCount }: { event: Event, metadata: Event | null, replyCount: number}) => { // Replace 10 with the actual number of comments for each post const numberOfComments = 10; - const { comment, file } = parseContent(event); - - // const replyList = await relay.list([ - // { - // kinds: [1], - // limit: 200, - // }, - // ]); const colorCombo = getColorFromHash(event.pubkey, colorCombos); + let metadataParsed = null; + if (metadata !== null) { + metadataParsed = getMetadata(metadata); + } + return ( <> @@ -70,13 +73,22 @@ const PostCard = ({ event}: { event: Event }) => {
-
+ {metadataParsed ? + <> + +
{metadataParsed.name}
+ + : + <> +
Anonymous
+ + }
{timeAgo(event.created_at)}
- {numberOfComments} + {replyCount}
diff --git a/client/src/components/Thread/Thread.tsx b/client/src/components/Thread/Thread.tsx index dcb9adc..963ee54 100644 --- a/client/src/components/Thread/Thread.tsx +++ b/client/src/components/Thread/Thread.tsx @@ -5,7 +5,6 @@ import { subNote } from '../../utils/subscriptions'; import { useEffect } from 'react'; import PostCard from '../PostCard/PostCard'; import { uniqBy } from '../../utils/utils'; -import OPPostCard from '../PostCard/OPPostCard'; import { DocumentTextIcon, FolderPlusIcon } from '@heroicons/react/24/outline'; const Thread = () => { @@ -62,14 +61,14 @@ const Thread = () => { <>
- +
{/* This is the white line separator */} - {uniqEvents.sort((a, b) => b.created_at - a.created_at).map((event, index) => ( - + {uniqEvents.slice(1).sort((a, b) => b.created_at - a.created_at).map((event, index) => ( + ))}
diff --git a/client/src/utils/subscriptions.ts b/client/src/utils/subscriptions.ts index cf219c4..d6be2f7 100644 --- a/client/src/utils/subscriptions.ts +++ b/client/src/utils/subscriptions.ts @@ -14,6 +14,7 @@ export const subGlobalFeed = (onEvent: SubCallback) => { const now = Math.floor(Date.now() * 0.001); const pubkeys = new Set(); const notes = new Set(); + const replies = new Set(); const prefix = Math.floor(16 / 4); // 4 bits in each '0' character sub({ // get past events cb: (evt, relay) => { @@ -30,19 +31,19 @@ export const subGlobalFeed = (onEvent: SubCallback) => { unsub: true }); - // New Callback to only add events that pass the PoW requirement - const powFilteredCallback = (evt: Event, relay: string) => { - if (getPow(evt.id) > 2) { // Replace '5' with your actual PoW requirement - pubkeys.add(evt.pubkey); - notes.add(evt.id); - onEvent(evt, relay); - } - }; + // // New Callback to only add events that pass the PoW requirement + // const powFilteredCallback = (evt: Event, relay: string) => { + // if (getPow(evt.id) > 2) { // Replace '5' with your actual PoW requirement + // pubkeys.add(evt.pubkey); + // notes.add(evt.id); + // onEvent(evt, relay); + // } + // }; setTimeout(() => { // get profile info sub({ - cb: powFilteredCallback, + cb: onEvent, filter: { authors: Array.from(pubkeys), kinds: [0], @@ -51,6 +52,16 @@ export const subGlobalFeed = (onEvent: SubCallback) => { unsub: true, }); pubkeys.clear(); + + sub({ + cb: onEvent, + filter: { + '#e': Array.from(notes), + kinds: [1], + }, + unsub: true, + }); + notes.clear(); }, 2000); diff --git a/client/src/utils/utils.ts b/client/src/utils/utils.ts index d2a7fc5..f85f308 100644 --- a/client/src/utils/utils.ts +++ b/client/src/utils/utils.ts @@ -1,3 +1,5 @@ +import { Event } from "nostr-tools" + export const uniqBy = (arr: T[], key: keyof T): T[] => { return Object.values( arr.reduce( @@ -10,12 +12,30 @@ export const uniqBy = (arr: T[], key: keyof T): T[] => { ) } - export const uniqValues = (value: string, index: number, self: string[]) => { - return self.indexOf(value) === index - } - - export const dateToUnix = (_date?: Date) => { - const date = _date || new Date() - - return Math.floor(date.getTime() / 1000) - } \ No newline at end of file +export const uniqValues = (value: string, index: number, self: string[]) => { + return self.indexOf(value) === index +} + +export const dateToUnix = (_date?: Date) => { + const date = _date || new Date() + + return Math.floor(date.getTime() / 1000) +} + +export interface Metadata { + name?: string + username?: string + display_name?: string + picture?: string + banner?: string + about?: string + website?: string + lud06?: string + lud16?: string + nip05?: string +} + +export const getMetadata = (event: Event) => { + const metadata: Metadata = JSON.parse(event.content) + return metadata +} \ No newline at end of file