Skip to content

Commit

Permalink
[DTRA] Maryia/DTRA-1546/fix: [V2] style & animation for Digits Curren…
Browse files Browse the repository at this point in the history
…t spot price + active_symbols request (deriv-com#16225)

* fix: styles & animation for current spot for digit trade types

* fix: active_symbols call for rise/fall and higher/lower

* fix: useActiveSymbols usage

* fix: active_symbols call with relevant barrier_category + error handling same like in prod
  • Loading branch information
maryia-deriv authored Jul 30, 2024
1 parent fd346e1 commit bd32ef2
Show file tree
Hide file tree
Showing 12 changed files with 122 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type TActiveSymbolsList = {
};

const ActiveSymbolsList = observer(({ isOpen, setIsOpen }: TActiveSymbolsList) => {
const { default_symbol } = useActiveSymbols({});
const { default_symbol } = useActiveSymbols();

const [isSearching, setIsSearching] = useState(false);
const [selectedSymbol, setSelectedSymbol] = useState(default_symbol);
Expand Down
21 changes: 21 additions & 0 deletions packages/trader/src/AppV2/Components/CurrentSpot/current-spot.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
align-items: center;

.current-spot {
position: relative;
display: flex;
gap: var(--core-spacing-100);

Expand Down Expand Up @@ -71,20 +72,28 @@
}
}
}
&--winning,
&--won {
border: var(--core-borderWidth-75) solid var(--core-color-solid-green-700);

.current-spot__last-digit {
color: var(--core-color-solid-green-700);
}
}
&--losing,
&--lost {
border: var(--core-borderWidth-75) solid var(--core-color-solid-red-700);

.current-spot__last-digit {
color: var(--core-color-solid-red-700);
}
}
&--won {
background-color: var(--core-color-solid-green-100);
}
&--lost {
background-color: var(--core-color-solid-red-100);
}
&--has-contract {
.current-spot {
&__display {
Expand All @@ -104,4 +113,16 @@
}
}
}
&--enter-from-right {
.current-spot {
animation: enter-from-right var(--motion-duration-snappy) ease-out;

@keyframes enter-from-right {
from {
transform: translateX(-50%);
margin-inline-start: 100%;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ const CurrentSpot = observer(() => {
const { tick_data, symbol } = useTraderStore();
const { contract_id, entry_tick, date_start, contract_type, tick_stream, underlying } = contract_info;
const prev_contract_id = usePrevious(contract_id);
const last_contract_ticks = last_contract.contract_info?.tick_stream?.length;
const prev_last_contract_ticks = usePrevious(last_contract_ticks);

let tick = tick_data;

Expand Down Expand Up @@ -86,7 +88,7 @@ const CurrentSpot = observer(() => {
const should_show_tick_count = has_contract && has_relevant_tick_data;
const should_enter_from_left =
!prev_contract?.contract_info ||
!!(is_prev_contract_elapsed && last_contract.contract_info?.tick_stream?.length === 1);
!!(is_prev_contract_elapsed && last_contract_ticks === 1 && !prev_last_contract_ticks);

const setNewData = React.useCallback(() => {
setDisplayedTick(current_tick);
Expand Down Expand Up @@ -128,8 +130,11 @@ const CurrentSpot = observer(() => {
'trade__current-spot',
should_show_tick_count && 'trade__current-spot--has-contract',
should_show_tick_count && should_enter_from_left && 'trade__current-spot--enter-from-left',
(is_won || (has_open_contract && is_winning)) && 'trade__current-spot--won',
(is_lost || (has_open_contract && !is_winning)) && 'trade__current-spot--lost'
!should_show_tick_count && is_contract_elapsed && 'trade__current-spot--enter-from-right',
has_open_contract && is_winning && 'trade__current-spot--winning',
is_won && 'trade__current-spot--won',
has_open_contract && !is_winning && 'trade__current-spot--losing',
is_lost && 'trade__current-spot--lost'
)}
>
{tick && has_relevant_tick_data && displayed_spot ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type TMarketCategories = {

const MarketCategories = forwardRef(
({ selectedSymbol, setSelectedSymbol, setIsOpen, isOpen }: TMarketCategories, ref: Ref<HTMLDivElement>) => {
const { activeSymbols } = useActiveSymbols({});
const { activeSymbols } = useActiveSymbols();
const categorizedSymbols = categorizeSymbols(activeSymbols);
return (
<React.Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Skeleton } from '@deriv/components';

const MarketSelector = observer(() => {
const [isOpen, setIsOpen] = useState(false);
const { default_symbol, activeSymbols } = useActiveSymbols({});
const { default_symbol, activeSymbols } = useActiveSymbols();
const { symbol: storeSymbol, tick_data } = useTraderStore();
const currentSymbol = activeSymbols.find(
symbol => symbol.symbol === storeSymbol || symbol.symbol === default_symbol
Expand Down
2 changes: 1 addition & 1 deletion packages/trader/src/AppV2/Containers/Chart/trade-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const TradeChart = observer(() => {
const { all_positions } = portfolio;
const { is_chart_countdown_visible, is_chart_layout_default, is_dark_mode_on, is_positions_drawer_on } = ui;
const { current_language, is_socket_opened } = common;
const { default_symbol, activeSymbols: active_symbols } = useActiveSymbols({});
const { default_symbol, activeSymbols: active_symbols } = useActiveSymbols();
const {
barriers_flattened: extra_barriers,
chartStateChange,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('useActiveSymbols', () => {
it('should fetch active symbols when not logged in', async () => {
// Need the opposite return value (true) of usePrevious(is_logged_in) for fetchActiveSymbols to trigger:
(usePrevious as jest.Mock).mockReturnValueOnce(true).mockReturnValueOnce(TRADE_TYPES.RISE_FALL);
const { result } = renderHook(() => useActiveSymbols({ barrier_category: [] }), {
const { result } = renderHook(() => useActiveSymbols(), {
wrapper,
});
await waitFor(() => {
Expand All @@ -74,7 +74,7 @@ describe('useActiveSymbols', () => {
mocked_store.client.is_logged_in = true;
mocked_store.modules.trade.active_symbols = logged_in_active_symbols;
mocked_store.modules.trade.has_symbols_for_v2 = true;
const { result } = renderHook(() => useActiveSymbols({ barrier_category: [] }), {
const { result } = renderHook(() => useActiveSymbols(), {
wrapper,
});
await waitFor(() => {
Expand All @@ -83,7 +83,7 @@ describe('useActiveSymbols', () => {
});
it('should set correct default_symbol and call correct onChange when store symbol is not set', async () => {
(usePrevious as jest.Mock).mockReturnValueOnce(true).mockReturnValueOnce(TRADE_TYPES.RISE_FALL);
const { result } = renderHook(() => useActiveSymbols({ barrier_category: [] }), {
const { result } = renderHook(() => useActiveSymbols(), {
wrapper,
});

Expand All @@ -97,7 +97,7 @@ describe('useActiveSymbols', () => {
it('should set correct default_symbol and call correct onChange when store symbol is set', async () => {
(usePrevious as jest.Mock).mockReturnValueOnce(true).mockReturnValueOnce(TRADE_TYPES.RISE_FALL);
mocked_store.modules.trade.symbol = 'test';
const { result } = renderHook(() => useActiveSymbols({ barrier_category: [] }), {
const { result } = renderHook(() => useActiveSymbols(), {
wrapper,
});

Expand All @@ -112,7 +112,7 @@ describe('useActiveSymbols', () => {
(usePrevious as jest.Mock).mockReturnValueOnce(false).mockReturnValueOnce(TRADE_TYPES.RISE_FALL);
mocked_store.modules.trade.active_symbols = [{ symbol: 'fromStore' }];
mocked_store.modules.trade.has_symbols_for_v2 = true;
const { result } = renderHook(() => useActiveSymbols({ barrier_category: [] }), {
const { result } = renderHook(() => useActiveSymbols(), {
wrapper,
});

Expand Down
38 changes: 23 additions & 15 deletions packages/trader/src/AppV2/Hooks/useActiveSymbols.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { useState, useEffect, useCallback, useRef } from 'react';
import { WS, getContractTypesConfig, pickDefaultSymbol } from '@deriv/shared';
import { TRADE_TYPES, WS, getContractTypesConfig, pickDefaultSymbol } from '@deriv/shared';
import { useStore } from '@deriv/stores';
import { localize } from '@deriv/translations';
import { ActiveSymbols } from '@deriv/api-types';
import { useTraderStore } from 'Stores/useTraderStores';
import { usePrevious } from '@deriv/components';
import { useTraderStore } from 'Stores/useTraderStores';
import { ContractType } from 'Stores/Modules/Trading/Helpers/contract-type';

type TUseActiveSymbols = {
barrier_category?: string[];
};
//TODO: barrier_category needs to come from trade-store after calling contracts_for
const useActiveSymbols = ({ barrier_category = [] }: TUseActiveSymbols) => {
const useActiveSymbols = () => {
const [activeSymbols, setActiveSymbols] = useState<ActiveSymbols | []>([]);
const { client } = useStore();
const { client, common } = useStore();
const { is_logged_in } = client;
const { showError } = common;
const {
active_symbols: symbols_from_store,
contract_type,
Expand All @@ -30,10 +29,19 @@ const useActiveSymbols = ({ barrier_category = [] }: TUseActiveSymbols) => {
async (trade_type = '') => {
let response;

const trade_types_with_barrier_category = [
TRADE_TYPES.RISE_FALL,
TRADE_TYPES.RISE_FALL_EQUAL,
TRADE_TYPES.HIGH_LOW,
] as string[];
const barrier_category = ContractType.getBarrierCategory(trade_type).barrier_category;

const request = {
active_symbols: 'brief',
contract_type: getContractTypesConfig()[trade_type]?.trade_types ?? [],
barrier_category,
...(trade_types_with_barrier_category.includes(trade_type) && barrier_category
? { barrier_category: [barrier_category] }
: {}),
};

if (is_logged_in) {
Expand All @@ -42,20 +50,20 @@ const useActiveSymbols = ({ barrier_category = [] }: TUseActiveSymbols) => {
response = await WS.activeSymbols(request);
}

const { active_symbols, error } = response;

setActiveSymbolsV2(active_symbols);

if (!active_symbols?.length || error) {
const { active_symbols = [], error } = response;
if (error) {
showError({ message: localize('Trading is unavailable at this time.') });
} else if (!active_symbols?.length) {
setActiveSymbols([]);
} else {
setActiveSymbols(active_symbols);
setActiveSymbolsV2(active_symbols);
default_symbol_ref.current = symbol || (await pickDefaultSymbol(active_symbols)) || '1HZ100V';
onChange({ target: { name: 'symbol', value: default_symbol_ref.current } });
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[barrier_category, is_logged_in, symbol]
[is_logged_in, symbol]
);
useEffect(() => {
const is_logged_in_changed = previous_logged_in !== undefined && previous_logged_in !== is_logged_in;
Expand Down
2 changes: 1 addition & 1 deletion packages/trader/src/AppV2/Hooks/useGetFavoriteSymbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import sortSymbols from 'AppV2/Utils/sort-symbols-utils';
import { useModulesStore } from 'Stores/useModulesStores';

export const useGetFavoriteSymbols = () => {
const { activeSymbols } = useActiveSymbols({});
const { activeSymbols } = useActiveSymbols();
const { markets } = useModulesStore();
const { favoriteSymbols } = markets;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import useActiveSymbols from 'AppV2/Hooks/useActiveSymbols';
import sortSymbols from 'AppV2/Utils/sort-symbols-utils';

export const useGetSymbolSearchResults = (searchValue: string) => {
const { activeSymbols } = useActiveSymbols({});
const { activeSymbols } = useActiveSymbols();

const searchResults = useMemo(() => {
if (searchValue.trim() === '') return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import ServerTime from '_common/base/server_time';
import { ContractType } from '../contract-type';
import moment from 'moment';
import { mockStore } from '@deriv/stores';
import { TRADE_TYPES } from '@deriv/shared';

jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
Expand Down Expand Up @@ -63,6 +64,43 @@ jest.mock('@deriv/shared', () => ({
submarket: 'major_pairs',
underlying_symbol: 'frxAUDJPY',
},
{
barrier_category: 'euro_atm',
barriers: 0,
contract_category: 'callputequal',
contract_category_display: 'Rise/Fall Equal',
contract_display: 'Higher',
contract_type: 'CALLE',
default_stake: 10,
exchange_name: 'FOREX',
expiry_type: 'daily',
market: 'forex',
max_contract_duration: '365d',
min_contract_duration: '1d',
sentiment: 'up',
start_type: 'spot',
submarket: 'major_pairs',
underlying_symbol: 'frxAUDJPY',
},
{
barrier: '101.389',
barrier_category: 'euro_non_atm',
barriers: 1,
contract_category: 'callput',
contract_category_display: 'Up/Down',
contract_display: 'Higher',
contract_type: 'CALL',
default_stake: 10,
exchange_name: 'FOREX',
expiry_type: 'daily',
market: 'forex',
max_contract_duration: '365d',
min_contract_duration: '1d',
sentiment: 'up',
start_type: 'spot',
submarket: 'major_pairs',
underlying_symbol: 'frxAUDJPY',
},
],
close: 1701215999,
feed_license: 'realtime',
Expand Down Expand Up @@ -565,3 +603,17 @@ describe('ContractType.getContractCategories', () => {
expect(result.non_available_contract_types_list).not.toEqual({});
});
});
describe('ContractType.getBarrierCategory', () => {
it('should return a correct barrier_category for Rise/Fall', () => {
const { barrier_category } = ContractType.getBarrierCategory(TRADE_TYPES.RISE_FALL);
expect(barrier_category).toEqual('euro_atm');
});
it('should return a correct barrier_category for Rise/Fall Equal', () => {
const { barrier_category } = ContractType.getBarrierCategory(TRADE_TYPES.RISE_FALL);
expect(barrier_category).toEqual('euro_atm');
});
it('should return a correct barrier_category for Higher/Lower', () => {
const { barrier_category } = ContractType.getBarrierCategory(TRADE_TYPES.HIGH_LOW);
expect(barrier_category).toEqual('euro_non_atm');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ type TConfig = ReturnType<typeof getContractTypesConfig>[string]['config'] & {
has_spot?: boolean;
durations?: ReturnType<typeof buildDurationConfig>;
trade_types?: { [key: string]: string };
barrier_category?: string;
barriers?: ReturnType<typeof buildBarriersConfig>;
forward_starting_dates?: ReturnType<typeof buildForwardStartingConfig>;
growth_rate_range?: number[];
Expand Down Expand Up @@ -130,6 +131,7 @@ export const ContractType = (() => {
config.durations = config.hide_duration ? undefined : buildDurationConfig(contract, config.durations);
config.trade_types = buildTradeTypesConfig(contract, config.trade_types);
config.barriers = buildBarriersConfig(contract, config.barriers);
config.barrier_category = contract.barrier_category as TConfig['barrier_category'];
config.barrier_choices = contract.barrier_choices as TConfig['barrier_choices'];
config.forward_starting_dates = buildForwardStartingConfig(contract, config.forward_starting_dates);
config.growth_rate_range = contract.growth_rate_range as TConfig['growth_rate_range'];
Expand Down Expand Up @@ -641,6 +643,10 @@ export const ContractType = (() => {
[],
});

const getBarrierCategory = (contract_type: string) => ({
barrier_category: getPropertyValue(available_contract_types, [contract_type, 'config', 'barrier_category']),
});

const getBarrierChoices = (contract_type: string, stored_barrier_choices = [] as string[]) => ({
barrier_choices: stored_barrier_choices.length
? stored_barrier_choices
Expand Down Expand Up @@ -696,6 +702,7 @@ export const ContractType = (() => {

return {
buildContractTypesConfig,
getBarrierCategory,
getBarriers,
getContractType,
getContractValues,
Expand Down

0 comments on commit bd32ef2

Please sign in to comment.