diff --git a/src/app/onboarding/create/[...slug]/page.tsx b/src/app/onboarding/create/[...slug]/page.tsx index 3491abfb..dede8f66 100644 --- a/src/app/onboarding/create/[...slug]/page.tsx +++ b/src/app/onboarding/create/[...slug]/page.tsx @@ -4,7 +4,8 @@ import { RelayContext } from '@components/relaysProvider'; import { UserBase } from '@components/user/base'; import { fetchProfileMetadata } from '@utils/hooks/useProfileMetadata'; -import { followsTag } from '@utils/transform'; +import { createPleb, updateAccount } from '@utils/storage'; +import { arrayToNIP02 } from '@utils/transform'; import { createClient } from '@supabase/supabase-js'; import { CheckCircle } from 'iconoir-react'; @@ -52,10 +53,13 @@ const initialList = [ { pubkey: 'ff04a0e6cd80c141b0b55825fed127d4532a6eecdb7e743a38a3c28bf9f44609' }, ]; -export default function Page({ params }: { params: { id: string; pubkey: string; privkey: string } }) { +export default function Page({ params }: { params: { slug: string } }) { const router = useRouter(); - const [pool, relays]: any = useContext(RelayContext); + const pubkey = params.slug[0]; + const privkey = params.slug[1]; + + const [pool, relays]: any = useContext(RelayContext); const [loading, setLoading] = useState(false); const [list, setList]: any = useState(initialList); const [follows, setFollows] = useState([]); @@ -68,18 +72,17 @@ export default function Page({ params }: { params: { id: string; pubkey: string; // save follows to database then broadcast const submit = useCallback(async () => { - const { createPleb } = await import('@utils/bindings'); setLoading(true); + const nip02 = arrayToNIP02(follows); - for (const follow of follows) { - const metadata: any = await fetchProfileMetadata(follow); - createPleb({ - pleb_id: follow + '-lume' + params.id, - pubkey: follow, - kind: 0, - metadata: metadata.content, - account_id: parseInt(params.id), - }).catch(console.error); + // update account's folllows with nip03 tag list + updateAccount('follows', nip02, pubkey); + + // create pleb + for (const tag of follows) { + fetchProfileMetadata(tag) + .then((res: any) => createPleb(tag, res.content)) + .catch(console.error); } // build event @@ -87,15 +90,17 @@ export default function Page({ params }: { params: { id: string; pubkey: string; content: '', created_at: Math.floor(Date.now() / 1000), kind: 3, - pubkey: params.pubkey, - tags: followsTag(follows), + pubkey: pubkey, + tags: nip02, }; + console.log(event); event.id = getEventHash(event); - event.sig = signEvent(event, params.privkey); - + event.sig = signEvent(event, privkey); + // broadcast pool.publish(event, relays); + // redirect to splashscreen router.replace('/'); - }, [params.pubkey, params.privkey, params.id, follows, pool, relays, router]); + }, [pubkey, privkey, follows, pool, relays, router]); useEffect(() => { const fetchData = async () => { diff --git a/src/app/onboarding/create/page.tsx b/src/app/onboarding/create/page.tsx index c2dd7856..d38e5882 100644 --- a/src/app/onboarding/create/page.tsx +++ b/src/app/onboarding/create/page.tsx @@ -2,7 +2,9 @@ import { RelayContext } from '@components/relaysProvider'; -import { ArrowLeft, EyeClose, EyeEmpty } from 'iconoir-react'; +import { createAccount } from '@utils/storage'; + +import { EyeClose, EyeEmpty } from 'iconoir-react'; import Image from 'next/image'; import { useRouter } from 'next/navigation'; import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools'; @@ -20,16 +22,12 @@ export default function Page() { const [type, setType] = useState('password'); const [loading, setLoading] = useState(false); - const [privKey] = useState(() => generatePrivateKey()); - const [name] = useState(() => uniqueNamesGenerator(config).toString()); + const privkey = useMemo(() => generatePrivateKey(), []); + const name = useMemo(() => uniqueNamesGenerator(config).toString(), []); - const pubKey = getPublicKey(privKey); - const npub = nip19.npubEncode(pubKey); - const nsec = nip19.nsecEncode(privKey); - - const goBack = () => { - router.back(); - }; + const pubkey = getPublicKey(privkey); + const npub = nip19.npubEncode(pubkey); + const nsec = nip19.nsecEncode(privkey); // auto-generated profile metadata const metadata: any = useMemo( @@ -53,7 +51,6 @@ export default function Page() { // create account and broadcast to all relays const submit = useCallback(async () => { - const { createAccount } = await import('@utils/bindings'); setLoading(true); // build event @@ -61,36 +58,25 @@ export default function Page() { content: JSON.stringify(metadata), created_at: Math.floor(Date.now() / 1000), kind: 0, - pubkey: pubKey, + pubkey: pubkey, tags: [], }; event.id = getEventHash(event); - event.sig = signEvent(event, privKey); - - // insert to database then broadcast - createAccount({ pubkey: pubKey, privkey: privKey, metadata: metadata }) - .then((res) => { - pool.publish(event, relays); - router.push(`/onboarding/create/${res.id}/${res.pubkey}/${res.privkey}`); - }) - .catch(console.error); - }, [pool, pubKey, privKey, metadata, relays, router]); + event.sig = signEvent(event, privkey); + // insert to database + createAccount(pubkey, privkey, metadata); + // broadcast + pool.publish(event, relays); + // redirect to next step + router.push(`/onboarding/create/${pubkey}/${privkey}`); + }, [pool, pubkey, privkey, metadata, relays, router]); return (
-
- -
-

- Create new account -

-
-
+
+

+ Create new account +

diff --git a/src/app/onboarding/login/[...slug]/page.tsx b/src/app/onboarding/login/[privkey]/page.tsx similarity index 72% rename from src/app/onboarding/login/[...slug]/page.tsx rename to src/app/onboarding/login/[privkey]/page.tsx index f257ca8c..0f1f113d 100644 --- a/src/app/onboarding/login/[...slug]/page.tsx +++ b/src/app/onboarding/login/[privkey]/page.tsx @@ -6,81 +6,72 @@ import { DEFAULT_AVATAR } from '@stores/constants'; import { fetchProfileMetadata } from '@utils/hooks/useProfileMetadata'; import { shortenKey } from '@utils/shortenKey'; +import { createAccount, createPleb } from '@utils/storage'; import Image from 'next/image'; import { useRouter } from 'next/navigation'; import { getPublicKey } from 'nostr-tools'; -import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; export default function Page({ params }: { params: { privkey: string } }) { const router = useRouter(); + const [pool, relays]: any = useContext(RelayContext); - const pubkey = useMemo(() => (params.privkey ? getPublicKey(params.privkey) : null), [params.privkey]); + const eose = useRef(0); - const [profile, setProfile] = useState({ id: null, metadata: null }); + const [profile, setProfile] = useState({ metadata: null }); const [done, setDone] = useState(false); - const insertAccountToStorage = useCallback(async (pubkey, privkey, metadata) => { - const { createAccount } = await import('@utils/bindings'); - createAccount({ pubkey: pubkey, privkey: privkey, metadata: metadata }) - .then((res) => - setProfile({ - id: res.id, - metadata: JSON.parse(res.metadata), - }) - ) - .catch(console.error); + const createPlebs = useCallback(async (tags: string[]) => { + for (const tag of tags) { + fetchProfileMetadata(tag[1]) + .then((res: any) => createPleb(tag[1], res)) + .catch(console.error); + } }, []); - const insertFollowsToStorage = useCallback( - async (tags) => { - const { createPleb } = await import('@utils/bindings'); - if (profile?.id !== null) { - for (const tag of tags) { - const metadata: any = await fetchProfileMetadata(tag[1]); - createPleb({ - pleb_id: tag[1] + '-lume' + profile.id.toString(), - pubkey: tag[1], - kind: 0, - metadata: metadata.content, - account_id: profile.id, - }).catch(console.error); - } - } - }, - [profile.id] - ); - useEffect(() => { const unsubscribe = pool.subscribe( [ { authors: [pubkey], kinds: [0, 3], - since: 0, }, ], relays, (event: any) => { if (event.kind === 0) { - insertAccountToStorage(pubkey, params.privkey, event.content); + // create account + createAccount(pubkey, params.privkey, event.content); + // update state + setProfile({ + metadata: JSON.parse(event.metadata), + }); } else { if (event.tags.length > 0) { - insertFollowsToStorage(event.tags); + createPlebs(event.tags); } } }, undefined, () => { - setDone(true); + if (eose.current > 5) { + setDone(true); + } else { + eose.current += 1; + } + }, + { + unsubscribeOnEose: true, + logAllEvents: false, } ); return () => { unsubscribe; }; - }, [insertAccountToStorage, insertFollowsToStorage, pool, relays, pubkey, params.privkey]); + }, [pool, relays, pubkey, params.privkey, createPlebs]); // submit then redirect to home const submit = () => { @@ -90,11 +81,9 @@ export default function Page({ params }: { params: { privkey: string } }) { return (
-
-

- Bringing back your profile... -

-
+

+ Bringing back your profile... +

diff --git a/src/app/onboarding/login/page.tsx b/src/app/onboarding/login/page.tsx index f7a3b98a..44fbb03c 100644 --- a/src/app/onboarding/login/page.tsx +++ b/src/app/onboarding/login/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { ArrowLeft, CableTag } from 'iconoir-react'; +import { CableTag } from 'iconoir-react'; import { useRouter } from 'next/navigation'; import { nip19 } from 'nostr-tools'; import { Resolver, useForm } from 'react-hook-form'; @@ -32,10 +32,6 @@ export default function Page() { formState: { errors, isDirty, isValid, isSubmitting }, } = useForm({ resolver }); - const goBack = () => { - router.back(); - }; - const onSubmit = async (data: any) => { let privkey = data['key']; @@ -55,19 +51,10 @@ export default function Page() { return (
-
- -
-

- Login with Private Key -

-
-
+
+

+ Login with Private Key +

diff --git a/src/components/relaysProvider.tsx b/src/components/relaysProvider.tsx index 872efa13..5797a4df 100644 --- a/src/components/relaysProvider.tsx +++ b/src/components/relaysProvider.tsx @@ -15,7 +15,7 @@ const relays = [ 'wss://offchain.pub', 'wss://relay.current.fyi', 'wss://nostr.bitcoiner.social', - 'wss://relay.nostr.info', + //'wss://relay.nostr.info', 'wss://nostr-01.dorafactory.org', 'wss://nostr.zhongwen.world', 'wss://nostro.cc', diff --git a/src/utils/storage.tsx b/src/utils/storage.tsx index 7914ac7d..47891e7e 100644 --- a/src/utils/storage.tsx +++ b/src/utils/storage.tsx @@ -21,19 +21,19 @@ export async function getActiveAccount() { } // create account -export async function createAccount(data: { pubkey: string; privkey: string; metadata: string }) { +export async function createAccount(pubkey: string, privkey: string, metadata: string) { const db = await connect(); return await db.execute('INSERT OR IGNORE INTO accounts (pubkey, privkey, metadata) VALUES (?, ?, ?);', [ - data.pubkey, - data.privkey, - data.metadata, + pubkey, + privkey, + metadata, ]); } // update account -export async function updateAccount(column: string, value: string, pubkey: string) { +export async function updateAccount(column: string, value: string | string[], pubkey: string) { const db = await connect(); - return await db.execute(`UPDATE accounts SET ${column} = "${value}" WHERE pubkey = "${pubkey}";`); + return await db.execute(`UPDATE accounts SET ${column} = '${JSON.stringify(value)}' WHERE pubkey = "${pubkey}";`); } // create pleb diff --git a/src/utils/transform.tsx b/src/utils/transform.tsx index 980fd8c9..6c95bd4f 100644 --- a/src/utils/transform.tsx +++ b/src/utils/transform.tsx @@ -9,13 +9,13 @@ export const tagsToArray = (arr) => { return newarr; }; -export const followsTag = (arr) => { - const newarr = []; - // push item to tags +// convert array to NIP-02 tag list +export const arrayToNIP02 = (arr: string[]) => { + const nip03_array = []; arr.forEach((item) => { - newarr.push(['p', item]); + nip03_array.push(['p', item]); }); - return newarr; + return nip03_array; }; export const pubkeyArray = (arr) => {