[tauri-sql] updated onboarding pages

This commit is contained in:
Ren Amamiya 2023-04-18 12:36:15 +07:00
parent 075fbcf507
commit fc1101f97b
7 changed files with 92 additions and 125 deletions

View File

@ -4,7 +4,8 @@ import { RelayContext } from '@components/relaysProvider';
import { UserBase } from '@components/user/base'; import { UserBase } from '@components/user/base';
import { fetchProfileMetadata } from '@utils/hooks/useProfileMetadata'; 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 { createClient } from '@supabase/supabase-js';
import { CheckCircle } from 'iconoir-react'; import { CheckCircle } from 'iconoir-react';
@ -52,10 +53,13 @@ const initialList = [
{ pubkey: 'ff04a0e6cd80c141b0b55825fed127d4532a6eecdb7e743a38a3c28bf9f44609' }, { 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 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 [loading, setLoading] = useState(false);
const [list, setList]: any = useState(initialList); const [list, setList]: any = useState(initialList);
const [follows, setFollows] = useState([]); const [follows, setFollows] = useState([]);
@ -68,18 +72,17 @@ export default function Page({ params }: { params: { id: string; pubkey: string;
// save follows to database then broadcast // save follows to database then broadcast
const submit = useCallback(async () => { const submit = useCallback(async () => {
const { createPleb } = await import('@utils/bindings');
setLoading(true); setLoading(true);
const nip02 = arrayToNIP02(follows);
for (const follow of follows) { // update account's folllows with nip03 tag list
const metadata: any = await fetchProfileMetadata(follow); updateAccount('follows', nip02, pubkey);
createPleb({
pleb_id: follow + '-lume' + params.id, // create pleb
pubkey: follow, for (const tag of follows) {
kind: 0, fetchProfileMetadata(tag)
metadata: metadata.content, .then((res: any) => createPleb(tag, res.content))
account_id: parseInt(params.id), .catch(console.error);
}).catch(console.error);
} }
// build event // build event
@ -87,15 +90,17 @@ export default function Page({ params }: { params: { id: string; pubkey: string;
content: '', content: '',
created_at: Math.floor(Date.now() / 1000), created_at: Math.floor(Date.now() / 1000),
kind: 3, kind: 3,
pubkey: params.pubkey, pubkey: pubkey,
tags: followsTag(follows), tags: nip02,
}; };
console.log(event);
event.id = getEventHash(event); event.id = getEventHash(event);
event.sig = signEvent(event, params.privkey); event.sig = signEvent(event, privkey);
// broadcast
pool.publish(event, relays); pool.publish(event, relays);
// redirect to splashscreen
router.replace('/'); router.replace('/');
}, [params.pubkey, params.privkey, params.id, follows, pool, relays, router]); }, [pubkey, privkey, follows, pool, relays, router]);
useEffect(() => { useEffect(() => {
const fetchData = async () => { const fetchData = async () => {

View File

@ -2,7 +2,9 @@
import { RelayContext } from '@components/relaysProvider'; 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 Image from 'next/image';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools'; import { generatePrivateKey, getEventHash, getPublicKey, nip19, signEvent } from 'nostr-tools';
@ -20,16 +22,12 @@ export default function Page() {
const [type, setType] = useState('password'); const [type, setType] = useState('password');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [privKey] = useState(() => generatePrivateKey()); const privkey = useMemo(() => generatePrivateKey(), []);
const [name] = useState(() => uniqueNamesGenerator(config).toString()); const name = useMemo(() => uniqueNamesGenerator(config).toString(), []);
const pubKey = getPublicKey(privKey); const pubkey = getPublicKey(privkey);
const npub = nip19.npubEncode(pubKey); const npub = nip19.npubEncode(pubkey);
const nsec = nip19.nsecEncode(privKey); const nsec = nip19.nsecEncode(privkey);
const goBack = () => {
router.back();
};
// auto-generated profile metadata // auto-generated profile metadata
const metadata: any = useMemo( const metadata: any = useMemo(
@ -53,7 +51,6 @@ export default function Page() {
// create account and broadcast to all relays // create account and broadcast to all relays
const submit = useCallback(async () => { const submit = useCallback(async () => {
const { createAccount } = await import('@utils/bindings');
setLoading(true); setLoading(true);
// build event // build event
@ -61,36 +58,25 @@ export default function Page() {
content: JSON.stringify(metadata), content: JSON.stringify(metadata),
created_at: Math.floor(Date.now() / 1000), created_at: Math.floor(Date.now() / 1000),
kind: 0, kind: 0,
pubkey: pubKey, pubkey: pubkey,
tags: [], tags: [],
}; };
event.id = getEventHash(event); event.id = getEventHash(event);
event.sig = signEvent(event, privKey); event.sig = signEvent(event, privkey);
// insert to database
// insert to database then broadcast createAccount(pubkey, privkey, metadata);
createAccount({ pubkey: pubKey, privkey: privKey, metadata: metadata }) // broadcast
.then((res) => { pool.publish(event, relays);
pool.publish(event, relays); // redirect to next step
router.push(`/onboarding/create/${res.id}/${res.pubkey}/${res.privkey}`); router.push(`/onboarding/create/${pubkey}/${privkey}`);
}) }, [pool, pubkey, privkey, metadata, relays, router]);
.catch(console.error);
}, [pool, pubKey, privKey, metadata, relays, router]);
return ( return (
<div className="grid h-full w-full grid-rows-5"> <div className="grid h-full w-full grid-rows-5">
<div className="row-span-1 mx-auto flex w-full max-w-md items-center justify-between"> <div className="row-span-1 mx-auto flex w-full max-w-md items-center justify-center">
<button <h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent">
onClick={() => goBack()} Create new account
className="group inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-zinc-900" </h1>
>
<ArrowLeft width={16} height={16} className="text-zinc-500 group-hover:text-zinc-300" />
</button>
<div>
<h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent">
Create new account
</h1>
</div>
<div></div>
</div> </div>
<div className="row-span-4"> <div className="row-span-4">
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">

View File

@ -6,81 +6,72 @@ import { DEFAULT_AVATAR } from '@stores/constants';
import { fetchProfileMetadata } from '@utils/hooks/useProfileMetadata'; import { fetchProfileMetadata } from '@utils/hooks/useProfileMetadata';
import { shortenKey } from '@utils/shortenKey'; import { shortenKey } from '@utils/shortenKey';
import { createAccount, createPleb } from '@utils/storage';
import Image from 'next/image'; import Image from 'next/image';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { getPublicKey } from 'nostr-tools'; 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 } }) { export default function Page({ params }: { params: { privkey: string } }) {
const router = useRouter(); const router = useRouter();
const [pool, relays]: any = useContext(RelayContext); const [pool, relays]: any = useContext(RelayContext);
const pubkey = useMemo(() => (params.privkey ? getPublicKey(params.privkey) : null), [params.privkey]); 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 [done, setDone] = useState(false);
const insertAccountToStorage = useCallback(async (pubkey, privkey, metadata) => { const createPlebs = useCallback(async (tags: string[]) => {
const { createAccount } = await import('@utils/bindings'); for (const tag of tags) {
createAccount({ pubkey: pubkey, privkey: privkey, metadata: metadata }) fetchProfileMetadata(tag[1])
.then((res) => .then((res: any) => createPleb(tag[1], res))
setProfile({ .catch(console.error);
id: res.id, }
metadata: JSON.parse(res.metadata),
})
)
.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(() => { useEffect(() => {
const unsubscribe = pool.subscribe( const unsubscribe = pool.subscribe(
[ [
{ {
authors: [pubkey], authors: [pubkey],
kinds: [0, 3], kinds: [0, 3],
since: 0,
}, },
], ],
relays, relays,
(event: any) => { (event: any) => {
if (event.kind === 0) { 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 { } else {
if (event.tags.length > 0) { if (event.tags.length > 0) {
insertFollowsToStorage(event.tags); createPlebs(event.tags);
} }
} }
}, },
undefined, undefined,
() => { () => {
setDone(true); if (eose.current > 5) {
setDone(true);
} else {
eose.current += 1;
}
},
{
unsubscribeOnEose: true,
logAllEvents: false,
} }
); );
return () => { return () => {
unsubscribe; unsubscribe;
}; };
}, [insertAccountToStorage, insertFollowsToStorage, pool, relays, pubkey, params.privkey]); }, [pool, relays, pubkey, params.privkey, createPlebs]);
// submit then redirect to home // submit then redirect to home
const submit = () => { const submit = () => {
@ -90,11 +81,9 @@ export default function Page({ params }: { params: { privkey: string } }) {
return ( return (
<div className="grid h-full w-full grid-rows-5"> <div className="grid h-full w-full grid-rows-5">
<div className="row-span-1 flex items-center justify-center"> <div className="row-span-1 flex items-center justify-center">
<div> <h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent">
<h1 className="bg-gradient-to-br from-zinc-200 to-zinc-400 bg-clip-text text-3xl font-medium text-transparent"> Bringing back your profile...
Bringing back your profile... </h1>
</h1>
</div>
</div> </div>
<div className="row-span-4 flex flex-col gap-8"> <div className="row-span-4 flex flex-col gap-8">
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import { ArrowLeft, CableTag } from 'iconoir-react'; import { CableTag } from 'iconoir-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { nip19 } from 'nostr-tools'; import { nip19 } from 'nostr-tools';
import { Resolver, useForm } from 'react-hook-form'; import { Resolver, useForm } from 'react-hook-form';
@ -32,10 +32,6 @@ export default function Page() {
formState: { errors, isDirty, isValid, isSubmitting }, formState: { errors, isDirty, isValid, isSubmitting },
} = useForm<FormValues>({ resolver }); } = useForm<FormValues>({ resolver });
const goBack = () => {
router.back();
};
const onSubmit = async (data: any) => { const onSubmit = async (data: any) => {
let privkey = data['key']; let privkey = data['key'];
@ -55,19 +51,10 @@ export default function Page() {
return ( return (
<div className="grid h-full w-full grid-rows-5"> <div className="grid h-full w-full grid-rows-5">
<div className="row-span-1 mx-auto flex w-full max-w-md items-center justify-between"> <div className="row-span-1 mx-auto flex w-full max-w-md items-center justify-center">
<button <h1 className="bg-gradient-to-br from-zinc-200 via-white to-zinc-300 bg-clip-text text-3xl font-semibold text-transparent">
onClick={() => goBack()} Login with Private Key
className="group inline-flex h-6 w-6 items-center justify-center rounded-md hover:bg-zinc-900" </h1>
>
<ArrowLeft width={16} height={16} className="text-zinc-500 group-hover:text-zinc-300" />
</button>
<div>
<h1 className="bg-gradient-to-br from-zinc-200 via-white to-zinc-300 bg-clip-text text-3xl font-semibold text-transparent">
Login with Private Key
</h1>
</div>
<div></div>
</div> </div>
<form onSubmit={handleSubmit(onSubmit)} className="row-span-4"> <form onSubmit={handleSubmit(onSubmit)} className="row-span-4">
<div className="mx-auto w-full max-w-md"> <div className="mx-auto w-full max-w-md">

View File

@ -15,7 +15,7 @@ const relays = [
'wss://offchain.pub', 'wss://offchain.pub',
'wss://relay.current.fyi', 'wss://relay.current.fyi',
'wss://nostr.bitcoiner.social', 'wss://nostr.bitcoiner.social',
'wss://relay.nostr.info', //'wss://relay.nostr.info',
'wss://nostr-01.dorafactory.org', 'wss://nostr-01.dorafactory.org',
'wss://nostr.zhongwen.world', 'wss://nostr.zhongwen.world',
'wss://nostro.cc', 'wss://nostro.cc',

View File

@ -21,19 +21,19 @@ export async function getActiveAccount() {
} }
// create account // 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(); const db = await connect();
return await db.execute('INSERT OR IGNORE INTO accounts (pubkey, privkey, metadata) VALUES (?, ?, ?);', [ return await db.execute('INSERT OR IGNORE INTO accounts (pubkey, privkey, metadata) VALUES (?, ?, ?);', [
data.pubkey, pubkey,
data.privkey, privkey,
data.metadata, metadata,
]); ]);
} }
// update account // 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(); 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 // create pleb

View File

@ -9,13 +9,13 @@ export const tagsToArray = (arr) => {
return newarr; return newarr;
}; };
export const followsTag = (arr) => { // convert array to NIP-02 tag list
const newarr = []; export const arrayToNIP02 = (arr: string[]) => {
// push item to tags const nip03_array = [];
arr.forEach((item) => { arr.forEach((item) => {
newarr.push(['p', item]); nip03_array.push(['p', item]);
}); });
return newarr; return nip03_array;
}; };
export const pubkeyArray = (arr) => { export const pubkeyArray = (arr) => {