diff --git a/packages/yoroi-extension/app/actions/profile-actions.js b/packages/yoroi-extension/app/actions/profile-actions.js index 74d43dd115..656ef6b3fd 100644 --- a/packages/yoroi-extension/app/actions/profile-actions.js +++ b/packages/yoroi-extension/app/actions/profile-actions.js @@ -9,5 +9,8 @@ export default class ProfileActions extends BaseProfileActions { acceptTermsOfUse: AsyncAction = new AsyncAction(); acceptUriScheme: AsyncAction = new AsyncAction(); toggleSidebar: AsyncAction = new AsyncAction(); + updateSortedWalletList: AsyncAction<{| + sortedWallets: Array, + |}> = new AsyncAction(); setSelectedNetwork: Action> = new Action(); } diff --git a/packages/yoroi-extension/app/api/localStorage/index.js b/packages/yoroi-extension/app/api/localStorage/index.js index cd1f1170ed..d41f524ab4 100644 --- a/packages/yoroi-extension/app/api/localStorage/index.js +++ b/packages/yoroi-extension/app/api/localStorage/index.js @@ -30,6 +30,7 @@ const storageKeys = { COIN_PRICE_PUB_KEY_DATA: networkForLocalStorage + '-COIN-PRICE-PUB-KEY-DATA', EXTERNAL_STORAGE: networkForLocalStorage + '-EXTERNAL-STORAGE', TOGGLE_SIDEBAR: networkForLocalStorage + '-TOGGLE-SIDEBAR', + SORTED_WALLETS: networkForLocalStorage + '-SORTED-WALLET', // ========== CONNECTOR ========== // ERGO_CONNECTOR_WHITELIST: 'connector_whitelist', }; @@ -277,6 +278,17 @@ export default class LocalStorageApi { } } + + // ========== Sort wallets - Revamp ========== // + getSortedWallets: void => Promise> = async () => { + const result = await getLocalItem(storageKeys.SORTED_WALLETS); + if (result === undefined || result === null) return undefined; + return JSON.parse(result); + }; + + setSortedWallets: (Array) => Promise = value => + setLocalItem(storageKeys.SORTED_WALLETS, JSON.stringify(value ?? [])); + async reset(): Promise { await this.unsetUserLocale(); await this.unsetTermsOfUseAcceptance(); diff --git a/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/drag.inline.svg b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/drag.inline.svg new file mode 100644 index 0000000000..87945494eb --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/drag.inline.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/star.inline.svg b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/star.inline.svg new file mode 100644 index 0000000000..56462429f6 --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/star.inline.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/stared.inline.svg b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/stared.inline.svg new file mode 100644 index 0000000000..43a43becfb --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/add-wallet/wallet-list/stared.inline.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.js b/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.js index 9bed8fd10d..def61e9f72 100644 --- a/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.js +++ b/packages/yoroi-extension/app/components/topbar/NavWalletDetailsRevamp.js @@ -6,12 +6,10 @@ import classnames from 'classnames'; import { intlShape } from 'react-intl'; import { splitAmount, truncateToken } from '../../utils/formatters'; -// import globalMessages from '../../i18n/global-messages'; import styles from './NavWalletDetailsRevamp.scss'; import IconEyeOpen from '../../assets/images/my-wallets/icon_eye_open.inline.svg'; import IconEyeClosed from '../../assets/images/my-wallets/icon_eye_closed.inline.svg'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; -// import WalletCurrency from '../wallet/my-wallets/WalletCurrency'; import { hiddenAmount } from '../../utils/strings'; import { MultiToken } from '../../api/common/lib/MultiToken'; import type { TokenLookupKey } from '../../api/common/lib/MultiToken'; @@ -111,14 +109,12 @@ export default class NavWalletDetailsRevamp extends Component { })}
-

- {/* TODO: fix value to USD */} - {this.renderAmountDisplay({ - shouldHideBalance, - amount: totalAmount, - })}{' '} - USD -

+ {/* TODO: fix value to USD */} + {this.renderAmountDisplay({ + shouldHideBalance, + amount: totalAmount, + })}{' '} + USD
{totalAmount != null && showEyeIconSafe && ( diff --git a/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.js b/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.js index 9213f22b88..53e967cfb4 100644 --- a/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.js +++ b/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.js @@ -5,6 +5,7 @@ import { observer } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import type { $npm$ReactIntl$IntlFormat } from 'react-intl'; import styles from './NoWalletsAccessList.scss'; +import StarIcon from '../../assets/images/add-wallet/wallet-list/stared.inline.svg'; const messages = defineMessages({ quickAccess: { @@ -32,11 +33,10 @@ export default class NoWalletsAccessList extends Component { render(): Node { const { intl } = this.context; - // ; - return (
+

{intl.formatMessage(messages.quickAccess)}

diff --git a/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.scss b/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.scss index 2637cc2ec4..dc338b5c95 100644 --- a/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.scss +++ b/packages/yoroi-extension/app/components/topbar/NoWalletsAccessList.scss @@ -5,11 +5,16 @@ display: flex; flex-direction: column; justify-content: center; - padding: 40px; + padding: 40px 36px; text-align: center; font-family: var(--font-regular); } .header { + display: flex; + align-items: center; + svg { + margin-right: 8px; + } h3 { font-size: 24px; color: var(--theme-wallet-dropdown-main-text-color); diff --git a/packages/yoroi-extension/app/components/topbar/WalletCard.js b/packages/yoroi-extension/app/components/topbar/WalletCard.js index 6cff728bc9..54efbd7ef4 100644 --- a/packages/yoroi-extension/app/components/topbar/WalletCard.js +++ b/packages/yoroi-extension/app/components/topbar/WalletCard.js @@ -25,7 +25,9 @@ import { getTokenName } from '../../stores/stateless/tokenHelpers'; import { hiddenAmount } from '../../utils/strings'; import type { TokenLookupKey } from '../../api/common/lib/MultiToken'; import type { TokenRow } from '../../api/ada/lib/storage/database/primitives/tables'; -import RandomIcon from '../../assets/images/sidebar/revamp/wallet.inline.svg'; +import DragIcon from '../../assets/images/add-wallet/wallet-list/drag.inline.svg'; +import StarIcon from '../../assets/images/add-wallet/wallet-list/star.inline.svg'; +import { Draggable } from 'react-beautiful-dnd'; const messages = defineMessages({ tokenTypes: { @@ -62,6 +64,8 @@ type Props = {| +getTokenInfo: ($ReadOnly>) => $ReadOnly, +isCurrentWallet?: boolean, +onSelect?: void => void, + +walletId: string, + +idx: number, |}; type State = {| +isActionsShow: boolean |}; @@ -140,7 +144,7 @@ export default class WalletCard extends Component { render(): Node { const { intl } = this.context; - const { shouldHideBalance } = this.props; + const { shouldHideBalance, walletId, idx } = this.props; const { isActionsShow } = this.state; const [, iconComponent] = this.props.plate @@ -153,70 +157,75 @@ export default class WalletCard extends Component { .join(' - '); const totalAmount = this.getTotalAmount(); - const wrapperClassname = classnames( - styles.cardWrapper, - this.props.isCurrentWallet !== null && - this.props.isCurrentWallet === true && - styles.currentCardWrapper - ); - return ( - +
+
+ +
- - ) : null} -
- +
+
+ )} + ); } diff --git a/packages/yoroi-extension/app/components/topbar/WalletCard.scss b/packages/yoroi-extension/app/components/topbar/WalletCard.scss index 9e59b83721..29b693bf40 100644 --- a/packages/yoroi-extension/app/components/topbar/WalletCard.scss +++ b/packages/yoroi-extension/app/components/topbar/WalletCard.scss @@ -79,21 +79,28 @@ } .actions { min-width: 80px; + opacity: 0; + transition: opacity 0.3s; svg { max-width: 24px; max-height: 24px; color: #6b7384; } - button { + & > * { width: 40px; height: 40px; border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; &:hover { background: #eaedf2; } } } - +.showActions { + opacity: 1; +} .cardWrapper { padding: 16px; display: flex; @@ -113,6 +120,10 @@ } } +.isDragging { + border: 1px solid #eaedf2; +} + .currentCardWrapper { border: 1px solid #3154cb; diff --git a/packages/yoroi-extension/app/components/topbar/WalletListDialog.js b/packages/yoroi-extension/app/components/topbar/WalletListDialog.js index 13b65d5bd8..5a889e3211 100644 --- a/packages/yoroi-extension/app/components/topbar/WalletListDialog.js +++ b/packages/yoroi-extension/app/components/topbar/WalletListDialog.js @@ -16,6 +16,8 @@ import { hiddenAmount } from '../../utils/strings'; import type { TokenLookupKey } from '../../api/common/lib/MultiToken'; import type { TokenRow } from '../../api/ada/lib/storage/database/primitives/tables'; import { MultiToken } from '../../api/common/lib/MultiToken'; +import WalletCard from './WalletCard'; +import { DragDropContext, Droppable } from 'react-beautiful-dnd'; const messages = defineMessages({ allWalletsLabel: { @@ -33,21 +35,62 @@ const messages = defineMessages({ }); type Props = {| - +walletsComponent: Node, +close: void => void, - +walletsCount: number, +shouldHideBalance: boolean, +onUpdateHideBalance: void => Promise, +getTokenInfo: ($ReadOnly>) => $ReadOnly, +walletAmount: MultiToken | null, +onAddWallet: void => void, + +wallets: Array, + +currentSortedWallets: Array | void, + +updateSortedWalletList: ({| sortedWallets: Array |}) => Promise, +|}; +type State = {| + walletListIdx: Array, |}; +const reorder = (list, startIndex, endIndex) => { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + return result; +}; @observer -export default class WalletListDialog extends Component { +export default class WalletListDialog extends Component { static contextTypes: {| intl: $npm$ReactIntl$IntlFormat |} = { intl: intlShape.isRequired, }; + state: State = { + walletListIdx: [], + }; + + async componentDidMount(): Promise { + const sortedWalletListIdx = this.props.currentSortedWallets; + const currentWalletIdx = this.props.wallets.map(wallet => wallet.walletId); + + let generatedWalletIds; + if (sortedWalletListIdx !== undefined && sortedWalletListIdx.length > 0) { + const newWalletIds = currentWalletIdx.filter(id => { + const index = sortedWalletListIdx.indexOf(id); + if (index === -1) { + return true; + } + return false; + }); + generatedWalletIds = [...sortedWalletListIdx, ...newWalletIds]; + } else { + generatedWalletIds = currentWalletIdx; + } + + this.setState( + { + walletListIdx: generatedWalletIds, + }, + async () => { + await this.props.updateSortedWalletList({ sortedWallets: generatedWalletIds }); + } + ); + } renderAmountDisplay: ({| shouldHideBalance: boolean, @@ -84,21 +127,46 @@ export default class WalletListDialog extends Component { ); }; + + onDragEnd: Object => any = async result => { + const { destination, source } = result; + if (!destination || destination.index === source.index) { + return; + } + + this.setState( + prev => { + const walletListIdx = reorder( + prev.walletListIdx, + result.source.index, + result.destination.index + ); + return { + walletListIdx, + }; + }, + async function () { + await this.props.updateSortedWalletList({ sortedWallets: this.state.walletListIdx }); + } + ); + }; + render(): Node { const { intl } = this.context; + const { walletListIdx } = this.state; + const { - walletsCount, shouldHideBalance, onAddWallet, walletAmount, onUpdateHideBalance, - walletsComponent, + wallets, } = this.props; return ( } onClose={this.props.close} @@ -120,7 +188,20 @@ export default class WalletListDialog extends Component { -
{walletsComponent}
+ + + {provided => ( +
+ {walletListIdx.length > 0 && + walletListIdx.map((walletId, idx) => { + const wallet = this.props.wallets.find(w => w.walletId === walletId); + return ; + })} + {provided.placeholder} +
+ )} +
+