Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Farhan/Lock Dtrader Tablet View on Landscape Mode #14781

Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .stylelintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ module.exports = {
'shorthand-property-no-redundant-values': true,
'string-no-newline': true,
'time-min-milliseconds': 100,
'unit-allowed-list': ['fr', 'px', 'em', 'rem', '%', 'svh', 'vw', 'vh', 'deg', 'ms', 's', 'dpcm'],
'unit-allowed-list': ['fr', 'px', 'em', 'rem', '%', 'svh', 'svw', 'vw', 'vh', 'deg', 'ms', 's', 'dpcm'],
'value-keyword-case': 'lower',
},
extends: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
}
}

@include desktop {
@include desktop-screen {
display: none;
}

@include mobile {
@include mobile-screen {
@media screen and (max-aspect-ratio: 13/9) {
display: none;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React from 'react';
import { useLocation } from 'react-router-dom';
import { isDisabledLandscapeBlockerRoute } from '@deriv/shared';
import { isDisabledLandscapeBlockerRoute, isTabletOs, routes } from '@deriv/shared';
import LandscapeBlockerSvg from 'Assets/SvgComponents/settings/landscape-blocker.svg';
import './landscape-blocker.scss';

const LandscapeBlocker = () => {
const location = useLocation();
const pathname = location?.pathname;
const is_hidden_landscape_blocker = isDisabledLandscapeBlockerRoute(pathname);
const shouldShowDtraderTabletView = pathname === routes.trade && isTabletOs;

if (is_hidden_landscape_blocker) return null;
if (is_hidden_landscape_blocker || shouldShowDtraderTabletView) return null;

return (
<div id='landscape_blocker' className='landscape-blocker'>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import classNames from 'classnames';
import React from 'react';
import { Counter, DesktopWrapper, Icon, MobileWrapper, Popover } from '@deriv/components';
import { Counter, Icon, Popover } from '@deriv/components';
import NotificationsDialog from 'App/Containers/NotificationsDialog';
import 'Sass/app/modules/notifications-dialog.scss';
import { useDevice } from '@deriv-com/ui';

const ToggleNotificationsDrawer = ({
count,
Expand All @@ -11,6 +12,7 @@ const ToggleNotificationsDrawer = ({
tooltip_message,
should_disable_pointer_events = false,
}) => {
const { isMobile } = useDevice();
const notifications_toggler_el = (
<div
className={classNames('notifications-toggle__icon-wrapper', {
Expand All @@ -23,28 +25,35 @@ const ToggleNotificationsDrawer = ({
</div>
);

if (isMobile) {
return (
<div
className={classNames('notifications-toggle', {
'notifications-toggle--active': is_visible,
})}
>
{notifications_toggler_el}
<NotificationsDialog is_visible={is_visible} toggleDialog={toggleDialog} />
</div>
);
}

return (
<div
className={classNames('notifications-toggle', {
'notifications-toggle--active': is_visible,
})}
>
<DesktopWrapper>
<Popover
classNameBubble='notifications-toggle__tooltip'
alignment='bottom'
message={tooltip_message}
should_disable_pointer_events={should_disable_pointer_events}
zIndex={9999}
>
{notifications_toggler_el}
</Popover>
<NotificationsDialog is_visible={is_visible} toggleDialog={toggleDialog} />
</DesktopWrapper>
<MobileWrapper>
<Popover
classNameBubble='notifications-toggle__tooltip'
alignment='bottom'
message={tooltip_message}
should_disable_pointer_events={should_disable_pointer_events}
zIndex='9999'
>
{notifications_toggler_el}
<NotificationsDialog is_visible={is_visible} toggleDialog={toggleDialog} />
</MobileWrapper>
</Popover>
<NotificationsDialog is_visible={is_visible} toggleDialog={toggleDialog} />
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import React from 'react';
import { StoreProvider, mockStore } from '@deriv/stores';
import { render, screen } from '@testing-library/react';
import DefaultHeader from '../default-header';
import { useDevice } from '@deriv-com/ui';

jest.mock('@deriv-com/ui', () => ({
...jest.requireActual('@deriv-com/ui'),
useDevice: jest.fn(() => ({ isDesktop: true })),
}));

jest.mock('App/Components/Layout/Header', () => ({
MenuLinks: jest.fn(() => <div>Mocked Menu Links</div>),
Expand All @@ -14,7 +20,7 @@ jest.mock('App/Components/Layout/Header/toggle-menu-drawer.jsx', () =>
jest.mock('../header-account-actions', () => jest.fn(() => <div>Mocked Header Account Action</div>));

describe('DefaultHeader', () => {
const mock_store = mockStore({ ui: { is_desktop: true, is_real_acc_signup_on: true } });
const mock_store = mockStore({ ui: { is_real_acc_signup_on: true } });
const renderComponent = (modified_store = mock_store) =>
render(
<StoreProvider store={modified_store}>
Expand All @@ -31,9 +37,10 @@ describe('DefaultHeader', () => {
});

it('should render Toggle Menu Drawer, Menu Links, Account action and Real Account SignUp components, in Mobile view', () => {
(useDevice as jest.Mock).mockReturnValue({ isDesktop: false });
renderComponent(
mockStore({
ui: { is_desktop: false, is_mobile: true, is_real_acc_signup_on: true },
ui: { is_real_acc_signup_on: true },
modules: { cashier: { payment_agent: 'MOCK_PAYMENT_AGENT' } },
})
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import ToggleMenuDrawer from 'App/Components/Layout/Header/toggle-menu-drawer.js
import platform_config from 'App/Constants/platform-config';
import { useHistory } from 'react-router-dom';
import HeaderAccountActions from './header-account-actions';
import { useDevice } from '@deriv-com/ui';

const DefaultHeader = observer(() => {
const { client, common, notifications, traders_hub, ui } = useStore();
Expand All @@ -29,14 +30,14 @@ const DefaultHeader = observer(() => {
const { setTogglePlatformType } = traders_hub;
const {
header_extension,
is_mobile,
is_app_disabled,
is_route_modal_on,
is_trading_assessment_for_existing_user_enabled,
is_real_acc_signup_on,
} = ui;

const history = useHistory();
const { isDesktop } = useDevice();

const addUpdateNotification = () => addNotificationMessage(client_notifications?.new_version_available);
const removeUpdateNotification = React.useCallback(
Expand Down Expand Up @@ -78,7 +79,7 @@ const DefaultHeader = observer(() => {
>
<div className='header__menu-items'>
<div className='header__menu-left'>
{!is_mobile && (
{isDesktop ? (
<PlatformSwitcher
app_routing_history={app_routing_history}
is_landing_company_loaded={is_landing_company_loaded}
Expand All @@ -88,8 +89,7 @@ const DefaultHeader = observer(() => {
setTogglePlatformType={setTogglePlatformType}
current_language={current_language}
/>
)}
{is_mobile && (
) : (
<React.Fragment>
<ToggleMenuDrawer platform_config={filterPlatformsForClients(platform_config)} />
{header_extension && is_logged_in && (
Expand All @@ -101,7 +101,7 @@ const DefaultHeader = observer(() => {
</div>
<div
className={classNames('header__menu-right', {
'header__menu-right--hidden': is_mobile && is_logging_in,
'header__menu-right--hidden': !isDesktop && is_logging_in,
})}
>
{(is_logging_in || is_switching) && (
Expand All @@ -112,7 +112,7 @@ const DefaultHeader = observer(() => {
'acc-info__preloader--is-crypto': getDecimalPlaces(currency) > 2,
})}
>
<AccountsInfoLoader is_logged_in={is_logged_in} is_mobile={is_mobile} speed={3} />
<AccountsInfoLoader is_logged_in={is_logged_in} is_mobile={!isDesktop} speed={3} />
</div>
)}
<HeaderAccountActions onClickDeposit={onClickDeposit} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React from 'react';
import { isDesktop, isMobile } from '@deriv/shared';
import { StoreProvider, mockStore } from '@deriv/stores';
import { render, screen } from '@testing-library/react';
import NotificationsDialog from '../notifications-dialog';
import { useDevice } from '@deriv-com/ui';

jest.mock('react-transition-group', () => ({ CSSTransition: () => 'MockedCSSTransition' }));
jest.mock('@deriv/components', () => ({
...jest.requireActual('@deriv/components'),
MobileDialog: () => 'MockedMobileDialog',
}));
jest.mock('@deriv/shared', () => ({
...jest.requireActual('@deriv/shared'),
isDesktop: jest.fn(() => true),
isMobile: jest.fn(() => false),
jest.mock('@deriv-com/ui', () => ({
useDevice: jest.fn(() => ({ isMobile: false })),
}));

describe('NotificationsDialog', () => {
Expand Down Expand Up @@ -50,8 +48,7 @@ describe('NotificationsDialog', () => {
});

it('should render the component MobileDialog in mobile mode', () => {
(isDesktop as jest.Mock).mockReturnValue(false);
(isMobile as jest.Mock).mockReturnValue(true);
(useDevice as jest.Mock).mockReturnValue({ isMobile: true });
renderComponent();
expect(screen.getByText('MockedMobileDialog')).toBeInTheDocument();
expect(screen.queryByText('MockedCSSTransition')).not.toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React from 'react';
import { CSSTransition } from 'react-transition-group';
import { DesktopWrapper, MobileDialog, MobileWrapper, useOnClickOutside } from '@deriv/components';
import { MobileDialog, useOnClickOutside } from '@deriv/components';
import { LocalStore } from '@deriv/shared';
import { observer, useStore } from '@deriv/stores';
import { Localize } from '@deriv/translations';
import NotificationListWrapper from './notification-list-wrapper';
import { useDevice } from '@deriv-com/ui';

const NotificationsDialog = observer(() => {
const { client, notifications } = useStore();
Expand All @@ -19,6 +20,7 @@ const NotificationsDialog = observer(() => {
} = notifications;

const wrapper_ref = React.useRef<HTMLDivElement>(null);
const { isMobile } = useDevice();

const handleClickOutside = (event: MouseEvent) => {
const notifications_toggle_btn = !(event?.target as Element)?.classList.contains(
Expand Down Expand Up @@ -52,34 +54,33 @@ const NotificationsDialog = observer(() => {

useOnClickOutside(wrapper_ref, handleClickOutside);

if (isMobile) {
return (
<MobileDialog
portal_element_id='modal_root'
title={<Localize i18n_default_text='Notifications' />}
wrapper_classname='notifications-mobile-dialog'
visible={is_notifications_visible}
onClose={toggleNotificationsModal}
>
<NotificationListWrapper clearNotifications={clearNotifications} ref={wrapper_ref} />
</MobileDialog>
);
}

return (
<React.Fragment>
<MobileWrapper>
<MobileDialog
portal_element_id='modal_root'
title={<Localize i18n_default_text='Notifications' />}
wrapper_classname='notifications-mobile-dialog'
visible={is_notifications_visible}
onClose={toggleNotificationsModal}
>
<NotificationListWrapper clearNotifications={clearNotifications} ref={wrapper_ref} />
</MobileDialog>
</MobileWrapper>
<DesktopWrapper>
<CSSTransition
in={is_notifications_visible}
classNames={{
enter: 'notifications-dialog--enter',
enterDone: 'notifications-dialog--enter-done',
exit: 'notifications-dialog--exit',
}}
timeout={150}
unmountOnExit
>
<NotificationListWrapper clearNotifications={clearNotifications} ref={wrapper_ref} />
</CSSTransition>
</DesktopWrapper>
</React.Fragment>
<CSSTransition
in={is_notifications_visible}
classNames={{
enter: 'notifications-dialog--enter',
enterDone: 'notifications-dialog--enter-done',
exit: 'notifications-dialog--exit',
}}
timeout={150}
unmountOnExit
>
<NotificationListWrapper clearNotifications={clearNotifications} ref={wrapper_ref} />
</CSSTransition>
);
});

Expand Down
4 changes: 4 additions & 0 deletions packages/shared/src/utils/os/os_detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export const isDesktopOs = () => {
export const isMobileOs = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

export const isTabletOs =
/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()) ||
(/android/i.test(navigator.userAgent.toLowerCase()) && !/mobile/i.test(navigator.userAgent.toLowerCase()));

export const OSDetect = () => {
// For testing purposes or more compatibility, if we set 'config.os'
// inside our localStorage, we ignore fetching information from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const TogglePositionsMobile = observer(
}: TTogglePositionsMobile) => {
const { togglePositionsDrawer, is_positions_drawer_on } = useStore().ui;
const [hidden_positions_ids, setHiddenPositionsIds] = React.useState<THiddenPositionsId[]>([]);
const { isMobile } = useDevice();
const { isMobile, isTablet } = useDevice();

const displayed_positions = filtered_positions
.filter(p =>
Expand Down Expand Up @@ -96,7 +96,7 @@ const TogglePositionsMobile = observer(
width={isMobile ? 'calc(100vw - 32px)' : undefined}
className='toggle-positions'
>
<Div100vhContainer className='positions-modal' height_offset='48px'>
<Div100vhContainer className='positions-modal' height_offset={isTablet ? '16rvh' : '48px'}>
<div className='positions-modal__header'>
<Text size='xxxs' className='positions-modal__title'>
<Icon icon='IcPortfolio' className='positions-modal__title-icon' />
Expand Down
16 changes: 1 addition & 15 deletions packages/trader/src/App/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type { TWebSocket } from 'Types';
import initStore from './init-store';
import 'Sass/app.scss';
import type { TCoreStores } from '@deriv/stores/types';
import { useDevice } from '@deriv-com/ui';
import TraderProviders from '../trader-providers';

type Apptypes = {
Expand All @@ -26,24 +25,11 @@ const TradeModals = Loadable({

const App = ({ passthrough }: Apptypes) => {
const root_store = initStore(passthrough.root_store, passthrough.WS);
const { isTabletPortrait } = useDevice();

React.useEffect(() => {
return () => root_store.ui.setPromptHandler(false);
}, [root_store]);

React.useEffect(() => {
const landscapeBlockerElement = document.querySelector('.landscape-blocker');
if (landscapeBlockerElement && !isTabletPortrait) {
landscapeBlockerElement.classList.add('landscape-blocker--hidden');
}

return () => {
if (landscapeBlockerElement) {
landscapeBlockerElement.classList.remove('landscape-blocker--hidden');
}
};
}, [isTabletPortrait]);

return (
<TraderProviders store={root_store}>
<Routes />
Expand Down
Loading