diff --git a/packages/yoroi-extension/app/assets/images/revamp/tx-submitted.inline.svg b/packages/yoroi-extension/app/assets/images/revamp/tx-submitted.inline.svg new file mode 100644 index 0000000000..f53cfa9eec --- /dev/null +++ b/packages/yoroi-extension/app/assets/images/revamp/tx-submitted.inline.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/yoroi-extension/app/components/common/assets/AssetPair.js b/packages/yoroi-extension/app/components/common/assets/AssetPair.js index 88335642b3..5a9b29491d 100644 --- a/packages/yoroi-extension/app/components/common/assets/AssetPair.js +++ b/packages/yoroi-extension/app/components/common/assets/AssetPair.js @@ -1,9 +1,9 @@ //@flow import { Box } from '@mui/material'; -import type { AssetAmount } from '../../swap/types'; import adaTokenImage from '../../../assets/images/ada.inline.svg'; -import { urlResolveForIpfsAndCorsproxy } from '../../../coreUtils'; import defaultTokenImage from '../../../assets/images/revamp/token-default.inline.svg'; +import { urlResolveForIpfsAndCorsproxy } from '../../../coreUtils'; +import type { AssetAmount } from '../../swap/types'; import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types'; type Props = {| @@ -14,8 +14,9 @@ type Props = {| |}; function tokenImgSrc(token, defaultTokenInfo): string { - return token.ticker === defaultTokenInfo.ticker ? adaTokenImage - : (urlResolveForIpfsAndCorsproxy(token.image) ?? defaultTokenImage); + return token.ticker === defaultTokenInfo.ticker + ? adaTokenImage + : urlResolveForIpfsAndCorsproxy(token.image) ?? defaultTokenImage; } function tokenImg(token, defaultTokenInfo): React$Node { @@ -23,7 +24,11 @@ function tokenImg(token, defaultTokenInfo): React$Node { svg': { width: '100%', height: '100%' } }} + sx={{ + overflowY: 'hidden', + '& > svg': { width: '100%', height: '100%' }, + borderRadius: '4px', + }} > - ) + ); } export default function AssetPair({ from, to, defaultTokenInfo, sx = {} }: Props): React$Node { diff --git a/packages/yoroi-extension/app/components/swap/PriceImpact.js b/packages/yoroi-extension/app/components/swap/PriceImpact.js index c3d0ffcb98..fd1dd97060 100644 --- a/packages/yoroi-extension/app/components/swap/PriceImpact.js +++ b/packages/yoroi-extension/app/components/swap/PriceImpact.js @@ -1,15 +1,15 @@ // @flow -import type { Node } from 'react'; import { Box, Button, Typography } from '@mui/material'; -import Dialog from '../widgets/Dialog'; +import { useSwap } from '@yoroi/swap'; +import type { Node } from 'react'; import { ReactComponent as ErrorTriangleIcon } from '../../assets/images/revamp/error.triangle.svg'; import { ReactComponent as ExclamationCircleIcon } from '../../assets/images/revamp/exclamation.circle.svg'; -import type { PriceImpact } from './types'; -import { useSwap } from '@yoroi/swap'; -import Percent from '../common/Percent'; +import { useSwapForm } from '../../containers/swap/context/swap-form'; import { Quantities } from '../../utils/quantities'; +import Percent from '../common/Percent'; +import Dialog from '../widgets/Dialog'; import { PRICE_PRECISION } from './common'; -import { useSwapForm } from '../../containers/swap/context/swap-form'; +import type { PriceImpact } from './types'; function colorsBySeverity(isSevere: boolean) { return isSevere ? { fg: '#FF1351', bg: '#FFF1F5' } : { fg: '#ED8600', bg: '#FDF7E2' }; @@ -38,7 +38,7 @@ export function PriceImpactIcon({ small?: boolean, |}): Node { const sz = `${small ? 16 : 24}px`; - const marginTop = `${small ? -2 : 0}px`; + const marginTop = `${small ? -1 : 0}px`; const marginRight = `6px`; const svgProp = small ? { @@ -52,6 +52,7 @@ export function PriceImpactIcon({ height: sz, marginTop, marginRight, + marginLeft: '-3px', }} > {isSevere ? : } diff --git a/packages/yoroi-extension/app/components/swap/SelectAssetDialog.js b/packages/yoroi-extension/app/components/swap/SelectAssetDialog.js index cdd531fc4f..bd1ca3b39d 100644 --- a/packages/yoroi-extension/app/components/swap/SelectAssetDialog.js +++ b/packages/yoroi-extension/app/components/swap/SelectAssetDialog.js @@ -1,20 +1,20 @@ // @flow -import type { AssetAmount, PriceImpact } from './types'; -import { useEffect, useState } from 'react'; import { Box, Typography } from '@mui/material'; -import { ReactComponent as NoAssetsFound } from '../../assets/images/revamp/no-assets-found.inline.svg'; +import { useEffect, useState } from 'react'; +import type { RemoteTokenInfo } from '../../api/ada/lib/state-fetch/types'; +import adaTokenImage from '../../assets/images/ada.inline.svg'; +import defaultTokenImage from '../../assets/images/revamp/asset-default.inline.svg'; +import { ReactComponent as ArrowBottomIcon } from '../../assets/images/revamp/icons/arrow-bottom.inline.svg'; +import { ReactComponent as ArrowTopIcon } from '../../assets/images/revamp/icons/arrow-top.inline.svg'; import { ReactComponent as SearchIcon } from '../../assets/images/revamp/icons/search.inline.svg'; import { ReactComponent as WalletIcon } from '../../assets/images/revamp/icons/wallet.inline.svg'; -import { ReactComponent as ArrowTopIcon } from '../../assets/images/revamp/icons/arrow-top.inline.svg'; -import { ReactComponent as ArrowBottomIcon } from '../../assets/images/revamp/icons/arrow-bottom.inline.svg'; +import { ReactComponent as NoAssetsFound } from '../../assets/images/revamp/no-assets-found.inline.svg'; import { truncateAddressShort } from '../../utils/formatters'; -import adaTokenImage from '../../assets/images/ada.inline.svg'; -import defaultTokenImage from '../../assets/images/revamp/asset-default.inline.svg'; -import Dialog from '../widgets/Dialog'; import Table from '../common/table/Table'; -import type { RemoteTokenInfo } from '../../api/ada/lib/state-fetch/types'; -import { PriceImpactColored, PriceImpactIcon } from './PriceImpact'; +import Dialog from '../widgets/Dialog'; import { InfoTooltip } from '../widgets/InfoTooltip'; +import { PriceImpactColored, PriceImpactIcon } from './PriceImpact'; +import type { AssetAmount, PriceImpact } from './types'; const fromTemplateColumns = '1fr minmax(auto, 136px)'; const toTemplateColumns = '1fr minmax(auto, 152px) minmax(auto, 136px)'; @@ -27,7 +27,7 @@ type Props = {| onAssetSelected: any => void, onClose: void => void, defaultTokenInfo: RemoteTokenInfo, - getTokenInfoBatch: Array => { [string]: Promise }, + getTokenInfoBatch: (Array) => { [string]: Promise }, |}; export default function SelectAssetDialog({ @@ -54,8 +54,9 @@ export default function SelectAssetDialog({ .includes(searchTerm.toLowerCase()); }) || []; - const metadataPromiseMap: { [string]: Promise } = - getTokenInfoBatch(filteredAssets.map(a => a.id)) + const metadataPromiseMap: { [string]: Promise } = getTokenInfoBatch( + filteredAssets.map(a => a.id) + ); return ( - + {filteredAssets.length} assets {searchTerm ? 'found' : 'available'} @@ -184,7 +185,6 @@ export const AssetAndAmountRow = ({ displayAmount?: ?string, priceImpactState?: ?PriceImpact, |}): React$Node => { - const [remoteTokenLogo, setRemoteTokenLogo] = useState(null); const isFrom = type === 'from'; @@ -196,21 +196,21 @@ export const AssetAndAmountRow = ({ useEffect(() => { if (id != null) { - getTokenInfo(id).then(tokenInfo => { - if (tokenInfo.logo != null) { - setRemoteTokenLogo(`data:image/png;base64,${tokenInfo.logo}`); - } - return null; - }).catch(e => { - console.warn('Failed to resolve remote info for token: ' + id, e); - }); + getTokenInfo(id) + .then(tokenInfo => { + if (tokenInfo.logo != null) { + setRemoteTokenLogo(`data:image/png;base64,${tokenInfo.logo}`); + } + return null; + }) + .catch(e => { + console.warn('Failed to resolve remote info for token: ' + id, e); + }); } - }, [id]) + }, [id]); const imgSrc = - ticker === defaultTokenInfo.ticker - ? adaTokenImage - : remoteTokenLogo ?? defaultTokenImage; + ticker === defaultTokenInfo.ticker ? adaTokenImage : remoteTokenLogo ?? defaultTokenImage; const amount = displayAmount ?? assetAmount; diff --git a/packages/yoroi-extension/app/components/swap/SwapInput.js b/packages/yoroi-extension/app/components/swap/SwapInput.js index ae433227df..381f0848b2 100644 --- a/packages/yoroi-extension/app/components/swap/SwapInput.js +++ b/packages/yoroi-extension/app/components/swap/SwapInput.js @@ -1,13 +1,13 @@ // @flow -import type { Node } from 'react'; -import type { AssetAmount } from './types'; import { Box, Typography } from '@mui/material'; -import { ReactComponent as ChevronDownIcon } from '../../assets/images/revamp/icons/chevron-down.inline.svg'; +import type { Node } from 'react'; +import { useEffect, useState } from 'react'; import adaTokenImage from '../../assets/images/ada.inline.svg'; +import { ReactComponent as ChevronDownIcon } from '../../assets/images/revamp/icons/chevron-down.inline.svg'; import defaultTokenImage from '../../assets/images/revamp/token-default.inline.svg'; +import type { AssetAmount } from './types'; import type { RemoteTokenInfo } from '../../api/ada/lib/state-fetch/types'; import type { State } from '../../containers/swap/context/swap-form/types'; -import { useEffect, useState } from 'react'; type Props = {| label: string, @@ -63,9 +63,7 @@ export default function SwapInput({ }, [id]); const imgSrc = - ticker === defaultTokenInfo.ticker - ? adaTokenImage - : remoteTokenLogo ?? defaultTokenImage; + ticker === defaultTokenInfo.ticker ? adaTokenImage : remoteTokenLogo ?? defaultTokenImage; return ( @@ -128,7 +126,11 @@ export default function SwapInput({ svg': { width: '100%', height: '100%' } }} + sx={{ + overflowY: 'hidden', + '& > svg': { width: '100%', height: '100%' }, + borderRadius: '4px', + }} > ( [`& .${tooltipClasses.tooltip}`]: { backgroundColor: theme.palette.grayscale[900], opacity: 0.8, - lineHeight: 22, + lineHeight: 18, fontSize: 14, maxWidth: width, }, @@ -24,13 +24,12 @@ type Props = {| |}; export const InfoTooltip = ({ content, width, children }: Props): React$Node => { - const contentNode = typeof content === 'string' ? ( - {content} - ) : content; + const contentNode = + typeof content === 'string' ? {content} : content; return ( - - {children ?? ()} + + {children ?? } ); diff --git a/packages/yoroi-extension/app/containers/swap/asset-swap/ConfirmSwapTransaction.js b/packages/yoroi-extension/app/containers/swap/asset-swap/ConfirmSwapTransaction.js index 69e68cde9c..65e203a1fd 100644 --- a/packages/yoroi-extension/app/containers/swap/asset-swap/ConfirmSwapTransaction.js +++ b/packages/yoroi-extension/app/containers/swap/asset-swap/ConfirmSwapTransaction.js @@ -1,27 +1,27 @@ //@flow import { Box, Typography } from '@mui/material'; -import TextField from '../../../components/common/TextField'; -import { useSwapForm } from '../context/swap-form'; -import { AssetAndAmountRow } from '../../../components/swap/SelectAssetDialog'; import { makeLimitOrder, makePossibleMarketOrder, useSwap, useSwapCreateOrder } from '@yoroi/swap'; -import { SwapPoolLabel } from '../../../components/swap/SwapPoolComponents'; -import SwapPoolFullInfo from './edit-pool/PoolFullInfo'; -import { useSwapFeeDisplay } from '../hooks'; -import type { PriceImpact } from '../../../components/swap/types'; -import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types'; +import { useEffect } from 'react'; +import { IncorrectWalletPasswordError } from '../../../api/common/errors'; +import TextField from '../../../components/common/TextField'; import { FormattedActualPrice, - FormattedMarketPrice, FormattedLimitPrice, + FormattedMarketPrice, PriceImpactBanner, PriceImpactColored, PriceImpactIcon, PriceImpactPercent, } from '../../../components/swap/PriceImpact'; -import type { State } from '../context/swap-form/types'; -import { useEffect } from 'react'; -import { IncorrectWalletPasswordError } from '../../../api/common/errors'; +import { AssetAndAmountRow } from '../../../components/swap/SelectAssetDialog'; +import { SwapPoolLabel } from '../../../components/swap/SwapPoolComponents'; import { InfoTooltip } from '../../../components/widgets/InfoTooltip'; +import { useSwapForm } from '../context/swap-form'; +import { useSwapFeeDisplay } from '../hooks'; +import SwapPoolFullInfo from './edit-pool/PoolFullInfo'; +import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types'; +import type { PriceImpact } from '../../../components/swap/types'; +import type { State } from '../context/swap-form/types'; type Props = {| slippageValue: string, @@ -226,7 +226,7 @@ const SummaryRow = ({ col1, children, withInfo = false, infoText = '' }) => ( {col1} {withInfo ? ( - + {infoText}} /> ) : null} diff --git a/packages/yoroi-extension/app/containers/swap/asset-swap/TxSubmittedStep.js b/packages/yoroi-extension/app/containers/swap/asset-swap/TxSubmittedStep.js index 306f9457e7..e0d6aa724b 100644 --- a/packages/yoroi-extension/app/containers/swap/asset-swap/TxSubmittedStep.js +++ b/packages/yoroi-extension/app/containers/swap/asset-swap/TxSubmittedStep.js @@ -1,7 +1,7 @@ //@flow import { Box, Button, Typography } from '@mui/material'; -import { ReactComponent as TxSuccessfulImage } from '../../../assets/images/revamp/tx-successful.inline.svg'; import { ReactComponent as TxFailureImage } from '../../../assets/images/revamp/tx-failure.inline.svg'; +import { ReactComponent as TxSuccessfulImage } from '../../../assets/images/revamp/tx-submitted.inline.svg'; import type { State } from '../context/swap-form/types'; type Props = {| @@ -22,9 +22,9 @@ export default function TxSubmittedStep({ flexDirection="column" gap="16px" alignItems="center" - width="400px" + width="404px" mx="auto" - mt="80px" + mt="131px" > {isSuccessful ? : } @@ -33,13 +33,13 @@ export default function TxSubmittedStep({ {isSuccessful - ? 'Your transactions will be displayed both in the list of transaction and Open swap orders' + ? 'Check this transaction in the list of wallet transactions' : 'Your transaction has not been processed properly due to technical issues'} {!isSuccessful && ( diff --git a/packages/yoroi-extension/app/containers/swap/asset-swap/edit-pool/EditPool.js b/packages/yoroi-extension/app/containers/swap/asset-swap/edit-pool/EditPool.js index 430964ad2e..8d16049f17 100644 --- a/packages/yoroi-extension/app/containers/swap/asset-swap/edit-pool/EditPool.js +++ b/packages/yoroi-extension/app/containers/swap/asset-swap/edit-pool/EditPool.js @@ -1,15 +1,15 @@ // @flow -import { useState } from 'react'; import { Box, Typography } from '@mui/material'; -import { ReactComponent as EditIcon } from '../../../../assets/images/revamp/icons/edit.inline.svg'; -import { ReactComponent as ChevronDownIcon } from '../../../../assets/images/revamp/icons/chevron-down.inline.svg'; import { useSwap } from '@yoroi/swap'; import { capitalize } from 'lodash'; +import { useState } from 'react'; +import { ReactComponent as ChevronDownIcon } from '../../../../assets/images/revamp/icons/chevron-down.inline.svg'; +import { ReactComponent as EditIcon } from '../../../../assets/images/revamp/icons/edit.inline.svg'; import { SwapPoolIcon } from '../../../../components/swap/SwapPoolComponents'; -import SwapPoolFullInfo from './PoolFullInfo'; -import { useSwapForm } from '../../context/swap-form'; import { maybe } from '../../../../coreUtils'; +import { useSwapForm } from '../../context/swap-form'; import { useSwapFeeDisplay } from '../../hooks'; +import SwapPoolFullInfo from './PoolFullInfo'; import type { RemoteTokenInfo } from '../../../../api/ada/lib/state-fetch/types'; type Props = {| @@ -90,6 +90,8 @@ export default function EditSwapPool({ handleEditPool, defaultTokenInfo }: Props display: 'flex', alignItems: 'center', justifyContent: 'space-between', + marginBottom: showFullInfo && '8px', + cursor: 'pointer', }} onClick={handleShowFullInfo} > diff --git a/packages/yoroi-extension/app/containers/swap/orders/OrdersPage.js b/packages/yoroi-extension/app/containers/swap/orders/OrdersPage.js index 7b5db97f39..4398d29670 100644 --- a/packages/yoroi-extension/app/containers/swap/orders/OrdersPage.js +++ b/packages/yoroi-extension/app/containers/swap/orders/OrdersPage.js @@ -1,29 +1,32 @@ // @flow +import { Box, Button } from '@mui/material'; +import { useSwap } from '@yoroi/swap'; +import moment from 'moment'; import type { Node } from 'react'; import { useState } from 'react'; -import { Box, Button } from '@mui/material'; -import Table from '../../../components/common/table/Table'; -import CancelSwapOrderDialog from '../../../components/swap/CancelOrderDialog'; +import { addressBech32ToHex } from '../../../api/ada/lib/cardanoCrypto/utils'; +import { signTransactionHex } from '../../../api/ada/transactions/signTransactionHex'; +import { + getTransactionFeeFromCbor, + getTransactionTotalOutputFromCbor, +} from '../../../api/ada/transactions/utils'; import AssetPair from '../../../components/common/assets/AssetPair'; +import Table from '../../../components/common/table/Table'; import Tabs from '../../../components/common/tabs/Tabs'; -import type { MappedOrder } from './hooks'; -import { useRichOrders } from './hooks'; -import type { StoresAndActionsProps } from '../../../types/injectedProps.types'; +import CancelSwapOrderDialog from '../../../components/swap/CancelOrderDialog'; import { SwapPoolLabel } from '../../../components/swap/SwapPoolComponents'; -import ExplorableHashContainer from '../../widgets/ExplorableHashContainer'; -import { truncateAddressShort } from '../../../utils/formatters'; -import { Quantities } from '../../../utils/quantities'; +import type { CardanoConnectorSignRequest } from '../../../connector/types'; import { fail, forceNonNull, maybe } from '../../../coreUtils'; -import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types'; -import { useSwap } from '@yoroi/swap'; -import { addressBech32ToHex } from '../../../api/ada/lib/cardanoCrypto/utils'; -import { getTransactionFeeFromCbor, getTransactionTotalOutputFromCbor, } from '../../../api/ada/transactions/utils'; import { SelectedExplorer } from '../../../domain/SelectedExplorer'; -import type { CardanoConnectorSignRequest } from '../../../connector/types'; import { genLookupOrFail } from '../../../stores/stateless/tokenHelpers'; -import moment from 'moment'; -import { signTransactionHex } from '../../../api/ada/transactions/signTransactionHex'; +import type { StoresAndActionsProps } from '../../../types/injectedProps.types'; +import { truncateAddressShort } from '../../../utils/formatters'; +import { Quantities } from '../../../utils/quantities'; +import ExplorableHashContainer from '../../widgets/ExplorableHashContainer'; +import { useRichOrders } from './hooks'; import { createFormattedTokenValues } from './util'; +import type { RemoteTokenInfo } from '../../../api/ada/lib/state-fetch/types'; +import type { MappedOrder } from './hooks'; import type { FormattedTokenValue } from './util'; type ColumnContext = {| @@ -83,9 +86,7 @@ const orderColumns: Array = [ ]; export default function SwapOrdersPage(props: StoresAndActionsProps): Node { - const { - order: orderApi, - } = useSwap(); + const { order: orderApi } = useSwap(); const [showCompletedOrders, setShowCompletedOrders] = useState(false); const [cancellationState, setCancellationState] = useState(null); - const { wallets, tokenInfoStore, explorers, substores: { ada: { swapStore } } } = props.stores; + const { + wallets, + tokenInfoStore, + explorers, + substores: { + ada: { swapStore }, + }, + } = props.stores; const wallet = wallets.selectedOrFail; const network = wallet.getParent().getNetworkInfo(); const walletVariant = wallet.getParent().getWalletVariant(); - const defaultTokenInfo = tokenInfoStore.getDefaultTokenInfoSummary( - network.NetworkId - ); + const defaultTokenInfo = tokenInfoStore.getDefaultTokenInfoSummary(network.NetworkId); const selectedExplorer = - explorers.selectedExplorer.get(network.NetworkId) ?? - fail('No explorer for wallet network'); + explorers.selectedExplorer.get(network.NetworkId) ?? fail('No explorer for wallet network'); - const fetchTransactionTimestamps = txHashes => swapStore.fetchTransactionTimestamps({ wallet, txHashes }); - let { openOrders, completedOrders, transactionTimestamps } = useRichOrders(defaultTokenInfo, fetchTransactionTimestamps); + const fetchTransactionTimestamps = txHashes => + swapStore.fetchTransactionTimestamps({ wallet, txHashes }); + let { openOrders, completedOrders, transactionTimestamps } = useRichOrders( + defaultTokenInfo, + fetchTransactionTimestamps + ); const txHashToRenderedTimestamp: string => string = txHash => { const date = transactionTimestamps[txHash]; @@ -293,6 +302,7 @@ export default function SwapOrdersPage(props: StoresAndActionsProps): Node { columnLeftPaddings={columnLeftPaddings} gridTemplateColumns={gridTemplateColumns} columnGap="0px" + columnRightPaddings={['0px', '0px', '0px', '0px', '0px', '0px', '0px']} > {showCompletedOrders ? completedOrders.map(order => ( diff --git a/packages/yoroi-extension/package-lock.json b/packages/yoroi-extension/package-lock.json index d92c6dc348..e8b258ede1 100644 --- a/packages/yoroi-extension/package-lock.json +++ b/packages/yoroi-extension/package-lock.json @@ -1,12 +1,12 @@ { "name": "yoroi", - "version": "5.2.100", + "version": "5.2.101", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "yoroi", - "version": "5.2.100", + "version": "5.2.101", "license": "MIT", "dependencies": { "@amplitude/analytics-browser": "^2.1.3", diff --git a/packages/yoroi-extension/package.json b/packages/yoroi-extension/package.json index a9550b6318..a183f23ccd 100644 --- a/packages/yoroi-extension/package.json +++ b/packages/yoroi-extension/package.json @@ -1,6 +1,6 @@ { "name": "yoroi", - "version": "5.2.100", + "version": "5.2.101", "description": "Cardano ADA wallet", "scripts": { "dev-mv2": "rimraf dev/ && NODE_OPTIONS=--openssl-legacy-provider babel-node scripts-mv2/build --type=debug --env 'mainnet'",