From e7e6882606270e1809dacd55fb3ef099d71b3fa4 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Mon, 2 Oct 2023 10:55:28 +0200 Subject: [PATCH 01/15] Add account name field to account settings --- .changelog/1699.feature.md | 1 + .../Account/ManageableAccountDetails.tsx | 27 +++++++++++++++---- src/locales/en/translation.json | 2 ++ 3 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 .changelog/1699.feature.md diff --git a/.changelog/1699.feature.md b/.changelog/1699.feature.md new file mode 100644 index 0000000000..bd1ffc51d9 --- /dev/null +++ b/.changelog/1699.feature.md @@ -0,0 +1 @@ +Named accounts feature diff --git a/src/app/components/Toolbar/Features/Account/ManageableAccountDetails.tsx b/src/app/components/Toolbar/Features/Account/ManageableAccountDetails.tsx index a83b5e4af4..4eff237f76 100644 --- a/src/app/components/Toolbar/Features/Account/ManageableAccountDetails.tsx +++ b/src/app/components/Toolbar/Features/Account/ManageableAccountDetails.tsx @@ -2,11 +2,13 @@ import { useContext, useState } from 'react' import copy from 'copy-to-clipboard' import { Box } from 'grommet/es6/components/Box' import { Button } from 'grommet/es6/components/Button' +import { FormField } from 'grommet/es6/components/FormField' import { Notification } from 'grommet/es6/components/Notification' import { ResponsiveContext } from 'grommet/es6/contexts/ResponsiveContext' import { Tab } from 'grommet/es6/components/Tab' import { Tabs } from 'grommet/es6/components/Tabs' import { Text } from 'grommet/es6/components/Text' +import { TextInput } from 'grommet/es6/components/TextInput' import { Tip } from 'grommet/es6/components/Tip' import { Copy } from 'grommet-icons/es6/icons/Copy' import { CircleInformation } from 'grommet-icons/es6/icons/CircleInformation' @@ -46,11 +48,26 @@ export const ManageableAccountDetails = ({ deleteAccount, wallet }: ManageableAc return ( <> - - - - - + + + name.trim().length > 16 + ? { + message: t('toolbar.settings.nameLengthError', 'No more than 16 characters'), + status: 'error', + } + : undefined + } + > + + + + + + + + should render address properly 1`] = ` + `; diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index 93cfa2c040..63c339bae1 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -9,7 +9,8 @@ import { Button } from 'grommet/es6/components/Button' import { Text } from 'grommet/es6/components/Text' import { Notification } from 'grommet/es6/components/Notification' import { Copy } from 'grommet-icons/es6/icons/Copy' -import React, { memo, useState } from 'react' +import { Edit } from 'grommet-icons/es6/icons/Edit' +import { memo, useState } from 'react' import { useTranslation } from 'react-i18next' import { PrettyAddress } from '../PrettyAddress' @@ -40,13 +41,13 @@ export const AddressBox = memo((props: Props) => { align="center" round="5px" pad={{ right: 'small' }} - width="fit-content" border={props.border && { color: 'brand' }} > should match snapshot 1`] = ` +
Total @@ -1047,7 +1094,7 @@ exports[` should match snapshot 1`] = ` 100.000001111 should match snapshot 1`] = ` 100.0 should match snapshot 1`] = ` 0.000001111 should match snapshot 1`] = ` 0.0 should match snapshot 1`] = `
should match snapshot 1`] = `
should match snapshot 1`] = `

No transactions found.

