Skip to content

Commit

Permalink
[WALL] george / WALL-4518 / Update Fiat Onramp Implementation (#16976)
Browse files Browse the repository at this point in the history
* feat: ✨ hide fiat onramp for unsupported currencies

* fix(wallets): 🚑 align back button and transaction status

* style(cashier): 💄 fix side note order in mobile view, remove onramp box, improve logic
  • Loading branch information
heorhi-deriv authored Oct 7, 2024
1 parent bbf796b commit 497efba
Show file tree
Hide file tree
Showing 20 changed files with 309 additions and 147 deletions.
18 changes: 15 additions & 3 deletions packages/cashier/src/containers/cashier/__tests__/cashier.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,23 @@ describe('<Cashier />', () => {
toggleCashier: jest.fn(),
},
client: {
active_accounts: [],
currency: 'USD',
is_account_setting_loaded: true,
is_logged_in: true,
is_logging_in: false,
active_accounts: [],
is_crypto: jest.fn(),
website_status: {
currencies_config: {
USD: {
//@ts-expect-error need to update `@deriv/api-types` library to the latest version
platform: { cashier: ['doughflow'], ramp: [] },
},
BTC: {
//@ts-expect-error need to update `@deriv/api-types` library to the latest version
platform: { cashier: ['crypto'], ramp: ['ramp'] },
},
},
},
},
notifications: {
showAccountSwitchToRealNotification: jest.fn(),
Expand Down Expand Up @@ -167,10 +179,10 @@ describe('<Cashier />', () => {
});

it('renders the component if logged in and account setting is loaded', () => {
mockRootStore.client.currency = 'BTC';
mockRootStore.client.is_account_setting_loaded = true;
mockRootStore.client.is_logged_in = true;
mockRootStore.client.is_logging_in = false;
mockRootStore.client.is_crypto = jest.fn(() => true);
mockRootStore.modules.cashier.general_store.is_cashier_onboarding = true;

renderWithRouter(<Cashier routes={getRoutesConfig()[0].routes || []} />, mockRootStore);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import React from 'react';
import { routes } from '@deriv/shared';
import { mockStore } from '@deriv/stores';
import { fireEvent, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import CashierProviders from '../../../../../cashier-providers';
import CashierOnboardingOnrampCard from '../cashier-onboarding-onramp-card';

jest.mock('@deriv/api', () => ({
...jest.requireActual('@deriv/api'),
useFetch: jest.fn(() => ({
data: {
website_status: {
currencies_config: {
USD: { type: 'fiat', name: 'US Dollar' },
BTC: { type: 'crypto', name: 'Bitcoin' },
},
},
},
jest.mock('@deriv/hooks', () => ({
...jest.requireActual('@deriv/hooks'),
useCurrentCurrencyConfig: jest.fn(() => ({
is_crypto: true,
platform: { cashier: ['crypto'], ramp: ['banxa'] },
})),
}));

describe('CashierOnboardingOnrampCard', () => {
test('should call the onClick callback when clicked', () => {
describe('user clicks on cashier onramp onboarding card', () => {
const mock = mockStore({
client: {
currency: 'USD',
account_list: [
{ loginid: '1', title: 'USD' },
{ loginid: '2', title: 'BTC' },
],
available_onramp_currencies: ['ETH', 'LTC', 'BTC'],
currency: 'BTC',
},
modules: {
cashier: {
Expand All @@ -31,17 +32,53 @@ describe('CashierOnboardingOnrampCard', () => {
},
},
},
ui: {
openRealAccountSignup: jest.fn(),
shouldNavigateAfterChooseCrypto: jest.fn(),
},
});

it('calls the onClick callback when clicked', () => {
const wrapper = ({ children }: { children: JSX.Element }) => (
<CashierProviders store={mock}>{children}</CashierProviders>
);
render(<CashierOnboardingOnrampCard />, { wrapper });

const container = screen.getByTestId('dt_cashier_onboarding_card');

userEvent.click(container);

expect(mock.modules.cashier.general_store.setDepositTarget).toHaveBeenCalledWith(routes.cashier_onramp);
});

const wrapper = ({ children }: { children: JSX.Element }) => (
<CashierProviders store={mock}>{children}</CashierProviders>
);
render(<CashierOnboardingOnrampCard />, { wrapper });
it('calls `Choose account` modal and navigates to `/cashier/on-ramp` if the user has onramp supported accounts', () => {
const wrapper = ({ children }: { children: JSX.Element }) => (
<CashierProviders store={mock}>{children}</CashierProviders>
);
render(<CashierOnboardingOnrampCard />, { wrapper });

const container = screen.getByTestId('dt_cashier_onboarding_card');
const container = screen.getByTestId('dt_cashier_onboarding_card');

fireEvent.click(container);
userEvent.click(container);

expect(mock.modules.cashier.general_store.setDepositTarget).toBeCalledTimes(1);
expect(mock.ui.openRealAccountSignup).toHaveBeenCalledWith('choose');
expect(mock.ui.shouldNavigateAfterChooseCrypto).toHaveBeenCalledWith(routes.cashier_onramp);
});

it('calls `Create account` modal if the user does not have onramp supported accounts', () => {
mock.client.account_list = [{ loginid: '1', title: 'USD' }];
mock.client.currency = 'USD';

const wrapper = ({ children }: { children: JSX.Element }) => (
<CashierProviders store={mock}>{children}</CashierProviders>
);
render(<CashierOnboardingOnrampCard />, { wrapper });

const container = screen.getByTestId('dt_cashier_onboarding_card');

userEvent.click(container);

expect(mock.ui.openRealAccountSignup).toHaveBeenCalledWith('add_crypto');
});
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { useCurrentCurrencyConfig, useHasCryptoCurrency } from '@deriv/hooks';
import { useCurrentCurrencyConfig } from '@deriv/hooks';
import { observer, useStore } from '@deriv/stores';
import { localize } from '@deriv/translations';
import { useCashierStore } from '../../../../stores/useCashierStores';
Expand All @@ -9,16 +9,19 @@ import { CashierOnboardingIconMarquee } from '../cashier-onboarding-icon-marquee
const icons: React.ComponentProps<typeof CashierOnboardingIconMarquee>['icons'] = ['IcCashierBanxa'];

const CashierOnboardingOnrampCard: React.FC = observer(() => {
const { ui } = useStore();
const { client, ui } = useStore();
const { available_onramp_currencies, account_list } = client;
const { general_store } = useCashierStore();
const { openRealAccountSignup, shouldNavigateAfterChooseCrypto, is_dark_mode_on } = ui;
const { setDepositTarget } = general_store;
const has_crypto_account = useHasCryptoCurrency();
const currency_config = useCurrentCurrencyConfig();
const has_onramp_accounts = account_list.some(
account => account.title && available_onramp_currencies.includes(account.title)
);

const onClick = () => {
setDepositTarget('/cashier/on-ramp');
if (currency_config?.is_crypto || has_crypto_account) {
if (has_onramp_accounts) {
openRealAccountSignup('choose');
shouldNavigateAfterChooseCrypto('/cashier/on-ramp');
} else {
Expand Down
18 changes: 10 additions & 8 deletions packages/cashier/src/modules/deposit-crypto/deposit-crypto.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import {
import DepositCryptoSideNoteTryFiatOnRamp from './components/deposit-crypto-side-notes/deposit-crypto-side-note-try-fiat-onramp';

const DepositCrypto: React.FC = observer(() => {
const { isDesktop } = useDevice();
const { isDesktop: is_desktop } = useDevice();
const { general_store } = useCashierStore();
const currency_config = useCurrentCurrencyConfig();
const { setIsDeposit } = general_store;
const is_onramp_available = currency_config.platform.ramp.length > 0;

useEffect(() => {
setIsDeposit(true);
Expand All @@ -33,19 +34,20 @@ const DepositCrypto: React.FC = observer(() => {
// Hide the side note and render it in the page content on mobile to match the design,
// Need to talk with the design team to put `DepositCryptoSideNoteTryFiatOnRamp` in the
// side notes for consistency and then we can remove unnecessary components from the children.
right={!isDesktop ? undefined : <DepositCryptoSideNotes />}
right={!is_desktop ? undefined : <DepositCryptoSideNotes />}
>
<DepositSubPageAnalyticsEventTracker deposit_category='crypto' />
{currency_config?.is_tUSDT && <DepositCryptoInfoNotice />}
<DepositCryptoCurrencyDetails />
<DepositCryptoWalletAddress />
<Divider />
{!isDesktop && <DepositCryptoSideNotes />}
{!isDesktop && <Divider />}
{(!is_desktop || is_onramp_available) && <Divider />}
{/* This should be in the side notes, Need to talk to the design team to change it */}
<div style={{ alignSelf: !isDesktop ? 'unset' : 'center' }}>
<DepositCryptoSideNoteTryFiatOnRamp />
</div>
{is_onramp_available && (
<div style={{ alignSelf: !is_desktop ? 'unset' : 'center' }}>
<DepositCryptoSideNoteTryFiatOnRamp />
</div>
)}
{!is_desktop && <DepositCryptoSideNotes />}
</PageContainer>
);
});
Expand Down
4 changes: 2 additions & 2 deletions packages/cashier/src/pages/deposit/__tests__/deposit.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jest.mock('@deriv/hooks', () => ({
useCashierLocked: jest.fn(() => false),
useIsSystemMaintenance: jest.fn(() => false),
useCurrentCurrencyConfig: jest.fn(() => ({
platform: { cashier: ['doughflow'] },
platform: { cashier: ['doughflow'], ramp: [] },
})),
}));

Expand Down Expand Up @@ -118,7 +118,7 @@ describe('<Deposit />', () => {
});

(useCurrentCurrencyConfig as jest.Mock).mockReturnValue({
platform: { cashier: ['crypto'] },
platform: { cashier: ['crypto'], ramp: ['banxa'] },
});

render(<Deposit />, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { useDevice } from '@deriv-com/ui';
import { FormSubmitButton, Icon, Text, ThemedScrollbars } from '@deriv/components';
import { localize, Localize } from '@deriv/translations';
import { observer, useStore } from '@deriv/stores';
import { reorderCurrencies, website_name } from '@deriv/shared';
import { isMobile, reorderCurrencies, routes, website_name } from '@deriv/shared';
import { CurrencyRadioButtonGroup, CurrencyRadioButton } from '@deriv/account';
import CurrencyProvider from './choose-currency';
import AddCurrencyNote from './add-currency-note';
import './currency-selector.scss';

const messages = () => [
Expand Down Expand Up @@ -43,17 +45,23 @@ const AddCryptoCurrency = observer(
hasNoAvailableCrypto,
}) => {
const { isDesktop } = useDevice();
const { client, ui } = useStore();
const { client, modules, ui } = useStore();
const { available_crypto_currencies, upgradeable_currencies: legal_allowed_currencies, has_fiat } = client;
const { should_show_cancel } = ui;
const { cashier } = modules;

const deposit_target = cashier.general_store.deposit_target;

const getReorderedFiatCurrencies = () =>
reorderCurrencies(legal_allowed_currencies.filter(currency => currency.type === FIAT_CURRENCY_TYPE));
const getReorderedCryptoCurrencies = () =>
reorderCurrencies(
legal_allowed_currencies.filter(currency => currency.type === CRYPTO_CURRENCY_TYPE),
CRYPTO_CURRENCY_TYPE
);
const getReorderedCryptoCurrencies = () => {
const currencies =
deposit_target === routes.cashier_onramp
? CurrencyProvider.currenciesOnRampAvailability(legal_allowed_currencies)
: legal_allowed_currencies.filter(currency => currency.type === CRYPTO_CURRENCY_TYPE);

return reorderCurrencies(currencies, CRYPTO_CURRENCY_TYPE);
};
const canAddFiat = () => !has_fiat && !should_show_crypto_only;
const canAddCrypto = currency => {
// check if the cryptocurrency has not been created
Expand All @@ -74,30 +82,28 @@ const AddCryptoCurrency = observer(
<Headers heading={is_add_fiat ? messages()[4] : messages()[2]} subheading={messages()[3]} />
)}
{canAddFiat() && (
<React.Fragment>
<ThemedScrollbars>
<CurrencyRadioButtonGroup
id='fiat_currency'
is_fiat
className='currency-selector__radio-group currency-selector__radio-group--with-margin'
value={values.currency}
error={errors.currency}
touched={touched.currency}
is_title_enabled={canAddFiat()}
item_count={getReorderedFiatCurrencies().length}
>
{getReorderedFiatCurrencies().map(currency => (
<Field
key={currency.value}
component={CurrencyRadioButton}
name='currency'
id={currency.value}
label={currency.name}
/>
))}
</CurrencyRadioButtonGroup>
</ThemedScrollbars>
</React.Fragment>
<ThemedScrollbars>
<CurrencyRadioButtonGroup
id='fiat_currency'
is_fiat
className='currency-selector__radio-group currency-selector__radio-group--with-margin'
value={values.currency}
error={errors.currency}
touched={touched.currency}
is_title_enabled={canAddFiat()}
item_count={getReorderedFiatCurrencies().length}
>
{getReorderedFiatCurrencies().map(currency => (
<Field
key={currency.value}
component={CurrencyRadioButton}
name='currency'
id={currency.value}
label={currency.name}
/>
))}
</CurrencyRadioButtonGroup>
</ThemedScrollbars>
)}
{canAddFiat() && (
<Text
Expand Down Expand Up @@ -129,29 +135,36 @@ const AddCryptoCurrency = observer(
)}
{!should_show_fiat_only &&
(available_crypto_currencies.length !== 0 ? (
<ThemedScrollbars>
<CurrencyRadioButtonGroup
id='crypto_currency'
className='currency-selector__radio-group currency-selector__radio-group--with-margin'
label={localize('Cryptocurrencies')}
value={values.currency}
error={errors.currency}
touched={touched.currency}
is_title_enabled={canAddFiat()}
item_count={getReorderedCryptoCurrencies().length}
>
{getReorderedCryptoCurrencies().map(currency => (
<Field
key={currency.value}
component={CurrencyRadioButton}
name='currency'
id={currency.value}
label={currency.name}
selected={canAddCrypto(currency)}
/>
))}
</CurrencyRadioButtonGroup>
</ThemedScrollbars>
<>
<ThemedScrollbars height={isMobile() ? window.innerHeight - 240 : '460px'}>
<CurrencyRadioButtonGroup
id='crypto_currency'
className='currency-selector__radio-group currency-selector__radio-group--with-margin'
label={localize('Cryptocurrencies')}
value={values.currency}
error={errors.currency}
touched={touched.currency}
is_title_enabled={canAddFiat()}
item_count={getReorderedCryptoCurrencies().length}
>
{getReorderedCryptoCurrencies().map(currency => (
<Field
key={currency.value}
component={CurrencyRadioButton}
name='currency'
id={currency.value}
label={currency.name}
selected={canAddCrypto(currency)}
/>
))}
</CurrencyRadioButtonGroup>
</ThemedScrollbars>
{deposit_target === routes.cashier_onramp && (
<AddCurrencyNote
message={localize('Some currencies may not be supported by fiat onramp.')}
/>
)}
</>
) : (
<ThemedScrollbars>
<CurrencyRadioButtonGroup
Expand Down
Loading

0 comments on commit 497efba

Please sign in to comment.