thread cache

This commit is contained in:
smolgrrr 2024-08-16 20:43:56 +10:00
parent 361187c5b7
commit 6b98269cad
4 changed files with 86 additions and 59 deletions

View File

@ -0,0 +1,63 @@
import { useState } from "react";
import { Event } from "nostr-tools"
import { DocumentTextIcon, FolderPlusIcon, DocumentDuplicateIcon, ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline';
import NewNoteCard from '../forms/PostFormCard';
import RepostNote from '../forms/RepostNote';
type PostType = "" | "Reply" | "Quote" | undefined;
const ThreadPostModal = ({ OPEvent }: { OPEvent: Event }) => {
const [showForm, setShowForm] = useState(false);
const [showRepost, setShowRepost] = useState(false);
const [postType, setPostType] = useState<PostType>("");
return (
<>
<div className="col-span-full flex justify-center space-x-16 pb-4">
<DocumentTextIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowForm(prevShowForm => !prevShowForm);
setPostType('Reply');
setShowRepost(false)
}}
/>
<DocumentDuplicateIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowRepost(prevShowRepost => !prevShowRepost);
setShowForm(false);
}}
/>
<FolderPlusIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowForm(prevShowForm => !prevShowForm);
setPostType('Quote');
setShowRepost(false)
}}
/>
<a href={`nostr:${OPEvent.id}`} target="_blank" rel="noopener noreferrer">
<ArrowTopRightOnSquareIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
/>
</a>
</div>
{(showForm && postType) &&
<div className="w-full px-4 sm:px-0 sm:max-w-xl mx-auto my-2">
<div className='text-center'>
<span >{postType}-post</span>
</div>
<NewNoteCard refEvent={OPEvent} tagType={postType} />
</div>}
{showRepost && OPEvent && <div className="w-full px-4 sm:px-0 sm:max-w-xl mx-auto my-2">
<div className='text-center'>
<span>Repost note</span>
</div>
<RepostNote refEvent={OPEvent} />
</div>}
</>
);
};
export default ThreadPostModal;

View File

