Skip to content

Commit

Permalink
[TRAH-2991] shahzaib / real account currency selector config from web…
Browse files Browse the repository at this point in the history
…site status (#13763)

* chore: dynamic currencies based on website status

* chore: revert context value

* chore: update docs

* chore: update docs

* fix: fixed typo
  • Loading branch information
shahzaib-deriv committed Feb 23, 2024
1 parent 0505cce commit e839280
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 99 deletions.
13 changes: 13 additions & 0 deletions packages/tradershub/src/constants/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@ export const IconToCurrencyMapper: IconToCurrencyMapperType = {
},
};

export const CurrencyTypes = {
CRYPTO: 'CRYPTO',
FIAT: 'FIAT',
} as const;

export const Regulation = {
EU: 'EU',
NonEU: 'Non-EU',
Expand All @@ -121,3 +126,11 @@ export const BrokerCodes = {
CR: 'CR',
MF: 'MF',
} as const;

export const CurrenciesListOrder: {
CRYPTO: string[];
FIAT: string[];
} = {
FIAT: ['USD', 'EUR', 'GBP', 'AUD'],
CRYPTO: ['TUSDT', 'BTC', 'ETH', 'LTC', 'UST', 'eUSDT', 'BUSD', 'DAI', 'EURS', 'IDK', 'PAX', 'TUSD', 'USDC', 'USDK'],
};
22 changes: 22 additions & 0 deletions packages/tradershub/src/helpers/currencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CurrenciesListOrder } from '@/constants';
import { TCurrencyConfig } from '@/hooks/useCurrencies';

/**
* Reorder currencies list based on the type and the defined order as `CurrenciesListOrder`.
* @param {TCurrencyConfig[]} list - The list of currencies.
* @param {keyof typeof CurrenciesListOrder} type - The type of the order.
* @returns {TCurrencyConfig[]} The reordered list of currencies.
*/
export const reorderCurrencies = (list: TCurrencyConfig[], type: keyof typeof CurrenciesListOrder) => {
const newOrder = CurrenciesListOrder[type];

return list.sort((a, b) => {
if (newOrder.indexOf(a.id) < newOrder.indexOf(b.id)) {
return -1;
}
if (newOrder.indexOf(a.id) > newOrder.indexOf(b.id)) {
return 1;
}
return 0;
});
};
72 changes: 0 additions & 72 deletions packages/tradershub/src/helpers/currencyConfig.tsx

This file was deleted.

2 changes: 1 addition & 1 deletion packages/tradershub/src/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './currencyConfig';
export * from './currencies';
export * from './formikHelpers';
export * from './signupModalHelpers';
export * from './urls';
1 change: 1 addition & 0 deletions packages/tradershub/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as useCFDAssets } from './useCFDAssets';
export { default as useCurrencies } from './useCurrencies';
export { default as useMT5AccountHandler } from './useMT5AccountHandler';
export { default as useNewCRRealAccount } from './useNewCRRealAccount';
export { default as usePlatformAssets } from './usePlatformAssets';
Expand Down
48 changes: 48 additions & 0 deletions packages/tradershub/src/hooks/useCurrencies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useMemo } from 'react';
import { reorderCurrencies } from '@/helpers';
import { useQuery } from '@deriv/api';

type TWebsiteStatus = NonNullable<ReturnType<typeof useQuery<'website_status'>>['data']>['website_status'];
export type TCurrencyConfig = NonNullable<TWebsiteStatus>['currencies_config'][string] & {
id: string;
};

export type TCurrencies = {
CRYPTO: TCurrencyConfig[];
FIAT: TCurrencyConfig[];
};

/** A custom hook to get the currency config information from `website_status` endpoint and in predefined order */
const useCurrencies = () => {
const { data, ...rest } = useQuery('website_status');

const currencyConfig = useMemo(() => {
if (!data?.website_status?.currencies_config) return;
const currencies: TCurrencies = {
FIAT: [],
CRYPTO: [],
};

// map the currencies to their respective types (FIAT or CRYPTO) with their id
Object.entries(data?.website_status?.currencies_config).forEach(([key, value]) => {
if (value.type === 'fiat') {
currencies.FIAT.push({ ...value, id: key });
} else {
currencies.CRYPTO.push({ ...value, id: key });
}
});

// reorder the currencies based on the predefined order
return {
FIAT: reorderCurrencies(currencies.FIAT, 'FIAT'),
CRYPTO: reorderCurrencies(currencies.CRYPTO, 'CRYPTO'),
};
}, [data?.website_status?.currencies_config]);

return {
data: currencyConfig,
...rest,
};
};

export default useCurrencies;
23 changes: 12 additions & 11 deletions packages/tradershub/src/screens/CurrencySelector/Currencies.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,38 @@
import React, { useMemo } from 'react';
import React from 'react';
import { twMerge } from 'tailwind-merge';
import { CurrencyTypes } from '@/constants';
import { TCurrencyConfig } from '@/hooks/useCurrencies';
import { InlineMessage, Text } from '@deriv-com/ui';
import { CURRENCY_TYPES, getCurrencyConfig } from '../../helpers/currencyConfig';
import CurrencyCard from './CurrencyCard';

type TCurrencies = {
type: keyof typeof CURRENCY_TYPES;
list: TCurrencyConfig[];
type: keyof typeof CurrencyTypes;
};

