mirror of
https://github.com/smolgrrr/TAO.git
synced 2024-09-20 01:11:25 +00:00
thread cache
This commit is contained in:
parent
361187c5b7
commit
6b98269cad
63
client/src/components/forms/ThreadPostModal.tsx
Normal file
63
client/src/components/forms/ThreadPostModal.tsx
Normal 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;
|
@ -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)}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -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);
|
||||||
|
@ -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) => (
|
||||||
|
Loading…
Reference in New Issue
Block a user