From 9ba584bf1483f9ac2bd39516c17fd88274c22528 Mon Sep 17 00:00:00 2001 From: reya Date: Fri, 26 Jan 2024 10:17:23 +0700 Subject: [PATCH] feat: improve onboarding --- apps/desktop/package.json | 1 + .../src/routes/auth/create-address.tsx | 10 +- apps/desktop/src/routes/auth/create-keys.tsx | 205 +++++++++++++----- apps/desktop/src/routes/auth/create.tsx | 32 ++- apps/desktop/src/routes/auth/login-key.tsx | 2 +- .../src/routes/auth/login-nsecbunker.tsx | 2 +- apps/desktop/src/routes/auth/login-oauth.tsx | 2 +- apps/desktop/src/routes/auth/login.tsx | 2 +- apps/desktop/src/routes/auth/onboarding.tsx | 33 +-- packages/ark/src/ark.ts | 2 +- packages/ui/src/onboarding/interest.tsx | 5 +- packages/ui/src/onboarding/profile.tsx | 12 +- packages/ui/src/routes/suggest.tsx | 8 +- pnpm-lock.yaml | 31 +++ 14 files changed, 222 insertions(+), 125 deletions(-) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index de615d53..785f5cfd 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -25,6 +25,7 @@ "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-avatar": "^1.0.4", + "@radix-ui/react-checkbox": "^1.0.4", "@radix-ui/react-collapsible": "^1.0.3", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", diff --git a/apps/desktop/src/routes/auth/create-address.tsx b/apps/desktop/src/routes/auth/create-address.tsx index 8a525bdc..c99ac938 100644 --- a/apps/desktop/src/routes/auth/create-address.tsx +++ b/apps/desktop/src/routes/auth/create-address.tsx @@ -124,11 +124,11 @@ export function CreateAccountAddress() { // add account to storage await storage.createSetting("nsecbunker", "1"); - const dbAccount = await storage.createAccount({ + const newAccount = await storage.createAccount({ pubkey: account, privkey: localSigner.privateKey, }); - ark.account = dbAccount; + ark.account = newAccount; // get final signer with newly created account const finalSigner = new NDKNip46Signer(bunker, account, localSigner); @@ -153,9 +153,11 @@ export function CreateAccountAddress() { return (
-
+
-

Create Account

+

+ Let's set up your account on Nostr +

