Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TW-1579: Market page / Exolix Top-up #1233

Merged
merged 29 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4270b7d
market page / remove withdraw tab
lendihop Nov 28, 2024
665bfee
fix some minor bugs
lendihop Nov 28, 2024
8283415
update icon
lendihop Nov 29, 2024
41f13fb
first step basic layout
lendihop Dec 2, 2024
e388988
order creation step layout
lendihop Dec 3, 2024
483bbe4
fix input button overlapping value
lendihop Dec 3, 2024
36c472a
Merge branch 'refs/heads/development-2' into TW-1579-market-page-exol…
lendihop Dec 6, 2024
69fd738
resolve merge conflicts
lendihop Dec 6, 2024
b90e575
show send/get tokens
lendihop Dec 7, 2024
9c36515
layout effect
lendihop Dec 7, 2024
08726bb
fade transition
lendihop Dec 9, 2024
bc7531f
Merge branch 'refs/heads/development-2' into TW-1579-market-page-exol…
lendihop Dec 9, 2024
d192fa8
some renaming
lendihop Dec 9, 2024
2fcbe08
order creation step
lendihop Dec 11, 2024
e90a922
deposit step layout
lendihop Dec 11, 2024
91a4f35
deposit step finished
lendihop Dec 12, 2024
b6a5a23
status tracking screens
lendihop Dec 13, 2024
08f2031
some fixes
lendihop Dec 13, 2024
5ea93df
move networksMap to backend
lendihop Dec 13, 2024
6649241
applied changes according to review comments
lendihop Dec 17, 2024
8fa29b7
rm unused export
lendihop Dec 17, 2024
fa65c56
fix review comment
lendihop Dec 17, 2024
50348e3
show depositExtraId + some minor fixes
lendihop Dec 20, 2024
852efa9
fix import
lendihop Dec 20, 2024
59584c0
fix typo
lendihop Dec 20, 2024
320488f
apply review changes
lendihop Dec 20, 2024
412d5f2
Merge branch 'refs/heads/development-2' into TW-1579-market-page-exol…
lendihop Dec 30, 2024
7efe4b8
fix after-merge issues
lendihop Dec 30, 2024
9ea7e64
fix import
lendihop Dec 30, 2024
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
11 changes: 6 additions & 5 deletions src/app/a11y/FadeTransition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,20 @@ export const FadeTransition: FC<PropsWithChildren> = ({ children }) => {

const [booted, setBooted] = useState(false);

useLayoutEffect(() => {
setBooted(true);
}, [setBooted]);
useLayoutEffect(() => void setBooted(true), [setBooted]);

return (
<CSSTransition
/**
* CSSTransition works by detecting changes to the "in" prop.
* If the value of "in" changes from false to true, it triggers the "enter" transition.
*/
in={booted}
nodeRef={nodeRef}
timeout={300}
classNames={{
enter: 'opacity-0',
enterActive: 'opacity-100 transition ease-out duration-300',
exit: 'opacity-0 transition ease-in duration-300'
enterActive: 'opacity-100 transition ease-out duration-300'
}}
>
<div ref={nodeRef} className="flex flex-col h-full">
Expand Down
2 changes: 1 addition & 1 deletion src/app/atoms/FormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ export const FormField = forwardRef<FormFieldElement, FormFieldProps>(
FORM_FIELD_CLASS_NAME,
readOnly && '!placeholder-grey-1',
smallPaddings ? 'py-2 pl-2' : 'p-3',
errorCaption ? 'border-error' : warning ? 'border-warning' : 'border-none',
errorCaption ? 'border-error' : warning ? 'border-warning' : 'border-input-low',
className
)}
style={fieldStyle}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const ExchangeCountdown = memo<Props>(({ className }) => {
<Countdown
renderer={props => (
<span className={className}>
{props.minutes}:{props.seconds < 10 ? '0' + props.seconds : props.seconds}
{props.minutes}:{String(props.seconds).padStart(2, '0')}
</span>
)}
date={new Date(exchangeData.createdAt).getTime() + ORDER_EXPIRATION_TIMEOUT}
Expand Down
22 changes: 13 additions & 9 deletions src/app/pages/Market/crypto-exchange/components/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { FC, memo } from 'react';
import React, { FC, memo, useMemo } from 'react';

import clsx from 'clsx';
import { range } from 'lodash';

import { Steps } from '../context';

Expand All @@ -11,21 +12,24 @@ interface Props {
}

export const Stepper = memo<Props>(({ currentStep }) => {
const first: Status = currentStep === 0 ? 'next' : 'active';
const second: Status = currentStep > 1 ? 'active' : currentStep === 1 ? 'next' : 'default';
const third: Status = currentStep > 2 ? 'active' : currentStep === 2 ? 'next' : 'default';

const stepsStatuses = useMemo(
() =>
range(0, 3).map(stepIndex =>
currentStep > stepIndex ? 'active' : currentStep === stepIndex ? 'next' : 'default'
),
[currentStep]
);
return (
<div className="flex flex-row h-2.5 items-center gap-x-1">
<Step status={first} />
<Step status={second} />
<Step status={third} />
{stepsStatuses.map((status, index) => (
<Step key={index} status={status} />
))}
</div>
);
});

interface StepProps {
status?: Status;
status: Status;
}

const bgColorRecord = {
Expand Down
2 changes: 2 additions & 0 deletions src/app/pages/Market/crypto-exchange/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export const EXOLIX_PRIVICY_LINK = 'https://exolix.com/privacy';

export const TEZOS_EXOLIX_NETWORK_CODE = 'XTZ';

export const VALUE_PLACEHOLDER = '---';

export const INITIAL_INPUT_CURRENCY: StoredExolixCurrency = {
code: 'ETH',
name: 'Ethereum',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import React, { memo, useCallback, useMemo } from 'react';

import { Anchor, HashShortView, IconBase } from 'app/atoms';
import { Anchor, HashShortView, IconBase, Money } from 'app/atoms';
import { HashChip } from 'app/atoms/HashChip';
import Money from 'app/atoms/Money';
import { ReactComponent as CopyIcon } from 'app/icons/base/copy.svg';
import { ReactComponent as OutLinkIcon } from 'app/icons/base/outLink.svg';
import { toastSuccess } from 'app/toaster';
import { ExchangeHash } from 'lib/apis/exolix/types';
import { t } from 'lib/i18n';

import { CurrencyIcon } from '../../../components/CurrencyIcon';
import { InfoContainer, InfoRaw } from '../../../components/InfoBlock';
import { VALUE_PLACEHOLDER } from '../../../config';
import { useCryptoExchangeDataState } from '../../../context';

export const CompletedStatusInfoBlocks = memo(() => {
const { exchangeData } = useCryptoExchangeDataState();

const handleCopyTxId = useCallback(() => {
window.navigator.clipboard.writeText(exchangeData!.id);
toastSuccess('Copied');
toastSuccess(t('copiedHash'));
}, [exchangeData]);

const sendTime = useMemo(() => {
Expand Down Expand Up @@ -126,5 +127,5 @@ const TxHash = memo<TxHashProps>(({ exchangeHash }) => {
);
}

return <span className="p-1 text-font-description">---</span>;
return <span className="p-1 text-font-description">{VALUE_PLACEHOLDER}</span>;
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { HashChip } from 'app/atoms/HashChip';
import Money from 'app/atoms/Money';
import { ReactComponent as CopyIcon } from 'app/icons/base/copy.svg';
import { toastSuccess } from 'app/toaster';
import { t } from 'lib/i18n';

import { CurrencyIcon } from '../../../components/CurrencyIcon';
import { InfoContainer, InfoRaw } from '../../../components/InfoBlock';
Expand All @@ -15,7 +16,7 @@ export const InProgressStatusInfoBlocks = memo(() => {

const handleCopyTxId = useCallback(() => {
window.navigator.clipboard.writeText(exchangeData!.id);
toastSuccess('Copied');
toastSuccess(t('copiedHash'));
}, [exchangeData]);

if (!exchangeData) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IconButton } from 'app/atoms/IconButton';
import { ReactComponent as CopyIcon } from 'app/icons/base/copy.svg';
import { ReactComponent as QrCodeIcon } from 'app/icons/base/qr_code.svg';
import { toastSuccess } from 'app/toaster';
import { T } from 'lib/i18n';
import { t, T } from 'lib/i18n';
import { useBooleanState } from 'lib/ui/hooks';

import { useCryptoExchangeDataState } from '../../../context';
Expand All @@ -24,7 +24,7 @@ export const DepositAddressBlock = memo<Props>(({ className }) => {

const handleCopyButtonClick = useCallback(() => {
window.navigator.clipboard.writeText(exchangeData!.depositAddress);
toastSuccess('Address Copied');
toastSuccess(t('copiedAddress'));
}, [exchangeData]);

if (!exchangeData) return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { memo } from 'react';

import { QRCode } from 'app/atoms';
import { Money, QRCode } from 'app/atoms';
import { ActionModal, ActionModalBodyContainer } from 'app/atoms/action-modal';
import { T } from 'lib/i18n';

import Money from '../../../../../../atoms/Money';
import { CurrencyIcon } from '../../../components/CurrencyIcon';
import { useCryptoExchangeDataState } from '../../../context';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import React, { memo } from 'react';

import clsx from 'clsx';

import Money from 'app/atoms/Money';
import { T } from 'lib/i18n';

import Money from '../../../../../../atoms/Money';
import { CurrencyIcon } from '../../../components/CurrencyIcon';
import { ExchangeCountdown } from '../../../components/ExchangeCountdown';
import { useCryptoExchangeDataState } from '../../../context';
Expand Down
3 changes: 1 addition & 2 deletions src/app/pages/Market/crypto-exchange/steps/Deposit/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { memo, useCallback, useEffect, useState } from 'react';

import { FadeTransition } from 'app/a11y/FadeTransition';
import { CaptionAlert, IconBase } from 'app/atoms';
import Money from 'app/atoms/Money';
import { CaptionAlert, IconBase, Money } from 'app/atoms';
import { ActionsButtonsBox } from 'app/atoms/PageModal';
import { StyledButton } from 'app/atoms/StyledButton';
import { ReactComponent as CopyIcon } from 'app/icons/base/copy.svg';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FC, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';

import BigNumber from 'bignumber.js';
import clsx from 'clsx';
import { isEmpty } from 'lodash';
import { Controller, useFormContext, SubmitHandler, FieldError } from 'react-hook-form-v7';
Expand All @@ -19,7 +18,12 @@ import { useAccountAddressForEvm, useAccountAddressForTezos } from 'temple/front

import { StepLabel } from '../../../components/StepLabel';
import { Stepper } from '../../../components/Stepper';
import { defaultModalHeaderConfig, ModalHeaderConfig, TEZOS_EXOLIX_NETWORK_CODE } from '../../../config';
import {
defaultModalHeaderConfig,
ModalHeaderConfig,
TEZOS_EXOLIX_NETWORK_CODE,
VALUE_PLACEHOLDER
} from '../../../config';
import { useCryptoExchangeDataState } from '../../../context';
import { getCurrencyDisplayCode } from '../../../utils';
import { CryptoExchangeFormData } from '../types';
Expand All @@ -31,7 +35,6 @@ import { SelectTokenContent } from './SelectCurrencyContent';
const MIN_ERROR = 'min';
const MAX_ERROR = 'max';
const EXOLIX_DECIMALS = 8;
const VALUE_PLACEHOLDER = '---';

const DEFAULT_SWR_CONGIG = {
shouldRetryOnError: false,
Expand Down Expand Up @@ -114,14 +117,6 @@ export const FormContent: FC<Props> = ({ setModalHeaderConfig, setModalContent }
[ratesData]
);

const displayRate = useMemo(
() =>
rate
? `1 ${inputCurrency.code} ≈ ${new BigNumber(rate).decimalPlaces(2).toFixed()} ${outputCurrency.code}`
: VALUE_PLACEHOLDER,
[inputCurrency.code, outputCurrency.code, rate]
);

const withdrawalAddress = useMemo(() => {
if (outputCurrency.network.code === TEZOS_EXOLIX_NETWORK_CODE) {
return tezosAddress;
Expand Down Expand Up @@ -232,7 +227,7 @@ export const FormContent: FC<Props> = ({ setModalHeaderConfig, setModalContent }
containerClassName="pb-5"
/>

<InfoCard exchangeRate={displayRate} />
<InfoCard rate={rate} inputCurrencyCode={inputCurrency.code} outputCurrencyCode={outputCurrency.code} />
</form>

<ActionsButtonsBox>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import React, { memo } from 'react';

import Money from 'app/atoms/Money';
import { T } from 'lib/i18n';

import { InfoContainer, InfoRaw } from '../../../components/InfoBlock';
import { EXOLIX_PRIVICY_LINK, EXOLIX_TERMS_LINK } from '../../../config';
import { EXOLIX_PRIVICY_LINK, EXOLIX_TERMS_LINK, VALUE_PLACEHOLDER } from '../../../config';

interface Props {
exchangeRate: string;
rate: number | nullish;
inputCurrencyCode: string;
outputCurrencyCode: string;
}

export const InfoCard = memo<Props>(({ exchangeRate }) => (
export const InfoCard = memo<Props>(({ rate, inputCurrencyCode, outputCurrencyCode }) => (
<InfoContainer className="mb-8">
<InfoRaw bottomSeparator title="exchangeRate">
<span className="p-1 text-font-description">{exchangeRate}</span>
<span className="p-1 text-font-description">
{rate ? (
<>
<span>{`1 ${inputCurrencyCode} ≈ `}</span>
<Money cryptoDecimals={2} smallFractionFont={false} tooltipPlacement="bottom">
lendihop marked this conversation as resolved.
Show resolved Hide resolved
{rate}
</Money>{' '}
{outputCurrencyCode}
</>
) : (
VALUE_PLACEHOLDER
)}
</span>
</InfoRaw>

<div className="pt-2 px-1 flex flex-col gap-y-2 text-font-small text-grey-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ interface Props {

export const SelectCurrencyButton = memo<Props>(({ currency, onClick }) => (
<Button
className="cursor-pointer flex justify-between items-center bg-white py-0.5 px-2 gap-x-1 rounded-8 w-[144px] h-[44px]"
className="cursor-pointer flex justify-between items-center bg-white py-0.5 px-2 gap-x-1 rounded-8 w-[144px] h-[46px]"
onClick={onClick}
>
<div className="flex items-center gap-x-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { useAccountAddressForEvm, useAccountAddressForTezos, useEnabledEvmChains

import { CurrencyIcon } from '../../../components/CurrencyIcon';
import { ModalHeaderConfig, TEZOS_EXOLIX_NETWORK_CODE } from '../../../config';
import { getCurrencyDisplayCode } from '../../../utils';
import { getCurrencyDisplayCode, isSameExolixCurrency } from '../../../utils';
import { CryptoExchangeFormData } from '../types';

const FULLPAGE_ITEMS_COUNT = 11;
Expand Down Expand Up @@ -65,10 +65,7 @@ export const SelectCurrencyContent: FC<Props> = ({ content, setModalHeaderConfig
);

const inputCurrencies = useMemo(
() =>
allCurrencies.filter(
currency => !(currency.code === outputCurrency.code && currency.network.code === outputCurrency.network.code)
),
() => allCurrencies.filter(currency => !isSameExolixCurrency(currency, outputCurrency)),
[allCurrencies, outputCurrency]
);

Expand All @@ -77,13 +74,13 @@ export const SelectCurrencyContent: FC<Props> = ({ content, setModalHeaderConfig
allCurrencies.filter(currency => {
const networkCode = currency.network.code;

const isInputCurrency = currency.code === inputCurrency.code && networkCode === inputCurrency.network.code;
const isInputCurrency = isSameExolixCurrency(currency, inputCurrency);
const isTezosNetwork = Boolean(tezosAddress) && networkCode === TEZOS_EXOLIX_NETWORK_CODE;
const isEnabledEvmNetwork = Boolean(evmAddress) && enabledExolixNetworkCodes.includes(networkCode);

return !isInputCurrency && (isTezosNetwork || isEnabledEvmNetwork);
}),
[allCurrencies, enabledExolixNetworkCodes, evmAddress, inputCurrency.code, inputCurrency.network.code, tezosAddress]
[allCurrencies, enabledExolixNetworkCodes, evmAddress, inputCurrency, tezosAddress]
);

const displayCurrencies = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
import React, { FC, useCallback, useMemo, useState } from 'react';

import { FormProvider, useForm } from 'react-hook-form-v7';

import { dispatch } from 'app/store';
import { loadExolixCurrenciesActions, loadExolixNetworksMapActions } from 'app/store/crypto-exchange/actions';
import { useDidMount } from 'lib/ui/hooks';
import { useAccountAddressForTezos } from 'temple/front';

import {
Expand All @@ -26,10 +27,10 @@ interface Props {
export const OrderCreation: FC<Props> = ({ setModalHeaderConfig }) => {
const [modalContent, setModalContent] = useState<ModalContent>('form');

useEffect(() => {
useDidMount(() => {
dispatch(loadExolixNetworksMapActions.submit());
dispatch(loadExolixCurrenciesActions.submit());
}, []);
});

const tezosAddress = useAccountAddressForTezos();

Expand Down
4 changes: 4 additions & 0 deletions src/app/pages/Market/crypto-exchange/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { StoredExolixCurrency } from 'app/store/crypto-exchange/state';
import { TEZOS_METADATA } from 'lib/metadata';

import { TEZOS_EXOLIX_NETWORK_CODE } from './config';

export const getCurrencyDisplayCode = (currencyCode: string) =>
currencyCode === TEZOS_EXOLIX_NETWORK_CODE ? TEZOS_METADATA.symbol : currencyCode;

export const isSameExolixCurrency = (a: StoredExolixCurrency, b: StoredExolixCurrency): boolean =>
a.code === b.code && a.network.code === b.network.code;
2 changes: 1 addition & 1 deletion src/lib/apis/exolix/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface ExolixNetwork {
interface ExolixNetwork {
addressRegex: string;
blockExplorer: string | null;
depositMinAmount: number | null;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/apis/exolix/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import axios from 'axios';
import { StoredExolixCurrency } from 'app/store/crypto-exchange/state';
import { EnvVars } from 'lib/env';

import { ExchangeData, ExolixCurrenciesResponse, ExolixNetwork, GetRateRequestData, GetRateResponse } from './types';
import { ExchangeData, ExolixCurrenciesResponse, GetRateRequestData, GetRateResponse } from './types';

const API_KEY = EnvVars.TEMPLE_WALLET_EXOLIX_API_KEY;

Expand Down Expand Up @@ -37,7 +37,7 @@ export const getAllCurrencies = async (): Promise<Array<StoredExolixCurrency>> =
}
return totalData
.map(({ code, icon, name, networks }) =>
networks.map((network: ExolixNetwork) => ({
networks.map(network => ({
code,
icon,
name,
Expand Down
Loading