From a099cd99bb9e2fc1136f327ebaad3d04b42bc684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Wed, 23 Oct 2024 13:03:12 +0200 Subject: [PATCH 1/4] List actual accounts in Accounts page --- .../popup/popupX/pages/Accounts/Accounts.scss | 4 + .../popup/popupX/pages/Accounts/Accounts.tsx | 145 +++++++++--------- .../popup/popupX/pages/Accounts/i18n/en.ts | 2 +- 3 files changed, 80 insertions(+), 71 deletions(-) diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss index d5cae019d..610b83a29 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss @@ -25,6 +25,10 @@ color: $color-white; } + .capture__main_small { + overflow-wrap: anywhere; + } + .button__icon { gap: rem(16px); diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx index a81d2bd9d..526d51084 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx @@ -13,34 +13,86 @@ import Text from '@popup/popupX/shared/Text'; import { useNavigate } from 'react-router-dom'; import { absoluteRoutes } from '@popup/popupX/constants/routes'; import { copyToClipboard } from '@popup/popupX/shared/utils/helpers'; +import { useAtomValue } from 'jotai'; +import { credentialsAtom } from '@popup/store/account'; +import { WalletCredential } from '@shared/storage/types'; +import { useIdentityName } from '@popup/shared/utils/account-helpers'; +import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext'; +import { displayAsCcd } from 'wallet-common-helpers'; -const ACCOUNT_LIST = [ - { - account: 'Account 1', - address: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', - balance: '4,227.38', - attached: 'Identity 1', - }, - { - account: 'Account 2', - address: 'bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh', - balance: '4,227.38', - attached: 'Identity 1', - }, - { - account: 'Account 3', - address: 'tt2kgdygjrsqtzq2n0yrf2493p83kkfjh50eo', - balance: '1,195.41', - attached: 'Identity 2', - }, -]; +function fallbackAccountName(credentialNumber: number): string { + return `Account ${1 + credentialNumber}`; +} -export default function Accounts() { +type AccountListItemProps = { + credential: WalletCredential; +}; + +function AccountListItem({ credential }: AccountListItemProps) { const { t } = useTranslation('x', { keyPrefix: 'accounts' }); const nav = useNavigate(); const navToPrivateKey = () => nav(absoluteRoutes.settings.accounts.privateKey.path); const navToConnectedSites = () => nav(absoluteRoutes.settings.accounts.connectedSites.path); const navToIdCards = () => nav(absoluteRoutes.settings.idCards.path); + + const identityName = useIdentityName(credential); + const accountInfo = useAccountInfo(credential); + + const accountName = credential.credName !== '' ? credential.credName : fallbackAccountName(credential.credNumber); + const { address } = credential; + const ccdBalance = + accountInfo === undefined ? 'Loading' : displayAsCcd(accountInfo.accountAmount.microCcdAmount, false); + return ( + + + {accountName} + } /> + + + {address} + copyToClipboard(address)} icon={} /> + + + {t('ccdBalance')} + {ccdBalance} + + + {t('connectedSites')} + } + leftLabel + /> + + + {t('privateKey')} + } + leftLabel + /> + + + {t('attachedTo')} + } + leftLabel + /> + + + ); +} + +export default function Accounts() { + const { t } = useTranslation('x', { keyPrefix: 'accounts' }); + const accounts = useAtomValue(credentialsAtom); return ( @@ -49,55 +101,8 @@ export default function Accounts() { } /> - {ACCOUNT_LIST.map(({ account, address, balance, attached }) => ( - - - {account} - } /> - - - {address} - copyToClipboard(address)} - icon={} - /> - - - {t('totalBalance')} - {balance} USD - - - {t('connectedSites')} - } - leftLabel - /> - - - {t('privateKey')} - } - leftLabel - /> - - - {t('attachedTo')} - } - leftLabel - /> - - + {accounts.map((item) => ( + ))} diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/i18n/en.ts b/packages/browser-wallet/src/popup/popupX/pages/Accounts/i18n/en.ts index 9fb69e2de..96e7d0f0f 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/i18n/en.ts +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/i18n/en.ts @@ -1,6 +1,6 @@ const t = { accounts: 'Accounts', - totalBalance: 'Total Balance', + ccdBalance: 'CCD Balance', connectedSites: 'Connected sites', seeList: 'See list', privateKey: 'Private key', From 81e611c7597af03f26a236fe39267d0d157e7e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Thu, 24 Oct 2024 11:16:27 +0200 Subject: [PATCH 2/4] Support editing account name in account list --- .../src/assets/svgX/checkmark.svg | 3 + .../popup/popupX/pages/Accounts/Accounts.scss | 17 ++++ .../popup/popupX/pages/Accounts/Accounts.tsx | 79 +++++++++++++++++-- .../src/popup/shared/utils/account-helpers.ts | 6 +- 4 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 packages/browser-wallet/src/assets/svgX/checkmark.svg diff --git a/packages/browser-wallet/src/assets/svgX/checkmark.svg b/packages/browser-wallet/src/assets/svgX/checkmark.svg new file mode 100644 index 000000000..e4db7bbc7 --- /dev/null +++ b/packages/browser-wallet/src/assets/svgX/checkmark.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss index 610b83a29..9f6052779 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss @@ -29,8 +29,25 @@ overflow-wrap: anywhere; } + input.editable { + background: none; + color: inherit; + border: none; + font-weight: inherit; + font-size: inherit; + font-family: inherit; + padding: 0; + margin: 0; + + &:focus { + outline: none; + } + } + .button__icon { gap: rem(16px); + height: rem(16px); + width: rem(16px); .label__main { color: $color-white; diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx index 526d51084..7ad3d8c5f 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx @@ -1,8 +1,10 @@ -import React from 'react'; +import React, { ChangeEvent, KeyboardEvent, useState } from 'react'; import Plus from '@assets/svgX/plus.svg'; import Arrows from '@assets/svgX/arrows-down-up.svg'; import MagnifyingGlass from '@assets/svgX/magnifying-glass.svg'; import Pencil from '@assets/svgX/pencil-simple.svg'; +import Checkmark from '@assets/svgX/checkmark.svg'; +import Close from '@assets/svgX/close.svg'; import Copy from '@assets/svgX/copy.svg'; import ArrowRight from '@assets/svgX/arrow-right.svg'; import Page from '@popup/popupX/shared/Page'; @@ -16,7 +18,7 @@ import { copyToClipboard } from '@popup/popupX/shared/utils/helpers'; import { useAtomValue } from 'jotai'; import { credentialsAtom } from '@popup/store/account'; import { WalletCredential } from '@shared/storage/types'; -import { useIdentityName } from '@popup/shared/utils/account-helpers'; +import { useIdentityName, useWritableSelectedAccount } from '@popup/shared/utils/account-helpers'; import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext'; import { displayAsCcd } from 'wallet-common-helpers'; @@ -24,6 +26,65 @@ function fallbackAccountName(credentialNumber: number): string { return `Account ${1 + credentialNumber}`; } +type EditableAccountNameProps = { + currentName: string; + fallbackName: string; + onNewName: (newName: string) => void; +}; + +function EditableAccountName({ currentName, fallbackName, onNewName }: EditableAccountNameProps) { + const [isEditingName, setIsEditingName] = useState(false); + const [editedName, setEditedName] = useState(currentName); + // Using editedName instead of currentName to avoid flickering after completing. + const displayName = editedName === '' ? fallbackName : editedName; + const onAbort = () => { + setIsEditingName(false); + setEditedName(currentName); + }; + const onComplete = () => { + onNewName(editedName.trim()); + setIsEditingName(false); + }; + const onEdit = () => { + setEditedName(currentName); + setIsEditingName(true); + }; + const onInputChange = (event: ChangeEvent) => { + setEditedName(event.target.value); + }; + const onKeyUp = (event: KeyboardEvent) => { + if (event.key === 'Enter') { + event.preventDefault(); + onComplete(); + } + }; + if (isEditingName) { + return ( + <> + + + + } onClick={onComplete} /> + } onClick={onAbort} /> + + ); + } + return ( + <> + {displayName} + } onClick={onEdit} /> + + ); +} + type AccountListItemProps = { credential: WalletCredential; }; @@ -34,19 +95,23 @@ function AccountListItem({ credential }: AccountListItemProps) { const navToPrivateKey = () => nav(absoluteRoutes.settings.accounts.privateKey.path); const navToConnectedSites = () => nav(absoluteRoutes.settings.accounts.connectedSites.path); const navToIdCards = () => nav(absoluteRoutes.settings.idCards.path); - const identityName = useIdentityName(credential); const accountInfo = useAccountInfo(credential); - - const accountName = credential.credName !== '' ? credential.credName : fallbackAccountName(credential.credNumber); + const setAccount = useWritableSelectedAccount(credential.address); + const fallbackName = fallbackAccountName(credential.credNumber); + const accountName = credential.credName !== '' ? credential.credName : fallbackName; const { address } = credential; const ccdBalance = accountInfo === undefined ? 'Loading' : displayAsCcd(accountInfo.accountAmount.microCcdAmount, false); + const onNewAccountName = (newName: string) => setAccount({ credName: newName }); return ( - {accountName} - } /> + {address} diff --git a/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts b/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts index 18d4e2816..82bb89e83 100644 --- a/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts +++ b/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts @@ -51,9 +51,11 @@ export function useIdentityName(credential: WalletCredential, fallback?: string) export function useWritableSelectedAccount(accountAddress: string) { const [accounts, setAccounts] = useAtom(writableCredentialAtom); - const setAccount = (update: WalletCredential) => + const setAccount = (update: Partial) => setAccounts( - accounts.map((account) => (account.address === accountAddress ? { ...account, ...update } : account)) + accounts.map((account) => + account.address === accountAddress ? ({ ...account, ...update } as WalletCredential) : account + ) ); return setAccount; From 6c6cbacbbc0b9fb2671f6c82f8008ed2be485580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Thu, 24 Oct 2024 11:35:10 +0200 Subject: [PATCH 3/4] Fix icon buttons on accounts page --- .../src/popup/popupX/pages/Accounts/Accounts.scss | 8 +++++--- .../src/popup/popupX/pages/Accounts/Accounts.tsx | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss index 9f6052779..e78b5334f 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss @@ -25,7 +25,7 @@ color: $color-white; } - .capture__main_small { + .wrap-anywhere { overflow-wrap: anywhere; } @@ -46,8 +46,10 @@ .button__icon { gap: rem(16px); - height: rem(16px); - width: rem(16px); + + svg { + width: rem(16px); + } .label__main { color: $color-white; diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx index 7ad3d8c5f..9c965656d 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx @@ -114,7 +114,7 @@ function AccountListItem({ credential }: AccountListItemProps) { /> - {address} + {address} copyToClipboard(address)} icon={} /> From 8cf8eefafd505c8c8e05edd4a6510f499b073131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emil=20Holm=20Gj=C3=B8rup?= Date: Thu, 24 Oct 2024 13:51:46 +0200 Subject: [PATCH 4/4] Address review comments --- .../popup/popupX/pages/Accounts/Accounts.scss | 16 ++++++++++++---- .../popup/popupX/pages/Accounts/Accounts.tsx | 18 ++++++++++-------- .../src/popup/shared/utils/account-helpers.ts | 10 +++++++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss index e78b5334f..b5005fb30 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.scss @@ -44,12 +44,20 @@ } } - .button__icon { + .gap-16 { gap: rem(16px); + } - svg { - width: rem(16px); - } + .width-16 { + width: rem(16px); + } + + .width-12 { + width: rem(12px); + } + + .button__icon { + gap: rem(16px); .label__main { color: $color-white; diff --git a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx index 9c965656d..d95223644 100644 --- a/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx +++ b/packages/browser-wallet/src/popup/popupX/pages/Accounts/Accounts.tsx @@ -18,14 +18,10 @@ import { copyToClipboard } from '@popup/popupX/shared/utils/helpers'; import { useAtomValue } from 'jotai'; import { credentialsAtom } from '@popup/store/account'; import { WalletCredential } from '@shared/storage/types'; -import { useIdentityName, useWritableSelectedAccount } from '@popup/shared/utils/account-helpers'; +import { displaySplitAddress, useIdentityName, useWritableSelectedAccount } from '@popup/shared/utils/account-helpers'; import { useAccountInfo } from '@popup/shared/AccountInfoListenerContext'; import { displayAsCcd } from 'wallet-common-helpers'; -function fallbackAccountName(credentialNumber: number): string { - return `Account ${1 + credentialNumber}`; -} - type EditableAccountNameProps = { currentName: string; fallbackName: string; @@ -72,8 +68,14 @@ function EditableAccountName({ currentName, fallbackName, onNewName }: EditableA maxLength={25} /> - } onClick={onComplete} /> - } onClick={onAbort} /> +
+ } + onClick={onComplete} + /> + } onClick={onAbort} /> +
); } @@ -98,7 +100,7 @@ function AccountListItem({ credential }: AccountListItemProps) { const identityName = useIdentityName(credential); const accountInfo = useAccountInfo(credential); const setAccount = useWritableSelectedAccount(credential.address); - const fallbackName = fallbackAccountName(credential.credNumber); + const fallbackName = displaySplitAddress(credential.address); const accountName = credential.credName !== '' ? credential.credName : fallbackName; const { address } = credential; const ccdBalance = diff --git a/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts b/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts index 82bb89e83..10abf351d 100644 --- a/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts +++ b/packages/browser-wallet/src/popup/shared/utils/account-helpers.ts @@ -10,15 +10,19 @@ import { isIdentityOfCredential } from '@shared/utils/identity-helpers'; import { getNextUnused } from '@shared/utils/number-helpers'; import { useDecryptedSeedPhrase } from './seed-phrase-helpers'; +/** Format an account address for display by showing the 4 first and last characters in the base58check representation. */ +export function displaySplitAddress(address: string) { + return `${address.slice(0, 4)}...${address.slice(-4)}`; +} + export const displayNameOrSplitAddress = (account: WalletCredential | undefined) => { const { credName, address } = account || { address: '' }; - return credName || `${address.slice(0, 4)}...${address.slice(address.length - 4)}`; + return credName || displaySplitAddress(address); }; export const displayNameAndSplitAddress = (account: WalletCredential | undefined) => { const { credName, address } = account || { address: '' }; - const splitAddress = `${address.slice(0, 4)}...${address.slice(address.length - 4)}`; - return `${credName ? `${credName} / ` : ''}${splitAddress}`; + return `${credName ? `${credName} / ` : ''}${displaySplitAddress(address)}`; }; export function useIdentityOf(cred?: WalletCredential) {