/**
* @name Currencies
* @description The Currencies component is used to display the currencies in the currency selector screen.
* @param {string} type - The type of the currency.
* @param {TCurrencyConfig[]} list - The list of the currency.
* @returns {React.ReactNode}
* @example <Currencies type={type} />
* @example <Currencies type={CURRENCY_TYPES.FIAT} />
* @example <Currencies type={CurrencyTypes.FIAT} />
*/
const Currencies = ({ type }: TCurrencies) => {
const currencies = useMemo(() => getCurrencyConfig(type), [type]);

const Currencies = ({ type, list: currencies = [] }: TCurrencies) => {
return (
<div className='text-center'>
<Text align='center' as='p' className='mb-6' weight='bold'>
{type === CURRENCY_TYPES.CRYPTO ? 'Cryptocurrencies' : 'Fiat Currencies'}
{type === CurrencyTypes.CRYPTO ? 'Cryptocurrencies' : 'Fiat Currencies'}
</Text>
{type === CURRENCY_TYPES.FIAT && (
{type === CurrencyTypes.FIAT && (
<InlineMessage className='my-16 lg:w-[261px]' variant='info'>
Please note that you can only have 1 fiat account.
</InlineMessage>
)}
<div className={twMerge('flex flex-wrap justify-start', currencies.length < 4 ? 'lg:justify-center' : '')}>
{currencies.map(currency => (
<CurrencyCard {...currency} key={currency.id} />
{currencies?.map(currency => (
<CurrencyCard id={currency?.id} key={currency?.id} title={currency?.name ?? ''} />
))}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import React from 'react';
import { useFormikContext } from 'formik';
import { twMerge } from 'tailwind-merge';
import { IconComponent } from '@/components';
import { StandaloneCircleInfoRegularIcon as CircleInfoIcon } from '@deriv/quill-icons';
import { Text } from '@deriv-com/ui';
import { getCurrencyConfig } from '../../helpers/currencyConfig';

type TCurrencyCard = ReturnType<typeof getCurrencyConfig>[number];
type TCurrencyCard = { id: string; info?: boolean; title: string };

// write docs for the component
/**
* @name CurrencyCard
* @description The CurrencyCard component is used to display the currency card in the currency selector screen.
* @param {React.ReactNode} icon - The icon of the currency.
* @param {string} id - The id of the currency.
* @param {boolean} info - The info of the currency.
* @param {boolean} info - The flag to display an info for a specific currency.
* @param {string} title - The title of the currency.
* @returns {React.ReactNode}
* @example <CurrencyCard icon={Icon} id={id} info={info} title={title} />
* @example <CurrencyCard id={id} info={info} title={title} />
*/
const CurrencyCard = ({ icon: Icon, id, info, title }: TCurrencyCard) => {
const CurrencyCard = ({ id, info, title }: TCurrencyCard) => {
const { setFieldValue, values } = useFormikContext<{ currency: string }>();
const isSelected = values.currency === id;
return (
Expand All @@ -34,7 +32,7 @@ const CurrencyCard = ({ icon: Icon, id, info, title }: TCurrencyCard) => {
onClick={() => setFieldValue('currency', isSelected ? '' : id)}
type='button'
>
<Icon />
<IconComponent icon={id} />
{info && <CircleInfoIcon className='absolute top-0 opacity-50' />}
<div className='flex flex-col items-center gap-4 pt-4'>
<Text as='p' className='my-4' size='sm' weight={isSelected ? 'bold' : 'normal'}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import React, { Fragment } from 'react';
import { Form, Formik, FormikValues } from 'formik';
import { CurrencyTypes } from '@/constants';
import { WizardScreenActions, WizardScreenWrapper } from '@/flows';
import { CURRENCY_TYPES } from '@/helpers';
import useCurrencies from '@/hooks/useCurrencies';
import { ACTION_TYPES, useRealAccountCreationContext } from '@/providers';
import { Divider } from '@deriv-com/ui';
import { Divider, Loader } from '@deriv-com/ui';
import Currencies from './Currencies';

/**
Expand All @@ -13,11 +14,13 @@ import Currencies from './Currencies';
*/
const CurrencySelector = () => {
const { dispatch, helpers, state } = useRealAccountCreationContext();
const { data: currencies, isLoading } = useCurrencies();

const handleSubmit = (values: FormikValues) => {
dispatch({ payload: { currency: values.currency }, type: ACTION_TYPES.SET_CURRENCY });
helpers.goToNextStep();
};

return (
<WizardScreenWrapper heading='Select your preferred currency'>
<Formik
Expand All @@ -28,10 +31,18 @@ const CurrencySelector = () => {
>
{({ values }) => (
<Form className='flex flex-col flex-grow w-full overflow-y-auto'>
<div className='flex-1 p-16 overflow-y-auto lg:p-24'>
<Currencies type={CURRENCY_TYPES.FIAT} />
<Divider className='my-24' />
<Currencies type={CURRENCY_TYPES.CRYPTO} />
<div className='relative flex-1 p-16 overflow-y-auto lg:p-24'>
{/** temporarily setting a loader here until a proper design, needs to be here for center alignment */}
{isLoading && <Loader />}

{/** currencies as a type guard for typescript */}
{currencies && (
<Fragment>
<Currencies list={currencies[CurrencyTypes.FIAT]} type={CurrencyTypes.FIAT} />
<Divider className='my-24' />
<Currencies list={currencies[CurrencyTypes.CRYPTO]} type={CurrencyTypes.CRYPTO} />
</Fragment>
)}
</div>
<WizardScreenActions submitDisabled={!values.currency} />
</Form>
Expand Down

0 comments on commit e839280

Please sign in to comment.