From 5437ec5c92f953cb26ace6777aab190821d481fd Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Thu, 6 Apr 2023 09:25:18 +0700 Subject: [PATCH] added useMetadata and refactor user component --- .../migration.sql | 5 ++ .../migration.sql | 23 ++++++++ src-tauri/prisma/schema.prisma | 5 +- src-tauri/src/main.rs | 23 +++++--- .../multiAccounts/activeAccount.tsx | 10 +++- src/components/note/base.tsx | 9 ++- src/components/user/base.tsx | 14 +---- src/components/user/extend.tsx | 50 ++-------------- src/components/user/follow.tsx | 21 +------ src/components/user/large.tsx | 20 +------ src/components/user/mention.tsx | 37 +----------- src/components/user/mini.tsx | 57 ++++++------------- src/pages/newsfeed/following.tsx | 11 ++-- src/pages/onboarding/create/step-2.tsx | 10 +++- src/pages/onboarding/login/step-2.tsx | 10 +++- src/utils/bindings.ts | 34 +++++------ src/utils/metadata.tsx | 33 +++++++++++ 17 files changed, 161 insertions(+), 211 deletions(-) create mode 100644 src-tauri/prisma/migrations/20230406012222_remove_unique_from_pleb/migration.sql create mode 100644 src-tauri/prisma/migrations/20230406014004_add_plebid_to_pleb/migration.sql diff --git a/src-tauri/prisma/migrations/20230406012222_remove_unique_from_pleb/migration.sql b/src-tauri/prisma/migrations/20230406012222_remove_unique_from_pleb/migration.sql new file mode 100644 index 00000000..8bac356c --- /dev/null +++ b/src-tauri/prisma/migrations/20230406012222_remove_unique_from_pleb/migration.sql @@ -0,0 +1,5 @@ +-- DropIndex +DROP INDEX "Pleb_pubkey_idx"; + +-- DropIndex +DROP INDEX "Pleb_pubkey_key"; diff --git a/src-tauri/prisma/migrations/20230406014004_add_plebid_to_pleb/migration.sql b/src-tauri/prisma/migrations/20230406014004_add_plebid_to_pleb/migration.sql new file mode 100644 index 00000000..e2ed75a4 --- /dev/null +++ b/src-tauri/prisma/migrations/20230406014004_add_plebid_to_pleb/migration.sql @@ -0,0 +1,23 @@ +/* + Warnings: + + - Added the required column `plebId` to the `Pleb` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Pleb" ( + "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "plebId" TEXT NOT NULL, + "pubkey" TEXT NOT NULL, + "kind" INTEGER NOT NULL, + "metadata" TEXT NOT NULL, + "accountId" INTEGER NOT NULL, + CONSTRAINT "Pleb_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account" ("id") ON DELETE RESTRICT ON UPDATE CASCADE +); +INSERT INTO "new_Pleb" ("accountId", "id", "kind", "metadata", "pubkey") SELECT "accountId", "id", "kind", "metadata", "pubkey" FROM "Pleb"; +DROP TABLE "Pleb"; +ALTER TABLE "new_Pleb" RENAME TO "Pleb"; +CREATE UNIQUE INDEX "Pleb_plebId_key" ON "Pleb"("plebId"); +PRAGMA foreign_key_check; +PRAGMA foreign_keys=ON; diff --git a/src-tauri/prisma/schema.prisma b/src-tauri/prisma/schema.prisma index 234522da..780eca94 100644 --- a/src-tauri/prisma/schema.prisma +++ b/src-tauri/prisma/schema.prisma @@ -27,14 +27,13 @@ model Account { model Pleb { id Int @id @default(autoincrement()) - pubkey String @unique + plebId String @unique + pubkey String kind Int metadata String Account Account @relation(fields: [accountId], references: [id]) accountId Int - - @@index([pubkey]) } model Note { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 84332605..fe5caa84 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -19,7 +19,7 @@ mod db; use db::*; use serde::Deserialize; use specta::{collect_types, Type}; -use std::sync::Arc; +use std::{sync::Arc, vec}; use tauri::State; use tauri_specta::ts; @@ -44,6 +44,7 @@ struct GetPlebPubkeyData { #[derive(Deserialize, Type)] struct CreatePlebData { + pleb_id: String, pubkey: String, kind: i32, metadata: String, @@ -126,13 +127,21 @@ async fn get_pleb_by_pubkey( #[tauri::command] #[specta::specta] async fn create_pleb(db: DbState<'_>, data: CreatePlebData) -> Result { + let pleb_id = data.pleb_id.clone(); + let metadata = data.metadata.clone(); + db.pleb() - .create( - data.pubkey, - data.kind, - data.metadata, - account::id::equals(data.account_id), - vec![], + .upsert( + pleb::pleb_id::equals(pleb_id), + pleb::create( + data.pleb_id, + data.pubkey, + data.kind, + data.metadata, + account::id::equals(data.account_id), + vec![], + ), + vec![pleb::metadata::set(metadata)], ) .exec() .await diff --git a/src/components/multiAccounts/activeAccount.tsx b/src/components/multiAccounts/activeAccount.tsx index fa843fcc..46a8926a 100644 --- a/src/components/multiAccounts/activeAccount.tsx +++ b/src/components/multiAccounts/activeAccount.tsx @@ -33,9 +33,13 @@ export const ActiveAccount = memo(function ActiveAccount({ user }: { user: any } for (const tag of tags) { const metadata: any = await fetchMetadata(tag[1], pool, relays); - createPleb({ pubkey: tag[1], kind: 0, metadata: metadata.content, account_id: activeAccount.id }).catch( - console.error - ); + createPleb({ + pleb_id: tag[1] + '-lume' + activeAccount.id.toString(), + pubkey: tag[1], + kind: 0, + metadata: metadata.content, + account_id: activeAccount.id, + }).catch(console.error); } }, [pool, relays] diff --git a/src/components/note/base.tsx b/src/components/note/base.tsx index 4ad3dae5..17e7d90f 100644 --- a/src/components/note/base.tsx +++ b/src/components/note/base.tsx @@ -71,6 +71,11 @@ export const NoteBase = memo(function NoteBase({ event }: { event: any }) { return; }, [event.content, event.eventId, event.parent_id]); + const openUserPage = (e) => { + e.stopPropagation(); + router.push(`/users/${event.pubkey}`); + }; + const openThread = (e) => { const selection = window.getSelection(); if (selection.toString().length === 0) { @@ -87,7 +92,9 @@ export const NoteBase = memo(function NoteBase({ event }: { event: any }) { > <>{getParent}
- +
openUserPage(e)}> + +
diff --git a/src/components/user/base.tsx b/src/components/user/base.tsx index e6680769..7551b520 100644 --- a/src/components/user/base.tsx +++ b/src/components/user/base.tsx @@ -1,22 +1,14 @@ import { ImageWithFallback } from '@components/imageWithFallback'; -import { RelayContext } from '@components/relaysProvider'; import { DEFAULT_AVATAR } from '@stores/constants'; +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; -import { Author } from 'nostr-relaypool'; -import { memo, useContext, useEffect, useState } from 'react'; +import { memo } from 'react'; export const UserBase = memo(function UserBase({ pubkey }: { pubkey: string }) { - const [pool, relays]: any = useContext(RelayContext); - - const [profile, setProfile] = useState(null); - - useEffect(() => { - const user = new Author(pool, relays, pubkey); - user.metaData((res) => setProfile(JSON.parse(res.content)), 0); - }, [pool, relays, pubkey]); + const profile = useMetadata(pubkey); return (
diff --git a/src/components/user/extend.tsx b/src/components/user/extend.tsx index 64a37557..bc8bd7cd 100644 --- a/src/components/user/extend.tsx +++ b/src/components/user/extend.tsx @@ -2,63 +2,21 @@ import { ImageWithFallback } from '@components/imageWithFallback'; import { DEFAULT_AVATAR } from '@stores/constants'; +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; import { DotsHorizontalIcon } from '@radix-ui/react-icons'; -import { fetch } from '@tauri-apps/api/http'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; -import { useRouter } from 'next/router'; -import { useCallback, useEffect, useState } from 'react'; dayjs.extend(relativeTime); export const UserExtend = ({ pubkey, time }: { pubkey: string; time: number }) => { - const router = useRouter(); - const [profile, setProfile] = useState(null); - - const openUserPage = (e) => { - e.stopPropagation(); - router.push(`/users/${pubkey}`); - }; - - const fetchMetadata = useCallback(async (pubkey: string) => { - const res = await fetch(`https://rbr.bio/${pubkey}/metadata.json`, { - method: 'GET', - timeout: 5, - }); - return res.data; - }, []); - - const getCachedMetadata = useCallback(async () => { - const { getPlebByPubkey } = await import('@utils/bindings'); - getPlebByPubkey({ pubkey: pubkey }) - .then((res) => { - if (res) { - const metadata = JSON.parse(res.metadata); - setProfile(metadata); - } else { - fetchMetadata(pubkey).then((res: any) => { - if (res.content) { - const metadata = JSON.parse(res.content); - setProfile(metadata); - } - }); - } - }) - .catch(console.error); - }, [fetchMetadata, pubkey]); - - useEffect(() => { - getCachedMetadata().catch(console.error); - }, [getCachedMetadata]); + const profile = useMetadata(pubkey); return (
-
openUserPage(e)} - className="relative h-11 w-11 shrink overflow-hidden rounded-md bg-zinc-900 ring-fuchsia-500 ring-offset-1 ring-offset-zinc-900 group-hover:ring-1" - > +
- openUserPage(e)} className="font-bold leading-tight group-hover:underline"> + {profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')} ยท diff --git a/src/components/user/follow.tsx b/src/components/user/follow.tsx index 41f8db9b..fe7b0306 100644 --- a/src/components/user/follow.tsx +++ b/src/components/user/follow.tsx @@ -2,28 +2,11 @@ import { ImageWithFallback } from '@components/imageWithFallback'; import { DEFAULT_AVATAR } from '@stores/constants'; +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; -import { useCallback, useEffect, useState } from 'react'; - export const UserFollow = ({ pubkey }: { pubkey: string }) => { - const [profile, setProfile] = useState(null); - - const getCachedMetadata = useCallback(async () => { - const { getPlebByPubkey } = await import('@utils/bindings'); - getPlebByPubkey({ pubkey: pubkey }) - .then((res) => { - if (res) { - const metadata = JSON.parse(res.metadata); - setProfile(metadata); - } - }) - .catch(console.error); - }, [pubkey]); - - useEffect(() => { - getCachedMetadata().catch(console.error); - }, [getCachedMetadata]); + const profile = useMetadata(pubkey); return (
diff --git a/src/components/user/large.tsx b/src/components/user/large.tsx index 58d579c4..d896e379 100644 --- a/src/components/user/large.tsx +++ b/src/components/user/large.tsx @@ -2,33 +2,17 @@ import { ImageWithFallback } from '@components/imageWithFallback'; import { DEFAULT_AVATAR } from '@stores/constants'; +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; import { DotsHorizontalIcon } from '@radix-ui/react-icons'; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; -import { useCallback, useEffect, useState } from 'react'; dayjs.extend(relativeTime); export const UserLarge = ({ pubkey, time }: { pubkey: string; time: number }) => { - const [profile, setProfile] = useState(null); - - const getCachedMetadata = useCallback(async () => { - const { getPlebByPubkey } = await import('@utils/bindings'); - getPlebByPubkey({ pubkey: pubkey }) - .then((res) => { - if (res) { - const metadata = JSON.parse(res.metadata); - setProfile(metadata); - } - }) - .catch(console.error); - }, [pubkey]); - - useEffect(() => { - getCachedMetadata().catch(console.error); - }, [getCachedMetadata]); + const profile = useMetadata(pubkey); return (
diff --git a/src/components/user/mention.tsx b/src/components/user/mention.tsx index 72d1d8c5..2d210350 100644 --- a/src/components/user/mention.tsx +++ b/src/components/user/mention.tsx @@ -1,41 +1,10 @@ +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; -import { fetch } from '@tauri-apps/api/http'; -import { memo, useCallback, useEffect, useState } from 'react'; +import { memo } from 'react'; export const UserMention = memo(function UserMention({ pubkey }: { pubkey: string }) { - const [profile, setProfile] = useState(null); - - const fetchMetadata = useCallback(async (pubkey: string) => { - const res = await fetch(`https://rbr.bio/${pubkey}/metadata.json`, { - method: 'GET', - timeout: 5, - }); - return res.data; - }, []); - - const getCachedMetadata = useCallback(async () => { - const { getPlebByPubkey } = await import('@utils/bindings'); - getPlebByPubkey({ pubkey: pubkey }) - .then((res) => { - if (res) { - const metadata = JSON.parse(res.metadata); - setProfile(metadata); - } else { - fetchMetadata(pubkey).then((res: any) => { - if (res.content) { - const metadata = JSON.parse(res.content); - setProfile(metadata); - } - }); - } - }) - .catch(console.error); - }, [fetchMetadata, pubkey]); - - useEffect(() => { - getCachedMetadata().catch(console.error); - }, [getCachedMetadata]); + const profile = useMetadata(pubkey); return @{profile?.name || truncate(pubkey, 16, ' .... ')}; }); diff --git a/src/components/user/mini.tsx b/src/components/user/mini.tsx index 0869d483..5f2a7505 100644 --- a/src/components/user/mini.tsx +++ b/src/components/user/mini.tsx @@ -2,48 +2,27 @@ import { ImageWithFallback } from '@components/imageWithFallback'; import { DEFAULT_AVATAR } from '@stores/constants'; +import { useMetadata } from '@utils/metadata'; import { truncate } from '@utils/truncate'; -import { useCallback, useEffect, useState } from 'react'; - export const UserMini = ({ pubkey }: { pubkey: string }) => { - const [profile, setProfile] = useState(null); + const profile = useMetadata(pubkey); - const getCachedMetadata = useCallback(async () => { - const { getPlebByPubkey } = await import('@utils/bindings'); - getPlebByPubkey({ pubkey: pubkey }) - .then((res) => { - if (res) { - const metadata = JSON.parse(res.metadata); - setProfile(metadata); - } - }) - .catch(console.error); - }, [pubkey]); - - useEffect(() => { - getCachedMetadata().catch(console.error); - }, [getCachedMetadata]); - - if (profile) { - return ( -
-
- -
-
-

- {profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')} -

-
+ return ( +
+
+
- ); - } else { - return <>; - } +
+

+ {profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')} +

+
+
+ ); }; diff --git a/src/pages/newsfeed/following.tsx b/src/pages/newsfeed/following.tsx index cc36a953..22969499 100644 --- a/src/pages/newsfeed/following.tsx +++ b/src/pages/newsfeed/following.tsx @@ -54,8 +54,7 @@ export default function Page() { limit: limit.current, offset: offset.current, }); - const filteredResult = filteredData(result); - setData((data) => [...data, ...filteredResult]); + setData((data) => [...data, ...result]); }, []); const loadMore = useCallback(async () => { @@ -67,8 +66,7 @@ export default function Page() { limit: limit.current, offset: offset.current, }); - const filteredResult = filteredData(result); - setData((data) => [...data, ...filteredResult]); + setData((data) => [...data, ...result]); }, []); const loadLatest = useCallback(async () => { @@ -76,8 +74,7 @@ export default function Page() { // next query const result: any = await getLatestNotes({ date: dateToUnix(now.current) }); // update data - const filteredResult = filteredData(result); - setData((data) => [...data, ...filteredResult]); + setData((data) => [...data, ...result]); // hide newer trigger setHasNewerNote(false); // scroll to top @@ -103,7 +100,7 @@ export default function Page() { )} ('get_note_by_id', { data }); } -export type CreatePlebData = { pubkey: string; kind: number; metadata: string; account_id: number }; -export type Account = { id: number; pubkey: string; privkey: string; active: boolean; metadata: string }; -export type GetLatestNoteData = { date: number }; -export type Pleb = { id: number; pubkey: string; kind: number; metadata: string; accountId: number }; -export type GetPlebPubkeyData = { pubkey: string }; +export type CreateNoteData = { + event_id: string; + pubkey: string; + kind: number; + tags: string; + content: string; + parent_id: string; + parent_comment_id: string; + created_at: number; + account_id: number; +}; +export type CreatePlebData = { pleb_id: string; pubkey: string; kind: number; metadata: string; account_id: number }; +export type GetNoteByIdData = { event_id: string }; +export type Pleb = { id: number; plebId: string; pubkey: string; kind: number; metadata: string; accountId: number }; export type Note = { id: number; eventId: string; @@ -61,18 +70,9 @@ export type Note = { createdAt: number; accountId: number; }; +export type Account = { id: number; pubkey: string; privkey: string; active: boolean; metadata: string }; +export type GetPlebPubkeyData = { pubkey: string }; export type GetPlebData = { account_id: number }; export type CreateAccountData = { pubkey: string; privkey: string; metadata: string }; -export type CreateNoteData = { - event_id: string; - pubkey: string; - kind: number; - tags: string; - content: string; - parent_id: string; - parent_comment_id: string; - created_at: number; - account_id: number; -}; -export type GetNoteByIdData = { event_id: string }; +export type GetLatestNoteData = { date: number }; export type GetNoteData = { date: number; limit: number; offset: number }; diff --git a/src/utils/metadata.tsx b/src/utils/metadata.tsx index 5598ed8a..2a599ffb 100644 --- a/src/utils/metadata.tsx +++ b/src/utils/metadata.tsx @@ -1,6 +1,39 @@ +import { RelayContext } from '@components/relaysProvider'; + import { Author } from 'nostr-relaypool'; +import { useCallback, useContext, useEffect, useState } from 'react'; export const fetchMetadata = (pubkey: string, pool: any, relays: any) => { const author = new Author(pool, relays, pubkey); return new Promise((resolve) => author.metaData(resolve, 0)); }; + +export const useMetadata = (pubkey) => { + const [pool, relays]: any = useContext(RelayContext); + const [profile, setProfile] = useState(null); + + const getCachedMetadata = useCallback(async () => { + const { getPlebByPubkey } = await import('@utils/bindings'); + getPlebByPubkey({ pubkey: pubkey }) + .then((res) => { + if (res) { + const metadata = JSON.parse(res.metadata); + setProfile(metadata); + } else { + fetchMetadata(pubkey, pool, relays).then((res: any) => { + if (res.content) { + const metadata = JSON.parse(res.content); + setProfile(metadata); + } + }); + } + }) + .catch(console.error); + }, [pool, relays, pubkey]); + + useEffect(() => { + getCachedMetadata().catch(console.error); + }, [getCachedMetadata]); + + return profile; +};