diff --git a/package.json b/package.json index f8e607ea..698f9b6b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@radix-ui/react-popover": "^1.0.5", "@radix-ui/react-tabs": "^1.0.3", "@supabase/supabase-js": "^2.12.1", + "@tanstack/query-core": "^4.27.0", "@tanstack/react-virtual": "3.0.0-beta.54", "@tauri-apps/api": "^1.2.0", "@uiw/react-markdown-preview": "^4.1.10", @@ -29,6 +30,7 @@ "framer-motion": "^9.1.7", "jotai": "^2.0.3", "jotai-cache": "^0.3.0", + "jotai-tanstack-query": "^0.6.0", "next": "^13.2.4", "next-remove-imports": "^1.0.10", "nostr-relaypool": "^0.5.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f8fa932c..34e47510 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,7 @@ specifiers: '@radix-ui/react-tabs': ^1.0.3 '@supabase/supabase-js': ^2.12.1 '@tailwindcss/typography': ^0.5.9 + '@tanstack/query-core': ^4.27.0 '@tanstack/react-virtual': 3.0.0-beta.54 '@tauri-apps/api': ^1.2.0 '@tauri-apps/cli': ^1.2.3 @@ -34,6 +35,7 @@ specifiers: husky: ^8.0.3 jotai: ^2.0.3 jotai-cache: ^0.3.0 + jotai-tanstack-query: ^0.6.0 lint-staged: ^13.2.0 next: ^13.2.4 next-remove-imports: ^1.0.10 @@ -63,6 +65,7 @@ dependencies: '@radix-ui/react-popover': 1.0.5_zula6vjvt3wdocc4mwcxqa6nzi '@radix-ui/react-tabs': 1.0.3_biqbaboplfbrettd7655fr4n2y '@supabase/supabase-js': 2.12.1 + '@tanstack/query-core': 4.27.0 '@tanstack/react-virtual': 3.0.0-beta.54_react@18.2.0 '@tauri-apps/api': 1.2.0 '@uiw/react-markdown-preview': 4.1.10_zula6vjvt3wdocc4mwcxqa6nzi @@ -73,6 +76,7 @@ dependencies: framer-motion: 9.1.7_biqbaboplfbrettd7655fr4n2y jotai: 2.0.3_react@18.2.0 jotai-cache: 0.3.0_jotai@2.0.3 + jotai-tanstack-query: 0.6.0_jqgumvl52k2nlr5n23qdneaa6y next: 13.2.4_biqbaboplfbrettd7655fr4n2y next-remove-imports: 1.0.10 nostr-relaypool: 0.5.18_ws@8.13.0 @@ -1286,6 +1290,11 @@ packages: tailwindcss: 3.2.7_postcss@8.4.21 dev: true + /@tanstack/query-core/4.27.0: + resolution: + { integrity: sha512-sm+QncWaPmM73IPwFlmWSKPqjdTXZeFf/7aEmWh00z7yl2FjqophPt0dE1EHW9P1giMC5rMviv7OUbSDmWzXXA== } + dev: false + /@tanstack/react-virtual/3.0.0-beta.54_react@18.2.0: resolution: { integrity: sha512-D1mDMf4UPbrtHRZZriCly5bXTBMhylslm4dhcHqTtDJ6brQcgGmk8YD9JdWBGWfGSWPKoh2x1H3e7eh+hgPXtQ== } @@ -3829,6 +3838,17 @@ packages: jotai: 2.0.3_react@18.2.0 dev: false + /jotai-tanstack-query/0.6.0_jqgumvl52k2nlr5n23qdneaa6y: + resolution: + { integrity: sha512-87oD6MnjrgfLWeCJXB/dQt4xyCmyFYZeG9jw4Y2lIprtwLKS5s/vCEjNP5fnYG2nuPBkopiRECTEqtIysvHSxg== } + peerDependencies: + '@tanstack/query-core': '*' + jotai: '>=1.11.0' + dependencies: + '@tanstack/query-core': 4.27.0 + jotai: 2.0.3_react@18.2.0 + dev: false + /jotai/2.0.3_react@18.2.0: resolution: { integrity: sha512-MMjhSPAL3RoeZD9WbObufRT2quThEAEknHHridf2ma8Ml7ZVQmUiHk0ssdbR3F0h3kcwhYqSGJ59OjhPge7RRg== } diff --git a/src/components/columns/account/active.tsx b/src/components/columns/account/active.tsx index 7daa181b..dff9e4ea 100644 --- a/src/components/columns/account/active.tsx +++ b/src/components/columns/account/active.tsx @@ -3,18 +3,18 @@ import { RelayContext } from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; import { createFollows } from '@utils/storage'; -import { tagsToArray } from '@utils/tags'; +import { tagsToArray } from '@utils/transform'; import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { AvatarIcon, ExitIcon, GearIcon } from '@radix-ui/react-icons'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { memo, useContext, useEffect } from 'react'; export const ActiveAccount = memo(function ActiveAccount({ user }: { user: any }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const router = useRouter(); const userData = JSON.parse(user.metadata); diff --git a/src/components/note/connector.tsx b/src/components/note/connector.tsx index d725f155..1edcb83f 100644 --- a/src/components/note/connector.tsx +++ b/src/components/note/connector.tsx @@ -6,29 +6,28 @@ import { relaysAtom } from '@stores/relays'; import { dateToUnix, hoursAgo } from '@utils/getDate'; import { createCacheNote, getAllFollowsByID } from '@utils/storage'; +import { pubkeyArray } from '@utils/transform'; -import { useAtom, useSetAtom } from 'jotai'; +import { useAtom, useAtomValue, useSetAtom } from 'jotai'; import { memo, useContext, useEffect, useRef, useState } from 'react'; export const NoteConnector = memo(function NoteConnector() { const pool: any = useContext(RelayContext); const setHasNewerNote = useSetAtom(hasNewerNoteAtom); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); const [isOnline] = useState(true); const now = useRef(new Date()); useEffect(() => { - let unsubscribe; - getAllFollowsByID(activeAccount.id).then((follows) => { - unsubscribe = pool.subscribe( + pool.subscribe( [ { kinds: [1], - authors: follows, + authors: pubkeyArray(follows), since: dateToUnix(hoursAgo(12, now.current)), }, ], @@ -43,10 +42,6 @@ export const NoteConnector = memo(function NoteConnector() { } ); }); - - return () => { - unsubscribe(); - }; }, [activeAccount.id, pool, relays, setHasNewerNote]); return ( diff --git a/src/components/note/content/index.tsx b/src/components/note/content/index.tsx index bc1b75a8..090c109e 100644 --- a/src/components/note/content/index.tsx +++ b/src/components/note/content/index.tsx @@ -8,7 +8,7 @@ import destr from 'destr'; import { memo, useMemo } from 'react'; import reactStringReplace from 'react-string-replace'; -export const Content = memo(function Content({ data }: { data: any }) { +export const NoteContent = memo(function NoteContent({ data }: { data: any }) { const content = useMemo(() => { let parsedContent; // get data tags @@ -33,7 +33,7 @@ export const Content = memo(function Content({ data }: { data: any }) { if (tags[match][0] === 'p') { return ; } else if (tags[match][0] === 'e') { - return ; + return ; } }); } diff --git a/src/components/note/content/metadata.tsx b/src/components/note/content/metadata.tsx index 5a110239..f991dba5 100644 --- a/src/components/note/content/metadata.tsx +++ b/src/components/note/content/metadata.tsx @@ -4,7 +4,7 @@ import { RelayContext } from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import { useContext, useEffect, useState } from 'react'; export default function NoteMetadata({ @@ -19,7 +19,7 @@ export default function NoteMetadata({ eventContent: any; }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [likes, setLikes] = useState(0); const [comments, setComments] = useState(0); diff --git a/src/components/note/counter/comments.tsx b/src/components/note/counter/comments.tsx index 1deeb615..819de01c 100644 --- a/src/components/note/counter/comments.tsx +++ b/src/components/note/counter/comments.tsx @@ -11,7 +11,7 @@ import CommentIcon from '@assets/icons/comment'; import * as Dialog from '@radix-ui/react-dialog'; import { SizeIcon } from '@radix-ui/react-icons'; -import { useAtom } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import { useRouter } from 'next/router'; import { getEventHash, signEvent } from 'nostr-tools'; import { memo, useContext, useState } from 'react'; @@ -32,7 +32,7 @@ export const CommentsCounter = memo(function CommentsCounter({ const router = useRouter(); const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); const [open, setOpen] = useState(false); diff --git a/src/components/note/counter/likes.tsx b/src/components/note/counter/likes.tsx index 37ee6dc1..eb1ccccd 100644 --- a/src/components/note/counter/likes.tsx +++ b/src/components/note/counter/likes.tsx @@ -8,7 +8,7 @@ import { dateToUnix } from '@utils/getDate'; import LikeIcon from '@assets/icons/like'; import LikedIcon from '@assets/icons/liked'; -import { useAtom } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import { getEventHash, signEvent } from 'nostr-tools'; import { memo, useContext, useEffect, useState } from 'react'; @@ -23,7 +23,7 @@ export const LikesCounter = memo(function LikesCounter({ }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); const [isReact, setIsReact] = useState(false); diff --git a/src/components/note/form/basic.tsx b/src/components/note/form/basic.tsx index d10d47aa..a44a49ae 100644 --- a/src/components/note/form/basic.tsx +++ b/src/components/note/form/basic.tsx @@ -8,7 +8,7 @@ import { dateToUnix } from '@utils/getDate'; import * as Dialog from '@radix-ui/react-dialog'; import { SizeIcon } from '@radix-ui/react-icons'; import * as commands from '@uiw/react-md-editor/lib/commands'; -import { useAtom } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import dynamic from 'next/dynamic'; import { getEventHash, signEvent } from 'nostr-tools'; import { useContext, useState } from 'react'; @@ -20,7 +20,7 @@ const MDEditor = dynamic(() => import('@uiw/react-md-editor').then((mod) => mod. export default function FormBasic() { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); const [open, setOpen] = useState(false); diff --git a/src/components/note/form/comment.tsx b/src/components/note/form/comment.tsx index 91a60c2b..5c54b4fd 100644 --- a/src/components/note/form/comment.tsx +++ b/src/components/note/form/comment.tsx @@ -6,14 +6,14 @@ import { relaysAtom } from '@stores/relays'; import { dateToUnix } from '@utils/getDate'; -import { useAtom } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import { getEventHash, signEvent } from 'nostr-tools'; import { useContext, useState } from 'react'; export default function FormComment({ eventID }: { eventID: any }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [activeAccount] = useAtom(activeAccountAtom); const [value, setValue] = useState(''); diff --git a/src/components/note/index.tsx b/src/components/note/index.tsx index 9ebabe9c..25ef9983 100644 --- a/src/components/note/index.tsx +++ b/src/components/note/index.tsx @@ -1,16 +1,16 @@ -import { Content } from '@components/note/content'; +import { NoteContent } from '@components/note/content'; import { RootNote } from '@components/note/root'; import destr from 'destr'; import { useRouter } from 'next/router'; -import { memo, useMemo, useRef } from 'react'; +import { memo, useCallback, useRef } from 'react'; export const Note = memo(function Note({ event }: { event: any }) { const router = useRouter(); const tags = destr(event.tags); const rootEventID = useRef(null); - const fetchRootEvent = useMemo(() => { + const fetchRootEvent = useCallback(() => { if (tags.length > 0) { if (tags[0][0] === 'e' || tags[0][2] === 'root') { rootEventID.current = tags[0][1]; @@ -43,8 +43,8 @@ export const Note = memo(function Note({ event }: { event: any }) { onClick={(e) => openThread(e)} className="relative z-10 flex h-min min-h-min w-full select-text flex-col border-b border-zinc-800 py-5 px-3 hover:bg-black/20" > - <>{fetchRootEvent} - +
{fetchRootEvent()}
+ ); }); diff --git a/src/components/note/mention.tsx b/src/components/note/mention.tsx index 29df6b14..4ab3cf5e 100644 --- a/src/components/note/mention.tsx +++ b/src/components/note/mention.tsx @@ -5,13 +5,13 @@ import { relaysAtom } from '@stores/relays'; import { createCacheNote, getNoteByID } from '@utils/storage'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import { memo, useCallback, useContext, useEffect, useState } from 'react'; export const MentionNote = memo(function MentionNote({ id }: { id: string }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [event, setEvent] = useState(null); const fetchEvent = useCallback(() => { diff --git a/src/components/note/root.tsx b/src/components/note/root.tsx index ec4750f4..7244f00a 100644 --- a/src/components/note/root.tsx +++ b/src/components/note/root.tsx @@ -1,17 +1,17 @@ -import { Content } from '@components/note/content'; +import { NoteContent } from '@components/note/content'; import { RelayContext } from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; import { createCacheNote, getNoteByID } from '@utils/storage'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import { memo, useCallback, useContext, useEffect, useState } from 'react'; export const RootNote = memo(function RootNote({ id }: { id: string }) { const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [event, setEvent] = useState(null); const fetchEvent = useCallback(() => { @@ -51,7 +51,7 @@ export const RootNote = memo(function RootNote({ id }: { id: string }) { return (
- +
); } else { diff --git a/src/components/profile/followers.tsx b/src/components/profile/followers.tsx index febb62c7..31d3945a 100644 --- a/src/components/profile/followers.tsx +++ b/src/components/profile/followers.tsx @@ -1,20 +1,22 @@ -import { RelayContext } from '@components/contexts/relay'; +import { RelayContext } from '@components/relaysProvider'; + +import { relaysAtom } from '@stores/relays'; -import useLocalStorage from '@rehooks/local-storage'; import destr from 'destr'; +import { useAtomValue } from 'jotai'; import { Author } from 'nostr-relaypool'; import { useContext, useEffect, useState } from 'react'; export default function ProfileFollowers({ id }: { id: string }) { - const relayPool: any = useContext(RelayContext); - const [relays]: any = useLocalStorage('relays'); + const pool: any = useContext(RelayContext); + const relays: any = useAtomValue(relaysAtom); const [followers, setFollowers] = useState(null); useEffect(() => { - const user = new Author(relayPool, relays, id); + const user = new Author(pool, relays, id); user.followers((res) => setFollowers(destr(res.tags)), 0, 100); - }, [id, relayPool, relays]); + }, [id, pool, relays]); return (
diff --git a/src/components/profile/follows.tsx b/src/components/profile/follows.tsx index 9ba8b4ed..38faa255 100644 --- a/src/components/profile/follows.tsx +++ b/src/components/profile/follows.tsx @@ -1,19 +1,21 @@ -import { RelayContext } from '@components/contexts/relay'; +import { RelayContext } from '@components/relaysProvider'; -import useLocalStorage from '@rehooks/local-storage'; +import { relaysAtom } from '@stores/relays'; + +import { useAtomValue } from 'jotai'; import { Author } from 'nostr-relaypool'; import { useContext, useEffect, useState } from 'react'; export default function ProfileFollows({ id }: { id: string }) { - const relayPool: any = useContext(RelayContext); - const [relays]: any = useLocalStorage('relays'); + const pool: any = useContext(RelayContext); + const relays: any = useAtomValue(relaysAtom); const [follows, setFollows] = useState(null); useEffect(() => { - const user = new Author(relayPool, relays, id); + const user = new Author(pool, relays, id); user.follows((res) => setFollows(res), 0); - }, [id, relayPool, relays]); + }, [id, pool, relays]); return (
diff --git a/src/components/profile/metadata.tsx b/src/components/profile/metadata.tsx index 8b3b3cdc..60be0da9 100644 --- a/src/components/profile/metadata.tsx +++ b/src/components/profile/metadata.tsx @@ -1,11 +1,13 @@ -import { RelayContext } from '@components/contexts/relay'; import { ImageWithFallback } from '@components/imageWithFallback'; +import { RelayContext } from '@components/relaysProvider'; + +import { relaysAtom } from '@stores/relays'; import { truncate } from '@utils/truncate'; -import useLocalStorage from '@rehooks/local-storage'; import Avatar from 'boring-avatars'; import destr from 'destr'; +import { useAtomValue } from 'jotai'; import Image from 'next/image'; import { Author } from 'nostr-relaypool'; import { useContext, useEffect, useState } from 'react'; @@ -13,15 +15,15 @@ import { useContext, useEffect, useState } from 'react'; const DEFAULT_BANNER = 'https://bafybeiacwit7hjmdefqggxqtgh6ht5dhth7ndptwn2msl5kpkodudsr7py.ipfs.w3s.link/banner-1.jpg'; export default function ProfileMetadata({ id }: { id: string }) { - const relayPool: any = useContext(RelayContext); - const [relays]: any = useLocalStorage('relays'); + const pool: any = useContext(RelayContext); + const relays: any = useAtomValue(relaysAtom); const [profile, setProfile] = useState(null); useEffect(() => { - const user = new Author(relayPool, relays, id); + const user = new Author(pool, relays, id); user.metaData((res) => setProfile(destr(res.content)), 0); - }, [id, relayPool, relays]); + }, [id, pool, relays]); return ( <> diff --git a/src/components/profile/notes.tsx b/src/components/profile/notes.tsx index f3f9c979..1edb8d3f 100644 --- a/src/components/profile/notes.tsx +++ b/src/components/profile/notes.tsx @@ -1,20 +1,22 @@ -import { RelayContext } from '@components/contexts/relay'; import { Content } from '@components/note/content'; +import { RelayContext } from '@components/relaysProvider'; -import useLocalStorage from '@rehooks/local-storage'; +import { relaysAtom } from '@stores/relays'; + +import { useAtomValue } from 'jotai'; import { Author } from 'nostr-relaypool'; import { useContext, useEffect, useState } from 'react'; export default function ProfileNotes({ id }: { id: string }) { - const relayPool: any = useContext(RelayContext); - const [relays]: any = useLocalStorage('relays'); + const pool: any = useContext(RelayContext); + const relays: any = useAtomValue(relaysAtom); const [data, setData] = useState([]); useEffect(() => { - const user = new Author(relayPool, relays, id); + const user = new Author(pool, relays, id); user.text((res) => setData((data) => [...data, res]), 0, 100); - }, [id, relayPool, relays]); + }, [id, pool, relays]); return (
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index cac8697f..8af6cb7d 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -2,7 +2,7 @@ import RelayProvider from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; -import { Provider, useAtom } from 'jotai'; +import { Provider, useAtomValue } from 'jotai'; import type { NextPage } from 'next'; import type { AppProps } from 'next/app'; import { ReactElement, ReactNode } from 'react'; @@ -21,7 +21,7 @@ type AppPropsWithLayout = AppProps & { export default function MyApp({ Component, pageProps }: AppPropsWithLayout) { // Use the layout defined at the page level, if available const getLayout = Component.getLayout ?? ((page) => page); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); return ( diff --git a/src/pages/index.tsx b/src/pages/index.tsx index a88903d7..6149c8df 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -14,7 +14,7 @@ export default function Page() { getAccounts() .then((res: any) => { if (res.length > 0) { - router.push('/newsfeed/circle'); + router.push('/newsfeed/following'); } else { router.push('/onboarding'); } diff --git a/src/pages/newsfeed/[id].tsx b/src/pages/newsfeed/[id].tsx index b6d7ce27..caa7d991 100644 --- a/src/pages/newsfeed/[id].tsx +++ b/src/pages/newsfeed/[id].tsx @@ -6,9 +6,11 @@ import { ContentExtend } from '@components/note/content/extend'; import FormComment from '@components/note/form/comment'; import { RelayContext } from '@components/relaysProvider'; +import { relaysAtom } from '@stores/relays'; + import { getNoteByID } from '@utils/storage'; -import useLocalStorage from '@rehooks/local-storage'; +import { useAtomValue } from 'jotai'; import { useRouter } from 'next/router'; import { JSXElementConstructor, @@ -26,7 +28,7 @@ export default function Page() { const router = useRouter(); const id = router.query.id; - const [relays]: any = useLocalStorage('relays'); + const relays: any = useAtomValue(relaysAtom); const [rootEvent, setRootEvent] = useState(null); const [comments, setComments] = useState([]); diff --git a/src/pages/newsfeed/circle.tsx b/src/pages/newsfeed/circle.tsx index 1f7d6c53..f37272fc 100644 --- a/src/pages/newsfeed/circle.tsx +++ b/src/pages/newsfeed/circle.tsx @@ -1,43 +1,10 @@ import BaseLayout from '@layouts/base'; import WithSidebarLayout from '@layouts/withSidebar'; -import { Note } from '@components/note'; - -import { notesAtom } from '@stores/note'; - -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useAtom } from 'jotai'; -import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useRef } from 'react'; +import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal } from 'react'; export default function Page() { - const [data]: any = useAtom(notesAtom); - - const parentRef = useRef(null); - - const virtualizer = useVirtualizer({ - count: data.length, - overscan: 5, - estimateSize: () => 600, - getScrollElement: () => parentRef.current, - getItemKey: (index) => data[index].id, - }); - const items = virtualizer.getVirtualItems(); - - return ( -
- {items.length > 0 && ( -
-
- {items.map((virtualRow) => ( -
- -
- ))} -
-
- )} -
- ); + return <>; } Page.getLayout = function getLayout( diff --git a/src/pages/newsfeed/following.tsx b/src/pages/newsfeed/following.tsx index 84b7e3db..cacc1d0d 100644 --- a/src/pages/newsfeed/following.tsx +++ b/src/pages/newsfeed/following.tsx @@ -1,132 +1,64 @@ import BaseLayout from '@layouts/base'; import WithSidebarLayout from '@layouts/withSidebar'; -import { DatabaseContext } from '@components/contexts/database'; import { Note } from '@components/note'; import FormBasic from '@components/note/form/basic'; -import { Placeholder } from '@components/note/placeholder'; -import { hasNewerNoteAtom } from '@stores/note'; - -import { dateToUnix } from '@utils/getDate'; +import { hasNewerNoteAtom, notesAtom } from '@stores/note'; +import { useVirtualizer } from '@tanstack/react-virtual'; import { useAtom } from 'jotai'; -import { Key, useCallback, useState } from 'react'; -import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useContext, useEffect, useRef } from 'react'; -import { Virtuoso } from 'react-virtuoso'; +import { JSXElementConstructor, ReactElement, ReactFragment, ReactPortal, useRef } from 'react'; export default function Page() { - const { db }: any = useContext(DatabaseContext); - - const [data, setData] = useState([]); - const [reload, setReload] = useState(false); + const [data]: any = useAtom(notesAtom); const [hasNewerNote, setHasNewerNote] = useAtom(hasNewerNoteAtom); - const now = useRef(new Date()); - const limit = useRef(30); - const offset = useRef(0); + const parentRef = useRef(null); - const loadMore = useCallback(async () => { - offset.current += limit.current; - // next query - const result = await db.select( - `SELECT * FROM - cache_notes - WHERE created_at <= ${dateToUnix(now.current)} AND is_root = 0 - ORDER BY created_at DESC - LIMIT ${limit.current} OFFSET ${offset.current}` - ); - setData((data) => [...data, ...result]); - }, [db]); + const virtualizer = useVirtualizer({ + count: data.length, + overscan: 5, + estimateSize: () => 600, + getScrollElement: () => parentRef.current, + getItemKey: (index) => data[index].id, + }); + const items = virtualizer.getVirtualItems(); - const loadNewest = useCallback(async () => { - const result = await db.select( - `SELECT * FROM - cache_notes - WHERE created_at > ${dateToUnix(now.current)} AND is_root = 0 - ORDER BY created_at DESC - LIMIT ${limit.current}` - ); - // update data - setData((data) => [...result, ...data]); - // update hasNewerNote to false to disable button - setHasNewerNote(false); - // update current time, fixed duplicate note - now.current = new Date(); - }, [db, setHasNewerNote]); - - const ItemContent = useCallback( - (index: Key) => { - const event = data[index]; - return ; - }, - [data] - ); - - const computeItemKey = useCallback( - (index: Key) => { - return data[index].id + data[index].created_at; - }, - [data] - ); - - useEffect(() => { - const getData = async () => { - const result = await db.select( - `SELECT * FROM cache_notes WHERE is_root = 0 ORDER BY created_at DESC LIMIT ${limit.current}` - ); - if (result.length > 0) { - setData(result); - } else { - setReload(true); - } - }; - - if (reload === false) { - getData().catch(console.error); - } else { - // auto reload after 8s - const timer = setTimeout(() => { - getData().catch(console.error); - }, 8000); - - return () => clearTimeout(timer); - } - }, [db, reload]); + const loadNewest = () => { + console.log('load'); + }; return ( -
- {hasNewerNote && ( -
- -
- )} - , - EmptyPlaceholder: () => , - ScrollSeekPlaceholder: () => , - }} - computeItemKey={computeItemKey} - scrollSeekConfiguration={{ - enter: (velocity) => Math.abs(velocity) > 800, - exit: (velocity) => Math.abs(velocity) < 500, - }} - endReached={loadMore} - overscan={800} - increaseViewportBy={1000} - className="scrollbar-hide relative h-full w-full" - style={{ - contain: 'strict', - }} - /> +
+
+ {hasNewerNote && ( +
+ +
+ )} +
+
+ +
+
+ {items.length > 0 && ( +
+
+ {items.map((virtualRow) => ( +
+ +
+ ))} +
+
+ )} +
); } diff --git a/src/pages/onboarding/create/index.tsx b/src/pages/onboarding/create/index.tsx index 3dfbf87e..105f049b 100644 --- a/src/pages/onboarding/create/index.tsx +++ b/src/pages/onboarding/create/index.tsx @@ -7,7 +7,7 @@ import { relaysAtom } from '@stores/relays'; import { createAccount } from '@utils/storage'; import { EyeClosedIcon, EyeOpenIcon } from '@radix-ui/react-icons'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools'; @@ -22,7 +22,7 @@ export default function Page() { const router = useRouter(); const pool: any = useContext(RelayContext); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [type, setType] = useState('password'); const [loading, setLoading] = useState(false); diff --git a/src/pages/onboarding/create/step-2.tsx b/src/pages/onboarding/create/step-2.tsx index c2db11e1..5284c11c 100644 --- a/src/pages/onboarding/create/step-2.tsx +++ b/src/pages/onboarding/create/step-2.tsx @@ -9,7 +9,7 @@ import { createFollows } from '@utils/storage'; import { CheckCircledIcon } from '@radix-ui/react-icons'; import { createClient } from '@supabase/supabase-js'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import { useRouter } from 'next/router'; import { getEventHash, signEvent } from 'nostr-tools'; import { @@ -69,7 +69,7 @@ export default function Page() { const router = useRouter(); const { id, privkey }: any = router.query; - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [loading, setLoading] = useState(false); const [list, setList]: any = useState(initialList); const [follows, setFollows] = useState([]); diff --git a/src/pages/onboarding/login/step-2.tsx b/src/pages/onboarding/login/step-2.tsx index 9cf8c857..55826fa9 100644 --- a/src/pages/onboarding/login/step-2.tsx +++ b/src/pages/onboarding/login/step-2.tsx @@ -5,11 +5,11 @@ import { RelayContext } from '@components/relaysProvider'; import { relaysAtom } from '@stores/relays'; import { createAccount, createFollows } from '@utils/storage'; -import { tagsToArray } from '@utils/tags'; +import { tagsToArray } from '@utils/transform'; import { truncate } from '@utils/truncate'; import destr from 'destr'; -import { useAtom } from 'jotai'; +import { useAtomValue } from 'jotai'; import Image from 'next/image'; import { useRouter } from 'next/router'; import { getPublicKey, nip19 } from 'nostr-tools'; @@ -30,7 +30,7 @@ export default function Page() { const privkey: any = router.query.privkey; const pubkey = getPublicKey(privkey); - const [relays] = useAtom(relaysAtom); + const relays = useAtomValue(relaysAtom); const [profile, setProfile] = useState(null); useEffect(() => { diff --git a/src/stores/note.tsx b/src/stores/note.tsx index 05e8bf90..dc68f651 100644 --- a/src/stores/note.tsx +++ b/src/stores/note.tsx @@ -1,6 +1,15 @@ +import { getAllNotes } from '@utils/storage'; + import { atom } from 'jotai'; +import { atomsWithQuery } from 'jotai-tanstack-query'; // usecase: notify user that connector has receive newer note export const hasNewerNoteAtom = atom(false); // usecase: query notes from database -export const notesAtom = atom([]); +export const [notesAtom] = atomsWithQuery(() => ({ + queryKey: ['notes'], + queryFn: async ({ queryKey: [] }) => { + const res = await getAllNotes(); + return res; + }, +})); diff --git a/src/utils/storage.tsx b/src/utils/storage.tsx index b99e24f3..8dca4a06 100644 --- a/src/utils/storage.tsx +++ b/src/utils/storage.tsx @@ -86,6 +86,12 @@ export async function getCacheProfile(id) { return result[0]; } +// get note by id +export async function getAllNotes() { + const db = await connect(); + return await db.select(`SELECT * FROM cache_notes WHERE is_root = 0 ORDER BY created_at DESC LIMIT 1000`); +} + // get note by id export async function getNoteByID(id) { const db = await connect(); diff --git a/src/utils/tags.tsx b/src/utils/tags.tsx deleted file mode 100644 index a4d7b49e..00000000 --- a/src/utils/tags.tsx +++ /dev/null @@ -1,8 +0,0 @@ -export const tagsToArray = (arr) => { - const newarr = []; - // push item to newarr - arr.forEach((item) => { - newarr.push(item[1]); - }); - return newarr; -}; diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx new file mode 100644 index 00000000..e034ce63 --- /dev/null +++ b/src/utils/transform.tsx @@ -0,0 +1,17 @@ +export const tagsToArray = (arr) => { + const newarr = []; + // push item to newarr + arr.forEach((item) => { + newarr.push(item[1]); + }); + return newarr; +}; + +export const pubkeyArray = (arr) => { + const newarr = []; + // push item to newarr + arr.forEach((item) => { + newarr.push(item.pubkey); + }); + return newarr; +};