From 276f45118264969af57265a47f87d2ff4a6e8d5e Mon Sep 17 00:00:00 2001 From: Alec WM Date: Tue, 24 Dec 2024 16:15:12 +1100 Subject: [PATCH] feat: add account redesign (#1760) * feat: add account redesign * fix: deselect AccountTypeNetworkSearch on click * fix: optional AccountCreateMethodButton.networks prop * fix: include nativetoken symbol in network search * fix: copy feedback * fix: also disable account type picker on second add/watch account page * fix: navigate to correct tab when clicking on `Add Account` breadcrumb * fix: copy feedback * feat: add back button * fix: watched account form spacing * fix: trim account type network search input * fix: account type search field font size --- .changeset/silver-panthers-bathe.md | 5 + .../src/@talisman/util/truncateString.ts | 3 - .../dashboard/layout/LayoutBreadcrumb.tsx | 25 +- .../AccountAdd/AccountAddDcentWizard.tsx | 3 +- .../AccountAdd/AccountAddDerivedPage.tsx | 3 +- .../routes/AccountAdd/AccountAddJsonPage.tsx | 7 +- .../AccountAdd/AccountAddSignetWizard.tsx | 3 +- .../AccountAdd/AccountAddWatchedPage.tsx | 14 +- .../dashboard/routes/AccountAdd/index.tsx | 5 +- .../dashboard/routes/Networks/NetworkPage.tsx | 2 +- .../routes/Networks/NetworksPage.tsx | 2 +- .../apps/dashboard/routes/Portfolio/index.tsx | 2 +- .../dashboard/routes/Settings/AboutPage.tsx | 3 +- .../routes/Settings/AddressBookPage.tsx | 3 +- .../routes/Settings/AnalyticsOptInPage.tsx | 3 +- .../AssetsDiscovery/AssetDiscoveryPage.tsx | 2 +- .../routes/Settings/AutoLockTimerPage.tsx | 3 +- .../routes/Settings/ConnectedSitesPage.tsx | 3 +- .../routes/Settings/CurrencySettingsPage.tsx | 3 +- .../dashboard/routes/Settings/GeneralPage.tsx | 3 +- .../routes/Settings/LanguagePage.tsx | 3 +- .../routes/Settings/NetworksTokensPage.tsx | 3 +- .../routes/Settings/QrMetadataPage.tsx | 3 +- .../routes/Settings/SecurityPrivacyPage.tsx | 3 +- .../dashboard/routes/Tokens/TokenPage.tsx | 3 +- .../ui/apps/dashboard/routes/TxHistory.tsx | 3 +- .../AccountAddDerivedForm.tsx | 13 +- .../AccountAddJson/ImportJsonAccountsForm.tsx | 32 +- .../AccountAddJson/UnlockJsonFileForm.tsx | 4 +- .../AccountAddMnemonic/MnemonicForm.tsx | 102 +++-- .../AccountAdd/AccountAddPrivateKeyForm.tsx | 4 +- .../AccountAdd/AccountAddWatchedForm.tsx | 24 +- .../AccountAdd/BackToAddAccountButton.tsx | 16 + .../domains/Account/AccountAdd/Container.tsx | 415 +++++++++++------- .../ui/domains/Account/AccountAdd/context.ts | 33 +- .../Account/AccountTypeNetworkSearch.tsx | 195 ++++++++ .../domains/Account/AccountTypeSelector.tsx | 32 +- .../domains/Account/AllNetworksLogoStack.tsx | 121 +++++ .../AssetsTable/DashboardAssetRow.tsx | 4 +- .../AssetsTable/PopupAssetsTable.tsx | 4 +- ...ack.tsx => PortfolioNetworksLogoStack.tsx} | 10 +- .../src/ui/domains/Portfolio/NftTile.tsx | 4 +- .../domains/Portfolio/Nfts/DashboardNfts.tsx | 4 +- .../ui/domains/Portfolio/Nfts/PopupNfts.tsx | 4 +- apps/extension/src/ui/hooks/useNetworkInfo.ts | 4 +- packages/icons/src/icons/eye-plus.svg | 17 +- 46 files changed, 811 insertions(+), 346 deletions(-) create mode 100644 .changeset/silver-panthers-bathe.md delete mode 100644 apps/extension/src/@talisman/util/truncateString.ts create mode 100644 apps/extension/src/ui/domains/Account/AccountAdd/BackToAddAccountButton.tsx create mode 100644 apps/extension/src/ui/domains/Account/AccountTypeNetworkSearch.tsx create mode 100644 apps/extension/src/ui/domains/Account/AllNetworksLogoStack.tsx rename apps/extension/src/ui/domains/Portfolio/AssetsTable/{NetworksLogoStack.tsx => PortfolioNetworksLogoStack.tsx} (82%) diff --git a/.changeset/silver-panthers-bathe.md b/.changeset/silver-panthers-bathe.md new file mode 100644 index 0000000000..bd01f508a0 --- /dev/null +++ b/.changeset/silver-panthers-bathe.md @@ -0,0 +1,5 @@ +--- +"@talismn/icons": patch +--- + +fix: make eye-plus.svg react correctly to stroke-width diff --git a/apps/extension/src/@talisman/util/truncateString.ts b/apps/extension/src/@talisman/util/truncateString.ts deleted file mode 100644 index d01b98b466..0000000000 --- a/apps/extension/src/@talisman/util/truncateString.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint import/no-anonymous-default-export: [2, {"allowArrowFunction": true}] */ -export default (str?: string, start = 4, end = 4) => - str ? `${str.substring(0, start)}...${str.substring(str.length - end)}` : null diff --git a/apps/extension/src/ui/apps/dashboard/layout/LayoutBreadcrumb.tsx b/apps/extension/src/ui/apps/dashboard/layout/LayoutBreadcrumb.tsx index f6d04a616c..02a7f8f39c 100644 --- a/apps/extension/src/ui/apps/dashboard/layout/LayoutBreadcrumb.tsx +++ b/apps/extension/src/ui/apps/dashboard/layout/LayoutBreadcrumb.tsx @@ -4,6 +4,8 @@ import { FC, Fragment, ReactNode, useMemo } from "react" import { useTranslation } from "react-i18next" import { NavLink, To, useLocation } from "react-router-dom" +import { MethodType } from "@ui/domains/Account/AccountAdd/context" + const useBreadcrumbItems = (): Partial> => { const { t } = useTranslation() @@ -13,7 +15,10 @@ const useBreadcrumbItems = (): Partial> => // reusables const settings = { label: t("Settings"), to: "/settings/general" } const accounts = { label: t("Accounts"), to: "/settings/accounts" } - const accountsAdd = { label: t("Add Account"), to: "/accounts/add" } + const accountsAdd = (methodType?: MethodType) => ({ + label: t("Add Account"), + to: `/accounts/add${methodType ? `?methodType=${methodType}` : ""}`, + }) const securityAndPrivacy = { label: t("Security & Privacy"), to: "/settings/security-privacy-settings", @@ -22,53 +27,53 @@ const useBreadcrumbItems = (): Partial> => return { "/settings/accounts": [settings, accounts], - "/accounts/add": [settings, accounts, accountsAdd], + "/accounts/add": [settings, accounts, accountsAdd()], "/accounts/add/derived": [ settings, accounts, - accountsAdd, + accountsAdd(), { label: t("New"), to: "/accounts/add/derived" }, ], "/accounts/add/mnemonic": [ settings, accounts, - accountsAdd, + accountsAdd("import"), { label: t("Recovery Phrase"), to: "/accounts/add/mnemonic" }, ], "/accounts/add/pk": [ settings, accounts, - accountsAdd, + accountsAdd("import"), { label: t("Private Key"), to: "/accounts/add/pk" }, ], "/accounts/add/json": [ settings, accounts, - accountsAdd, + accountsAdd("import"), { label: t("JSON"), to: "/accounts/add/json" }, ], "/accounts/add/ledger": [ settings, accounts, - accountsAdd, + accountsAdd("connect"), { label: t("Ledger"), to: "/accounts/add/ledger" }, ], "/accounts/add/qr": [ settings, accounts, - accountsAdd, + accountsAdd("connect"), { label: t("Polkadot Vault"), to: "/accounts/add/qr" }, ], "/accounts/add/signet": [ settings, accounts, - accountsAdd, + accountsAdd("connect"), { label: t("Signet Vault"), to: "/accounts/add/signet" }, ], "/accounts/add/watched": [ settings, accounts, - accountsAdd, + accountsAdd("watched"), { label: t("Watched Account"), to: "/accounts/add/watched" }, ], diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDcentWizard.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDcentWizard.tsx index c6e31d797b..8b00047622 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDcentWizard.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDcentWizard.tsx @@ -1,7 +1,6 @@ +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountAddDcentDisabledMessage } from "@ui/domains/Account/AccountAdd/AccountAddDcent" -import { DashboardLayout } from "../../layout" - export const AccountAddDcentDashboardWizard = () => { return ( diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDerivedPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDerivedPage.tsx index 96cb83c8c0..dbfd4d1103 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDerivedPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddDerivedPage.tsx @@ -4,11 +4,10 @@ import { useSearchParams } from "react-router-dom" import { AccountAddressType } from "@extension/core" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountAddDerivedForm } from "@ui/domains/Account/AccountAdd/AccountAddDerived/AccountAddDerivedForm" import { useSelectAccountAndNavigate } from "@ui/hooks/useSelectAccountAndNavigate" -import { DashboardLayout } from "../../layout" - const Content = () => { const { t } = useTranslation("admin") // get type paramter from url diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddJsonPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddJsonPage.tsx index 61dc76b0db..becba8074e 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddJsonPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddJsonPage.tsx @@ -2,11 +2,10 @@ import { useTranslation } from "react-i18next" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountAddJson } from "@ui/domains/Account/AccountAdd/AccountAddJson" import { useSelectAccountAndNavigate } from "@ui/hooks/useSelectAccountAndNavigate" -import { DashboardLayout } from "../../layout" - const Content = () => { const { t } = useTranslation("admin") const { setAddress } = useSelectAccountAndNavigate("/portfolio") @@ -14,8 +13,8 @@ const Content = () => { return ( <> diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddSignetWizard.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddSignetWizard.tsx index 581b944565..b6676407b5 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddSignetWizard.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddSignetWizard.tsx @@ -1,8 +1,7 @@ +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountAddSignetWizard } from "@ui/domains/Account/AccountAdd/AccountAddSignet/index" import { useSelectAccountAndNavigate } from "@ui/hooks/useSelectAccountAndNavigate" -import { DashboardLayout } from "../../layout" - const Content = () => { const { setAddress } = useSelectAccountAndNavigate("/portfolio") diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddWatchedPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddWatchedPage.tsx index 093820aaff..403a06401e 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddWatchedPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/AccountAddWatchedPage.tsx @@ -1,23 +1,27 @@ import { useTranslation } from "react-i18next" +import { useSearchParams } from "react-router-dom" +import { AccountAddressType } from "@extension/core" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountAddWatchedForm } from "@ui/domains/Account/AccountAdd/AccountAddWatchedForm" import { useSelectAccountAndNavigate } from "@ui/hooks/useSelectAccountAndNavigate" -import { DashboardLayout } from "../../layout" - export const Content = () => { const { t } = useTranslation("admin") + // get type paramter from url + const [params] = useSearchParams() + const urlParamType = (params.get("type") ?? undefined) as AccountAddressType | undefined const { setAddress } = useSelectAccountAndNavigate("/portfolio") return ( <> - + ) diff --git a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/index.tsx b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/index.tsx index 231be7d506..4f5b5bdd48 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/index.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/AccountAdd/index.tsx @@ -1,11 +1,10 @@ import { useTranslation } from "react-i18next" import { HeaderBlock } from "@talisman/components/HeaderBlock" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountCreateMenu } from "@ui/domains/Account/AccountAdd" import { useBalancesHydrate } from "@ui/state" -import { DashboardLayout } from "../../layout" - const Content = () => { useBalancesHydrate() // preload const { t } = useTranslation() @@ -14,7 +13,7 @@ const Content = () => {
diff --git a/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworkPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworkPage.tsx index 2b4be0f303..5f181965d7 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworkPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworkPage.tsx @@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next" import { useNavigate, useParams } from "react-router-dom" import { AnalyticsPage } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { EvmNetworkForm, SubNetworkFormAdd, @@ -10,7 +11,6 @@ import { } from "@ui/domains/Settings/ManageNetworks/NetworkForm" import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView" -import { DashboardLayout } from "../../layout" import { useNetworksType } from "./useNetworksType" const ANALYTICS_PAGE: AnalyticsPage = { diff --git a/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworksPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworksPage.tsx index ade9f6778f..dba61296a3 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworksPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Networks/NetworksPage.tsx @@ -12,6 +12,7 @@ import { OptionSwitch } from "@talisman/components/OptionSwitch" import { SearchInput } from "@talisman/components/SearchInput" import { Spacer } from "@talisman/components/Spacer" import { sendAnalyticsEvent } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { EnableTestnetPillButton } from "@ui/domains/Settings/EnableTestnetPillButton" import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView" import { @@ -21,7 +22,6 @@ import { getSettingValue$, } from "@ui/state" -import { DashboardLayout } from "../../layout" import { ANALYTICS_PAGE } from "./analytics" import { ChainsList } from "./ChainsList" import { EvmNetworksList } from "./EvmNetworksList" diff --git a/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx b/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx index 90f2b11460..e5f79beedb 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Portfolio/index.tsx @@ -2,13 +2,13 @@ import { useEffect } from "react" import { Route, Routes, useSearchParams } from "react-router-dom" import { NavigateWithQuery } from "@talisman/components/NavigateWithQuery" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { useBuyTokensModal } from "@ui/domains/Asset/Buy/useBuyTokensModal" import { DashboardPortfolioHeader } from "@ui/domains/Portfolio/DashboardPortfolioHeader" import { PortfolioContainer } from "@ui/domains/Portfolio/PortfolioContainer" import { PortfolioToolbarNfts } from "@ui/domains/Portfolio/PortfolioToolbarNfts" import { PortfolioToolbarTokens } from "@ui/domains/Portfolio/PortfolioToolbarTokens" -import { DashboardLayout } from "../../layout" import { PortfolioAsset, PortfolioAssetHeader } from "./PortfolioAsset" import { PortfolioAssets } from "./PortfolioAssets" import { PortfolioNftCollection } from "./PortfolioNftCollection" diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/AboutPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/AboutPage.tsx index fc64324271..ce5d194bd9 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/AboutPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/AboutPage.tsx @@ -17,8 +17,7 @@ import { TERMS_OF_USE_URL, } from "@extension/shared" import { HeaderBlock } from "@talisman/components/HeaderBlock" - -import { DashboardLayout } from "../../layout" +import { DashboardLayout } from "@ui/apps/dashboard/layout" const Content = () => { const { t } = useTranslation("admin") diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/AddressBookPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/AddressBookPage.tsx index 9d8ac07da6..d9759e4c44 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/AddressBookPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/AddressBookPage.tsx @@ -31,6 +31,7 @@ import { Spacer } from "@talisman/components/Spacer" import { SuspenseTracker } from "@talisman/components/SuspenseTracker" import { useOpenClose } from "@talisman/hooks/useOpenClose" import { AnalyticsPage } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountIcon } from "@ui/domains/Account/AccountIcon" import { Address } from "@ui/domains/Account/Address" import { useCopyAddressModal } from "@ui/domains/CopyAddress" @@ -45,8 +46,6 @@ import { useAnalyticsPageView } from "@ui/hooks/useAnalyticsPageView" import { useSendFundsPopup } from "@ui/hooks/useSendFundsPopup" import { useBalances, useChainByGenesisHash } from "@ui/state" -import { DashboardLayout } from "../../layout" - const ANALYTICS_PAGE: AnalyticsPage = { container: "Fullscreen", feature: "Settings", diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/AnalyticsOptInPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/AnalyticsOptInPage.tsx index b173468a8f..fda35d591c 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/AnalyticsOptInPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/AnalyticsOptInPage.tsx @@ -2,11 +2,10 @@ import { useTranslation } from "react-i18next" import { Toggle } from "talisman-ui" import { Setting } from "@talisman/components/Setting" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AnalyticsOptInInfo } from "@ui/domains/Settings/Analytics/AnalyticsOptInInfo" import { useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - const Content = () => { const { t } = useTranslation("admin") const [useAnalyticsTracking, setUseAnalyticsTracking] = useSetting("useAnalyticsTracking") diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/AssetsDiscovery/AssetDiscoveryPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/AssetsDiscovery/AssetDiscoveryPage.tsx index 05f2b40542..2be91c8272 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/AssetsDiscovery/AssetDiscoveryPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/AssetsDiscovery/AssetDiscoveryPage.tsx @@ -42,6 +42,7 @@ import { Spacer } from "@talisman/components/Spacer" import { shortenAddress } from "@talisman/util/shortenAddress" import { api } from "@ui/api" import { AnalyticsPage } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AccountIcon } from "@ui/domains/Account/AccountIcon" import { AccountsStack } from "@ui/domains/Account/AccountIconsStack" import { ChainLogo } from "@ui/domains/Asset/ChainLogo" @@ -70,7 +71,6 @@ import { import { isErc20Token } from "@ui/util/isErc20Token" import { isUniswapV2Token } from "@ui/util/isUniswapV2Token" -import { DashboardLayout } from "../../../layout" import { useAssetDiscoveryFetchTokenRates, useAssetDiscoveryTokenRates, diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/AutoLockTimerPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/AutoLockTimerPage.tsx index 379647d603..99fcae04e9 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/AutoLockTimerPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/AutoLockTimerPage.tsx @@ -4,10 +4,9 @@ import { useTranslation } from "react-i18next" import { ExclusiveButtonsList } from "@talisman/components/ExclusiveButtonsList" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - type Option = { value: number; label: string } export const Content = () => { diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/ConnectedSitesPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/ConnectedSitesPage.tsx index 8de277cc78..1bc25d3f48 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/ConnectedSitesPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/ConnectedSitesPage.tsx @@ -1,7 +1,6 @@ +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AuthorisedSites } from "@ui/domains/Settings/AuthorisedSites/AuthorisedSites" -import { DashboardLayout } from "../../layout" - export const ConnectedSitesPage = () => ( diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/CurrencySettingsPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/CurrencySettingsPage.tsx index 747b071e39..8db35457e8 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/CurrencySettingsPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/CurrencySettingsPage.tsx @@ -3,12 +3,11 @@ import { useTranslation } from "react-i18next" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { currencyConfig, currencyOrder, sortCurrencies } from "@ui/domains/Asset/currencyConfig" import { useFavoriteCurrencies } from "@ui/hooks/useFavoriteCurrencies" import { useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - const Content = () => { const [favorites, setFavorites] = useFavoriteCurrencies() const [, setSelected] = useSetting("selectedCurrency") diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/GeneralPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/GeneralPage.tsx index 29ad8e3927..0393fb96e5 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/GeneralPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/GeneralPage.tsx @@ -17,12 +17,11 @@ import { SPIRIT_KEYS_DOCS_URL } from "@extension/shared" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Setting } from "@talisman/components/Setting" import { AnalyticsPage } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AvatarTypeSelect } from "@ui/domains/Settings/AvatarTypeSelect" import { useRuntimeReload } from "@ui/hooks/useRuntimeReload" import { useAppState, useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - const ANALYTICS_PAGE: AnalyticsPage = { container: "Fullscreen", feature: "Settings", diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/LanguagePage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/LanguagePage.tsx index b7ccb8c794..c29b82c6af 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/LanguagePage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/LanguagePage.tsx @@ -5,8 +5,7 @@ import { languages } from "@common/i18nConfig" import { ExclusiveButtonsList } from "@talisman/components/ExclusiveButtonsList" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Spacer } from "@talisman/components/Spacer" - -import { DashboardLayout } from "../../layout" +import { DashboardLayout } from "@ui/apps/dashboard/layout" const Content = () => { const { t, i18n } = useTranslation() diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/NetworksTokensPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/NetworksTokensPage.tsx index 724287c04d..f42edd604a 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/NetworksTokensPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/NetworksTokensPage.tsx @@ -12,10 +12,9 @@ import { CtaButton, Toggle } from "talisman-ui" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Setting } from "@talisman/components/Setting" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - const Content = () => { const { t } = useTranslation("admin") const [useTestnets, setUseTestnets] = useSetting("useTestnets") diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/QrMetadataPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/QrMetadataPage.tsx index 29f2686286..2b07c8d873 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/QrMetadataPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/QrMetadataPage.tsx @@ -10,6 +10,7 @@ import { FadeIn } from "@talisman/components/FadeIn" import { HeaderBlock } from "@talisman/components/HeaderBlock" import { notify } from "@talisman/components/Notifications" import { api } from "@ui/api" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { MnemonicCreateModal, MnemonicCreateModalProvider, @@ -21,8 +22,6 @@ import { MetadataQrCode } from "@ui/domains/Sign/Qr/MetadataQrCode" import { NetworkSpecsQrCode } from "@ui/domains/Sign/Qr/NetworkSpecsQrCode" import { useAppState, useBalancesHydrate, useChains, useMnemonic } from "@ui/state" -import { DashboardLayout } from "../../layout" - const SetVerifierCertificateContentInner = () => { const { t } = useTranslation("admin") const navigate = useNavigate() diff --git a/apps/extension/src/ui/apps/dashboard/routes/Settings/SecurityPrivacyPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Settings/SecurityPrivacyPage.tsx index fda52a81a9..0f7b01cce7 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Settings/SecurityPrivacyPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Settings/SecurityPrivacyPage.tsx @@ -15,11 +15,10 @@ import { CtaButton, Toggle, Tooltip, TooltipContent, TooltipTrigger } from "tali import { HeaderBlock } from "@talisman/components/HeaderBlock" import { Setting } from "@talisman/components/Setting" import { Spacer } from "@talisman/components/Spacer" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { useMnemonicBackup } from "@ui/hooks/useMnemonicBackup" import { useFeatureFlag, useSetting } from "@ui/state" -import { DashboardLayout } from "../../layout" - const Content = () => { const { t } = useTranslation("admin") const [useAnalyticsTracking, setUseAnalyticsTracking] = useSetting("useAnalyticsTracking") diff --git a/apps/extension/src/ui/apps/dashboard/routes/Tokens/TokenPage.tsx b/apps/extension/src/ui/apps/dashboard/routes/Tokens/TokenPage.tsx index e4a0d1fc3b..5e8b9cc1a4 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/Tokens/TokenPage.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/Tokens/TokenPage.tsx @@ -21,6 +21,7 @@ import { notify } from "@talisman/components/Notifications" import { useOpenClose } from "@talisman/hooks/useOpenClose" import { api } from "@ui/api" import { AnalyticsPage } from "@ui/api/analytics" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { AssetLogoBase } from "@ui/domains/Asset/AssetLogo" import { TokenTypePill } from "@ui/domains/Asset/TokenTypePill" import { NetworkSelect } from "@ui/domains/Ethereum/NetworkSelect" @@ -32,8 +33,6 @@ import { isCustomUniswapV2Token } from "@ui/util/isCustomUniswapV2Token" import { isErc20Token } from "@ui/util/isErc20Token" import { isUniswapV2Token } from "@ui/util/isUniswapV2Token" -import { DashboardLayout } from "../../layout" - const ConfirmRemove = ({ open, token, diff --git a/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx b/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx index e2bc66476c..780554e1b8 100644 --- a/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx +++ b/apps/extension/src/ui/apps/dashboard/routes/TxHistory.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect } from "react" import { useTranslation } from "react-i18next" import { useOpenClose } from "talisman-ui" +import { DashboardLayout } from "@ui/apps/dashboard/layout" import { ChainLogo } from "@ui/domains/Asset/ChainLogo" import { PortfolioContainer } from "@ui/domains/Portfolio/PortfolioContainer" import { usePortfolioNavigation } from "@ui/domains/Portfolio/usePortfolioNavigation" @@ -10,8 +11,6 @@ import { TxHistoryList, TxHistoryProvider } from "@ui/domains/Transactions/TxHis import { useTxHistory } from "@ui/domains/Transactions/TxHistory/TxHistoryContext" import { TxHistoryNetworkPicker } from "@ui/domains/Transactions/TxHistory/TxHistoryNetworkPicker" -import { DashboardLayout } from "../layout" - const NetworkFilterButton = () => { const { t } = useTranslation() const { network, networks, setNetworkId } = useTxHistory() diff --git a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddDerived/AccountAddDerivedForm.tsx b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddDerived/AccountAddDerivedForm.tsx index 668a55605b..5344c71004 100644 --- a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddDerived/AccountAddDerivedForm.tsx +++ b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddDerived/AccountAddDerivedForm.tsx @@ -33,10 +33,11 @@ import { MnemonicCreateModalProvider, useMnemonicCreateModal, } from "@ui/apps/dashboard/routes/Settings/Mnemonics/MnemonicCreateModal" +import { AccountIcon } from "@ui/domains/Account/AccountIcon" import { AccountTypeSelector } from "@ui/domains/Account/AccountTypeSelector" import { useAccounts, useMnemonics } from "@ui/state" -import { AccountIcon } from "../../AccountIcon" +import { BackToAddAccountButton } from "../BackToAddAccountButton" import { AccountAddPageProps } from "../types" import { AccountAddMnemonicDropdown } from "./AccountAddMnemonicDropdown" @@ -101,6 +102,7 @@ const AccountAddDerivedFormInner: FC = ({ onSuccess }) => { // get type paramter from url const [params] = useSearchParams() const urlParamType = (params.get("type") ?? undefined) as UiAccountAddressType | undefined + const disableOtherTypes = params.has("disableOtherTypes") const mnemonics = useMnemonics() const allAccounts = useAccounts() const accountNames = useMemo(() => allAccounts.map((a) => a.name), [allAccounts]) @@ -253,7 +255,11 @@ const AccountAddDerivedFormInner: FC = ({ onSuccess }) => { return (
- +
{!!mnemonics.length && ( @@ -306,7 +312,8 @@ const AccountAddDerivedFormInner: FC = ({ onSuccess }) => { -
+
+
-
- - +
+ +
+ + +
) diff --git a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddJson/UnlockJsonFileForm.tsx b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddJson/UnlockJsonFileForm.tsx index aff98da654..7c8a8304b0 100644 --- a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddJson/UnlockJsonFileForm.tsx +++ b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddJson/UnlockJsonFileForm.tsx @@ -10,6 +10,7 @@ import { log } from "@extension/shared" import { CapsLockWarningIcon } from "@talisman/components/CapsLockWarningIcon" import { FadeIn } from "@talisman/components/FadeIn" +import { BackToAddAccountButton } from "../BackToAddAccountButton" import { useJsonAccountImport } from "./context" type FormData = { @@ -86,7 +87,8 @@ export const UnlockJsonFileForm: FC = () => { after={} /> -
+
+ diff --git a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddMnemonic/MnemonicForm.tsx b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddMnemonic/MnemonicForm.tsx index f3acda8e53..329dc5b316 100644 --- a/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddMnemonic/MnemonicForm.tsx +++ b/apps/extension/src/ui/domains/Account/AccountAdd/AccountAddMnemonic/MnemonicForm.tsx @@ -26,6 +26,7 @@ import { AccountTypeSelector } from "@ui/domains/Account/AccountTypeSelector" import { useAccounts } from "@ui/state" import { isUiAccountAddressType } from "@ui/util/typeCheckers" +import { BackToAddAccountButton } from "../BackToAddAccountButton" import { AccountAddDerivationMode, useAccountAddSecret } from "./context" import { DerivationModeDropdown } from "./DerivationModeDropdown" @@ -216,62 +217,67 @@ export const AccountAddMnemonicForm = () => { return (
- - - +
+ + + + + + {targetAddress} + + ) : null + } + /> + + - - - - {targetAddress} - - ) : null - } - /> - - -
-
{t("Word count: {{words}}", { words })}
-
{errors.mnemonic?.message}
-
- - - - - - -
+
+
{t("Word count: {{words}}", { words })}
+
+ {errors.mnemonic?.message} +
+
+ + + + + + +
+
+
-
+
+ + + ) +} diff --git a/apps/extension/src/ui/domains/Account/AccountAdd/Container.tsx b/apps/extension/src/ui/domains/Account/AccountAdd/Container.tsx index 8bd6cd8991..5a336a4adb 100644 --- a/apps/extension/src/ui/domains/Account/AccountAdd/Container.tsx +++ b/apps/extension/src/ui/domains/Account/AccountAdd/Container.tsx @@ -1,129 +1,148 @@ -import { ChainIcon, EyePlusIcon, FilePlusIcon, PlusIcon } from "@talismn/icons" +import { ChainIcon, EyePlusIcon, FilePlusIcon, InfoIcon, PlusIcon } from "@talismn/icons" import { classNames } from "@talismn/util" -import { ReactNode, useCallback, useMemo } from "react" +import { cloneElement, ReactElement, ReactNode, useCallback, useMemo, useState } from "react" import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" +import { Tooltip, TooltipContent, TooltipTrigger } from "talisman-ui" import { IS_FIREFOX } from "@extension/shared" -import { SelectedIndicator } from "@talisman/components/SelectedIndicator" import { EthereumCircleBorderedLogo, PolkadotCircleBorderedLogo } from "@talisman/theme/logos" +import { AccountTypeNetworkSearch } from "@ui/domains/Account/AccountTypeNetworkSearch" +import { AllNetworksLogoStack } from "@ui/domains/Account/AllNetworksLogoStack" +import { useChains, useEvmNetworks } from "@ui/state" import { getIsLedgerCapable } from "@ui/util/getIsLedgerCapable" -import { MethodTypes, useAccountCreateContext } from "./context" +import { MethodType, useAccountCreateContext } from "./context" -type Props = { - className?: string +const methodButtonsFromMethodType = { + new: NewAccountMethodButtons, + import: ImportAccountMethodButtons, + connect: ConnectAccountMethodButtons, + watched: WatchedAccountMethodButtons, } -const AccountCreateMethodTypeButton = ({ - title, - subtitle, - icon, - methodType, -}: { - title: string - subtitle: string - icon: ReactNode - methodType: MethodTypes -}) => { - const { methodType: selectedMethodType, setMethodType } = useAccountCreateContext() - const isSelected = selectedMethodType === methodType +export const AccountCreateContainer = ({ className }: { className?: string }) => { + const { t } = useTranslation("admin") + const { methodType } = useAccountCreateContext() + const MethodButtonsComponent = methodButtonsFromMethodType[methodType] ?? null + return ( -
setMethodType(methodType)} - onKeyUp={(e) => { - if (e.key === "Enter") setMethodType(methodType) - }} - > - {isSelected && } -
- {icon} -
- {title} - {subtitle} -
+
+
+ } + title={t("New")} + subtitle={t("Create a new account")} + methodType="new" + /> + } + title={t("Import")} + subtitle={t("Import an existing account")} + methodType="import" + /> + } + title={t("Connect")} + subtitle={t("Ledger, Polkadot Vault, etc")} + methodType="connect" + /> + } + title={t("Watch")} + subtitle={t("Add a watched account")} + methodType="watched" + /> +
+
+
) } -const networkChoices = { - polkadot: , - ethereum: , -} - -const AccountCreateMethodButton = ({ +function MethodTypeTab({ + className, + icon, title, subtitle, - networks, - disabled, - to, + methodType, }: { - title: string - subtitle: string - networks: Array<"ethereum" | "polkadot"> - disabled?: boolean - to?: string -}) => { - const navigate = useNavigate() - const handleClick = useCallback(() => { - if (to) navigate(to) - }, [navigate, to]) + className?: string + icon: ReactElement + title: ReactNode + subtitle: ReactNode + methodType: MethodType +}) { + const { methodType: selectedMethodType, setMethodType } = useAccountCreateContext() + const isSelected = selectedMethodType === methodType return ( ) } -const NewAccountMethodButtons = () => { +function NewAccountMethodButtons() { const { t } = useTranslation("admin") + const [accountType, setAccountType] = useState() + return ( <> - + + + } + type="ethereum" + to={`/accounts/add/derived?type=ethereum${accountType ? "&disableOtherTypes" : ""}`} /> - + } + type="polkadot" + to={`/accounts/add/derived?type=sr25519${accountType ? "&disableOtherTypes" : ""}`} /> ) } -const ImportAccountMethodButtons = () => { +function ImportAccountMethodButtons() { const { t } = useTranslation("admin") + return ( <> { ) } -const ConnectAccountMethodButtons = () => { - const isLedgerCapable = getIsLedgerCapable() +function ConnectAccountMethodButtons() { const { t } = useTranslation("admin") + const isLedgerCapable = getIsLedgerCapable() + return ( <> { ) } -const AddWatchedAccountButton = () => { +function WatchedAccountMethodButtons() { const { t } = useTranslation("admin") - const navigate = useNavigate() - const handleClick = useCallback(() => { - navigate("/accounts/add/watched") - }, [navigate]) + const [accountType, setAccountType] = useState() return ( -
handleClick()} - onKeyUp={(e) => { - if (e.key === "Enter") handleClick() - }} - className="hover:text-grey-300 focus:text-grey-300 flex cursor-pointer flex-col items-center justify-center gap-4 rounded p-4 hover:bg-white hover:bg-opacity-10 focus:bg-white focus:bg-opacity-10" - > -
- - {t("Add Watched Account")} -
-
- {/* flex gap doesn't allow negatives */} - - -
-
+ <> + + + + } + type="ethereum" + to={`/accounts/add/watched?type=ethereum${accountType ? "&disableOtherTypes" : ""}`} + /> + + } + type="polkadot" + to={`/accounts/add/watched?type=sr25519${accountType ? "&disableOtherTypes" : ""}`} + /> + ) } -export const AccountCreateContainer = ({ className }: Props) => { - const { t } = useTranslation("admin") - const { methodType } = useAccountCreateContext() +function SelectAccountTypeSectionHeader() { + const { t } = useTranslation() + return ( + <> +
{t("Select account type")}
+
+ {t( + "If you don't know which to pick, search for the network you want to use and Talisman will recommend the account type.", + )} +
+ + ) +} - const MethodButtonsComponent = useMemo(() => { - switch (methodType) { - case "new": - return NewAccountMethodButtons - case "import": - return ImportAccountMethodButtons - case "connect": - return ConnectAccountMethodButtons +function SelectAccountTypeButtonHeader({ title, tooltip }: { title: string; tooltip: string }) { + return ( +
+ {title} + + +
+ +
+
+ +
{tooltip}
+
+
+
+ ) +} - default: - return null - } - }, [methodType]) +function AccountTypeMethodButton({ + title, + type, + disabled, + to, +}: { + title: ReactNode + type: "polkadot" | "ethereum" + disabled?: boolean + to?: string +}) { + const { t } = useTranslation() + const chains = useChains() + const ethereumNetworks = useEvmNetworks() + const supportedChainIds = useMemo( + () => + type === "polkadot" + ? [...(chains?.flatMap((c) => (c.account !== "secp256k1" ? c.id : [])) ?? [])] + : type === "ethereum" + ? [ + ...(chains?.flatMap((c) => (c.account === "secp256k1" ? c.id : [])) ?? []), + ...(ethereumNetworks?.flatMap((c) => c.id) ?? []), + ] + : [], + [chains, ethereumNetworks, type], + ) return ( -
-
-
-
- } - methodType="new" - /> - } - methodType="import" - /> - } - methodType="connect" - /> -
-
- {MethodButtonsComponent && } -
+ + +
{t("Networks supported")}
+ } + to={to} + disabled={disabled} + /> + ) +} -
-
- - - {t("Don't want to import your private key?")} - - -
+const networkChoices = { + polkadot: , + ethereum: , +} +function AccountCreateMethodButton({ + title, + subtitle, + networks, + disabled, + to, +}: { + title: ReactNode + subtitle: ReactNode + networks?: Array<"ethereum" | "polkadot"> + disabled?: boolean + to?: string +}) { + const navigate = useNavigate() + const handleClick = useCallback(() => to !== undefined && navigate(to), [navigate, to]) - -
-
-
+ return ( + ) } diff --git a/apps/extension/src/ui/domains/Account/AccountAdd/context.ts b/apps/extension/src/ui/domains/Account/AccountAdd/context.ts index 48638644ce..9eb7ae8074 100644 --- a/apps/extension/src/ui/domains/Account/AccountAdd/context.ts +++ b/apps/extension/src/ui/domains/Account/AccountAdd/context.ts @@ -1,25 +1,30 @@ -import { useState } from "react" +import { useCallback } from "react" import { useSearchParams } from "react-router-dom" import { provideContext } from "@talisman/util/provideContext" -const allMethodTypes = ["new", "import", "connect", "watched"] as const -export type MethodTypes = (typeof allMethodTypes)[number] +const allMethodTypes = ["new", "import", "connect", "watched"] as const satisfies string[] +export type MethodType = (typeof allMethodTypes)[number] -const isMethodType = (item: string | null): item is MethodTypes => +const isMethodType = (item: string | null): item is MethodType => typeof item === "string" && Array.from(allMethodTypes).includes(item) const useAccountCreate = () => { - const [searchParams] = useSearchParams() - const [methodType, setMethodType] = useState(() => { - const searchMethodType = searchParams.get("methodType") - return isMethodType(searchMethodType) ? searchMethodType : "new" - }) - - return { - methodType, - setMethodType, - } + const [searchParams, setSearchParams] = useSearchParams() + const searchMethodType = searchParams.get("methodType") + + const methodType = isMethodType(searchMethodType) ? searchMethodType : "new" + const setMethodType = useCallback( + (newMethodType: MethodType) => { + setSearchParams((params) => { + params.set("methodType", newMethodType) + return params + }) + }, + [setSearchParams], + ) + + return { methodType, setMethodType } } const [AccountCreateContextProvider, useAccountCreateContext] = provideContext(useAccountCreate) diff --git a/apps/extension/src/ui/domains/Account/AccountTypeNetworkSearch.tsx b/apps/extension/src/ui/domains/Account/AccountTypeNetworkSearch.tsx new file mode 100644 index 0000000000..8f20cede0e --- /dev/null +++ b/apps/extension/src/ui/domains/Account/AccountTypeNetworkSearch.tsx @@ -0,0 +1,195 @@ +import { + Combobox, + ComboboxButton, + ComboboxInput, + ComboboxOption, + ComboboxOptions, +} from "@headlessui/react" +import { Chain, SimpleEvmNetwork } from "@talismn/chaindata-provider" +import { ChevronDownIcon, ChevronUpIcon, CloseIcon, SearchIcon } from "@talismn/icons" +import { classNames } from "@talismn/util" +import { useVirtualizer } from "@tanstack/react-virtual" +import startCase from "lodash/startCase" +import { useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react" +import { useTranslation } from "react-i18next" + +import { ChainLogo } from "@ui/domains/Asset/ChainLogo" +import { getNetworkInfo } from "@ui/hooks/useNetworkInfo" +import { useChainsMap, useEvmNetworksMap, useTokensMap } from "@ui/state" + +export function AccountTypeNetworkSearch({ + setAccountType, +}: { + setAccountType: (accountType?: string) => void +}) { + const { t } = useTranslation() + + const inputId = useId() + + const [search, setSearch] = useState("") + + const chainsMap = useChainsMap() + const evmNetworksMap = useEvmNetworksMap() + const tokensMap = useTokensMap() + const allNetworks = useMemo( + () => + [ + ...Object.values(chainsMap).flatMap((chain) => { + if (chain.isTestnet) return [] + const relay = chain.relay?.id ? chainsMap[chain.relay.id] : null + const { label, type } = getNetworkInfo(t, { chain, relay }) + const symbol = tokensMap[chain.nativeToken?.id ?? ""]?.symbol + + return { id: chain.id, label, type, symbol, account: chain.account } + }), + ...Object.values(evmNetworksMap).flatMap((evmNetwork) => { + if (evmNetwork.isTestnet) return [] + const { label, type } = getNetworkInfo(t, { evmNetwork }) + const symbol = tokensMap[evmNetwork.nativeToken?.id ?? ""]?.symbol + + return { id: evmNetwork.id, label, type, symbol } + }), + ].sort((a, b) => a.label?.localeCompare(b.label ?? "") ?? 0), + + [t, chainsMap, evmNetworksMap, tokensMap], + ) + type Network = (typeof networks)[number] + + const networks = useMemo(() => { + if (!search) return allNetworks + return allNetworks.filter( + (network) => + network.label?.toLowerCase().includes(search.toLowerCase().trim()) || + network.symbol?.toLowerCase().includes(search.toLowerCase().trim()), + ) + }, [allNetworks, search]) + + const [selected, setSelected] = useState(null) + useEffect(() => { + if (!selected) return setAccountType() + + const network: Chain | SimpleEvmNetwork | undefined = + chainsMap[selected.id] ?? evmNetworksMap[selected.id] ?? undefined + setAccountType(getAccountType(network)) + }, [chainsMap, evmNetworksMap, selected, setAccountType]) + + const refContainer = useRef(null) + const virtualizer = useVirtualizer({ + count: networks.length, + estimateSize: () => 40, + overscan: 5, + getScrollElement: () => refContainer.current, + }) + + const Recalculate = useMemo( + () => + function Recalculate({ open }: { open: boolean }) { + useLayoutEffect(() => { + if (!open) return + virtualizer.measure() + }, [open]) + return null + }, + [virtualizer], + ) + const ClearSearch = useMemo( + () => + function ClearSearch({ open }: { open: boolean }) { + useEffect(() => { + if (open) return + setSearch("") + }, [open]) + return null + }, + [setSearch], + ) + + return ( + setSelected(null) : undefined} + > + {({ open }) => ( +
+ + + + + {selected && ( +
+ + {selected.label} +
+ )} + setSearch(e.target.value)} + value={search} + autoComplete="off" + /> +
+ + {!open && !selected && } + {open && } + + {selected && ( + setSelected(null)} /> + )} + +
+
{t("Network")}
+
{t("Account Type")}
+
+
+
+ {virtualizer.getVirtualItems().map((item) => { + const network = networks[item.index] + return ( + + + {network.label} + {network.type} +
+ {startCase(getAccountType(network))} + + ) + })} +
+
+ +
+ )} + + ) +} + +function getAccountType(network: T) { + if ("account" in network && network.account !== "secp256k1") return "polkadot" + if ("account" in network && network.account === "secp256k1") return "ethereum" + if (!("account" in network)) return "ethereum" + + throw new Error(`Unhandled network ${network}`) +} diff --git a/apps/extension/src/ui/domains/Account/AccountTypeSelector.tsx b/apps/extension/src/ui/domains/Account/AccountTypeSelector.tsx index 553389ddd4..e082b8a409 100644 --- a/apps/extension/src/ui/domains/Account/AccountTypeSelector.tsx +++ b/apps/extension/src/ui/domains/Account/AccountTypeSelector.tsx @@ -6,19 +6,23 @@ import { useTranslation } from "react-i18next" import { EthereumCircleLogo, PolkadotCircleLogo } from "@talisman/theme/logos" const AccountTypeButton: FC<{ - title: ReactNode className?: string icon: ReactNode + title: ReactNode subtitle: ReactNode + disabled?: boolean onClick: () => void -}> = ({ icon, title, subtitle, className, onClick }) => ( +}> = ({ className, icon, title, subtitle, disabled, onClick }) => (
diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx index 3a297904a4..7bcd36c700 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PopupAssetsTable.tsx @@ -25,7 +25,7 @@ import { StaleBalancesIcon } from "../StaleBalancesIcon" import { usePortfolioDisplayBalances } from "../useDisplayBalances" import { usePortfolioNavigation } from "../usePortfolioNavigation" import { useTokenBalancesSummary } from "../useTokenBalancesSummary" -import { NetworksLogoStack } from "./NetworksLogoStack" +import { PortfolioNetworksLogoStack } from "./PortfolioNetworksLogoStack" import { usePortfolioNetworkIds } from "./usePortfolioNetworkIds" import { usePortfolioSymbolBalancesByFilter } from "./usePortfolioSymbolBalances" @@ -118,7 +118,7 @@ const AssetRow: FC<{
{!!networkIds.length && (
- +
)}
diff --git a/apps/extension/src/ui/domains/Portfolio/AssetsTable/NetworksLogoStack.tsx b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PortfolioNetworksLogoStack.tsx similarity index 82% rename from apps/extension/src/ui/domains/Portfolio/AssetsTable/NetworksLogoStack.tsx rename to apps/extension/src/ui/domains/Portfolio/AssetsTable/PortfolioNetworksLogoStack.tsx index 393d9c0efd..b32f5dffc1 100644 --- a/apps/extension/src/ui/domains/Portfolio/AssetsTable/NetworksLogoStack.tsx +++ b/apps/extension/src/ui/domains/Portfolio/AssetsTable/PortfolioNetworksLogoStack.tsx @@ -7,7 +7,7 @@ import { ChainLogo } from "@ui/domains/Asset/ChainLogo" import { PortfolioNetwork, usePortfolioNetworks } from "./usePortfolioNetworks" -export const NetworksLogoStackItem = ({ network }: { network?: PortfolioNetwork }) => { +export const PortfolioNetworksLogoStackItem = ({ network }: { network?: PortfolioNetwork }) => { const tooltip = useMemo( () => `${network?.label} (${network?.type})`, [network?.label, network?.type], @@ -36,7 +36,7 @@ const MoreNetworksTooltip = ({ networks }: { networks: PortfolioNetwork[] }) => ) } -export const NetworksLogoStackMore = ({ networks }: { networks: PortfolioNetwork[] }) => { +export const PortfolioNetworksLogoStackMore = ({ networks }: { networks: PortfolioNetwork[] }) => { if (!networks.length) return null return ( @@ -52,7 +52,7 @@ export const NetworksLogoStackMore = ({ networks }: { networks: PortfolioNetwork type Props = { networkIds?: (ChainId | EvmNetworkId)[]; className?: string; max?: number } -export const NetworksLogoStack = ({ networkIds, className, max = 4 }: Props) => { +export const PortfolioNetworksLogoStack = ({ networkIds, className, max = 4 }: Props) => { const { networks } = usePortfolioNetworks(networkIds) const { visibleNetworks, moreNetworks } = useMemo(() => { @@ -65,9 +65,9 @@ export const NetworksLogoStack = ({ networkIds, className, max = 4 }: Props) => return (
{visibleNetworks.map((network, idx) => ( - + ))} - +
) } diff --git a/apps/extension/src/ui/domains/Portfolio/NftTile.tsx b/apps/extension/src/ui/domains/Portfolio/NftTile.tsx index 24c53be164..b29fd11be7 100644 --- a/apps/extension/src/ui/domains/Portfolio/NftTile.tsx +++ b/apps/extension/src/ui/domains/Portfolio/NftTile.tsx @@ -2,7 +2,7 @@ import { StarIcon } from "@talismn/icons" import { classNames } from "@talismn/util" import { FC } from "react" -import { NetworksLogoStack } from "./AssetsTable/NetworksLogoStack" +import { PortfolioNetworksLogoStack } from "./AssetsTable/PortfolioNetworksLogoStack" import { NftImage } from "./NftImage" export const NftTile: FC<{ @@ -40,7 +40,7 @@ export const NftTile: FC<{
{label}
- +
) diff --git a/apps/extension/src/ui/domains/Portfolio/Nfts/DashboardNfts.tsx b/apps/extension/src/ui/domains/Portfolio/Nfts/DashboardNfts.tsx index c2aa473fc4..b4fe46d864 100644 --- a/apps/extension/src/ui/domains/Portfolio/Nfts/DashboardNfts.tsx +++ b/apps/extension/src/ui/domains/Portfolio/Nfts/DashboardNfts.tsx @@ -8,7 +8,7 @@ import { Fiat } from "@ui/domains/Asset/Fiat" import { useNavigateWithQuery } from "@ui/hooks/useNavigateWithQuery" import { useEvmNetworksMap, useIsFavoriteNft, useNfts, useSetting } from "@ui/state" -import { NetworksLogoStack } from "../AssetsTable/NetworksLogoStack" +import { PortfolioNetworksLogoStack } from "../AssetsTable/PortfolioNetworksLogoStack" import { NftDialog } from "../NftDialog" import { NftImage } from "../NftImage" import { NftTile } from "../NftTile" @@ -103,7 +103,7 @@ const NftCollectionRowInner: FC<{ {isFavorite ? : null}
- +
{networkName}
diff --git a/apps/extension/src/ui/domains/Portfolio/Nfts/PopupNfts.tsx b/apps/extension/src/ui/domains/Portfolio/Nfts/PopupNfts.tsx index 380b1b5c90..fe7460956f 100644 --- a/apps/extension/src/ui/domains/Portfolio/Nfts/PopupNfts.tsx +++ b/apps/extension/src/ui/domains/Portfolio/Nfts/PopupNfts.tsx @@ -9,7 +9,7 @@ import { Fiat } from "@ui/domains/Asset/Fiat" import { useNavigateWithQuery } from "@ui/hooks/useNavigateWithQuery" import { useEvmNetworksMap, useIsFavoriteNft, useNfts, useSetting } from "@ui/state" -import { NetworksLogoStack } from "../AssetsTable/NetworksLogoStack" +import { PortfolioNetworksLogoStack } from "../AssetsTable/PortfolioNetworksLogoStack" import { NftDialog } from "../NftDialog" import { NftImage } from "../NftImage" import { NftTile } from "../NftTile" @@ -104,7 +104,7 @@ const NftCollectionRowInner: FC<{ {isFavorite ? : null}
- +
{networkName}
diff --git a/apps/extension/src/ui/hooks/useNetworkInfo.ts b/apps/extension/src/ui/hooks/useNetworkInfo.ts index d7440a3116..1b952ebc4c 100644 --- a/apps/extension/src/ui/hooks/useNetworkInfo.ts +++ b/apps/extension/src/ui/hooks/useNetworkInfo.ts @@ -2,11 +2,11 @@ import { TFunction } from "i18next" import { useMemo } from "react" import { useTranslation } from "react-i18next" -import { Chain, EvmNetwork } from "@extension/core" +import { Chain, SimpleEvmNetwork } from "@extension/core" export type NetworkInfoProps = { chain?: Chain | null - evmNetwork?: EvmNetwork | null + evmNetwork?: SimpleEvmNetwork | null relay?: Chain | null } diff --git a/packages/icons/src/icons/eye-plus.svg b/packages/icons/src/icons/eye-plus.svg index ce0bced6b6..7639c60b6e 100644 --- a/packages/icons/src/icons/eye-plus.svg +++ b/packages/icons/src/icons/eye-plus.svg @@ -1,12 +1,7 @@ - - - - - - - - - - - + + + + + +