Skip to content

Commit

Permalink
Merge pull request #126 from shontzu-deriv/shontzu/CFDS-3634/add-comp…
Browse files Browse the repository at this point in the history
…are-accounts-page

[REFACTORING] [CFDS] [TRAH] shontzu/CFDS-3634/add-compare-accounts-page
  • Loading branch information
thisyahlen-deriv authored Apr 26, 2024
2 parents a36c835 + b4e17cd commit 00e22b7
Show file tree
Hide file tree
Showing 30 changed files with 1,333 additions and 28 deletions.
27 changes: 27 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"dotenv": "^16.4.5",
"embla-carousel": "^8.0.2",
"embla-carousel-react": "^8.0.2",
"formik": "^2.4.5",
"js-cookie": "^3.0.5",
"qrcode.react": "^3.1.0",
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 9 additions & 9 deletions src/assets/cfd/tradingInstruments/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Baskets from './ic-instrument-baskets.svg';
import Commodities from './ic-instrument-commodities.svg';
import Cryptocurrencies from './ic-instrument-cryptocurrencies.svg';
import DerivedFX from './ic-instrument-derived-fx.svg';
import ETF from './ic-instrument-etf.svg';
import Forex from './ic-instrument-forex.svg';
import StockIndices from './ic-instrument-stock-indices.svg';
import Stocks from './ic-instrument-stocks.svg';
import Synthetics from './ic-instrument-synthetics.svg';
import Baskets from './ic-instrument-baskets.svg?react';
import Commodities from './ic-instrument-commodities.svg?react';
import Cryptocurrencies from './ic-instrument-cryptocurrencies.svg?react';
import DerivedFX from './ic-instrument-derived-fx.svg?react';
import ETF from './ic-instrument-etf.svg?react';
import Forex from './ic-instrument-forex.svg?react';
import StockIndices from './ic-instrument-stock-indices.svg?react';
import Stocks from './ic-instrument-stocks.svg?react';
import Synthetics from './ic-instrument-synthetics.svg?react';

