From b98a5f78b26d5d536c9aa3c4c34a027f055c614a Mon Sep 17 00:00:00 2001 From: kyranjamie Date: Fri, 6 Dec 2024 13:40:39 +0100 Subject: [PATCH] feat: migrate legacy auth request to approver ux --- .eslintrc.cjs | 5 +- src/app/common/focus-tab.ts | 10 ++++ .../current-accout-displayer.tsx | 47 ++++++++++++++++ .../pages/choose-account/choose-account.tsx | 53 ------------------- .../components/accounts.tsx | 0 .../legacy-account-auth.tsx | 43 +++++++++++++++ .../components/get-addresses.layout.tsx | 4 +- .../rpc-get-addresses/rpc-get-addresses.tsx | 43 +-------------- .../rpc-get-addresses/use-get-addresses.ts | 6 +-- src/app/routes/app-routes.tsx | 4 +- 10 files changed, 109 insertions(+), 106 deletions(-) create mode 100644 src/app/common/focus-tab.ts create mode 100644 src/app/features/current-account/current-accout-displayer.tsx delete mode 100644 src/app/pages/choose-account/choose-account.tsx rename src/app/pages/{choose-account => legacy-account-auth}/components/accounts.tsx (100%) create mode 100644 src/app/pages/legacy-account-auth/legacy-account-auth.tsx diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 8b854719a1a..6fbcb6000d1 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -25,16 +25,13 @@ module.exports = { 'plugin:storybook/csf', ], ignorePatterns: ['./leather-styles'], - plugins: ['react', 'react-hooks', '@typescript-eslint', 'deprecation'], + plugins: ['react', 'react-hooks', '@typescript-eslint'], settings: { react: { version: 'detect', }, }, rules: { - // This rule helps highlight areas of the code that use deprecated - // methods, such as implicit use of signed transactions - 'deprecation/deprecation': 'warn', 'no-console': ['error'], 'no-duplicate-imports': ['error'], 'prefer-const': [ diff --git a/src/app/common/focus-tab.ts b/src/app/common/focus-tab.ts new file mode 100644 index 00000000000..09f74c91964 --- /dev/null +++ b/src/app/common/focus-tab.ts @@ -0,0 +1,10 @@ +export function focusTab(tabId: number | null) { + chrome.tabs.update(tabId ?? 0, { active: true }); +} + +export function focusTabAndWindow(tabId: number | null) { + chrome.tabs.update(tabId ?? 0, { active: true }, tab => { + if (!tab) return; + chrome.windows.update(tab.windowId, { focused: true }); + }); +} diff --git a/src/app/features/current-account/current-accout-displayer.tsx b/src/app/features/current-account/current-accout-displayer.tsx new file mode 100644 index 00000000000..585b75eb5f8 --- /dev/null +++ b/src/app/features/current-account/current-accout-displayer.tsx @@ -0,0 +1,47 @@ +import { Box } from 'leather-styles/jsx'; + +import { useAccountDisplayName } from '@app/common/hooks/account/use-account-names'; +import { AccountTotalBalance } from '@app/components/account-total-balance'; +import { AcccountAddresses } from '@app/components/account/account-addresses'; +import { AccountListItemLayout } from '@app/components/account/account-list-item.layout'; +import { AccountNameLayout } from '@app/components/account/account-name'; +import { useCurrentAccountIndex } from '@app/store/accounts/account'; +import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; +import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; +import { AccountAvatarItem } from '@app/ui/components/account/account-avatar/account-avatar-item'; + +interface CurrentAccountDisplayerProps { + onSelectAccount(): void; +} +export function CurrentAccountDisplayer({ onSelectAccount }: CurrentAccountDisplayerProps) { + const index = useCurrentAccountIndex(); + const stacksAccounts = useStacksAccounts(); + const stxAddress = stacksAccounts[index]?.address || ''; + const { data: name = '' } = useAccountDisplayName({ address: stxAddress, index }); + const bitcoinSigner = useNativeSegwitSigner(index); + const bitcoinAddress = bitcoinSigner?.(0).address || ''; + return ( + } + accountName={{name}} + avatar={ + + } + balanceLabel={ + // Hack to center element without adjusting AccountListItemLayout + + + + } + index={index} + isLoading={false} + isSelected={false} + onSelectAccount={() => onSelectAccount()} + /> + ); +} diff --git a/src/app/pages/choose-account/choose-account.tsx b/src/app/pages/choose-account/choose-account.tsx deleted file mode 100644 index 2b0eccc8e10..00000000000 --- a/src/app/pages/choose-account/choose-account.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useEffect } from 'react'; -import { Outlet } from 'react-router-dom'; - -import { Flex, Stack, styled } from 'leather-styles/jsx'; - -import { LeatherLogomarkIcon } from '@leather.io/ui'; - -import { closeWindow } from '@shared/utils'; - -import { useCancelAuthRequest } from '@app/common/authentication/use-cancel-auth-request'; -import { useAppDetails } from '@app/common/hooks/auth/use-app-details'; -import { RequesterFlag } from '@app/components/requester-flag'; -import { ChooseAccountsList } from '@app/pages/choose-account/components/accounts'; -import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; -import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; - -export function ChooseAccount() { - const { url } = useAppDetails(); - const accounts = useStacksAccounts(); - const hasConnectedStacksAccounts = accounts.length > 0; - - const cancelAuthentication = useCancelAuthRequest(); - - useOnOriginTabClose(() => closeWindow()); - - const handleUnmount = async () => cancelAuthentication(); - - useEffect(() => { - window.addEventListener('beforeunload', handleUnmount); - return () => window.removeEventListener('beforeunload', handleUnmount); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - <> - - - {url && } - - - - {hasConnectedStacksAccounts - ? 'Choose an account to connect' - : 'No connected accounts found'} - - - - {hasConnectedStacksAccounts && } - - - - ); -} diff --git a/src/app/pages/choose-account/components/accounts.tsx b/src/app/pages/legacy-account-auth/components/accounts.tsx similarity index 100% rename from src/app/pages/choose-account/components/accounts.tsx rename to src/app/pages/legacy-account-auth/components/accounts.tsx diff --git a/src/app/pages/legacy-account-auth/legacy-account-auth.tsx b/src/app/pages/legacy-account-auth/legacy-account-auth.tsx new file mode 100644 index 00000000000..abea16827f5 --- /dev/null +++ b/src/app/pages/legacy-account-auth/legacy-account-auth.tsx @@ -0,0 +1,43 @@ +import { noop } from 'rxjs'; + +import { closeWindow } from '@shared/utils'; + +import { useCancelAuthRequest } from '@app/common/authentication/use-cancel-auth-request'; +import { useFinishAuthRequest } from '@app/common/authentication/use-finish-auth-request'; +import { useAppDetails } from '@app/common/hooks/auth/use-app-details'; +import { useOnMount } from '@app/common/hooks/use-on-mount'; +import { useSwitchAccountSheet } from '@app/common/switch-account/use-switch-account-sheet-context'; +import { openInNewTab } from '@app/common/utils/open-in-new-tab'; +import { CurrentAccountDisplayer } from '@app/features/current-account/current-accout-displayer'; +import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; +import { useCurrentAccountIndex } from '@app/store/accounts/account'; + +import { GetAddressesLayout } from '../rpc-get-addresses/components/get-addresses.layout'; + +export function LegacyAccountAuth() { + const { url } = useAppDetails(); + const accountIndex = useCurrentAccountIndex(); + const finishSignIn = useFinishAuthRequest(); + const { toggleSwitchAccount } = useSwitchAccountSheet(); + + useOnOriginTabClose(() => closeWindow()); + + const cancelAuthentication = useCancelAuthRequest(); + + const handleUnmount = async () => cancelAuthentication(); + useOnMount(() => window.addEventListener('beforeunload', handleUnmount)); + + if (!url) throw new Error('No app details found'); + + return ( + finishSignIn(accountIndex)} + // Here we should refocus the tab that initiated the request, however + // because the old auth code doesn't have the tab id and should be + // eventually removed, we just open in a new tab + onClickRequestedByLink={() => openInNewTab(url.origin)} + switchAccount={} + /> + ); +} diff --git a/src/app/pages/rpc-get-addresses/components/get-addresses.layout.tsx b/src/app/pages/rpc-get-addresses/components/get-addresses.layout.tsx index 6a40b309560..7575bf585c1 100644 --- a/src/app/pages/rpc-get-addresses/components/get-addresses.layout.tsx +++ b/src/app/pages/rpc-get-addresses/components/get-addresses.layout.tsx @@ -22,7 +22,7 @@ interface GetAddressesLayoutProps { requester: string; switchAccount: ReactNode; onBeforeAnimation?(): void; - onUserApprovesGetAddresses(): void; + onUserApprovesGetAddresses(): void | Promise; onClickRequestedByLink(): void; } export function GetAddressesLayout({ @@ -61,7 +61,7 @@ export function GetAddressesLayout({ }); await checkmarkEnters.start({ scale: 0.5, dur: 0.32 }); await delay(280); - onUserApprovesGetAddresses(); + await onUserApprovesGetAddresses(); await delay(280); await originLogoAnimation.start({ scale: 0, diff --git a/src/app/pages/rpc-get-addresses/rpc-get-addresses.tsx b/src/app/pages/rpc-get-addresses/rpc-get-addresses.tsx index f3b899ca591..ddac23e9f0e 100644 --- a/src/app/pages/rpc-get-addresses/rpc-get-addresses.tsx +++ b/src/app/pages/rpc-get-addresses/rpc-get-addresses.tsx @@ -1,30 +1,14 @@ -import { Box } from 'leather-styles/jsx'; - import { closeWindow } from '@shared/utils'; -import { useAccountDisplayName } from '@app/common/hooks/account/use-account-names'; import { useSwitchAccountSheet } from '@app/common/switch-account/use-switch-account-sheet-context'; -import { AccountTotalBalance } from '@app/components/account-total-balance'; -import { AcccountAddresses } from '@app/components/account/account-addresses'; -import { AccountListItemLayout } from '@app/components/account/account-list-item.layout'; -import { AccountNameLayout } from '@app/components/account/account-name'; +import { CurrentAccountDisplayer } from '@app/features/current-account/current-accout-displayer'; import { useOnOriginTabClose } from '@app/routes/hooks/use-on-tab-closed'; -import { useCurrentAccountIndex } from '@app/store/accounts/account'; -import { useNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; -import { useStacksAccounts } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; -import { AccountAvatarItem } from '@app/ui/components/account/account-avatar/account-avatar-item'; import { GetAddressesLayout } from './components/get-addresses.layout'; import { useGetAddresses } from './use-get-addresses'; export function RpcGetAddresses() { const { focusInitatingTab, origin, onUserApproveGetAddresses } = useGetAddresses(); - const index = useCurrentAccountIndex(); - const stacksAccounts = useStacksAccounts(); - const stxAddress = stacksAccounts[index]?.address || ''; - const { data: name = '' } = useAccountDisplayName({ address: stxAddress, index }); - const bitcoinSigner = useNativeSegwitSigner(index); - const bitcoinAddress = bitcoinSigner?.(0).address || ''; useOnOriginTabClose(() => closeWindow()); @@ -39,30 +23,7 @@ export function RpcGetAddresses() { } - accountName={{name}} - avatar={ - - } - balanceLabel={ - // Hack to center element without adjusting AccountListItemLayout - - - - } - index={0} - isLoading={false} - isSelected={false} - onSelectAccount={() => toggleSwitchAccount()} - /> - } + switchAccount={} onUserApprovesGetAddresses={onUserApproveGetAddresses} /> ); diff --git a/src/app/pages/rpc-get-addresses/use-get-addresses.ts b/src/app/pages/rpc-get-addresses/use-get-addresses.ts index fdb511b599e..f8eeb201a50 100644 --- a/src/app/pages/rpc-get-addresses/use-get-addresses.ts +++ b/src/app/pages/rpc-get-addresses/use-get-addresses.ts @@ -7,6 +7,7 @@ import { logger } from '@shared/logger'; import { makeRpcSuccessResponse } from '@shared/rpc/rpc-methods'; import { analytics } from '@shared/utils/analytics'; +import { focusTab } from '@app/common/focus-tab'; import { useRpcRequestParams } from '@app/common/rpc-helpers'; import { useCurrentAccountNativeSegwitSigner } from '@app/store/accounts/blockchain/bitcoin/native-segwit-account.hooks'; import { useCurrentAccountTaprootSigner } from '@app/store/accounts/blockchain/bitcoin/taproot-account.hooks'; @@ -23,10 +24,7 @@ export function useGetAddresses() { function focusInitatingTab() { void analytics.track('user_clicked_requested_by_link', { endpoint: 'getAddresses' }); - chrome.tabs.update(tabId ?? 0, { active: true }, tab => { - if (!tab) return; - chrome.windows.update(tab.windowId, { focused: true }); - }); + focusTab(tabId); } return { diff --git a/src/app/routes/app-routes.tsx b/src/app/routes/app-routes.tsx index 0bf52bfc341..11848ea7037 100644 --- a/src/app/routes/app-routes.tsx +++ b/src/app/routes/app-routes.tsx @@ -30,10 +30,10 @@ import { ledgerStacksTxSigningRoutes } from '@app/features/ledger/flows/stacks-t import { UnsupportedBrowserLayout } from '@app/features/ledger/generic-steps'; import { ConnectLedgerStart } from '@app/features/ledger/generic-steps/connect-device/connect-ledger-start'; import { RetrieveTaprootToNativeSegwit } from '@app/features/retrieve-taproot-to-native-segwit/retrieve-taproot-to-native-segwit'; -import { ChooseAccount } from '@app/pages/choose-account/choose-account'; import { ChooseCryptoAssetToFund } from '@app/pages/fund/choose-asset-to-fund/choose-asset-to-fund'; import { FundPage } from '@app/pages/fund/fund'; import { Home } from '@app/pages/home/home'; +import { LegacyAccountAuth } from '@app/pages/legacy-account-auth/legacy-account-auth'; import { BackUpSecretKeyPage } from '@app/pages/onboarding/back-up-secret-key/back-up-secret-key'; import { SignIn } from '@app/pages/onboarding/sign-in/sign-in'; import { WelcomePage } from '@app/pages/onboarding/welcome/welcome'; @@ -262,7 +262,7 @@ function useAppRoutes() { path={RouteUrls.ChooseAccount} element={ - + } >