Skip to content

Commit 684872d

Browse files
authored
DTRA / Kate / DTRA-930 / Update Trade Type section modal behaviour (#13773)
* refactor: improve collapsible behaviour * fix: timeout issue * refactor: add tests * refactor: apply usability suggestions * refactor: increase clickable area * refactor: add tests
1 parent 1487110 commit 684872d

File tree

6 files changed

+56
-18
lines changed

6 files changed

+56
-18
lines changed

packages/components/src/components/collapsible/__tests__/collapsible.spec.tsx

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import React from 'react';
22
import { render, screen } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
34
import Collapsible from '../collapsible';
45

5-
const className = 'dc-collapsible--has-collapsible-btn';
6-
const testId = 'dt_collapsible';
6+
const collapsibleButtonClassName = 'dc-collapsible--has-collapsible-btn';
7+
const expandedClassName = 'dc-collapsible--is-expanded';
8+
const collapsedClassName = 'dc-collapsible--is-collapsed';
9+
const collapsibleTestId = 'dt_collapsible';
10+
const handleButtonTestId = 'dt_handle_button';
11+
712
const mockedDefaultProps: React.ComponentProps<typeof Collapsible> = {
813
children: <div data-collapsible={true}>Children Component</div>,
914
onClick: jest.fn(),
@@ -14,7 +19,7 @@ describe('<Collapsible/>', () => {
1419
it('should render component with specific className if passed children have data-collapsible = true', () => {
1520
render(<Collapsible {...mockedDefaultProps} />);
1621

17-
expect(screen.getByTestId(testId)).toHaveClass(className);
22+
expect(screen.getByTestId(collapsibleTestId)).toHaveClass(collapsibleButtonClassName);
1823
});
1924

2025
it('should render component without specific className if passed children have no data-collapsible = true', () => {
@@ -24,7 +29,7 @@ describe('<Collapsible/>', () => {
2429
</Collapsible>
2530
);
2631

27-
expect(screen.getByTestId(testId)).not.toHaveClass(className);
32+
expect(screen.getByTestId(collapsibleTestId)).not.toHaveClass(collapsibleButtonClassName);
2833
});
2934

3035
it('should render component with specific className if passed children have no data-collapsible = true, but is_non_interactive is true', () => {
@@ -34,6 +39,18 @@ describe('<Collapsible/>', () => {
3439
</Collapsible>
3540
);
3641

37-
expect(screen.getByTestId(testId)).toHaveClass(className);
42+
expect(screen.getByTestId(collapsibleTestId)).toHaveClass(collapsibleButtonClassName);
43+
});
44+
45+
it('should change className if user clicks on handle button', () => {
46+
render(<Collapsible {...mockedDefaultProps} />);
47+
48+
expect(screen.getByTestId(collapsibleTestId)).toHaveClass(expandedClassName);
49+
expect(screen.queryByTestId(collapsibleTestId)).not.toHaveClass(collapsedClassName);
50+
51+
userEvent.click(screen.getByTestId(handleButtonTestId));
52+
53+
expect(screen.getByTestId(collapsibleTestId)).toHaveClass(collapsedClassName);
54+
expect(screen.queryByTestId(collapsibleTestId)).not.toHaveClass(expandedClassName);
3855
});
3956
});

packages/components/src/components/collapsible/arrow-button.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ const ArrowButton = ({
100100
})}
101101
onClick={toggleExpand}
102102
onKeyDown={toggleExpand}
103+
data-testid='dt_handle_button'
103104
>
104105
{show_collapsible_button && icon_arrow}
105106
</div>

packages/components/src/components/collapsible/collapsible.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ type TCollapsible = {
1414
};
1515

1616
const swipe_config = {
17-
delta: 100,
17+
delta: 10,
1818
trackTouch: true,
1919
trackMouse: true,
2020
};
@@ -58,8 +58,8 @@ const Collapsible = ({
5858
);
5959

6060
const swipe_handlers = useSwipeable({
61-
onSwipedUp: () => !is_open && should_show_collapsible && expand(true),
62-
onSwipedDown: () => is_open && should_show_collapsible && expand(false),
61+
onSwipedUp: () => !is_open && should_show_collapsible && toggleExpand(),
62+
onSwipedDown: () => is_open && should_show_collapsible && toggleExpand(),
6363
...swipe_config,
6464
});
6565

packages/trader/src/Modules/Trading/Components/Form/ContractType/contract-type-widget.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,14 @@ const ContractTypeWidget = observer(
4141
const [selected_category, setSelectedCategory] = React.useState<TList['key']>('All');
4242
const [search_query, setSearchQuery] = React.useState('');
4343
const [item, setItem] = React.useState<TContractType | null>(null);
44+
const animation_timeout = React.useRef<ReturnType<typeof setTimeout>>();
4445

4546
const handleClickOutside = React.useCallback(
4647
(event: MouseEvent) => {
4748
if (is_mobile) return;
4849
if (wrapper_ref && !wrapper_ref.current?.contains(event.target as Node) && is_dialog_open) {
4950
setDialogVisibility(false);
50-
setInfoDialogVisibility(false);
5151
setItem({ ...item, value });
52-
setHideBackButton(false);
5352
}
5453
},
5554
[item, value, is_dialog_open, is_mobile]
@@ -58,6 +57,12 @@ const ContractTypeWidget = observer(
5857
const getCategoryName = (clicked_item: TContractType) =>
5958
getContractTypes(list_with_category(), clicked_item)?.find(item => item.value === clicked_item.value)?.text;
6059

60+
React.useEffect(() => {
61+
return () => {
62+
clearTimeout(animation_timeout.current);
63+
};
64+
}, []);
65+
6166
React.useEffect(() => {
6267
document.addEventListener('mousedown', handleClickOutside);
6368
return () => {
@@ -127,10 +132,6 @@ const ContractTypeWidget = observer(
127132
});
128133
};
129134

130-
const handleVisibility = () => {
131-
setDialogVisibility(!is_dialog_open);
132-
};
133-
134135
const onSearchBlur = () => {
135136
if (search_query) {
136137
Analytics.trackEvent('ce_trade_types_form', {
@@ -142,8 +143,10 @@ const ContractTypeWidget = observer(
142143

143144
const onWidgetClick = () => {
144145
setDialogVisibility(!is_dialog_open);
145-
setHideBackButton(false);
146-
setInfoDialogVisibility(false);
146+
animation_timeout.current = setTimeout(() => {
147+
setHideBackButton(false);
148+
setInfoDialogVisibility(false);
149+
}, 200);
147150
setItem({ ...item, value });
148151
};
149152

@@ -155,8 +158,14 @@ const ContractTypeWidget = observer(
155158
const onChangeInput = (searchQueryItem: string) => setSearchQuery(searchQueryItem);
156159

157160
const handleLearnMore = () => {
158-
handleVisibility();
159-
handleInfoClick(item || { value });
161+
setDialogVisibility(true);
162+
setInfoDialogVisibility(true);
163+
setItem(item || { value });
164+
Analytics.trackEvent('ce_trade_types_form', {
165+
action: 'info_open',
166+
tab_name: selected_category,
167+
trade_type_name: getCategoryName(item || { value }),
168+
});
160169
setHideBackButton(true);
161170
};
162171

packages/trader/src/sass/app/_common/components/contract-type-widget.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,14 @@
139139
top: 1.5rem;
140140
background-color: transparent;
141141
margin: unset;
142+
143+
&:before {
144+
content: '';
145+
display: block;
146+
height: 3.5rem;
147+
width: 14rem;
148+
position: absolute;
149+
bottom: -1rem;
150+
}
142151
}
143152
}

packages/trader/src/sass/app/modules/trading-mobile.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
@include mobile {
22
/** @define dc-collapsible; weak */
33
.dc-collapsible {
4+
touch-action: pan-x;
5+
46
&:before {
57
content: '';
68
position: absolute;

0 commit comments

Comments
 (0)