diff --git a/client/src/components/Home.tsx b/client/src/components/Home.tsx index bec1bcf..f4771e6 100644 --- a/client/src/components/Home.tsx +++ b/client/src/components/Home.tsx @@ -1,72 +1,48 @@ import { useEffect, useState } from "react"; import PostCard from "./PostCard/PostCard"; import NewThreadCard from "./PostCard/NewThreadCard"; -import { getPow } from "../utils/mine"; -import { Event } from "nostr-tools"; +import { uniqBy } from "../utils/utils"; // Assume getPow is a correct import now import { subGlobalFeed } from "../utils/subscriptions"; -import { uniqBy } from "../utils/utils"; -// import PWAInstallPopup from "./Modals/PWACheckModal"; // Removed as it's not being used +import { verifyPow } from "../utils/mine"; +import { Event } from "nostr-tools"; -const Home = () => { - // State declarations +const useUniqEvents = () => { const [events, setEvents] = useState([]); - const [filterDifficulty, setFilterDifficulty] = useState(localStorage.getItem("filterDifficulty") || "20"); - const [sortByTime, setSortByTime] = useState(true); - // const [inBrowser, setInBrowser] = useState(false); // Removed as it's not being used - - // Function to handle new events - const onEvent = (event: Event) => { - setEvents((prevEvents) => [...prevEvents, event]); - }; useEffect(() => { - // Subscribe to the global feed - subGlobalFeed(onEvent); + const onEvent = (event: Event) => setEvents((prevEvents) => [...prevEvents, event]); + const unsubscribe = subGlobalFeed(onEvent); - // Event listener to handle difficulty changes - const handleDifficultyChange = (event: any) => { - const { filterDifficulty } = event.detail; - setFilterDifficulty(filterDifficulty); - }; - - // Attach event listener - window.addEventListener("difficultyChanged", handleDifficultyChange); - - // Cleanup listener on component unmount - return () => { - window.removeEventListener("difficultyChanged", handleDifficultyChange); - }; + return unsubscribe; }, []); - // Get unique events based on id - const uniqEvents = events.length > 0 ? uniqBy(events, "id") : []; + return uniqBy(events, "id"); +}; - // Filter and sort events - const filteredEvents = uniqEvents +const Home = () => { + const filterDifficulty = localStorage.getItem("filterDifficulty") || 20; + const [sortByTime, setSortByTime] = useState(true); + const uniqEvents = useUniqEvents(); + + const postEvents = uniqEvents .filter((event) => - getPow(event.id) > Number(filterDifficulty) && + verifyPow(event) >= Number(filterDifficulty) && event.kind === 1 && !event.tags.some((tag) => tag[0] === "e") ) + const sortedEvents = [...postEvents].sort((a, b) => + sortByTime ? b.created_at - a.created_at : verifyPow(b) - verifyPow(a) + ); + const toggleSort = () => { setSortByTime(prev => !prev); }; - // Events sorted by time - const eventsSortedByTime = [...filteredEvents].sort((a, b) => b.created_at - a.created_at); - - // Events sorted by PoW (assuming `getPow` returns a numerical representation of the PoW) - const eventsSortedByPow = [...filteredEvents].sort((a, b) => getPow(b.id) - getPow(a.id)); - - const displayedEvents = sortByTime ? eventsSortedByTime : eventsSortedByPow; - - // Get metadata for an event const getMetadataEvent = (event: Event) => { return uniqEvents.find((e) => e.pubkey === event.pubkey && e.kind === 0) || null; }; - // Count replies for an event const countReplies = (event: Event) => { return uniqEvents.filter((e) => e.tags.some((tag) => tag[0] === "e" && tag[1] === event.id)).length; }; @@ -88,10 +64,7 @@ const Home = () => { onChange={toggleSort} />
-
+
{sortByTime ? 'Sort by recent' : 'Sort by PoW'} @@ -99,7 +72,7 @@ const Home = () => {
- {displayedEvents.map((event) => ( + {sortedEvents.map((event) => ( void; -} - -const PWAInstallPopup: React.FC = ({ onClose }) => { - - return ( -
-
-

Install Our PWA

-

Click "Install" to add this app to your home screen and enjoy a full-screen experience!

- -
-
- ); -}; - -export default PWAInstallPopup; diff --git a/client/src/components/PostCard/PostCard.tsx b/client/src/components/PostCard/PostCard.tsx index 0add60c..afdb2aa 100644 --- a/client/src/components/PostCard/PostCard.tsx +++ b/client/src/components/PostCard/PostCard.tsx @@ -1,12 +1,12 @@ import CardContainer from "./CardContainer"; -import { FolderIcon } from "@heroicons/react/24/outline"; +import { FolderIcon, CpuChipIcon } from "@heroicons/react/24/outline"; import { parseContent } from "../../utils/content"; -import { Event } from "nostr-tools"; -import { nip19 } from "nostr-tools"; +import { Event, nip19 } from "nostr-tools"; import { getMetadata } from "../../utils/utils"; import ContentPreview from "../Modals/TextModal"; import { renderMedia } from "../../utils/FileUpload"; import { getIconFromHash } from "../../utils/deterministicProfileIcon"; +import { verifyPow } from "../../utils/mine"; const timeAgo = (unixTime: number) => { const seconds = Math.floor(new Date().getTime() / 1000 - unixTime); @@ -74,15 +74,15 @@ const PostCard = ({ )}
-
- {event.id.match(/^0*([^\0]{2})/)?.[0] || 0} +
+ {verifyPow(event)}
·
{timeAgo(event.created_at)}
· -
+
{replyCount}
diff --git a/client/src/utils/mine.ts b/client/src/utils/mine.ts index e4c544b..1746559 100644 --- a/client/src/utils/mine.ts +++ b/client/src/utils/mine.ts @@ -49,4 +49,20 @@ export function minePow(unsigned: UnsignedEvent, difficulty } return event +} + +/** Verify POW difficulty for a NOSTR event. */ +export function verifyPow(event: Event): number { + const hash = getEventHash(event) + const count = getPow(hash) + + // Extract the target difficulty level from the tags + const nonceTag = event.tags.find(tag => tag[0] === 'nonce'); + if (!nonceTag || nonceTag.length < 3) { + return 0 // Without specifying target difficulty, there is no PROOF of work + } + const targetDifficulty = parseInt(nonceTag[2], 10); + + // The proof-of-work is the minimum of actual hash result and target + return Math.min(count, targetDifficulty) } \ No newline at end of file