Skip to content

Commit 1d0a8c4

Browse files
committed
Merge branch 'master' into KYC-accounts-package-TS-migration--test-coverage/sprint-8
2 parents e2b2448 + 8f862fc commit 1d0a8c4

File tree

24 files changed

+667
-394
lines changed

24 files changed

+667
-394
lines changed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import React from 'react';
2+
import { screen, render } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
4+
import { isMobile, routes } from '@deriv/shared';
5+
import LanguageSettings from '../language-settings';
6+
import { mockStore, StoreProvider } from '@deriv/stores';
7+
8+
jest.mock('@deriv/shared', () => ({
9+
...jest.requireActual('@deriv/shared'),
10+
isMobile: jest.fn(() => false),
11+
}));
12+
13+
jest.mock('@deriv/translations', () => ({
14+
...jest.requireActual('@deriv/translations'),
15+
getAllowedLanguages: jest.fn(() => ({ lang_1: 'Test Lang 1', lang_2: 'Test Lang 2' })),
16+
}));
17+
18+
jest.mock('@deriv/components', () => ({
19+
...jest.requireActual('@deriv/components'),
20+
Icon: jest.fn(() => <div>Flag Icon</div>),
21+
}));
22+
23+
jest.mock('react-i18next', () => ({
24+
...jest.requireActual('react-i18next'),
25+
useTranslation: jest.fn(() => ({ i18n: { changeLanguage: jest.fn() } })),
26+
}));
27+
28+
jest.mock('react-router-dom', () => ({
29+
...jest.requireActual('react-router-dom'),
30+
Redirect: jest.fn(() => <div>Redirect</div>),
31+
}));
32+
33+
describe('LanguageSettings', () => {
34+
const mockRootStore = mockStore({
35+
common: {
36+
current_language: 'lang_1',
37+
},
38+
});
39+
40+
const renderLanguageSettings = () => {
41+
render(<LanguageSettings />, {
42+
wrapper: ({ children }) => <StoreProvider store={mockRootStore}>{children}</StoreProvider>,
43+
});
44+
};
45+
46+
it('should render LanguageSettings', () => {
47+
renderLanguageSettings();
48+
49+
expect(screen.getByText('Select Language')).toBeInTheDocument();
50+
51+
const flags_icons = screen.getAllByText('Flag Icon');
52+
const lang_1 = screen.getByText('Test Lang 1');
53+
const lang_2 = screen.getByText('Test Lang 2');
54+
55+
expect(flags_icons.length).toBe(2);
56+
expect(lang_1).toBeInTheDocument();
57+
expect(/(active)/i.test(lang_1.className)).toBeTruthy();
58+
expect(lang_2).toBeInTheDocument();
59+
expect(/(active)/i.test(lang_2.className)).toBeFalsy();
60+
});
61+
62+
it('should trigger language change', () => {
63+
renderLanguageSettings();
64+
65+
const lang_2 = screen.getByText('Test Lang 2');
66+
userEvent.click(lang_2);
67+
68+
expect(mockRootStore.common.changeSelectedLanguage).toHaveBeenCalled();
69+
});
70+
71+
it('should redirect for mobile', () => {
72+
(isMobile as jest.Mock).mockReturnValue(true);
73+
Object.defineProperty(window, 'location', {
74+
configurable: true,
75+
value: { pathname: routes.languages },
76+
});
77+
78+
renderLanguageSettings();
79+
80+
expect(screen.queryByText('Select Language')).not.toBeInTheDocument();
81+
expect(screen.getByText('Redirect')).toBeInTheDocument();
82+
});
83+
});

