Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions widget/embedded/src/components/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useSyncUrlAndStore } from '../hooks/useSyncUrlAndStore';
import { AddCustomTokenPage } from '../pages/AddCustomTokenPage';
import { ConfirmSwapPage } from '../pages/ConfirmSwapPage';
import { CustomTokensPage } from '../pages/CustomTokensPage';
import { DestinationWalletsPage } from '../pages/DestinationWalletPage/DestinationWalletPage';
import { HistoryPage } from '../pages/HistoryPage';
import { Home } from '../pages/Home';
import { LanguagePage } from '../pages/LanguagePage';
Expand Down Expand Up @@ -42,6 +43,10 @@ export function AppRoutes() {
path: navigationRoutes.sourceWallet,
element: <SourceWalletPage />,
},
{
path: navigationRoutes.destinationWallet,
element: <DestinationWalletsPage />,
},
{
path: navigationRoutes.fromSwap,
children: [
Expand Down
14 changes: 12 additions & 2 deletions widget/embedded/src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ function Layout(props: PropsWithChildren<PropTypes>) {
const navigateBack = useNavigateBack();
const { manager } = useManager();
const { isTablet, isMobile } = useScreenDetect();
const navigateBackSettingsRef = useRef<{
defaultPrevented: boolean;
}>({ defaultPrevented: false });
const pendingSwaps: PendingSwap[] = getPendingSwaps(manager).map(
({ swap }) => swap
);
Expand Down Expand Up @@ -176,9 +179,16 @@ function Layout(props: PropsWithChildren<PropTypes>) {
showBackButton ? (
<BackButton
onClick={() => {
navigateBack();
// As an example, used in routes page to add a custom logic when navigating back to the home page.
header.onBack?.();
header.onBack?.({
preventDefault: () =>
(navigateBackSettingsRef.current = {
defaultPrevented: true,
}),
});
if (!navigateBackSettingsRef.current.defaultPrevented) {
navigateBack();
}
}}
/>
) : null
Expand Down
2 changes: 1 addition & 1 deletion widget/embedded/src/components/Layout/Layout.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface PropTypes {
suffix?: React.ReactNode;
hasBackButton?: boolean;
onCancel?: () => void;
onBack?: () => void;
onBack?: (event: { preventDefault: () => void }) => void;
};
footer?: React.ReactNode;
height?: ContainerHeightProp;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { styled } from '@rango-dev/ui';

export const Container = styled('div', {
padding: '$20',
});

export const Description = styled('div', {
paddingBottom: '$15',
textAlign: 'center',
});

export const ListContainer = styled('div', {
display: 'flex',
justifyContent: 'space-evenly',
alignItems: 'center',
columnGap: '$5',
rowGap: '$10',
flexWrap: 'wrap',
height: '100%',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { PropTypes } from './MoreWalletsToSelect.types';

import { i18n } from '@lingui/core';
import { Typography } from '@rango-dev/ui';
import React from 'react';

import { WalletList } from '../ConfirmWalletsModal/WalletList';
import { Layout } from '../Layout';

import {
Container,
Description,
ListContainer,
} from './MoreWalletsToSelect.styles';

export function MoreWalletsToSelect(props: PropTypes) {
const { blockchain, isSelected, selectWallet, onClickBack } = props;
return (
<Layout
header={{
title: i18n.t('Connect {blockchain} wallet', {
blockchain,
}),
onBack: (event) => {
if (onClickBack) {
event.preventDefault();
onClickBack();
}
},
}}>
<Container>
<Description>
<Typography variant="body" size="small" color="neutral700">
{i18n.t('You need to connect {blockchain} wallet.', {
blockchain,
})}
</Typography>
</Description>
<ListContainer>
<WalletList
chain={blockchain}
isSelected={isSelected}
onShowMore={() => {
//
}}
selectWallet={selectWallet}
/>
</ListContainer>
</Container>
</Layout>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Wallet } from '../../types';

export type PropTypes = {
blockchain: string;
isSelected: (walletType: string, blockchain: string) => boolean;
selectWallet: (wallet: Wallet) => void;
onClickBack?: () => void;
};
1 change: 1 addition & 0 deletions widget/embedded/src/constants/navigationRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export const navigationRoutes = {
fromSwap: 'from-swap',
toSwap: 'to-swap',
sourceWallet: 'source-wallet',
destinationWallet: 'destination-wallet',
blockchains: 'blockchains',
settings: 'settings',
customTokens: 'custom-tokens',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { styled } from '@rango-dev/ui';

export const Container = styled('div', {
position: 'relative',
});

export const DestinationInputStyles = {
container: {
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import type { PropTypes } from './DestinationInput.types';

import { i18n } from '@lingui/core';
import { Divider, SwapInput } from '@rango-dev/ui';
import { useWallets } from '@rango-dev/wallets-react';
import React from 'react';
import { useNavigate } from 'react-router-dom';

import { errorMessages } from '../../../constants/errors';
import { navigationRoutes } from '../../../constants/navigationRoutes';
import {
PERCENTAGE_CHANGE_MAX_DECIMALS,
PERCENTAGE_CHANGE_MIN_DECIMALS,
TOKEN_AMOUNT_MAX_DECIMALS,
TOKEN_AMOUNT_MIN_DECIMALS,
USD_VALUE_MAX_DECIMALS,
USD_VALUE_MIN_DECIMALS,
} from '../../../constants/routing';
import { useAppStore } from '../../../store/AppStore';
import { useQuoteStore } from '../../../store/quote';
import { getContainer } from '../../../utils/common';
import { numberToString } from '../../../utils/numbers';
import { getPriceImpact, getPriceImpactLevel } from '../../../utils/quote';
import { canComputePriceImpact } from '../../../utils/swap';
import {
Container,
DestinationInputStyles,
} from '../DestinationInput/DestinationInput.styles';
import { SwapInputLabel } from '../SwapInputLabel';

export function DestinationInput(props: PropTypes) {
const { fetchingQuote, isExpandable, onClickToken } = props;
const { fetchStatus: fetchingMetaStatus } = useAppStore();
const destinationWallet = useAppStore().selectedWallet('destination');
const {
toToken,
toBlockchain,
inputAmount,
inputUsdValue,
outputAmount,
outputUsdValue,
selectedQuote,
customDestination,
} = useQuoteStore();
const { getWalletInfo } = useWallets();
const navigate = useNavigate();
const priceImpactOutputCanNotBeComputed = !canComputePriceImpact(
selectedQuote,
inputAmount,
outputUsdValue
);

const percentageChange =
!inputUsdValue || !outputUsdValue || !outputUsdValue.gt(0)
? null
: getPriceImpact(inputUsdValue.toString(), outputUsdValue.toString());

const selectedDestinationWallet =
customDestination && toBlockchain
? { address: customDestination, chain: toBlockchain.name }
: destinationWallet;

const relatedWallet = selectedDestinationWallet
? {
...selectedDestinationWallet,
image:
'walletType' in selectedDestinationWallet
? getWalletInfo(selectedDestinationWallet.walletType).img
: undefined,
}
: undefined;

const onClickWallet = () => {
navigate(
toBlockchain
? navigationRoutes.destinationWallet
: `../${navigationRoutes.wallets}`
);
};

return (
<Container>
<SwapInputLabel
label={i18n.t('To')}
onClickWallet={onClickWallet}
relatedWallet={relatedWallet}
/>
<Divider direction="vertical" size={2} />
<SwapInput
mode="To"
id="widget-swap-to-input"
style={
!isExpandable && (!!selectedQuote || fetchingQuote)
? DestinationInputStyles
: undefined
}
fetchingQuote={fetchingQuote}
chain={{
displayName: toBlockchain?.displayName || '',
image: toBlockchain?.logo,
}}
token={{
displayName: toToken?.symbol || '',
image: toToken?.image,
securityWarning: !!toToken?.warning,
}}
percentageChange={numberToString(
getPriceImpact(inputUsdValue, outputUsdValue),
PERCENTAGE_CHANGE_MIN_DECIMALS,
PERCENTAGE_CHANGE_MAX_DECIMALS
)}
warningLevel={getPriceImpactLevel(percentageChange ?? 0)}
price={{
value: numberToString(
outputAmount,
TOKEN_AMOUNT_MIN_DECIMALS,
TOKEN_AMOUNT_MAX_DECIMALS
),
usdValue: priceImpactOutputCanNotBeComputed
? undefined
: numberToString(
outputUsdValue,
USD_VALUE_MIN_DECIMALS,
USD_VALUE_MAX_DECIMALS
),
realValue: outputAmount?.toString(),
realUsdValue: priceImpactOutputCanNotBeComputed
? undefined
: outputUsdValue?.toString(),
error: priceImpactOutputCanNotBeComputed
? errorMessages().unknownPriceError.impactTitle
: undefined,
}}
onClickToken={onClickToken}
disabled={fetchingMetaStatus === 'failed'}
loading={fetchingMetaStatus === 'loading'}
tooltipContainer={getContainer()}
/>
</Container>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export type PropTypes = {
fetchingQuote: boolean;
isExpandable?: boolean;
onClickToken: () => void;
};
7 changes: 0 additions & 7 deletions widget/embedded/src/containers/Inputs/Inputs.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,3 @@ export const Container = styled('div', {
gap: '$5',
alignSelf: 'stretch',
});

export const DestinationInputStyles = {
container: {
borderBottomRightRadius: 0,
borderBottomLeftRadius: 0,
},
};
Loading