const InstrumentsIcons = {
Baskets,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { PropsWithChildren, useCallback, useEffect, useState } from 'react';
import { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel';
import useEmblaCarousel from 'embla-carousel-react';

import CFDCompareAccountsCarouselButton from './CompareAccountsCarouselButton';

const CompareAccountsCarousel = ({ children }: PropsWithChildren) => {
const options: EmblaOptionsType = {
align: 'start',
containScroll: 'trimSnaps',
};
const [emblaRef, emblaApi] = useEmblaCarousel(options);
const [prevBtnEnabled, setPrevBtnEnabled] = useState(false);
const [nextBtnEnabled, setNextBtnEnabled] = useState(false);

const scrollPrev = useCallback(() => emblaApi?.scrollPrev(), [emblaApi]);
const scrollNext = useCallback(() => emblaApi?.scrollNext(), [emblaApi]);

const onSelect = useCallback((emblaApi: EmblaCarouselType) => {
setPrevBtnEnabled(emblaApi.canScrollPrev());
setNextBtnEnabled(emblaApi.canScrollNext());
}, []);

useEffect(() => {
if (!emblaApi) return;

onSelect(emblaApi);
emblaApi.on('reInit', onSelect);
emblaApi.on('select', onSelect);
}, [emblaApi, onSelect]);

return (
<div className='relative overflow-hidden'>
<div className='w-full h-full overflow-hidden' ref={emblaRef}>
<div className='flex flex-row ease-in-out max-h-[auto] backface-hidden duration-0 -ml-10 touch-pan-y'>
{children}
</div>
</div>
<CFDCompareAccountsCarouselButton enabled={prevBtnEnabled} onClick={scrollPrev} />
<CFDCompareAccountsCarouselButton enabled={nextBtnEnabled} isNext onClick={scrollNext} />
</div>
);
};

export default CompareAccountsCarousel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { LabelPairedChevronLeftMdRegularIcon, LabelPairedChevronRightMdRegularIcon } from '@deriv/quill-icons';

type TPrevNextButtonProps = {
enabled: boolean;
isNext?: boolean;
onClick: () => void;
};

const CFDCompareAccountsCarouselButton = ({ enabled, isNext = false, onClick }: TPrevNextButtonProps) => (
<button
className={`bg-system-light-primary-background z-10 absolute flex items-center justify-center top-1/2 cursor-pointer w-40 h-40 rounded-[50%] disabled:opacity-8 disabled:hidden border-0 shadow-7,
${isNext && 'right-16'},
${!isNext && 'left-16'}`}
disabled={!enabled}
onClick={onClick}
>
{isNext ? <LabelPairedChevronRightMdRegularIcon /> : <LabelPairedChevronLeftMdRegularIcon />}
</button>
);
export default CFDCompareAccountsCarouselButton;
1 change: 1 addition & 0 deletions src/cfd/components/CompareAccountsCarousel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as CompareAccountsCarousel } from './CompareAccountsCarousel';
2 changes: 1 addition & 1 deletion src/cfd/components/MT5PlatformsList/MT5PlatformsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const MT5PlatformsList = () => {

return (
<AvailableMT5AccountsList
account={MT5Account as unknown as THooks.MT5AccountsList}
account={MT5Account as THooks.MT5AccountsList}
key={`available-mt5-list-${MT5Account.market_type}-${MT5Account.leverage}`}
/>
);
Expand Down
38 changes: 38 additions & 0 deletions src/cfd/screens/CFDCompareAccounts/CTraderCompareAccountsCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useMemo } from 'react';

import { useActiveDerivTradingAccount, useCFDAccountsList, useCFDCompareAccounts, useRegulationFlags } from '@/hooks';

import CFDCompareAccountsCard from './CompareAccountsCard';
import { isCTraderAccountAdded } from './CompareAccountsConfig';

const CTraderCompareAccountsCard = () => {
const { data: activeDerivTrading } = useActiveDerivTradingAccount();
const { regulationFlags } = useRegulationFlags();
const { isEU } = regulationFlags;

const { data: compareAccounts, hasCTraderAccountAvailable } = useCFDCompareAccounts();

const { is_virtual: isDemo = false } = activeDerivTrading ?? {};

const { data: cfdAccounts } = useCFDAccountsList();

const { ctraderAccount } = compareAccounts;

const isCtraderAdded = useMemo(
() => !!cfdAccounts && isCTraderAccountAdded(cfdAccounts.ctrader, !!isDemo),
[cfdAccounts, isDemo]
);

if (isEU || !hasCTraderAccountAvailable || !ctraderAccount) return null;

return (
<CFDCompareAccountsCard
isAccountAdded={isCtraderAdded}
marketType={ctraderAccount.market_type}
platform={ctraderAccount.platform}
shortCode={ctraderAccount.shortcode}
/>
);
};

export default CTraderCompareAccountsCard;
17 changes: 17 additions & 0 deletions src/cfd/screens/CFDCompareAccounts/CompareAccounts.classnames.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { cva, VariantProps } from 'class-variance-authority';

export const CompareAccountsPlatformLabelClass = cva('bg-system-light-platform-background p-[9px] rounded-t-xl', {
variants: { background: { CTrader: 'bg-[#ffeabf]', MT5: 'bg-[#e6f5ff]', DerivX: 'bg-[#e8fdf8]' } },
});

export const CompareAccountsPlatformLabelTextColorClass = cva('text-center', {
variants: { label: { CTrader: 'text-[#ff9c13]', MT5: 'text-[#2C9aff]', DerivX: 'text-[#17eabd]' } },
});

export type TCompareAccountsPlatformLabelClassProps = NonNullable<
VariantProps<typeof CompareAccountsPlatformLabelClass>
>;

export type TCompareAccountsPlatformLabelTextClassProps = NonNullable<
VariantProps<typeof CompareAccountsPlatformLabelTextColorClass>
>;
130 changes: 130 additions & 0 deletions src/cfd/screens/CFDCompareAccounts/CompareAccountsButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { useEffect, useMemo } from 'react';

import { Category, CFDPlatforms, MarketType } from '@cfd/constants';
import { Button } from '@deriv-com/ui';

import {
useActiveDerivTradingAccount,
useAuthentication,
useCreateOtherCFDAccount,
useMT5AccountsList,
useQueryParams,
useSettings,
} from '@/hooks';
import { THooks, TPlatforms } from '@/types';

import {
getAccountVerificationStatus,
shouldRestrictBviAccountCreation,
shouldRestrictVanuatuAccountCreation,
} from './CompareAccountsConfig';

type TCompareAccountButton = {
isAccountAdded: boolean;
platform: TPlatforms.All;
shortCode: THooks.AvailableMT5Accounts['shortcode'];
};

/*
* This is a button component for Compare Accounts that is used to add a CFD account.
@params {boolean} isAccountAdded - Whether the account is added or not.
@params {string} platform - The platform of the account.
@params {string} shortCode - The short code of the account.
@params {string} marketType - The market type of the account. //Removed for now as it is needed by Verification flow
*/
const CompareAccountsButton = ({ isAccountAdded, platform, shortCode }: TCompareAccountButton) => {
const { openModal } = useQueryParams();

const { data: accountSettings } = useSettings();
const { data: authenticationInfo } = useAuthentication();
const {
error: createAccountError,
isSuccess: isAccountCreated,
mutate: createAccount,
} = useCreateOtherCFDAccount();
const { data: mt5Accounts } = useMT5AccountsList();
const { data: activeTradingAccount } = useActiveDerivTradingAccount();

const { is_virtual: isDemo = false } = activeTradingAccount ?? {};

const {
account_opening_reason: accountOpeningReason,
citizen,
place_of_birth: placeOfBirth,
tax_identification_number: taxIdentificationNumber,
tax_residence: taxResidence,
} = accountSettings;

const hasSubmittedPersonalDetails = !!(
citizen &&
placeOfBirth &&
taxResidence &&
taxIdentificationNumber &&
accountOpeningReason
);

const restrictBviAccountCreation = useMemo(
() => shouldRestrictBviAccountCreation(mt5Accounts ?? []),
[mt5Accounts]
);

const restrictVanuatuAccountCreation = useMemo(
() => shouldRestrictVanuatuAccountCreation(mt5Accounts ?? []),
[mt5Accounts]
);

const isAccountStatusVerified = getAccountVerificationStatus(
shortCode,
restrictBviAccountCreation,
restrictVanuatuAccountCreation,
hasSubmittedPersonalDetails,
authenticationInfo,
!!isDemo
);

useEffect(() => {
if (isAccountCreated) {
openModal('CTraderSuccessModal');
}
if (createAccountError) {
// Error Component to be implemented
openModal('DummyComponentModal');
}
}, [createAccountError, isAccountCreated, isDemo, openModal]);

const onClickAdd = () => {
if (platform === CFDPlatforms.MT5) {
// Going to remove Placeholder once Verification flow is implemented
if (isAccountStatusVerified) return;

if (isAccountStatusVerified) {
openModal('MT5PasswordModal');
} else {
openModal('DummyComponentModal');
}
} else if (platform === CFDPlatforms.DXTRADE) {
openModal('DxtradePasswordModal');
} else {
createAccount({
account_type: isDemo ? Category.DEMO : Category.REAL,
market_type: MarketType.ALL,
platform: CFDPlatforms.CTRADER,
});
}
};
return (
<div className='h-40 m-20 w-[calc(100%-40px)]'>
<Button
className='w-full text-center text-system-light-primary-background'
color='primary-light'
data-testid='dt_compare_cfd_account_button'
disabled={isAccountAdded}
onClick={onClickAdd}
>
{isAccountAdded ? 'Added' : 'Add'}
</Button>
</div>
);
};

export default CompareAccountsButton;
Loading

0 comments on commit 00e22b7

Please sign in to comment.