From 4a6d0c354750c80c7c170612165aeecb98ed9d17 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Thu, 5 Oct 2023 09:09:23 +0200 Subject: [PATCH 03/15] Extract account edit modal --- .../Features/Account/ManageableAccount.tsx | 40 +----- .../Account/ManageableAccountDetails.tsx | 136 ++++++++++-------- 2 files changed, 87 insertions(+), 89 deletions(-) diff --git a/src/app/components/Toolbar/Features/Account/ManageableAccount.tsx b/src/app/components/Toolbar/Features/Account/ManageableAccount.tsx index 6a99209bc8..ef2477cfab 100644 --- a/src/app/components/Toolbar/Features/Account/ManageableAccount.tsx +++ b/src/app/components/Toolbar/Features/Account/ManageableAccount.tsx @@ -1,15 +1,7 @@ -import { useContext, useState } from 'react' -import { Box } from 'grommet/es6/components/Box' -import { Button } from 'grommet/es6/components/Button' -import { ResponsiveContext } from 'grommet/es6/contexts/ResponsiveContext' -import { Tab } from 'grommet/es6/components/Tab' -import { useTranslation } from 'react-i18next' +import { useState } from 'react' import { Account } from './Account' -import { Wallet } from '../../../../state/wallet/types' -import { Tabs } from 'grommet/es6/components/Tabs' -import { layerOverlayMinHeight } from '../layer' -import { LayerContainer } from './../LayerContainer' import { ManageableAccountDetails } from './ManageableAccountDetails' +import { Wallet } from '../../../../state/wallet/types' export const ManageableAccount = ({ wallet, @@ -22,9 +14,7 @@ export const ManageableAccount = ({ deleteWallet?: (address: string) => void selectWallet: (address: string) => void }) => { - const { t } = useTranslation() const [layerVisibility, setLayerVisibility] = useState(false) - const isMobile = useContext(ResponsiveContext) === 'small' const handleDelete = deleteWallet ? (address: string) => { deleteWallet(address) @@ -46,27 +36,11 @@ export const ManageableAccount = ({ }} /> {layerVisibility && ( - setLayerVisibility(false)}> - - - - - -
`; diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index 63c339bae1..fb96118c49 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -10,17 +10,18 @@ import { Text } from 'grommet/es6/components/Text' import { Notification } from 'grommet/es6/components/Notification' import { Copy } from 'grommet-icons/es6/icons/Copy' import { Edit } from 'grommet-icons/es6/icons/Edit' -import { memo, useState } from 'react' +import { memo, useState, ReactNode } from 'react' import { useTranslation } from 'react-i18next' - +import { Wallet } from 'app/state/wallet/types' import { PrettyAddress } from '../PrettyAddress' -interface Props { +interface AddressBoxProps { address: string border?: boolean + children?: ReactNode } -export const AddressBox = memo((props: Props) => { +export const AddressBox = memo((props: AddressBoxProps) => { const { t } = useTranslation() const [notificationVisible, setNotificationVisible] = useState(false) @@ -47,7 +48,7 @@ export const AddressBox = memo((props: Props) => { - - - + + + + +
- oasis1 qqur xkga vtcj jytn eume clx5 9ds3 avja qg7f tqph + + + oasis1 qqur xkga vtcj jytn eume clx5 9ds3 avja qg7f tqph + + - - +
+
`; diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index fb96118c49..221acabe5a 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -4,6 +4,8 @@ * */ import copy from 'copy-to-clipboard' +import styled from 'styled-components' +import { normalizeColor } from 'grommet/es6/utils' import { Box } from 'grommet/es6/components/Box' import { Button } from 'grommet/es6/components/Button' import { Text } from 'grommet/es6/components/Text' @@ -13,22 +15,29 @@ import { Edit } from 'grommet-icons/es6/icons/Edit' import { memo, useState, ReactNode } from 'react' import { useTranslation } from 'react-i18next' import { Wallet } from 'app/state/wallet/types' +import { trimLongString } from '../ShortAddress/trimLongString' import { PrettyAddress } from '../PrettyAddress' +const StyledButton = styled(Button)` + background-color: ${({ theme }) => normalizeColor('background-custom-2', theme)}; + border-width: 1px; + color: ${({ theme }) => normalizeColor('text-custom', theme)}; +` + interface AddressBoxProps { address: string border?: boolean children?: ReactNode } -export const AddressBox = memo((props: AddressBoxProps) => { +interface ContainerProps extends AddressBoxProps { + copyToClipboard: 'icon' | 'button' +} + +const Container = ({ address, border, children, copyToClipboard }: ContainerProps) => { const { t } = useTranslation() const [notificationVisible, setNotificationVisible] = useState(false) - const hideNotification = () => setNotificationVisible(false) - - const address = props.address - const copyAddress = () => { const wasCopied = copy(address) if (wasCopied) { @@ -42,13 +51,32 @@ export const AddressBox = memo((props: AddressBoxProps) => { align="center" round="5px" pad={{ right: 'small' }} - border={props.border && { color: 'brand' }} + border={border && { color: 'brand' }} > - - - + + + + +
- oasis1 qz0k 5q8v jqvu 4s4n wxyj 406y lnfl kc4v rcjg huwk + + + oasis1 qz0k 5q8v jqvu 4s4n wxyj 406y lnfl kc4v rcjg huwk + + + - - - +
+
Total @@ -1094,7 +1131,7 @@ exports[` should match snapshot 1`] = ` 100.000001111 should match snapshot 1`] = ` 100.0 should match snapshot 1`] = ` 0.000001111 should match snapshot 1`] = ` 0.0 should match snapshot 1`] = `
should match snapshot 1`] = `
should match snapshot 1`] = `

No transactions found.

diff --git a/src/styles/theme/ThemeProvider.tsx b/src/styles/theme/ThemeProvider.tsx index 4a9f0d4390..c0eec33187 100644 --- a/src/styles/theme/ThemeProvider.tsx +++ b/src/styles/theme/ThemeProvider.tsx @@ -164,6 +164,10 @@ const grommetCustomTheme: ThemeType = { dark: '#0E5265', light: '#00C8FF', }, + 'background-custom-2': { + dark: '#6FFFB0', + light: '#E8F5FF', + }, 'component-toolbar': { dark: '#0f346088', light: '#26a2f844', @@ -176,7 +180,10 @@ const grommetCustomTheme: ThemeType = { dark: '#6FFFB0', light: '#3fa900', }, - + 'text-custom': { + dark: '#16213E', + light: '#31435A', + }, text: { dark: '#F8F8F8', light: '#16213E', From 818031f01a39336ce9986c5a06664db9a19db4a7 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Thu, 5 Oct 2023 12:04:27 +0200 Subject: [PATCH 07/15] Limit access to named accounts --- src/app/components/AddressBox/index.tsx | 17 +- .../Features/Account/ManageableAccount.tsx | 2 +- .../Account/ManageableAccountDetails.tsx | 33 +- .../Features/AccountSelector/index.tsx | 14 +- .../Features/AccountSummary/index.tsx | 31 +- .../__snapshots__/index.test.tsx.snap | 317 ++++++++---------- src/app/pages/AccountPage/index.tsx | 8 +- src/locales/en/translation.json | 1 + 8 files changed, 204 insertions(+), 219 deletions(-) diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index 221acabe5a..ff1284509d 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -100,28 +100,23 @@ export const AddressBox = memo((props: AddressBoxProps) => { ) }) -interface EditableAddressBoxProps { - editHandler: () => void +interface EditableBoxProps { + openEditModal: () => void wallet: Wallet | undefined } -export const EditableAddressBox = ({ editHandler, wallet }: EditableAddressBoxProps) => { +export const EditableAddressBox = ({ openEditModal, wallet }: EditableBoxProps) => { if (!wallet) { return null } return ( -
Total @@ -1131,7 +1082,7 @@ exports[` should match snapshot 1`] = ` 100.000001111 should match snapshot 1`] = ` 100.0 should match snapshot 1`] = ` 0.000001111 should match snapshot 1`] = ` 0.0 should match snapshot 1`] = `
should match snapshot 1`] = `
should match snapshot 1`] = `

No transactions found.

diff --git a/src/app/pages/AccountPage/index.tsx b/src/app/pages/AccountPage/index.tsx index 8c48d2791d..cdec66ecf7 100644 --- a/src/app/pages/AccountPage/index.tsx +++ b/src/app/pages/AccountPage/index.tsx @@ -94,12 +94,7 @@ export function AccountPage(props: AccountPageProps) { ? null : (BigInt(account.available) + balanceDelegations + balanceDebondingDelegations).toString(), } - const editWalletHandler = (name: string) => { - if (!wallet) { - return - } - dispatch(walletActions.setWalletName({ address: wallet.address, name })) - } + // Restart fetching account balances if address or network changes useEffect(() => { dispatch(accountActions.openAccountPage(address)) @@ -147,7 +142,6 @@ export function AccountPage(props: AccountPageProps) { wallet!.address === address && dispatch(walletActions.selectFirstWallet()) } } - editHandler={editWalletHandler} wallet={wallet} walletHasAccounts={walletHasAccounts} /> diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index ae7036f95c..c772b69203 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -429,6 +429,7 @@ } }, "settings": { + "accountNamingNotAvailable": "To name your account create a profile while opening a wallet.", "cancel": "Cancel", "contacts": "Contacts", "delete": { From 7c9d85af106fc867e729e701c4f5e71acae68752 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Thu, 5 Oct 2023 12:24:37 +0200 Subject: [PATCH 08/15] Make account name look like account address --- .../__snapshots__/index.test.tsx.snap | 44 +- src/app/components/AddressBox/index.tsx | 45 +- .../Features/AccountSummary/index.tsx | 4 +- .../__snapshots__/index.test.tsx.snap | 395 ++++++++++-------- 4 files changed, 292 insertions(+), 196 deletions(-) diff --git a/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap b/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap index 1ecad1665f..20725cdfaa 100644 --- a/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap +++ b/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap @@ -60,7 +60,7 @@ exports[` should render address properly 1`] = ` display: flex; box-sizing: border-box; max-width: 100%; - margin-right: 96px; + margin-right: 48px; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; @@ -71,16 +71,38 @@ exports[` should render address properly 1`] = ` -webkit-flex-direction: row; -ms-flex-direction: row; flex-direction: row; + width: 690px; + -webkit-flex: 1 1; + -ms-flex: 1 1; + flex: 1 1; + padding-bottom: 6px; } .c4 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + max-width: 100%; + min-width: 0; + min-height: 0; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; +} + +.c5 { font-size: 18px; line-height: 24px; font-weight: bold; word-break: break-word; } -.c5 { +.c6 { font-size: inherit; line-height: normal; } @@ -150,7 +172,7 @@ exports[` should render address properly 1`] = ` @media only screen and (max-width:768px) { .c1 { - margin-right: 48px; + margin-right: 24px; } } @@ -160,6 +182,12 @@ exports[` should render address properly 1`] = ` } } +@media only screen and (max-width:768px) { + .c1 { + padding-bottom: 3px; + } +} +
should render address properly 1`] = ` /> -
+
{ const { t } = useTranslation() const [notificationVisible, setNotificationVisible] = useState(false) + const isMobile = useContext(ResponsiveContext) === 'small' const hideNotification = () => setNotificationVisible(false) const copyAddress = () => { const wasCopied = copy(address) @@ -47,25 +50,31 @@ const Container = ({ address, border, children, copyToClipboard }: ContainerProp return ( {copyToClipboard === 'icon' && ( -
+
should match snapshot 1`] = `
Total @@ -1082,7 +1125,7 @@ exports[` should match snapshot 1`] = ` 100.000001111 should match snapshot 1`] = ` 100.0 should match snapshot 1`] = ` 0.000001111 should match snapshot 1`] = ` 0.0 should match snapshot 1`] = `
should match snapshot 1`] = `
should match snapshot 1`] = `

No transactions found.

From 335d80c15f7543b5b179e9c469dc18ecfc83b227 Mon Sep 17 00:00:00 2001 From: Michal Zielenkiewicz Date: Thu, 5 Oct 2023 15:39:05 +0200 Subject: [PATCH 09/15] Make AddressBox separator optional --- .../__snapshots__/index.test.tsx.snap | 7 ----- src/app/components/AddressBox/index.tsx | 26 +++++++++++++------ .../Features/AccountSummary/index.tsx | 2 +- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap b/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap index 20725cdfaa..d2c62aebaa 100644 --- a/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap +++ b/src/app/components/AddressBox/__tests__/__snapshots__/index.test.tsx.snap @@ -65,7 +65,6 @@ exports[` should render address properly 1`] = ` -webkit-box-align: center; -ms-flex-align: center; align-items: center; - border-bottom: solid 1px background-front-border; min-width: 0; min-height: 0; -webkit-flex-direction: row; @@ -176,12 +175,6 @@ exports[` should render address properly 1`] = ` } } -@media only screen and (max-width:768px) { - .c1 { - border-bottom: solid 1px background-front-border; - } -} - @media only screen and (max-width:768px) { .c1 { padding-bottom: 3px; diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index b34675b092..d9b6d84cbd 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -30,13 +30,14 @@ interface AddressBoxProps { address: string border?: boolean children?: ReactNode + separator?: boolean } interface ContainerProps extends AddressBoxProps { copyToClipboard: 'icon' | 'button' } -const Container = ({ address, border, children, copyToClipboard }: ContainerProps) => { +const Container = ({ address, border, children, copyToClipboard, separator }: ContainerProps) => { const { t } = useTranslation() const [notificationVisible, setNotificationVisible] = useState(false) const isMobile = useContext(ResponsiveContext) === 'small' @@ -59,10 +60,14 @@ const Container = ({ address, border, children, copyToClipboard }: ContainerProp > ( export const AddressBox = memo((props: AddressBoxProps) => { return ( - + {props.children} @@ -135,7 +145,7 @@ export const EditableAddressBox = ({ openEditModal, wallet }: EditableBoxProps) return null } return ( - +
`; + +exports[` should render name properly 1`] = ` +.c5 { + display: inline-block; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: 16px; + height: 16px; + fill: link; + stroke: link; +} + +.c5 g { + fill: inherit; + stroke: inherit; +} + +.c5 *:not([stroke])[fill='none'] { + stroke-width: 0; +} + +.c5 *[stroke*='#'],.c5 *[STROKE*='#'] { + stroke: inherit; + fill: none; +} + +.c5 *[fill-rule], +.c5 *[FILL-RULE], +.c5 *[fill*='#'],.c5 *[FILL*='#'] { + fill: inherit; + stroke: none; +} + +.c10 { + display: inline-block; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: 18px; + height: 18px; + fill: currentColor; + stroke: currentColor; +} + +.c10 g { + fill: inherit; + stroke: inherit; +} + +.c10 *:not([stroke])[fill='none'] { + stroke-width: 0; +} + +.c10 *[stroke*='#'],.c10 *[STROKE*='#'] { + stroke: inherit; + fill: none; +} + +.c10 *[fill-rule], +.c10 *[FILL-RULE], +.c10 *[fill*='#'],.c10 *[FILL*='#'] { + fill: inherit; + stroke: none; +} + +.c0 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + max-width: 100%; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-width: 0; + min-height: 0; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding-right: 12px; + border-radius: 5px; +} + +.c1 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + max-width: 100%; + margin-right: 48px; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + border-bottom: solid 1px background-front-border; + min-width: 0; + min-height: 0; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + width: 690px; + -webkit-flex: 1 1; + -ms-flex: 1 1; + flex: 1 1; + padding-bottom: 6px; +} + +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + max-width: 100%; + min-width: 0; + min-height: 0; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-flex: 1 0 auto; + -ms-flex: 1 0 auto; + flex: 1 0 auto; +} + +.c8 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + box-sizing: border-box; + max-width: 100%; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + min-width: 0; + min-height: 0; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; +} + +.c9 { + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; + flex: 0 0 auto; + -webkit-align-self: stretch; + -ms-flex-item-align: stretch; + align-self: stretch; + width: 12px; +} + +.c3 { + font-size: 18px; + line-height: 24px; + font-weight: bold; + word-break: break-word; +} + +.c4 { + display: inline-block; + box-sizing: border-box; + cursor: pointer; + font: inherit; + -webkit-text-decoration: none; + text-decoration: none; + margin: 0; + background: transparent; + overflow: visible; + text-transform: none; + color: inherit; + outline: none; + border: none; + padding: 0; + text-align: inherit; + line-height: 0; + padding: 12px; +} + +.c4:focus { + outline: none; + box-shadow: 0 0 2px 2px #6FFFB0; +} + +.c4:focus > circle, +.c4:focus > ellipse, +.c4:focus > line, +.c4:focus > path, +.c4:focus > polygon, +.c4:focus > polyline, +.c4:focus > rect { + outline: none; + box-shadow: 0 0 2px 2px #6FFFB0; +} + +.c4:focus::-moz-focus-inner { + border: 0; +} + +.c4:focus:not(:focus-visible) { + outline: none; + box-shadow: none; +} + +.c4:focus:not(:focus-visible) > circle,.c4:focus:not(:focus-visible) > ellipse, +.c4:focus:not(:focus-visible) > line,.c4:focus:not(:focus-visible) > path, +.c4:focus:not(:focus-visible) > polygon,.c4:focus:not(:focus-visible) > polyline, +.c4:focus:not(:focus-visible) > rect { + outline: none; + box-shadow: none; +} + +.c4:focus:not(:focus-visible)::-moz-focus-inner { + border: 0; +} + +.c6 { + display: inline-block; + box-sizing: border-box; + cursor: pointer; + font: inherit; + -webkit-text-decoration: none; + text-decoration: none; + margin: 0; + background: transparent; + overflow: visible; + text-transform: none; + border: 2px solid #7D4CDB; + border-radius: 18px; + color: #444444; + padding: 4px 22px; + font-size: 18px; + line-height: 24px; + -webkit-transition-property: color,background-color,border-color,box-shadow; + transition-property: color,background-color,border-color,box-shadow; + -webkit-transition-duration: 0.1s; + transition-duration: 0.1s; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.c6:hover { + box-shadow: 0px 0px 0px 2px #7D4CDB; +} + +.c6:focus { + outline: none; + box-shadow: 0 0 2px 2px #6FFFB0; +} + +.c6:focus > circle, +.c6:focus > ellipse, +.c6:focus > line, +.c6:focus > path, +.c6:focus > polygon, +.c6:focus > polyline, +.c6:focus > rect { + outline: none; + box-shadow: 0 0 2px 2px #6FFFB0; +} + +.c6:focus::-moz-focus-inner { + border: 0; +} + +.c6:focus:not(:focus-visible) { + outline: none; + box-shadow: none; +} + +.c6:focus:not(:focus-visible) > circle,.c6:focus:not(:focus-visible) > ellipse, +.c6:focus:not(:focus-visible) > line,.c6:focus:not(:focus-visible) > path, +.c6:focus:not(:focus-visible) > polygon,.c6:focus:not(:focus-visible) > polyline, +.c6:focus:not(:focus-visible) > rect { + outline: none; + box-shadow: none; +} + +.c6:focus:not(:focus-visible)::-moz-focus-inner { + border: 0; +} + +.c7 { + background-color: background-custom-2; + border-width: 1px; + color: text-custom; +} + +@media only screen and (max-width:768px) { + .c0 { + padding-right: 6px; + } +} + +@media only screen and (max-width:768px) { + .c1 { + margin-right: 24px; + } +} + +@media only screen and (max-width:768px) { + .c1 { + border-bottom: solid 1px background-front-border; + } +} + +@media only screen and (max-width:768px) { + .c1 { + padding-bottom: 3px; + } +} + +
+
+
+
+ + My Wallet + + +
+
+ +
+
+`; diff --git a/src/app/components/AddressBox/__tests__/index.test.tsx b/src/app/components/AddressBox/__tests__/index.test.tsx index 79aa6351f4..e10cc20243 100644 --- a/src/app/components/AddressBox/__tests__/index.test.tsx +++ b/src/app/components/AddressBox/__tests__/index.test.tsx @@ -1,10 +1,9 @@ -import * as React from 'react' import copy from 'copy-to-clipboard' import { screen } from '@testing-library/dom' import { render } from '@testing-library/react' import userEvent from '@testing-library/user-event' -import { AddressBox } from '../index' +import { AddressBox, EditableAddressBox, EditableNameBox } from '../index' jest.mock('copy-to-clipboard') @@ -20,14 +19,58 @@ describe('', () => { it('should be able to copy address to clipboard', async () => { renderComponent() - await userEvent.click(screen.getByTestId('copy-address')) + await userEvent.click(screen.getByTestId('copy-address-icon')) expect(copy).toHaveBeenCalledWith(testAddress) }) it('should be able to show a notification', async () => { renderComponent() jest.mocked(copy).mockReturnValue(true) // Copy must return true so that the notification is actually displayed - await userEvent.click(screen.getByTestId('copy-address')) + await userEvent.click(screen.getByTestId('copy-address-icon')) expect(await screen.getByText('account.addressCopied')).toBeInTheDocument() }) }) + +const openEditModal = jest.fn() +const renderEditableNameBoxComponent = () => + render() + +describe('', () => { + it('should render name properly', () => { + const { container } = renderEditableNameBoxComponent() + expect(container).toMatchSnapshot() + }) + + it('should render edit icon', async () => { + renderEditableNameBoxComponent() + expect(screen.queryByTestId('editable-address-edit-button')).not.toBeInTheDocument() + await userEvent.click(screen.getByTestId('editable-name-edit-button')) + expect(openEditModal).toHaveBeenCalled() + }) + + it('should be able to copy address to clipboard', async () => { + renderEditableNameBoxComponent() + expect(screen.queryByTestId('copy-address-icon')).not.toBeInTheDocument() + await userEvent.click(screen.getByTestId('copy-address-button')) + expect(copy).toHaveBeenCalledWith(testAddress) + }) +}) + +const renderEditableAddressBoxComponent = () => + render() + +describe('', () => { + it('should render edit icon', async () => { + renderEditableAddressBoxComponent() + expect(screen.queryByTestId('editable-name-edit-button')).not.toBeInTheDocument() + await userEvent.click(screen.getByTestId('editable-address-edit-button')) + expect(openEditModal).toHaveBeenCalled() + }) + + it('should be able to copy address to clipboard', async () => { + renderEditableAddressBoxComponent() + expect(screen.queryByTestId('copy-address-button')).not.toBeInTheDocument() + await userEvent.click(screen.getByTestId('copy-address-icon')) + expect(copy).toHaveBeenCalledWith(testAddress) + }) +}) diff --git a/src/app/components/AddressBox/index.tsx b/src/app/components/AddressBox/index.tsx index d9b6d84cbd..6b39ae109b 100644 --- a/src/app/components/AddressBox/index.tsx +++ b/src/app/components/AddressBox/index.tsx @@ -16,7 +16,6 @@ import { Copy } from 'grommet-icons/es6/icons/Copy' import { Edit } from 'grommet-icons/es6/icons/Edit' import { memo, useState, ReactNode } from 'react' import { useTranslation } from 'react-i18next' -import { Wallet } from 'app/state/wallet/types' import { trimLongString } from '../ShortAddress/trimLongString' import { PrettyAddress } from '../PrettyAddress' @@ -75,7 +74,7 @@ const Container = ({ address, border, children, copyToClipboard, separator }: Co width="690px" // keep the same width for address and name variants > {copyToClipboard === 'icon' && ( - + + + + +