packages/account/src/Sections/Profile/LanguageSettings/language-settings.tsx

Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,40 @@
11
import React from 'react';
2-
import { useTranslation } from 'react-i18next';
3-
import { Button, DesktopWrapper } from '@deriv/components';
2+
import { Redirect } from 'react-router-dom';
43
import { localize, getAllowedLanguages } from '@deriv/translations';
4+
import { isMobile, routes } from '@deriv/shared';
5+
import { observer, useStore } from '@deriv/stores';
56
import FormSubHeader from 'Components/form-sub-header';
6-
import { Formik, FormikHandlers, FormikHelpers, FormikValues } from 'formik';
7-
import FormFooter from 'Components/form-footer';
87
import LanguageRadioButton from 'Components/language-settings';
9-
import { observer, useStore } from '@deriv/stores';
108

119
const LanguageSettings = observer(() => {
1210
const { common } = useStore();
13-
const { changeSelectedLanguage, current_language, isCurrentLanguage } = common;
14-
const { i18n } = useTranslation();
11+
const { changeSelectedLanguage, current_language } = common;
12+
13+
if (window.location.pathname === routes.languages && isMobile()) {
14+
return <Redirect to={routes.traders_hub} />;
15+
}
16+
1517
const allowed_language_keys: string[] = Object.keys(getAllowedLanguages());
16-
const initial_values = { language_code: current_language };
1718
return (
18-
<Formik
19-
initialValues={initial_values}
20-
onSubmit={async values => {
21-
const { language_code } = values;
22-
await changeSelectedLanguage(language_code);
23-
await i18n.changeLanguage?.(language_code);
24-
}}
25-
>
26-
{({ handleSubmit, setFieldValue, values }: FormikHandlers & FormikHelpers<FormikValues> & FormikValues) => {
27-
return (
28-
<form onSubmit={handleSubmit} className='account-form account-form--language-settings'>
29-
<div className='settings-language'>
30-
<DesktopWrapper>
31-
<FormSubHeader title={localize('Select Language')} />
32-
</DesktopWrapper>
33-
<div className='settings-language__language-container'>
34-
{allowed_language_keys.map(language_key => {
35-
return (
36-
<LanguageRadioButton
37-
key={language_key}
38-
id={language_key}
39-
language_code={language_key}
40-
is_current_language={values.language_code === language_key}
41-
name='language-radio-group'
42-
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
43-
setFieldValue('language_code', event.target.value)
44-
}
45-
/>
46-
);
47-
})}
48-
</div>
49-
</div>
50-
<FormFooter>
51-
<Button
52-
className='account-form__footer-btn'
53-
type='submit'
54-
data-testid={'submit-button'}
55-
has_effect
56-
text={localize('Submit')}
57-
large
58-
primary
59-
is_disabled={isCurrentLanguage(values.language_code)}
60-
/>
61-
</FormFooter>
62-
</form>
63-
);
64-
}}
65-
</Formik>
19+
<div className='settings-language'>
20+
<FormSubHeader title={localize('Select Language')} />
21+
<div className='settings-language__language-container'>
22+
{allowed_language_keys.map(language_key => {
23+
return (
24+
<LanguageRadioButton
25+
key={language_key}
26+
id={language_key}
27+
language_code={language_key}
28+
is_current_language={current_language === language_key}
29+
name='language-radio-group'
30+
onChange={() => {
31+
changeSelectedLanguage(language_key);
32+
}}
33+
/>
34+
);
35+
})}
36+
</div>
37+
</div>
6638
);
6739
});
6840

packages/components/src/components/mobile-drawer/mobile-drawer-submenu.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type TMobileDrawerSubmenu = {
1212
submenu_icon?: string;
1313
submenu_title?: string | React.ReactElement;
1414
submenu_suffix_icon?: string;
15-
route_config_path: string;
15+
route_config_path?: string;
1616
};
1717

