Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion src/assets/translations/en/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,21 @@
"body": "Use PIN layout shown on your device to find the location to press on the PIN pad.",
"button": "Unlock"
},
"currentPin": {
"header": "Enter Your Current PIN",
"body": "Confirm the PIN you use today, then you can choose a new one.",
"button": "Continue"
},
"newPin": {
"header": "Create New PIN",
"body": "Use the PIN layout shown on your device to choose a new PIN.",
"button": "Continue"
},
"newPinConfirm": {
"header": "Confirm New PIN",
"body": "Re-enter your new PIN using the layout shown on your device.",
"button": "Confirm"
},
"settings": {
"menuLabels": {
"bootloader": "Bootloader",
Expand Down Expand Up @@ -1613,7 +1628,9 @@
"timeout": "Your device goes to sleep after 10 minutes of inactivity by default. However, you can change this.",
"buttonPrompt": "Press and hold the button on your KeepKey to change the device %{setting}.",
"updateSuccess": "%{setting} successfully updated!",
"updateFailed": "An error occurred whilst updating the %{setting}.",
"updateFailed": "%{setting} update failed",
"passphraseEnabled": "Passphrase protection enabled. You'll be asked for a passphrase each time you connect.",
"passphraseDisabled": "Passphrase protection disabled",
"timeoutDuration": "%{minutes} minutes"
},
"alerts": {
Expand Down
80 changes: 21 additions & 59 deletions src/components/Layout/Header/NavBar/DrawerWalletHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
import { CloseIcon, RepeatIcon } from '@chakra-ui/icons'
import {
Flex,
Icon,
IconButton,
Menu,
MenuButton,
MenuDivider,
MenuGroup,
MenuItem,
MenuList,
Text,
} from '@chakra-ui/react'
import { Flex, Icon, IconButton, Menu, MenuButton, MenuList, Text } from '@chakra-ui/react'
import type { FC } from 'react'
import { memo, useCallback, useMemo } from 'react'
import { FiArrowLeft } from 'react-icons/fi'
import { TbDots, TbEdit, TbEyeOff, TbHistory, TbSettings } from 'react-icons/tb'
import { TbDots, TbEdit, TbHistory, TbSettings } from 'react-icons/tb'
import { useTranslate } from 'react-polyglot'
import { useNavigate } from 'react-router-dom'

import { WalletImage } from './WalletImage'
import { DrawerWalletMenu } from './DrawerWalletMenu'

import { QRCodeIcon } from '@/components/Icons/QRCode'
import { SUPPORTED_WALLETS } from '@/context/WalletProvider/config'
import type { InitialState } from '@/context/WalletProvider/WalletProvider'
import { useNewConversation } from '@/features/agenticChat/hooks/useNewConversation'
import { useModal } from '@/hooks/useModal/useModal'
Expand All @@ -34,10 +21,12 @@ import { useAppDispatch, useAppSelector } from '@/state/store'

const settingsIcon = <TbSettings />
const dotsIcon = <Icon as={TbDots} />
const eyeOffIcon = <Icon as={TbEyeOff} />
const qrCodeIcon = <QRCodeIcon />
const historyIcon = <TbHistory />
const newChatIcon = <TbEdit />
// 'full' is 100% of the popper, which sizes to content, so cap against the viewport instead
const menuMaxWidth = { base: 'calc(100vw - 1rem)', md: 'xs' }
const menuMinWidth = { base: 0, md: 'xs' }

type DrawerHeaderProps = {
walletInfo: InitialState['walletInfo']
Expand Down Expand Up @@ -116,19 +105,6 @@ export const DrawerWalletHeader: FC<DrawerHeaderProps> = memo(
navigate('/manage-hidden-assets')
}, [navigate])

const repeatIcon = useMemo(() => <RepeatIcon />, [])
const closeIcon = useMemo(() => <CloseIcon />, [])

const ConnectMenuComponent = useMemo(
() => connectedType && SUPPORTED_WALLETS[connectedType]?.connectedMenuComponent,
[connectedType],
)

const walletImageIcon = useMemo(
() => <WalletImage walletInfo={maybeMipdProvider?.info ?? walletInfo} />,
[walletInfo, maybeMipdProvider?.info],
)

const actionButtons = useMemo(() => {
if (isChatOpen) {
return (
Expand Down Expand Up @@ -192,7 +168,7 @@ export const DrawerWalletHeader: FC<DrawerHeaderProps> = memo(
size='md'
onClick={handleSettingsClick}
/>
<Menu>
<Menu isLazy>
<MenuButton
as={IconButton}
isRound
Expand All @@ -201,34 +177,20 @@ export const DrawerWalletHeader: FC<DrawerHeaderProps> = memo(
icon={dotsIcon}
size='md'
/>
<MenuList zIndex={'popover'}>
<MenuGroup title={translate('common.connectedWallet')} color='text.subtle'>
<MenuItem icon={walletImageIcon} isDisabled closeOnSelect={false}>
<Flex flexDir='row' justifyContent='space-between' alignItems='center'>
<Text>{label}</Text>
</Flex>
</MenuItem>
</MenuGroup>
<MenuDivider />
<MenuGroup title={translate('common.walletActions')} color='text.subtle'>
{ConnectMenuComponent && <ConnectMenuComponent />}
<MenuDivider />
<MenuItem icon={eyeOffIcon} onClick={handleManageHiddenAssetsClick}>
{translate('manageHiddenAssets.title')}
</MenuItem>
<MenuDivider />
<MenuItem icon={repeatIcon} onClick={onSwitchProvider}>
{translate('connectWallet.menu.switchWallet')}
</MenuItem>
<MenuItem
fontWeight='medium'
icon={closeIcon}
onClick={onDisconnect}
color='red.500'
>
{translate('connectWallet.menu.disconnect')}
</MenuItem>
</MenuGroup>
<MenuList
zIndex={'popover'}
maxWidth={menuMaxWidth}
minWidth={menuMinWidth}
overflow='hidden'
>
<DrawerWalletMenu
walletInfo={maybeMipdProvider?.info ?? walletInfo}
connectedType={connectedType}
label={label}
onDisconnect={onDisconnect}
onSwitchProvider={onSwitchProvider}
onManageHiddenAssets={handleManageHiddenAssetsClick}
/>
</MenuList>
</Menu>
</Flex>
Expand Down
153 changes: 153 additions & 0 deletions src/components/Layout/Header/NavBar/DrawerWalletMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import { ChevronRightIcon, CloseIcon, RepeatIcon } from '@chakra-ui/icons'
import { Flex, Icon, MenuDivider, MenuGroup, MenuItem, Text } from '@chakra-ui/react'
import { AnimatePresence } from 'framer-motion'
import type { ComponentProps } from 'react'
import { useCallback, useMemo } from 'react'
import { TbEyeOff } from 'react-icons/tb'
import { useTranslate } from 'react-polyglot'
import { MemoryRouter, useLocation } from 'react-router-dom'
import { Route, Switch } from 'wouter'

import { useMenuRoutes, WalletConnectedRoutes } from './hooks/useMenuRoutes'
import { SubMenuContainer } from './SubMenuContainer'
import { WalletImage } from './WalletImage'

import { CircularProgress } from '@/components/CircularProgress/CircularProgress'
import { SuspenseErrorBoundary } from '@/components/ErrorBoundary'
import type { WalletProviderRouteProps } from '@/context/WalletProvider/config'
import { SUPPORTED_WALLETS } from '@/context/WalletProvider/config'
import type { InitialState } from '@/context/WalletProvider/WalletProvider'

const entries = [WalletConnectedRoutes.Connected]

// The default loading fallback is full height, which blows the menu open while a chunk loads
const suspenseFallback = (
<Flex justifyContent='center' alignItems='center' height='120px'>
<CircularProgress />
</Flex>
)

const eyeOffIcon = <Icon as={TbEyeOff} />
const repeatIcon = <RepeatIcon />
const closeIcon = <CloseIcon />

export type DrawerWalletMenuProps = {
walletInfo: ComponentProps<typeof WalletImage>['walletInfo']
connectedType: InitialState['connectedType']
label: string | undefined
onDisconnect: () => void
onSwitchProvider: () => void
onManageHiddenAssets: () => void
}

const useConnectedWalletMenuRoutes = (connectedType: InitialState['connectedType']) =>
useMemo(
() => connectedType && SUPPORTED_WALLETS[connectedType]?.connectedWalletMenuRoutes,
[connectedType],
)

const DrawerWalletMenuRoot = ({
walletInfo,
connectedType,
label,
onDisconnect,
onSwitchProvider,
onManageHiddenAssets,
}: DrawerWalletMenuProps) => {
const translate = useTranslate()
const { navigateToRoute } = useMenuRoutes()

const connectedWalletMenuRoutes = useConnectedWalletMenuRoutes(connectedType)

const ConnectMenuComponent = useMemo(
() => connectedType && SUPPORTED_WALLETS[connectedType]?.connectedMenuComponent,
[connectedType],
)

const walletImageIcon = useMemo(() => <WalletImage walletInfo={walletInfo} />, [walletInfo])

const handleWalletClick = useCallback(() => {
if (!connectedWalletMenuRoutes) return

navigateToRoute(
(connectedType && SUPPORTED_WALLETS[connectedType]?.connectedWalletMenuInitialPath) ??
WalletConnectedRoutes.Connected,
)
}, [connectedType, connectedWalletMenuRoutes, navigateToRoute])

return (
<>
<MenuGroup title={translate('common.connectedWallet')} color='text.subtle'>
<MenuItem
icon={walletImageIcon}
isDisabled={!connectedWalletMenuRoutes}
closeOnSelect={false}
onClick={handleWalletClick}
>
<Flex flexDir='row' justifyContent='space-between' alignItems='center' width='100%'>
<Text>{label}</Text>
{connectedWalletMenuRoutes && <ChevronRightIcon />}
</Flex>
</MenuItem>
</MenuGroup>
<MenuDivider />
<MenuGroup title={translate('common.walletActions')} color='text.subtle'>
{/* GridPlus supplies a lazy component, and the menu remounts on every open */}
{ConnectMenuComponent && (
<SuspenseErrorBoundary loadingFallback={suspenseFallback}>
<ConnectMenuComponent />
</SuspenseErrorBoundary>
)}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<MenuDivider />
<MenuItem icon={eyeOffIcon} onClick={onManageHiddenAssets}>
{translate('manageHiddenAssets.title')}
</MenuItem>
<MenuDivider />
<MenuItem icon={repeatIcon} onClick={onSwitchProvider}>
{translate('connectWallet.menu.switchWallet')}
</MenuItem>
<MenuItem fontWeight='medium' icon={closeIcon} onClick={onDisconnect} color='red.500'>
{translate('connectWallet.menu.disconnect')}
</MenuItem>
</MenuGroup>
</>
)
}

const DrawerWalletMenuRoutes = (props: DrawerWalletMenuProps) => {
const location = useLocation()
const connectedWalletMenuRoutes = useConnectedWalletMenuRoutes(props.connectedType)

const renderRoute = useCallback((route: WalletProviderRouteProps, i: number) => {
const Component = route.component

return (
<Route key={`drawerWalletMenuRoute_${i}`} path={route.path || ''}>
<SuspenseErrorBoundary loadingFallback={suspenseFallback}>
<Component />
</SuspenseErrorBoundary>
</Route>
)
}, [])

return (
<AnimatePresence mode='wait' initial={false}>
<Switch location={location.pathname}>
<Route path={WalletConnectedRoutes.Connected}>
<SubMenuContainer>
<DrawerWalletMenuRoot {...props} />
</SubMenuContainer>
</Route>
{connectedWalletMenuRoutes?.map((route, index) => renderRoute(route, index))}
</Switch>
</AnimatePresence>
)
}

export const DrawerWalletMenu = (props: DrawerWalletMenuProps) => {
return (
<MemoryRouter initialEntries={entries}>
<DrawerWalletMenuRoutes {...props} />
</MemoryRouter>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
)
}
Loading
Loading