@ -8,6 +8,7 @@ import { verifyPow } from "../../utils/mine";
import { uniqBy } from "../../utils/otherUtils"; import { uniqBy } from "../../utils/otherUtils";
import ContentPreview from "./CardModals/TextModal"; import ContentPreview from "./CardModals/TextModal";
import CardContainer from "./CardContainer"; import CardContainer from "./CardContainer";
import { useState, useEffect } from "react";
interface CardProps { interface CardProps {
key?: string | number; key?: string | number;
@ -29,9 +30,16 @@ const PostCard = ({
// const { files } = parseContent(event); // const { files } = parseContent(event);
const icon = getIconFromHash(event.pubkey); const icon = getIconFromHash(event.pubkey);
const metadataParsed = metadata ? getMetadata(metadata) : null; const metadataParsed = metadata ? getMetadata(metadata) : null;
const [relatedEvents, setRelatedEvents] = useState<Event[]>([]);
useEffect(() => {
const allRelatedEvents = [event, ...(replies || [])];
setRelatedEvents(allRelatedEvents);
}, [event, replies]);
const handleClick = () => { const handleClick = () => {
if (type !== "OP") { if (type !== "OP") {
localStorage.setItem("cachedThread", JSON.stringify(relatedEvents));
window.location.href = `/thread/${nip19.noteEncode(event.id)}`; window.location.href = `/thread/${nip19.noteEncode(event.id)}`;
} }
}; };

View File

@ -17,7 +17,7 @@ const Home = () => {
(event.kind !== 1 || !event.tags.some((tag) => tag[0] === "e" || tag[0] === "a")) (event.kind !== 1 || !event.tags.some((tag) => tag[0] === "e" || tag[0] === "a"))
) )
let sortedEvents = [...postEvents] const sortedEvents = postEvents
.sort((a, b) => { .sort((a, b) => {
// Sort by PoW in descending order // Sort by PoW in descending order
const powDiff = verifyPow(b) - verifyPow(a); const powDiff = verifyPow(b) - verifyPow(a);

View File

@ -4,41 +4,39 @@ import { Event, nip19 } from "nostr-tools"
import { subNotesOnce } from '../../utils/subscriptions'; import { subNotesOnce } from '../../utils/subscriptions';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { uniqBy } from '../../utils/otherUtils'; import { uniqBy } from '../../utils/otherUtils';
import { DocumentTextIcon, FolderPlusIcon, DocumentDuplicateIcon, ArrowTopRightOnSquareIcon } from '@heroicons/react/24/outline';
import Placeholder from '../modals/Placeholder'; import Placeholder from '../modals/Placeholder';
import NewNoteCard from '../forms/PostFormCard';
import RepostNote from '../forms/RepostNote';
import PostCard from '../modals/PostCard'; import PostCard from '../modals/PostCard';
import { useFetchEvents } from '../../hooks/useFetchEvents'; import { useFetchEvents } from '../../hooks/useFetchEvents';
import ThreadPostModal from '../forms/ThreadPostModal';
type PostType = "" | "Reply" | "Quote" | undefined;
const Thread = () => { const Thread = () => {
const { id } = useParams(); const { id } = useParams();
const [showForm, setShowForm] = useState(false);
const [showRepost, setShowRepost] = useState(false);
const [postType, setPostType] = useState<PostType>("");
const [prevMentions, setPrevMentions] = useState<Event[]>([]); const [prevMentions, setPrevMentions] = useState<Event[]>([]);
// const filterDifficulty = useState(localStorage.getItem("filterDifficulty") || "20");
let decodeResult = nip19.decode(id as string); let decodeResult = nip19.decode(id as string);
let hexID = decodeResult.data as string; let hexID = decodeResult.data as string;
const { noteEvents, metadataEvents } = useFetchEvents(undefined,false,hexID); const { noteEvents, metadataEvents } = useFetchEvents(undefined,false,hexID);
// Load cached thread from localStorage
const [threadCache, setThreadCache] = useState<Event[]>(
JSON.parse(localStorage.getItem("cachedThread") || "[]")
);
// Combine noteEvents and threadCache into a single array
const allEvents = [...noteEvents, ...threadCache];
const countReplies = (event: Event) => { const countReplies = (event: Event) => {
return noteEvents.filter(e => e.tags.some(tag => tag[0] === 'e' && tag[1] === event.id)); return allEvents.filter(e => e.tags.some(tag => tag[0] === 'e' && tag[1] === event.id));
} }
const repliedList = (event: Event): Event[] => { const repliedList = (event: Event): Event[] => {
return noteEvents.filter(e => event.tags.some(tag => tag[0] === 'p' && tag[1] === e.pubkey)); return allEvents.filter(e => event.tags.some(tag => tag[0] === 'p' && tag[1] === e.pubkey));
} }
// Define your callback function for subGlobalFeed // Define your callback function for subGlobalFeed
const onEvent = (event: Event, relay: string) => { const onEvent = (event: Event) => {
setPrevMentions((prevEvents) => [...prevEvents, event]); setPrevMentions((prevEvents) => [...prevEvents, event]);
}; };
const OPEvent = noteEvents.find(event => event.id === hexID); const OPEvent = allEvents.find(event => event.id === hexID);
useEffect(() => { useEffect(() => {
if (OPEvent && prevMentions.length == 0) { if (OPEvent && prevMentions.length == 0) {
const OPMentionIDs = OPEvent.tags.filter(tag => tag[0] === 'e').map(tag => tag[1]); const OPMentionIDs = OPEvent.tags.filter(tag => tag[0] === 'e').map(tag => tag[1]);
@ -53,7 +51,7 @@ const Thread = () => {
e.created_at < OPEvent.created_at e.created_at < OPEvent.created_at
) )
const replyEvents = [...noteEvents].slice(1) const replyEvents = [...allEvents].slice(1)
.filter(event => .filter(event =>
!earlierEvents.map(e => e.id).includes(event.id) && !earlierEvents.map(e => e.id).includes(event.id) &&
(OPEvent ? OPEvent.id !== event.id : true) (OPEvent ? OPEvent.id !== event.id : true)
@ -70,49 +68,7 @@ const Thread = () => {
))} ))}
<PostCard event={OPEvent} metadata={metadataEvents.find((e) => e.pubkey === OPEvent.pubkey && e.kind === 0) || null} replies={countReplies(OPEvent)} type={'OP'}/> <PostCard event={OPEvent} metadata={metadataEvents.find((e) => e.pubkey === OPEvent.pubkey && e.kind === 0) || null} replies={countReplies(OPEvent)} type={'OP'}/>
</div> </div>
<div className="col-span-full flex justify-center space-x-16 pb-4"> <ThreadPostModal OPEvent={OPEvent} />
<DocumentTextIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowForm(prevShowForm => !prevShowForm);
setPostType('Reply');
setShowRepost(false)
}}
/>
<DocumentDuplicateIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowRepost(prevShowRepost => !prevShowRepost);
setShowForm(false);
}}
/>
<FolderPlusIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
onClick={() => {
setShowForm(prevShowForm => !prevShowForm);
setPostType('Quote');
setShowRepost(false)
}}
/>
<a href={`nostr:${id}`} target="_blank" rel="noopener noreferrer">
<ArrowTopRightOnSquareIcon
className="h-5 w-5 text-gray-200 cursor-pointer"
/>
</a>
</div>
{(showForm && postType) &&
<div className="w-full px-4 sm:px-0 sm:max-w-xl mx-auto my-2">
<div className='text-center'>
<span >{postType}-post</span>
</div>
<NewNoteCard refEvent={OPEvent} tagType={postType}/>
</div>}
{showRepost && OPEvent && <div className="w-full px-4 sm:px-0 sm:max-w-xl mx-auto my-2">
<div className='text-center'>
<span>Repost note</span>
</div>
<RepostNote refEvent={OPEvent}/>
</div>}
<div className="col-span-full h-0.5 bg-neutral-900"/> {/* This is the white line separator */} <div className="col-span-full h-0.5 bg-neutral-900"/> {/* This is the white line separator */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
{replyEvents.map((event, index) => ( {replyEvents.map((event, index) => (