1818
const SubMenu = ({
@@ -43,7 +43,9 @@ const SubMenu = ({
4343
<Text
4444
as='h3'
4545
size='xs'
46-
weight={window.location.pathname.startsWith(route_config_path) ? 'bold' : ''}
46+
weight={
47+
route_config_path && window.location.pathname.startsWith(route_config_path) ? 'bold' : ''
48+
}
4749
>
4850
{submenu_title}
4951
</Text>

packages/core/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"@deriv/shared": "^1.0.0",
105105
"@deriv/trader": "^3.8.0",
106106
"@deriv/translations": "^1.0.0",
107+
"@deriv/utils": "^1.0.0",
107108
"@livechat/customer-sdk": "^2.0.4",
108109
"acorn": "^6.1.1",
109110
"babel-polyfill": "^6.26.0",
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import MenuTitle from './menu-title';
2+
import MobileLanguageMenu from './mobile-language-menu';
3+
4+
export { MenuTitle, MobileLanguageMenu };
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import React from 'react';
2+
import { observer, useStore } from '@deriv/stores';
3+
import { Icon, Text } from '@deriv/components';
4+
import { localize, Localize } from '@deriv/translations';
5+
6+
const MenuTitle = observer(() => {
7+
const { common, ui } = useStore();
8+
const { current_language } = common;
9+
const { is_mobile_language_menu_open, setMobileLanguageMenuOpen } = ui;
10+
return (
11+
<React.Fragment>
12+
<div>{localize('Menu')}</div>
13+
<div
14+
className='settings-language__language-button_wrapper'
15+
onClick={() => {
16+
if (!is_mobile_language_menu_open) {
17+
setMobileLanguageMenuOpen(true);
18+
}
19+
}}
20+
>
21+
{!is_mobile_language_menu_open && (
22+
<React.Fragment>
23+
<Icon
24+
icon={`IcFlag${current_language.replace('_', '-')}`}
25+
data_testid='dt_icon'
26+
className='ic-settings-language__icon'
27+
size={22}
28+
/>
29+
<Text weight='bold' size='xxs'>
30+
<Localize i18n_default_text={current_language} />
31+
</Text>
32+
</React.Fragment>
33+
)}
34+
</div>
35+
</React.Fragment>
36+
);
37+
});
38+
39+
export default MenuTitle;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import classNames from 'classnames';
2+
import React from 'react';
3+
import { MobileDrawer } from '@deriv/components';
4+
import { observer, useStore } from '@deriv/stores';
5+
import { getAllowedLanguages, localize } from '@deriv/translations';
6+
import { LanguageLink } from 'App/Components/Routes';
7+
8+
type TMobileLanguageMenu = {
9+
expandSubMenu: (prop: boolean) => void;
10+
toggleDrawer: () => void;
11+
};
12+
13+
const MobileLanguageMenu = observer(({ expandSubMenu, toggleDrawer }: TMobileLanguageMenu) => {
14+
const { common, ui } = useStore();
15+
const { is_language_changing } = common;
16+
const { is_mobile_language_menu_open, setMobileLanguageMenuOpen } = ui;
17+
return (
18+
<MobileDrawer.SubMenu
19+
is_expanded={is_mobile_language_menu_open}
20+
has_subheader
21+
submenu_title={localize('Language')}
22+
onToggle={is_expanded => {
23+
expandSubMenu(is_expanded);
24+
setMobileLanguageMenuOpen(false);
25+
}}
26+
submenu_toggle_class='dc-mobile-drawer__submenu-toggle--hidden'
27+
>
28+
<div
29+
className={classNames('settings-language__language-container', {
30+
'settings-language__language-container--disabled': is_language_changing,
31+
})}
32+
>
33+
{Object.keys(getAllowedLanguages()).map(lang => (
34+
<LanguageLink
35+
key={lang}
36+
icon_classname='settings-language__language-flag'
37+
is_clickable
38+
lang={lang}
39+
toggleModal={() => {
40+
toggleDrawer();
41+
setMobileLanguageMenuOpen(false);
42+
}}
43+
/>
44+
))}
45+
</div>
46+
</MobileDrawer.SubMenu>
47+
);
48+
});
49+
50+
export default MobileLanguageMenu;

0 commit comments

Comments
 (0)