Skip to content

Commit 8ad0ed8

Browse files
authored
[DTRA] / Kate / DTRA-964 / Multipliers update (deriv-com#14226)
* refactor: update contract card, reports and notifications for multipliers * fix: turbos config * fix: failing tests * refactor: add tests for new files * feat: add video for multipliers * refactor: tests * refactor: existing tests * refactor: aplly suggestions * refactor: function parameters * fix: type * fix: test * chore: empty commit * fix: ui defect
1 parent 335fb4c commit 8ad0ed8

File tree

22 files changed

+217
-183
lines changed

22 files changed

+217
-183
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import { getContractTypeDisplay, CONTRACT_TYPES } from '@deriv/shared';
4+
import ContractTypeCell from '../contract-type-cell';
5+
6+
jest.mock('../../../icon-trade-types', () => jest.fn(({ type }) => <div>Icon trade type: {type}</div>));
7+
8+
const mock_props: React.ComponentProps<typeof ContractTypeCell> = {
9+
displayed_trade_param: '',
10+
getContractTypeDisplay,
11+
is_high_low: false,
12+
is_multipliers: false,
13+
is_turbos: false,
14+
type: CONTRACT_TYPES.VANILLA.CALL,
15+
};
16+
17+
describe('<ContractTypeCell />', () => {
18+
it('should render correct icon and contract type display name for passed type', () => {
19+
render(<ContractTypeCell {...mock_props} />);
20+
21+
expect(screen.getByText(/vanillalongcall/i)).toBeInTheDocument();
22+
expect(screen.getByText('Call')).toBeInTheDocument();
23+
});
24+
25+
it('should render specific icon with postfix "_barrier" if is_high_low === true and it is not Vanilla contract', () => {
26+
render(<ContractTypeCell {...mock_props} is_high_low type={CONTRACT_TYPES.LB_CALL} />);
27+
28+
expect(screen.getByText(/_barrier/i)).toBeInTheDocument();
29+
});
30+
31+
it('should render specific contract type display name for Multipliers', () => {
32+
render(<ContractTypeCell {...mock_props} is_multipliers type={CONTRACT_TYPES.MULTIPLIER.DOWN} />);
33+
34+
expect(screen.getByText('Multipliers')).toBeInTheDocument();
35+
expect(screen.queryByText('Up')).not.toBeInTheDocument();
36+
});
37+
38+
it('should render specific contract type display name for Turbos', () => {
39+
render(<ContractTypeCell {...mock_props} is_turbos type={CONTRACT_TYPES.TURBOS.LONG} />);
40+
41+
expect(screen.getByText('Turbos')).toBeInTheDocument();
42+
expect(screen.queryByText('Up')).not.toBeInTheDocument();
43+
});
44+
45+
it('should not render contract type display name if type is invalid', () => {
46+
const mock_trade_type = 'invalid';
47+
render(<ContractTypeCell {...mock_props} type={mock_trade_type} />);
48+
49+
expect(screen.queryByText(mock_trade_type)).not.toBeInTheDocument();
50+
});
51+
52+
it('should render displayed trade parameters content if displayed_trade_param was passed', () => {
53+
const mock_trade_param = 'Displayed trade parameters';
54+
render(<ContractTypeCell {...mock_props} displayed_trade_param={mock_trade_param} />);
55+
56+
expect(screen.getByText(mock_trade_param)).toBeInTheDocument();
57+
});
58+
});

packages/components/src/components/contract-card/contract-card-items/contract-card-header.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import {
77
getGrowthRatePercentage,
88
isAccumulatorContract,
99
isSmartTraderContract,
10-
isLookBacksContract,
1110
isBot,
1211
isMobile,
1312
isTurbosContract,
13+
isMultiplierContract,
1414
getLocalizedTurbosSubtype,
1515
} from '@deriv/shared';
1616
import ContractTypeCell from './contract-type-cell';
@@ -70,13 +70,16 @@ const ContractCardHeader = ({
7070
const is_smarttrader_contract = isSmartTraderContract(contract_type);
7171
const is_mobile = isMobile();
7272
const is_turbos = isTurbosContract(contract_type);
73-
const is_lookbacks = isLookBacksContract(contract_type);
73+
const is_multipliers = isMultiplierContract(contract_type);
74+
const is_high_low = isHighLow({ shortcode });
7475

7576
const contract_type_list_info = React.useMemo(
7677
() => [
7778
{
78-
is_param_displayed: multiplier && !is_lookbacks,
79-
displayed_param: `x${multiplier}`,
79+
is_param_displayed: is_multipliers,
80+
displayed_param: `${getContractTypeDisplay(contract_type ?? '', {
81+
isHighLow: is_high_low,
82+
})} x${multiplier}`.trim(),
8083
},
8184
{
8285
is_param_displayed: is_accumulator,
@@ -87,7 +90,8 @@ const ContractCardHeader = ({
8790
displayed_param: getLocalizedTurbosSubtype(contract_type),
8891
},
8992
],
90-
[multiplier, growth_rate, is_accumulator, is_turbos, is_lookbacks, contract_type]
93+
// eslint-disable-next-line react-hooks/exhaustive-deps
94+
[contract_type, growth_rate, multiplier, is_accumulator, is_multipliers, is_turbos, is_high_low]
9195
);
9296

9397
const displayed_trade_param =
@@ -100,9 +104,8 @@ const ContractCardHeader = ({
100104
className={classNames('dc-contract-card__grid', 'dc-contract-card__grid-underlying-trade', {
101105
'dc-contract-card__grid-underlying-trade--trader': !is_bot,
102106
'dc-contract-card__grid-underlying-trade--trader--accumulator': !is_mobile && is_accumulator,
103-
[`dc-contract-card__grid-underlying-trade--trader--${
104-
is_accumulator ? 'accumulator' : 'turbos'
105-
}-sold`]: (is_accumulator || is_turbos) && is_sold,
107+
'dc-contract-card__grid-underlying-trade--trader--sold':
108+
(is_accumulator || is_turbos || is_multipliers) && is_sold,
106109
})}
107110
>
108111
<div
@@ -135,7 +138,9 @@ const ContractCardHeader = ({
135138
<ContractTypeCell
136139
displayed_trade_param={displayed_trade_param}
137140
getContractTypeDisplay={getContractTypeDisplay}
138-
is_high_low={isHighLow({ shortcode })}
141+
is_high_low={is_high_low}
142+
is_multipliers={is_multipliers}
143+
is_turbos={is_turbos}
139144
type={contract_type}
140145
/>
141146
</div>

packages/components/src/components/contract-card/contract-card-items/contract-type-cell.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import { isVanillaContract, isSmartTraderContract, isLookBacksContract } from '@
77
export type TContractTypeCellProps = {
88
getContractTypeDisplay: TGetContractTypeDisplay;
99
is_high_low: boolean;
10-
multiplier?: number;
10+
is_multipliers?: boolean;
11+
is_turbos?: boolean;
1112
type?: string;
1213
displayed_trade_param?: React.ReactNode;
1314
};
@@ -16,6 +17,8 @@ const ContractTypeCell = ({
1617
displayed_trade_param,
1718
getContractTypeDisplay,
1819
is_high_low,
20+
is_multipliers,
21+
is_turbos,
1922
type = '',
2023
}: TContractTypeCellProps) => (
2124
<div className='dc-contract-type'>
@@ -30,9 +33,13 @@ const ContractTypeCell = ({
3033
className={classNames('dc-contract-type__type-label', {
3134
'dc-contract-type__type-label--smarttrader-contract': isSmartTraderContract(type),
3235
'dc-contract-type__type-label--lookbacks-contract': isLookBacksContract(type),
36+
'dc-contract-type__type-label--multipliers': is_multipliers,
3337
})}
3438
>
35-
<div>{getContractTypeDisplay(type, is_high_low) || ''}</div>
39+
<div>
40+
{getContractTypeDisplay(type, { isHighLow: is_high_low, showMainTitle: is_multipliers || is_turbos }) ||
41+
''}
42+
</div>
3643
{displayed_trade_param && (
3744
<div className='dc-contract-type__type-label-trade-param'>{displayed_trade_param}</div>
3845
)}

packages/components/src/components/contract-card/contract-card.scss

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,13 @@
4444
&--trader {
4545
grid-template-columns: 1.2fr 1fr;
4646

47-
&--accumulator,
48-
&--turbos {
47+
&--accumulator {
4948
display: flex;
5049
grid-gap: 1px;
51-
&-sold {
52-
padding-top: 1rem;
53-
}
50+
}
51+
52+
&--sold {
53+
padding-top: 1rem;
5454
}
5555
}
5656
&--mobile {
@@ -641,7 +641,8 @@
641641
/*rtl:ignore*/
642642
text-align: left;
643643

644-
&--smarttrader-contract {
644+
&--smarttrader-contract,
645+
&--multipliers {
645646
width: 7rem;
646647
@include mobile {
647648
width: 9rem;

packages/components/src/components/types/common.types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React from 'react';
22
import { getCardLabels, getContractTypeDisplay } from '@deriv/shared';
3+
import { TContractOptions } from '@deriv/shared/src/utils/contract/contract-types';
34

45
export type TGenericObjectType = {
56
[key: string]: React.ReactNode;
67
};
78
export type TGetCardLables = () => ReturnType<typeof getCardLabels>;
89

9-
export type TGetContractTypeDisplay = (type: string, is_high_low: boolean) => ReturnType<typeof getContractTypeDisplay>;
10+
export type TGetContractTypeDisplay = (
11+
type: string,
12+
options: TContractOptions
13+
) => ReturnType<typeof getContractTypeDisplay>;
1014

1115
export type TItem = {
1216
id: string;

packages/components/stories/contract-card/statics/contract.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,11 @@ export const getSupportedContracts = is_high_low => ({
183183
position: 'bottom',
184184
},
185185
TURBOSLONG: {
186-
button_name: 'Up',
187-
name: 'Turbos',
186+
name: 'Up',
188187
position: 'top',
189188
},
190189
TURBOSSHORT: {
191-
button_name: 'Down',
192-
name: 'Turbos',
190+
name: 'Down',
193191
position: 'bottom',
194192
},
195193
RUNHIGH: {

packages/core/src/Stores/notification-store.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
isHighLow,
2222
isMobile,
2323
isMultiplierContract,
24-
isTurbosContract,
2524
LocalStore,
2625
routes,
2726
unique,
@@ -201,16 +200,17 @@ export default class NotificationStore extends BaseStore {
201200
} = contract_info;
202201
const id = `${contract_id}_${status}`;
203202
if (this.trade_notifications.some(({ id: notification_id }) => notification_id === id)) return;
204-
const contract_main_title = getTradeTypeName(contract_type, isHighLow({ shortcode }), false, true);
203+
const contract_main_title = getTradeTypeName(contract_type, {
204+
isHighLow: isHighLow({ shortcode }),
205+
showMainTitle: true,
206+
});
205207
this.trade_notifications.push({
206208
id,
207209
buy_price,
208210
contract_id,
209-
contract_type: `${contract_main_title} ${getTradeTypeName(
210-
contract_type,
211-
isHighLow({ shortcode }),
212-
isTurbosContract(contract_type)
213-
)}`.trim(),
211+
contract_type: `${contract_main_title} ${getTradeTypeName(contract_type, {
212+
isHighLow: isHighLow({ shortcode }),
213+
})}`.trim(),
214214
currency,
215215
profit: isMultiplierContract(contract_type) && !isNaN(profit) ? getTotalProfit(contract_info) : profit,
216216
status,

packages/reports/src/Components/market-symbol-icon-row.tsx

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ const MarketSymbolIconRow = ({
2525
const should_show_category_icon = typeof payload.shortcode === 'string';
2626
const info_from_shortcode = extractInfoFromShortcode(payload.shortcode);
2727
const is_high_low = isHighLow({ shortcode_info: info_from_shortcode });
28-
const category_label = getTradeTypeName(
29-
info_from_shortcode.category as string,
30-
is_high_low,
31-
has_full_contract_title
32-
);
28+
const category_label = getTradeTypeName(info_from_shortcode.category, {
29+
isHighLow: is_high_low,
30+
showButtonName: has_full_contract_title,
31+
});
32+
const hover_message = `${getTradeTypeName(info_from_shortcode.category, {
33+
isHighLow: is_high_low,
34+
showMainTitle: true,
35+
})} ${category_label}`.trim();
36+
3337
if (should_show_category_icon && info_from_shortcode) {
3438
return (
3539
<div
@@ -63,7 +67,7 @@ const MarketSymbolIconRow = ({
6367
classNameTarget='category-type-icon__popover'
6468
classNameBubble='category-type-icon__popover-bubble'
6569
alignment='top'
66-
message={category_label}
70+
message={hover_message}
6771
is_bubble_hover_enabled
6872
disable_target_icon
6973
>

packages/shared/src/utils/constants/__tests__/contract.spec.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,19 +92,47 @@ describe('getContractConfig', () => {
9292

9393
describe('getContractTypeDisplay', () => {
9494
it('should return a specific button name if show_button_name === true and contract_config has a button_name field', () => {
95-
expect(getContractTypeDisplay(CONTRACT_TYPES.ACCUMULATOR, false, true)).toEqual('Buy');
95+
expect(getContractTypeDisplay(CONTRACT_TYPES.ACCUMULATOR, { showButtonName: true })).toEqual('Buy');
9696
});
9797
it('should return a specific contract name if show_button_name === false but contract_config has a button_name field', () => {
9898
expect(getContractTypeDisplay(CONTRACT_TYPES.ACCUMULATOR)).toEqual('Accumulators');
9999
});
100100
it('should return a specific contract name if show_button_name === true but contract_config has no button_name field', () => {
101-
expect(getContractTypeDisplay(CONTRACT_TYPES.MULTIPLIER.DOWN, true, true)).toEqual('Down');
101+
expect(
102+
getContractTypeDisplay(CONTRACT_TYPES.MULTIPLIER.DOWN, { isHighLow: true, showButtonName: true })
103+
).toEqual('Down');
102104
});
103105
it('should return an empty string if show_button_name === false and contract_config has no name field', () => {
104-
expect(getContractTypeDisplay('TEST', true, false)).toBe('');
106+
expect(getContractTypeDisplay('TEST', { isHighLow: true })).toBe('');
105107
});
106108
it('should return an empty string if show_button_name === true and contract_config has no name field and no button_name', () => {
107-
expect(getContractTypeDisplay('TEST', true, true)).toBe('');
109+
expect(getContractTypeDisplay('TEST', { isHighLow: true, showButtonName: true })).toBe('');
110+
});
111+
it('should return main title for contracts which have such field if show_main_title is true', () => {
112+
expect(
113+
getContractTypeDisplay(CONTRACT_TYPES.MULTIPLIER.DOWN, {
114+
isHighLow: true,
115+
showMainTitle: true,
116+
})
117+
).toBe('Multipliers');
118+
expect(
119+
getContractTypeDisplay(CONTRACT_TYPES.TURBOS.LONG, {
120+
showMainTitle: true,
121+
})
122+
).toBe('Turbos');
123+
expect(
124+
getContractTypeDisplay(CONTRACT_TYPES.VANILLA.CALL, {
125+
showMainTitle: true,
126+
})
127+
).toBe('Vanillas');
128+
});
129+
it('should not return main title for contracts which have such field but show_main_title is false', () => {
130+
expect(getContractTypeDisplay(CONTRACT_TYPES.TURBOS.LONG)).not.toBe('Turbos');
131+
expect(getContractTypeDisplay(CONTRACT_TYPES.VANILLA.CALL)).not.toBe('Vanillas');
132+
expect(getContractTypeDisplay(CONTRACT_TYPES.MULTIPLIER.DOWN)).not.toBe('Multipliers');
133+
});
134+
it('should not return main title for contracts which have not such field if show_main_title is true', () => {
135+
expect(getContractTypeDisplay(CONTRACT_TYPES.FALL, { showMainTitle: true })).toBeFalsy();
108136
});
109137
});
110138

packages/shared/src/utils/constants/contract.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React from 'react';
33
import { localize } from '@deriv/translations';
44

55
import { shouldShowCancellation, shouldShowExpiration, CONTRACT_TYPES, TRADE_TYPES } from '../contract';
6+
import { TContractOptions } from '../contract/contract-types';
67
import { cloneObject } from '../object';
78
import { LocalStore } from '../storage';
89

@@ -37,6 +38,7 @@ type TContractConfig = {
3738
feature_flag?: string;
3839
name: React.ReactNode;
3940
position: string;
41+
main_title?: JSX.Element;
4042
};
4143

4244
type TGetSupportedContracts = keyof ReturnType<typeof getSupportedContracts>;
@@ -485,14 +487,12 @@ export const getSupportedContracts = (is_high_low?: boolean) =>
485487
main_title: localize('Multipliers'),
486488
},
487489
[CONTRACT_TYPES.TURBOS.LONG]: {
488-
name: localize('Turbos'),
489-
button_name: localize('Up'),
490+
name: localize('Up'),
490491
position: 'top',
491492
main_title: localize('Turbos'),
492493
},
493494
[CONTRACT_TYPES.TURBOS.SHORT]: {
494-
name: localize('Turbos'),
495-
button_name: localize('Down'),
495+
name: localize('Down'),
496496
position: 'bottom',
497497
main_title: localize('Turbos'),
498498
},
@@ -605,13 +605,12 @@ export const getContractConfig = (is_high_low?: boolean) => ({
605605
...getUnsupportedContracts(),
606606
});
607607

608-
/*
609-
// TODO we can combine getContractTypeDisplay and getContractTypePosition functions.
610-
the difference between these two functions is just the property they return. (name/position)
611-
*/
612-
export const getContractTypeDisplay = (type: string, is_high_low = false, show_button_name = false) => {
613-
const contract_config = getContractConfig(is_high_low)[type as TGetSupportedContracts] as TContractConfig;
614-
return (show_button_name && contract_config?.button_name) || contract_config?.name || '';
608+
export const getContractTypeDisplay = (type: string, options: TContractOptions = {}) => {
609+
const { isHighLow = false, showButtonName = false, showMainTitle = false } = options;
610+
611+
const contract_config = getContractConfig(isHighLow)[type as TGetSupportedContracts] as TContractConfig;
612+
if (showMainTitle) return contract_config?.main_title ?? '';
613+
return (showButtonName && contract_config?.button_name) || contract_config?.name || '';
615614
};
616615

617616
export const getContractTypeFeatureFlag = (type: string, is_high_low = false) => {

0 commit comments

Comments
 (0)