diff --git a/components/brave_wallet/browser/brave_wallet_constants.h b/components/brave_wallet/browser/brave_wallet_constants.h index f193fc112513..717f2a3c0834 100644 --- a/components/brave_wallet/browser/brave_wallet_constants.h +++ b/components/brave_wallet/browser/brave_wallet_constants.h @@ -412,6 +412,8 @@ inline constexpr webui::LocalizedString kLocalizedStrings[] = { {"braveWalletAccountsEditVisibleAssets", IDS_BRAVE_WALLET_ACCOUNTS_EDIT_VISIBLE_ASSETS}, {"braveWalletAccountBalance", IDS_BRAVE_WALLET_ACCOUNT_BALANCE}, + {"braveWalletViewAddressOn", IDS_BRAVE_WALLET_VIEW_ADDRESS_ON}, + {"braveWalletNetworkExplorer", IDS_BRAVE_WALLET_NETWORK_EXPLORER}, {"braveWalletAddAccountCreate", IDS_BRAVE_WALLET_ADD_ACCOUNT_CREATE}, {"braveWalletCreateAccount", IDS_BRAVE_WALLET_CREATE_ACCOUNT}, {"braveWalletCreateAccountButton", IDS_BRAVE_WALLET_CREATE_ACCOUNT_BUTTON}, diff --git a/components/brave_wallet_ui/components/desktop/card-headers/account-details-header.tsx b/components/brave_wallet_ui/components/desktop/card-headers/account-details-header.tsx index 437cb9c851db..4e6db51a12d5 100644 --- a/components/brave_wallet_ui/components/desktop/card-headers/account-details-header.tsx +++ b/components/brave_wallet_ui/components/desktop/card-headers/account-details-header.tsx @@ -192,6 +192,17 @@ export const AccountDetailsHeader = (props: Props) => { (option: AccountButtonOptionsObjectType) => option.id !== 'privateKey' ) } + // We are currently not able to support viewing a + // BTC or ZEC account on a block explorer. + // Link to issue https://github.com/brave/brave-browser/issues/39699 + if ( + account.accountId.coin === BraveWallet.CoinType.BTC || + account.accountId.coin === BraveWallet.CoinType.ZEC + ) { + options = options.filter( + (option: AccountButtonOptionsObjectType) => option.id !== 'explorer' + ) + } return options }, [account]) diff --git a/components/brave_wallet_ui/components/desktop/popup-modals/style.ts b/components/brave_wallet_ui/components/desktop/popup-modals/style.ts index 19e022130aed..f09a28e76487 100644 --- a/components/brave_wallet_ui/components/desktop/popup-modals/style.ts +++ b/components/brave_wallet_ui/components/desktop/popup-modals/style.ts @@ -75,6 +75,9 @@ export const Header = styled.div<{ export const Title = styled.span` color: ${leo.color.text.primary}; font: ${leo.font.heading.h2}; + @media screen and (max-width: ${layoutPanelWidth}px) { + font: ${leo.font.heading.h4}; + } ` export const HeaderButton = styled(WalletButton)` diff --git a/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/network_button.tsx b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/network_button.tsx new file mode 100644 index 000000000000..7fc3f3452090 --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/network_button.tsx @@ -0,0 +1,56 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +import * as React from 'react' + +// Types +import { BraveWallet } from '../../../../constants/types' + +// Custom hooks +import { useExplorer } from '../../../../common/hooks/explorer' + +// Utils +import { getLocale } from '../../../../../common/locale' + +// Components +import { CreateNetworkIcon } from '../../../shared/create-network-icon' + +// Styles +import { Button, LaunchIcon } from './view_on_block_explorer_modal.style' +import { Text, Row } from '../../../shared/style' + +interface Props { + network: BraveWallet.NetworkInfo + address: string +} + +export const NetworkButton = (props: Props) => { + const { network, address } = props + + // Hooks + const onClickViewOnBlockExplorer = useExplorer(network) + + return ( + + ) +} diff --git a/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.style.ts b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.style.ts new file mode 100644 index 000000000000..c4faca9a4236 --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.style.ts @@ -0,0 +1,52 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +import styled from 'styled-components' +import * as leo from '@brave/leo/tokens/css/variables' +import Icon from '@brave/leo/react/icon' + +// Shared Styled +import { Row, WalletButton, Column, Text } from '../../../shared/style' + +export const StyledWrapper = styled(Column)` + overflow: hidden; +` + +export const AccountInfoRow = styled(Row)` + background-color: ${leo.color.container.highlight}; + border-radius: ${leo.radius.xl}; + padding: 8px; +` + +export const AddressText = styled(Text)` + word-break: break-all; +` + +export const Button = styled(WalletButton)` + cursor: pointer; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + background: none; + background-color: none; + outline: none; + border: none; + border-radius: ${leo.radius.m}; + width: 100%; + padding: 16px; + --icon-display: none; + &:hover { + background-color: ${leo.color.container.highlight}; + --icon-display: block; + } +` + +export const LaunchIcon = styled(Icon).attrs({ + name: 'launch' +})` + display: var(--icon-display); + --leo-icon-size: 16px; + color: ${leo.color.icon.interactive}; +` diff --git a/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.tsx b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.tsx new file mode 100644 index 000000000000..b9214580711c --- /dev/null +++ b/components/brave_wallet_ui/components/desktop/popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal.tsx @@ -0,0 +1,118 @@ +// Copyright (c) 2024 The Brave Authors. All rights reserved. +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at https://mozilla.org/MPL/2.0/. +import * as React from 'react' + +// Types +import { BraveWallet } from '../../../../constants/types' + +// Queries +import { + useGetVisibleNetworksQuery // +} from '../../../../common/slices/api.slice' + +// Utils +import { getLocale } from '../../../../../common/locale' +import { + getNetworkId // +} from '../../../../common/slices/entities/network.entity' + +// Components +import { PopupModal } from '../../popup-modals/index' +import { + CreateAccountIcon // +} from '../../../shared/create-account-icon/create-account-icon' +import { NetworkButton } from './network_button' + +// Styles +import { + AccountInfoRow, + StyledWrapper, + AddressText +} from './view_on_block_explorer_modal.style' +import { Column, Text, Row, ScrollableColumn } from '../../../shared/style' + +interface Props { + account: BraveWallet.AccountInfo + onClose: () => void +} + +export const ViewOnBlockExplorerModal = (props: Props) => { + const { account, onClose } = props + + // Queries + const { data: visibleNetworks = [] } = useGetVisibleNetworksQuery() + + // Memos + const networksByAccountCoinType = React.useMemo(() => { + return visibleNetworks.filter( + (network) => network.coin === account.accountId.coin + ) + }, [visibleNetworks, account]) + + return ( + + + + + + + {account.name} + + + {account.address} + + + + + + {getLocale('braveWalletViewAddressOn')} + + + + {networksByAccountCoinType.map((network) => ( + + ))} + + + + ) +} diff --git a/components/brave_wallet_ui/components/desktop/views/accounts/account.tsx b/components/brave_wallet_ui/components/desktop/views/accounts/account.tsx index b0208e5d3d82..77a4d0b129f0 100644 --- a/components/brave_wallet_ui/components/desktop/views/accounts/account.tsx +++ b/components/brave_wallet_ui/components/desktop/views/accounts/account.tsx @@ -20,7 +20,8 @@ import { CoinTypesMap, WalletRoutes, AccountModalTypes, - AccountPageTabs + AccountPageTabs, + SupportedTestNetworks } from '../../../../constants/types' // utils @@ -86,6 +87,9 @@ import { import { EmptyTokenListState // } from '../portfolio/components/empty-token-list-state/empty-token-list-state' +import { + ViewOnBlockExplorerModal // +} from '../../popup-modals/view_on_block_explorer_modal/view_on_block_explorer_modal' // options import { AccountDetailsOptions } from '../../../../options/nav-options' @@ -105,11 +109,19 @@ import { import { useBalancesFetcher // } from '../../../../common/hooks/use-balances-fetcher' +import { useExplorer } from '../../../../common/hooks/explorer' // Actions import { AccountsTabActions } from '../../../../page/reducers/accounts-tab-reducer' import { useAccountsQuery } from '../../../../common/slices/api.slice.extra' +const INDIVIDUAL_TESTNET_ACCOUNT_KEYRING_IDS = [ + BraveWallet.KeyringId.kBitcoin84Testnet, + BraveWallet.KeyringId.kBitcoinImportTestnet, + BraveWallet.KeyringId.kFilecoinTestnet, + BraveWallet.KeyringId.kZCashTestnet +] + const removedNFTsRouteOptions = AccountDetailsOptions.filter( (option) => option.id !== 'nfts' ) @@ -169,10 +181,42 @@ export const Account = () => { // state const [showAddNftModal, setShowAddNftModal] = React.useState(false) + const [showViewOnBlockExplorerModal, setShowViewOnBlockExplorerModal] = + React.useState(false) - // custom hooks + // custom hooks & memos const scrollIntoView = useScrollIntoView() + const networksFilteredByAccountsCoinType = React.useMemo(() => { + return !selectedAccount + ? [] + : networkList.filter( + (network) => network.coin === selectedAccount.accountId.coin + ) + }, [networkList, selectedAccount]) + + const networkForSelectedAccount = React.useMemo(() => { + if (!selectedAccount) { + return + } + // BTC, ZEC and FIL use different accounts for testnet. + // This checks if the selectedAccount is a testnet account + // and finds the appropriate network to use. + if ( + INDIVIDUAL_TESTNET_ACCOUNT_KEYRING_IDS.includes( + selectedAccount.accountId.keyringId + ) + ) + return networksFilteredByAccountsCoinType.find((network) => + SupportedTestNetworks.includes(network.chainId) + ) + return networksFilteredByAccountsCoinType.find( + (network) => !SupportedTestNetworks.includes(network.chainId) + ) + }, [selectedAccount, networksFilteredByAccountsCoinType]) + + const onClickViewOnBlockExplorer = useExplorer(networkForSelectedAccount) + // memos const transactionList = React.useMemo(() => { return sortTransactionByDate(unsortedTransactionList, 'descending') @@ -349,11 +393,36 @@ export const Account = () => { onRemoveAccount() return } + if ( + option === 'explorer' && + // Only show the Block Explorer modal if there is + // more than 1 network to show and if CoinType is + // ETH or SOL. + networksFilteredByAccountsCoinType.length > 1 && + (selectedAccount?.accountId.coin === BraveWallet.CoinType.ETH || + selectedAccount?.accountId.coin === BraveWallet.CoinType.SOL) + ) { + setShowViewOnBlockExplorerModal(true) + return + } + if (option === 'explorer' && selectedAccount?.accountId.address) { + onClickViewOnBlockExplorer( + 'address', + selectedAccount.accountId.address + )() + return + } dispatch(AccountsTabActions.setShowAccountModal(true)) dispatch(AccountsTabActions.setAccountModalType(option)) dispatch(AccountsTabActions.setSelectedAccount(selectedAccount)) }, - [dispatch, onRemoveAccount, selectedAccount] + [ + dispatch, + onRemoveAccount, + networksFilteredByAccountsCoinType, + selectedAccount, + onClickViewOnBlockExplorer + ] ) const checkIsTransactionFocused = React.useCallback( @@ -527,6 +596,13 @@ export const Account = () => { )} + {showViewOnBlockExplorerModal && ( + setShowViewOnBlockExplorerModal(false)} + /> + )} + {showAddNftModal && ( setShowAddNftModal(false)} diff --git a/components/brave_wallet_ui/constants/types.ts b/components/brave_wallet_ui/constants/types.ts index dc0171c9ad15..c5955317303d 100644 --- a/components/brave_wallet_ui/constants/types.ts +++ b/components/brave_wallet_ui/constants/types.ts @@ -840,6 +840,7 @@ export type AccountModalTypes = | 'details' | 'remove' | 'buy' + | 'explorer' export interface AccountButtonOptionsObjectType { name: string diff --git a/components/brave_wallet_ui/options/account-details-menu-options.ts b/components/brave_wallet_ui/options/account-details-menu-options.ts index a13b95afe2dc..99af0d7648c6 100644 --- a/components/brave_wallet_ui/options/account-details-menu-options.ts +++ b/components/brave_wallet_ui/options/account-details-menu-options.ts @@ -11,6 +11,11 @@ export const AccountDetailsMenuOptions: AccountButtonOptionsObjectType[] = [ name: 'braveWalletAllowSpendEditButton', icon: 'edit-pencil' }, + { + id: 'explorer', + name: 'braveWalletTransactionExplorer', + icon: 'web3-blockexplorer' + }, { id: 'deposit', name: 'braveWalletAccountsDeposit', diff --git a/components/brave_wallet_ui/stories/locale.ts b/components/brave_wallet_ui/stories/locale.ts index 6460c585a0e8..937a3e640e24 100644 --- a/components/brave_wallet_ui/stories/locale.ts +++ b/components/brave_wallet_ui/stories/locale.ts @@ -395,6 +395,8 @@ provideStrings({ braveWalletAccountsAssets: 'Assets', braveWalletAccountsEditVisibleAssets: 'Visible assets', braveWalletAccountBalance: 'Account balance', + braveWalletViewAddressOn: 'View address on:', + braveWalletNetworkExplorer: '$1 Explorer', // Add Account Options braveWalletCreateAccount: 'Create $1 account', diff --git a/components/resources/wallet_strings.grdp b/components/resources/wallet_strings.grdp index 6f3250469f1a..1f471e6efb0c 100644 --- a/components/resources/wallet_strings.grdp +++ b/components/resources/wallet_strings.grdp @@ -230,6 +230,8 @@ Assets Visible assets Account balance + View address on: + Ethereum Mainnet$1 Explorer Create Create account Create Ethereum$1 account diff --git a/ui/webui/resources/BUILD.gn b/ui/webui/resources/BUILD.gn index 298ca800199e..b03a6b5851a5 100644 --- a/ui/webui/resources/BUILD.gn +++ b/ui/webui/resources/BUILD.gn @@ -383,6 +383,7 @@ leo_icons = [ "warning-triangle-filled.svg", "warning-triangle-outline.svg", "web3.svg", + "web3-blockexplorer.svg", "web3-bridge.svg", "widget-generic.svg", "window-content.svg",