diff --git a/.changeset/five-llamas-bake.md b/.changeset/five-llamas-bake.md new file mode 100644 index 000000000..6f2b81748 --- /dev/null +++ b/.changeset/five-llamas-bake.md @@ -0,0 +1,7 @@ +--- +'@status-im/components': minor +'@status-im/wallet': minor +'wallet': minor +--- + +add import wallet flow diff --git a/.vscode/settings.json b/.vscode/settings.json index 196450acf..b4c74d1bd 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,9 @@ { "typescript.tsdk": "node_modules/typescript/lib", "npm.packageManager": "pnpm", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + }, "eslint.useESLintClass": true, "eslint.workingDirectories": [ "./packages/colors", @@ -17,6 +20,14 @@ "#comment": "See https://github.com/microsoft/vscode-eslint/issues/1161 for reason (i.e. multiple .eslintrc config files)" } ], + "eslint.validate": [ + // "markdown", + // "mdx", + "javascript", + "javascriptreact", + "typescript", + "typescriptreact" + ], "tailwindCSS.experimental.classRegex": [ ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] diff --git a/apps/wallet/package.json b/apps/wallet/package.json index 8deb47d2a..8533d2703 100644 --- a/apps/wallet/package.json +++ b/apps/wallet/package.json @@ -43,6 +43,9 @@ "@trpc/server": "10.45.2", "@trustwallet/wallet-core": "^4.2.10", "@wxt-dev/storage": "^1.1.0", + "@zxcvbn-ts/core": "^3.0.4", + "@zxcvbn-ts/language-common": "^3.0.4", + "@zxcvbn-ts/language-en": "^3.0.2", "bitcoinjs-lib": "^6.1.7", "bitcore-lib": "^10.8.0", "buffer": "^6.0.3", diff --git a/apps/wallet/src/assets/Illustration.png b/apps/wallet/src/assets/Illustration.png new file mode 100644 index 000000000..cea8aa2aa Binary files /dev/null and b/apps/wallet/src/assets/Illustration.png differ diff --git a/apps/wallet/src/data/api.test.ts b/apps/wallet/src/data/api.test.ts index 7aceb2047..9874e95d9 100644 --- a/apps/wallet/src/data/api.test.ts +++ b/apps/wallet/src/data/api.test.ts @@ -82,7 +82,7 @@ test('should add wallet', async () => { }) expect(addedWallet.mnemonic).toBeDefined() -}, 6000) +}, 7000) test('should import wallet', async () => { await createAPI() @@ -98,7 +98,7 @@ test('should import wallet', async () => { }) expect(importedWallet.mnemonic).toBe(mnemonic) -}, 6000) +}, 7000) test('should get wallet', async () => { await createAPI() @@ -119,4 +119,4 @@ test('should get wallet', async () => { }) expect(returnedWallet.mnemonic).toBe(mnemonic) -}, 6000) +}, 7000) diff --git a/apps/wallet/src/routes/__root.tsx b/apps/wallet/src/routes/__root.tsx index 94fbf8533..83a21b0d0 100644 --- a/apps/wallet/src/routes/__root.tsx +++ b/apps/wallet/src/routes/__root.tsx @@ -10,6 +10,7 @@ import { Link, // Navigate, Outlet, + redirect, } from '@tanstack/react-router' import { TanStackRouterDevtools } from '@tanstack/router-devtools' @@ -19,6 +20,7 @@ import { TanStackRouterDevtools } from '@tanstack/router-devtools' // import { QueryClientProvider } from '../../../portfolio/src/app/_providers/query-client-provider' // import { StatusProvider } from '../../../portfolio/src/app/_providers/status-provider' import { WagmiProvider } from '../../../portfolio/src/app/_providers/wagmi-provider' +import { apiClient } from '../providers/api-client' import { WalletProvider } from '../providers/wallet-context' // import { Inter } from 'next/font/google' @@ -34,6 +36,26 @@ import type { QueryClient } from '@tanstack/react-query' export const Route = createRootRouteWithContext<{ queryClient: QueryClient }>()({ + beforeLoad: async ({ location }) => { + const wallets = await apiClient.wallet.all.query() + const hasWallets = wallets && wallets.length > 0 + + if (location.pathname === '/') { + if (hasWallets) { + throw redirect({ to: '/portfolio' }) + } else { + throw redirect({ to: '/onboarding' }) + } + } + + if (location.pathname.startsWith('/portfolio') && !hasWallets) { + throw redirect({ to: '/onboarding' }) + } + + if (location.pathname.startsWith('/onboarding') && hasWallets) { + throw redirect({ to: '/portfolio' }) + } + }, head: () => ({ meta: [ { @@ -52,7 +74,6 @@ export const Route = createRootRouteWithContext<{ }) function RootComponent() { - const pathname = window.location.pathname return ( <> {/*
@@ -79,7 +100,7 @@ function RootComponent() { {/* */}
- +
diff --git a/apps/wallet/src/routes/index.tsx b/apps/wallet/src/routes/index.tsx index 1bb24ca6a..04f8acf2d 100644 --- a/apps/wallet/src/routes/index.tsx +++ b/apps/wallet/src/routes/index.tsx @@ -1,6 +1,4 @@ -import { createFileRoute, redirect } from '@tanstack/react-router' - -import { apiClient } from '../providers/api-client' +import { createFileRoute } from '@tanstack/react-router' export const Route = createFileRoute('/')({ component: RouteComponent, @@ -11,12 +9,6 @@ export const Route = createFileRoute('/')({ }, ], }), - beforeLoad: async () => { - const wallets = await apiClient.wallet.all.query() - if (wallets && wallets.length > 0) { - throw redirect({ to: '/portfolio' }) - } else throw redirect({ to: '/onboarding' }) - }, }) function RouteComponent() { diff --git a/apps/wallet/src/routes/onboarding/_layout.tsx b/apps/wallet/src/routes/onboarding/_layout.tsx index 458d0be3c..527e92da8 100644 --- a/apps/wallet/src/routes/onboarding/_layout.tsx +++ b/apps/wallet/src/routes/onboarding/_layout.tsx @@ -1,21 +1,33 @@ -import { createFileRoute, Outlet, redirect } from '@tanstack/react-router' - -import { apiClient } from '../../providers/api-client' +import { BlurredCircle } from '@status-im/wallet/components' +import { createFileRoute, Outlet } from '@tanstack/react-router' export const Route = createFileRoute('/onboarding')({ component: RouteComponent, - beforeLoad: async () => { - const wallets = await apiClient.wallet.all.query() - if (wallets && wallets.length > 0) { - throw redirect({ to: '/portfolio' }) - } - }, }) function RouteComponent() { return ( -
- +
+ + + + + +
+ +
) } diff --git a/apps/wallet/src/routes/onboarding/import.tsx b/apps/wallet/src/routes/onboarding/import.tsx index 5ce68cbac..4a42d7b31 100644 --- a/apps/wallet/src/routes/onboarding/import.tsx +++ b/apps/wallet/src/routes/onboarding/import.tsx @@ -1,11 +1,19 @@ -import { useState } from 'react' +import { useState, useTransition } from 'react' -import { Button, Input } from '@status-im/components' -import { createFileRoute } from '@tanstack/react-router' -import { useForm } from 'react-hook-form' +import { Button, Text } from '@status-im/components' +import { ArrowLeftIcon } from '@status-im/icons/20' +import { + CreatePasswordForm, + type CreatePasswordFormValues, + ImportRecoveryPhraseForm, + type ImportRecoveryPhraseFormValues, +} from '@status-im/wallet/components' +import { createFileRoute, useNavigate } from '@tanstack/react-router' import { useImportWallet } from '../../hooks/use-import-wallet' +import type { SubmitHandler } from 'react-hook-form' + export const Route = createFileRoute('/onboarding/import')({ component: RouteComponent, }) @@ -27,112 +35,115 @@ function RouteComponent() { }) return ( -
+
{onboardingState.type === 'import-wallet' && ( + onNext={(mnemonic: string) => { setOnboardingState({ type: 'create-password', mnemonic }) - } + }} /> )} {onboardingState.type === 'create-password' && ( - + + setOnboardingState({ + type: 'import-wallet', + mnemonic: '', + }) + } + /> )}
) } function ImportWallet({ onNext }: { onNext: (mnemonic: string) => void }) { - const { - register, - handleSubmit, - formState: { errors }, - } = useForm({ - defaultValues: { - mnemonic: '', - }, - }) + const [isPending, startTransition] = useTransition() - const onSubmit = handleSubmit(data => { - onNext(data.mnemonic) - }) + const onSubmit: SubmitHandler< + ImportRecoveryPhraseFormValues + > = async data => { + try { + startTransition(async () => { + onNext(data.mnemonic) + }) + } catch (error) { + console.error(error) + } + } return ( -
-