{!services ? (
diff --git a/apps/desktop/src/routes/auth/create-keys.tsx b/apps/desktop/src/routes/auth/create-keys.tsx index 4090075c..46cb4347 100644 --- a/apps/desktop/src/routes/auth/create-keys.tsx +++ b/apps/desktop/src/routes/auth/create-keys.tsx @@ -1,13 +1,16 @@ import { useArk } from "@lume/ark"; +import { CheckIcon, EyeOffIcon, EyeOnIcon, LoaderIcon } from "@lume/icons"; import { useStorage } from "@lume/storage"; import { onboardingAtom } from "@lume/utils"; import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; +import * as Checkbox from "@radix-ui/react-checkbox"; import { desktopDir } from "@tauri-apps/api/path"; import { save } from "@tauri-apps/plugin-dialog"; import { writeTextFile } from "@tauri-apps/plugin-fs"; import { useSetAtom } from "jotai"; import { nanoid } from "nanoid"; import { getPublicKey, nip19 } from "nostr-tools"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import { toast } from "sonner"; @@ -17,73 +20,165 @@ export function CreateAccountKeys() { const setOnboarding = useSetAtom(onboardingAtom); const navigate = useNavigate(); - const generateNostrKeys = async () => { - const signer = NDKPrivateKeySigner.generate(); - const pubkey = getPublicKey(signer.privateKey); + const [key, setKey] = useState(""); + const [loading, setLoading] = useState(false); + const [showKey, setShowKey] = useState(false); + const [confirm, setConfirm] = useState({ c1: false, c2: false, c3: false }); - const npub = nip19.npubEncode(pubkey); - const nsec = nip19.nsecEncode(signer.privateKey); + const submit = async () => { + try { + setLoading(true); - ark.updateNostrSigner({ signer }); + const privkey = nip19.decode(key).data as string; + const signer = new NDKPrivateKeySigner(privkey); + const pubkey = getPublicKey(privkey); - const downloadPath = await desktopDir(); - const fileName = `nostr_keys_${nanoid(4)}.txt`; - const filePath = await save({ - defaultPath: `${downloadPath}/${fileName}`, - }); + ark.updateNostrSigner({ signer }); - if (!filePath) { - return toast.info("You need to save account keys before continue."); + const downloadPath = await desktopDir(); + const fileName = `nostr_keys_${nanoid(4)}.txt`; + const filePath = await save({ + defaultPath: `${downloadPath}/${fileName}`, + }); + + if (!filePath) { + return toast.info("You need to save account keys before continue."); + } + + await writeTextFile( + filePath, + `Nostr Account\nGenerated by Lume (lume.nu)\n---\nPrivate key: ${key}`, + ); + + const newAccount = await storage.createAccount({ + pubkey: pubkey, + privkey: privkey, + }); + ark.account = newAccount; + + setLoading(false); + setOnboarding({ open: true, newUser: true }); + + return navigate("/auth/onboarding", { replace: true }); + } catch (e) { + setLoading(false); + toast.error(String(e)); } - - await writeTextFile( - filePath, - `Nostr Account\nGenerated by Lume (lume.nu)\n---\nPublic key: ${npub}\nPrivate key: ${nsec}`, - ); - - await storage.createAccount({ - pubkey: pubkey, - privkey: signer.privateKey, - }); - - setOnboarding({ open: true, newUser: true }); - - return navigate("/auth/onboarding", { replace: true }); }; + useEffect(() => { + const privkey = NDKPrivateKeySigner.generate().privateKey; + setKey(nip19.nsecEncode(privkey)); + }, []); + return (
-
+
-

Create Account

+

+ This is your new Account Key +

+

+ Keep your key in safe place. If you lose this key, you will lose + access to your account. +

-
-
- - -
-
- - +
+
+
+ + +
+
+
+ + setConfirm((state) => ({ ...state, c1: !state.c1 })) + } + className="flex size-7 appearance-none items-center justify-center rounded-lg bg-neutral-900 outline-none" + id="confirm1" + > + + + + + +
+
+ + setConfirm((state) => ({ ...state, c2: !state.c2 })) + } + className="flex size-7 appearance-none items-center justify-center rounded-lg bg-neutral-900 outline-none" + id="confirm2" + > + + + + + +
+
+ + setConfirm((state) => ({ ...state, c3: !state.c3 })) + } + className="flex size-7 appearance-none items-center justify-center rounded-lg bg-neutral-900 outline-none" + id="confirm3" + > + + + + + +
+
+
diff --git a/apps/desktop/src/routes/auth/create.tsx b/apps/desktop/src/routes/auth/create.tsx index 9a1a7c3f..c0b5a301 100644 --- a/apps/desktop/src/routes/auth/create.tsx +++ b/apps/desktop/src/routes/auth/create.tsx @@ -21,29 +21,14 @@ export function CreateAccountScreen() { return (
-
+
-

- Let's get you set up on Nostr. -

+

Let's Get Started

Choose one of methods below to create your account

- +
{isLoading ? ( -
+
) : isError ? ( -
+
Error. Cannot get trending users
) : ( @@ -171,9 +171,9 @@ export function SuggestRoute({ queryKey }: { queryKey: string[] }) { type="button" onClick={submit} disabled={loading} - className="inline-flex items-center justify-center gap-2 px-6 font-medium text-white transform bg-blue-500 rounded-full active:translate-y-1 w-36 h-11 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed" + className="inline-flex items-center justify-center gap-2 px-6 font-medium shadow-xl shadow-neutral-500/50 text-white transform bg-blue-500 rounded-full active:translate-y-1 w-36 h-11 hover:bg-blue-600 focus:outline-none disabled:cursor-not-allowed" > - Save + Save & Go Back
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24133739..55152cd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -117,6 +117,9 @@ importers: '@radix-ui/react-avatar': specifier: ^1.0.4 version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-checkbox': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-collapsible': specifier: ^1.0.3 version: 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) @@ -2138,6 +2141,34 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-checkbox@1.0.4(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.8 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-use-previous': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.48)(react@18.2.0) + '@types/react': 18.2.48 + '@types/react-dom': 18.2.18 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.18)(@types/react@18.2.48)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} peerDependencies: