This commit is contained in:
Ren Amamiya
2023-05-26 09:28:49 +07:00
parent 225179dd6d
commit 5c7b18bf29
41 changed files with 404 additions and 461 deletions

View File

@@ -1,11 +1,9 @@
import { Image } from "@shared/image";
import { DEFAULT_AVATAR } from "@stores/constants";
import { useProfile } from "@utils/hooks/useProfile";
import { shortenKey } from "@utils/shortenKey";
export default function User({ pubkey }: { pubkey: string }) {
export function User({ pubkey }: { pubkey: string }) {
const { user } = useProfile(pubkey);
return (
@@ -15,7 +13,6 @@ export default function User({ pubkey }: { pubkey: string }) {
src={user?.picture || DEFAULT_AVATAR}
alt={pubkey}
className="h-11 w-11 rounded-md object-cover"
loading="lazy"
decoding="async"
/>
</div>

View File

@@ -1,16 +1,12 @@
import EyeOffIcon from "@icons/eyeOff";
import EyeOnIcon from "@icons/eyeOn";
import { onboardingAtom } from "@stores/onboarding";
import { useSetAtom } from "jotai";
import { createAccount } from "@utils/storage";
import { generatePrivateKey, getPublicKey, nip19 } from "nostr-tools";
import { useMemo, useState } from "react";
import { navigate } from "vite-plugin-ssr/client/router";
export function Page() {
const [type, setType] = useState("password");
const setOnboarding = useSetAtom(onboardingAtom);
const privkey = useMemo(() => generatePrivateKey(), []);
const pubkey = getPublicKey(privkey);
@@ -26,9 +22,12 @@ export function Page() {
}
};
const submit = () => {
setOnboarding((prev) => ({ ...prev, pubkey: pubkey, privkey: privkey }));
navigate("/app/auth/create/step-2");
const submit = async () => {
const account = await createAccount(npub, pubkey, privkey, null, 1);
if (account) {
navigate("/app/auth/create/step-2");
}
};
return (

View File

@@ -1,38 +1,53 @@
import { AvatarUploader } from "@shared/avatarUploader";
import { Image } from "@shared/image";
import { DEFAULT_AVATAR } from "@stores/constants";
import { onboardingAtom } from "@stores/onboarding";
import { useAtom } from "jotai";
import { useEffect, useState } from "react";
import { RelayContext } from "@shared/relayProvider";
import { DEFAULT_AVATAR, WRITEONLY_RELAYS } from "@stores/constants";
import { useActiveAccount } from "@utils/hooks/useActiveAccount";
import { getEventHash, getSignature } from "nostr-tools";
import { useContext, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { navigate } from "vite-plugin-ssr/client/router";
export function Page() {
const pool: any = useContext(RelayContext);
const { account } = useActiveAccount();
const [image, setImage] = useState(DEFAULT_AVATAR);
const [loading, setLoading] = useState(false);
const [onboarding, setOnboarding] = useAtom(onboardingAtom);
const {
register,
handleSubmit,
setValue,
formState: { isDirty, isValid },
} = useForm({
defaultValues: async () => {
if (onboarding.metadata) {
return onboarding.metadata;
} else {
return null;
}
},
});
} = useForm();
const onSubmit = (data: any) => {
setLoading(true);
setOnboarding((prev) => ({ ...prev, metadata: data }));
navigate("/app/auth/create/step-3");
const event: any = {
content: JSON.stringify(data),
created_at: Math.floor(Date.now() / 1000),
kind: 0,
pubkey: account.pubkey,
tags: [],
};
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
// publish
pool.publish(event, WRITEONLY_RELAYS);
// redirect to step 3
setTimeout(
() =>
navigate("/app/auth/create/step-3", {
overwriteLastHistoryEntry: true,
}),
2000,
);
};
useEffect(() => {

View File

@@ -1,17 +1,11 @@
import User from "@app/auth/components/user";
import { RelayContext } from "@shared/relayProvider";
import { User } from "@app/auth/components/user";
import CheckCircleIcon from "@icons/checkCircle";
import { RelayContext } from "@shared/relayProvider";
import { WRITEONLY_RELAYS } from "@stores/constants";
import { onboardingAtom } from "@stores/onboarding";
import { createAccount, createPleb } from "@utils/storage";
import { useActiveAccount } from "@utils/hooks/useActiveAccount";
import { updateAccount } from "@utils/storage";
import { arrayToNIP02 } from "@utils/transform";
import { useAtom } from "jotai";
import { getEventHash, signEvent } from "nostr-tools";
import { getEventHash, getSignature } from "nostr-tools";
import { useContext, useState } from "react";
import { navigate } from "vite-plugin-ssr/client/router";
@@ -117,9 +111,10 @@ const initialList = [
export function Page() {
const pool: any = useContext(RelayContext);
const { account } = useActiveAccount();
const [loading, setLoading] = useState(false);
const [follows, setFollows] = useState([]);
const [onboarding] = useAtom(onboardingAtom);
// toggle follow state
const toggleFollow = (pubkey: string) => {
@@ -129,68 +124,37 @@ export function Page() {
setFollows(arr);
};
const broadcastAccount = () => {
// build event
const event: any = {
content: JSON.stringify(onboarding.metadata),
created_at: Math.floor(Date.now() / 1000),
kind: 0,
pubkey: onboarding.pubkey,
tags: [],
};
event.id = getEventHash(event);
event.sig = signEvent(event, onboarding.privkey);
// broadcast
pool.publish(event, WRITEONLY_RELAYS);
};
const broadcastContacts = () => {
const nip02 = arrayToNIP02(follows);
// build event
const event: any = {
content: "",
created_at: Math.floor(Date.now() / 1000),
kind: 3,
pubkey: onboarding.pubkey,
tags: nip02,
};
event.id = getEventHash(event);
event.sig = signEvent(event, onboarding.privkey);
// broadcast
pool.publish(event, WRITEONLY_RELAYS);
};
// save follows to database then broadcast
const submit = async () => {
setLoading(true);
const followsIncludeSelf = follows.concat([onboarding.pubkey]);
// insert to database
createAccount(
onboarding.pubkey,
onboarding.privkey,
onboarding.metadata,
arrayToNIP02(followsIncludeSelf),
1,
)
.then((res) => {
if (res) {
for (const tag of follows) {
fetch(`https://us.rbr.bio/${tag}/metadata.json`)
.then((data) => data.json())
.then((data) => createPleb(tag, data ?? ""));
}
broadcastAccount();
broadcastContacts();
setTimeout(
() => navigate("/", { overwriteLastHistoryEntry: true }),
2000,
);
} else {
console.error();
}
})
.catch(console.error);
// update account follows
updateAccount("follows", follows, account.pubkey);
const tags = arrayToNIP02(follows);
const event: any = {
content: "",
created_at: Math.floor(Date.now() / 1000),
kind: 3,
pubkey: account.pubkey,
tags: tags,
};
event.id = getEventHash(event);
event.sig = getSignature(event, account.privkey);
// publish
pool.publish(event, WRITEONLY_RELAYS);
// redirect to step 3
setTimeout(
() =>
navigate("/app/prefetch", {
overwriteLastHistoryEntry: true,
}),
2000,
);
};
return (

View File

@@ -1,6 +1,4 @@
import { onboardingAtom } from "@stores/onboarding";
import { useSetAtom } from "jotai";
import { createAccount } from "@utils/storage";
import { getPublicKey, nip19 } from "nostr-tools";
import { Resolver, useForm } from "react-hook-form";
import { navigate } from "vite-plugin-ssr/client/router";
@@ -24,8 +22,6 @@ const resolver: Resolver<FormValues> = async (values) => {
};
export function Page() {
const setOnboardingPrivkey = useSetAtom(onboardingAtom);
const {
register,
setError,
@@ -42,8 +38,14 @@ export function Page() {
}
if (typeof getPublicKey(privkey) === "string") {
setOnboardingPrivkey((prev) => ({ ...prev, privkey: privkey }));
navigate("/app/auth/import/step-2");
const pubkey = getPublicKey(privkey);
const npub = nip19.npubEncode(pubkey);
const account = await createAccount(npub, pubkey, privkey, null, 1);
if (account) {
navigate("/app/auth/import/step-2");
}
}
} catch (error) {
setError("key", {

View File

@@ -1,85 +1,55 @@
import { Image } from "@shared/image";
import { User } from "@app/auth/components/user";
import { RelayContext } from "@shared/relayProvider";
import { DEFAULT_AVATAR, READONLY_RELAYS } from "@stores/constants";
import { onboardingAtom } from "@stores/onboarding";
import { shortenKey } from "@utils/shortenKey";
import { createAccount, createPleb } from "@utils/storage";
import { useAtom } from "jotai";
import { getPublicKey } from "nostr-tools";
import { useContext, useMemo, useState } from "react";
import { READONLY_RELAYS } from "@stores/constants";
import { useActiveAccount } from "@utils/hooks/useActiveAccount";
import { updateAccount } from "@utils/storage";
import { nip02ToArray } from "@utils/transform";
import { useContext, useState } from "react";
import useSWRSubscription from "swr/subscription";
import { navigate } from "vite-plugin-ssr/client/router";
export function Page() {
const pool: any = useContext(RelayContext);
const { account } = useActiveAccount();
const [loading, setLoading] = useState(false);
const [onboarding, setOnboarding] = useAtom(onboardingAtom);
const pubkey = useMemo(
() => (onboarding.privkey ? getPublicKey(onboarding.privkey) : ""),
[onboarding.privkey],
);
const [follows, setFollows] = useState([]);
const { data, error } = useSWRSubscription(
pubkey ? pubkey : null,
(key, { next }) => {
const unsubscribe = pool.subscribe(
[
{
kinds: [0, 3],
authors: [key],
},
],
READONLY_RELAYS,
(event: any) => {
switch (event.kind) {
case 0:
// update state
next(null, JSON.parse(event.content));
// create account
setOnboarding((prev) => ({ ...prev, metadata: event.content }));
break;
case 3:
setOnboarding((prev) => ({ ...prev, follows: event.tags }));
break;
default:
break;
}
useSWRSubscription(account ? account.pubkey : null, (key: string) => {
const unsubscribe = pool.subscribe(
[
{
kinds: [3],
authors: [key],
},
);
],
READONLY_RELAYS,
(event: any) => {
setFollows(event.tags);
},
);
return () => {
unsubscribe();
};
},
);
return () => {
unsubscribe();
};
});
const submit = () => {
// show loading indicator
setLoading(true);
const follows = onboarding.follows.concat([["p", pubkey]]);
// insert to database
createAccount(pubkey, onboarding.privkey, onboarding.metadata, follows, 1)
.then((res) => {
if (res) {
for (const tag of onboarding.follows) {
fetch(`https://rbr.bio/${tag[1]}/metadata.json`)
.then((data) => data.json())
.then((data) => createPleb(tag[1], data ?? ""));
}
setTimeout(
() => navigate("/", { overwriteLastHistoryEntry: true }),
2000,
);
} else {
console.error();
}
})
.catch(console.error);
// follows as list
const followsList = nip02ToArray(follows);
// update account follows
updateAccount("follows", followsList, account.pubkey);
// redirect to home
setTimeout(
() => navigate("/app/prefetch", { overwriteLastHistoryEntry: true }),
2000,
);
};
return (
@@ -91,8 +61,7 @@ export function Page() {
</h1>
</div>
<div className="w-full rounded-lg border border-zinc-800 bg-zinc-900 p-4">
{error && <div>Failed to load profile</div>}
{!data ? (
{!account ? (
<div className="w-full">
<div className="flex items-center gap-2">
<div className="h-11 w-11 animate-pulse rounded-lg bg-zinc-800" />
@@ -104,21 +73,7 @@ export function Page() {
</div>
) : (
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<Image
className="relative inline-flex h-11 w-11 rounded-lg ring-2 ring-zinc-900"
src={data.picture || DEFAULT_AVATAR}
alt={pubkey}
/>
<div>
<h3 className="font-medium leading-none text-white">
{data.display_name || data.name}
</h3>
<p className="text-base text-zinc-400">
{data.nip05 || shortenKey(pubkey)}
</p>
</div>
</div>
<User pubkey={account.pubkey} />
<button
type="button"
onClick={() => submit()}