From 68fb3e8289231a823ebd7590445c72fd4d31d0fc Mon Sep 17 00:00:00 2001 From: Farhan Ahmad Nurzi <125247833+farhan-nurzi-deriv@users.noreply.github.com> Date: Tue, 23 Apr 2024 16:16:14 +0800 Subject: [PATCH 01/33] [DTRA] Farhan/DTRA-945/Dtrader's Tablet View (#14346) * feat: tablet view * revert: trade params test cases * chore: remove unused imports * chore: added test case for usedevice * fix: height * fix: accumulators stats * fix: layout * fix: test * refactor: update test * refactor: change mixins names * fix: platform switcher * refactor: remove shared isnewmobile and fix styles in contract page * fix: blocker showing in different page besides dtrader, comments * fix: comments * revert: unneded changes * fix: test failed * fix: breaking designs because of rtl * feat: empty * fix: account switcher * fix: account switcher and add blocker on portrait * chore: update test case * refactor: replace with hook from deriv-com/ui * fix: failing test cases * chore: update deriv-com/ui and remove redundant hook * fix: useonclickoutside --- __mocks__/globals.js | 14 ++ jest.config.base.js | 4 +- jest.config.js | 4 +- package-lock.json | 8 +- packages/account-v2/package.json | 2 +- packages/account-v2/src/modules/package.json | 2 +- packages/account/jest.config.js | 1 + packages/appstore/jest.config.js | 1 + packages/bot-skeleton/jest.config.js | 1 + packages/bot-web-ui/jest.config.js | 1 + packages/cashier-v2/package.json | 2 +- .../TransferDropdown/TransferDropdown.tsx | 3 +- packages/cashier/jest.config.js | 1 + packages/cfd/jest.config.js | 1 + packages/components/jest.config.js | 2 + packages/components/package.json | 1 + .../components/date-picker/date-picker.tsx | 104 +++++----- .../src/components/dropdown/dropdown.scss | 3 +- .../src/components/modal/modal.scss | 10 +- packages/core/jest.config.js | 1 + packages/core/package.json | 1 + packages/core/src/App/AppContent.tsx | 8 +- .../Layout/Header/account-actions.jsx | 66 +++--- .../Components/Layout/Header/account-info.jsx | 34 ++-- .../Components/Layout/Header/menu-links.jsx | 7 +- .../Layout/Header/platform-dropdown.jsx | 16 +- .../App/Containers/Layout/app-contents.jsx | 25 ++- .../header/__tests__/dtrader-header.spec.tsx | 11 +- .../Layout/header/dtrader-header.tsx | 39 ++-- .../_common/components/account-switcher.scss | 16 +- .../_common/components/platform-dropdown.scss | 6 +- .../sass/app/_common/layout/app-layouts.scss | 33 ++- .../src/sass/app/_common/layout/header.scss | 2 +- packages/hooks/package.json | 1 + packages/hooks/src/index.ts | 6 +- packages/p2p-v2/package.json | 2 +- packages/p2p/jest.config.js | 3 +- packages/reports/jest.config.js | 1 + packages/shared/jest.config.js | 5 +- packages/shared/src/styles/devices.scss | 34 ++++ packages/trader/build/constants.js | 1 + packages/trader/jest.config.js | 1 + packages/trader/package.json | 1 + .../Elements/ContentLoader/trade-params.tsx | 45 +++-- .../ContractAudit/contract-details.tsx | 5 +- .../__tests__/contract-drawer.spec.tsx | 20 +- .../ContractDrawer/contract-drawer-card.tsx | 25 +-- .../ContractDrawer/contract-drawer.tsx | 63 +++--- .../toggle-positions-mobile.tsx | 6 +- .../Containers/trade-header-extensions.tsx | 24 ++- packages/trader/src/App/app.tsx | 15 ++ .../__tests__/accumulators-stats.spec.tsx | 25 +-- .../AccumulatorsStats/accumulators-stats.tsx | 42 ++-- .../__tests__/contract-replay.spec.tsx | 14 +- .../Contract/Containers/contract-replay.tsx | 108 +++++----- .../Contract/Containers/replay-chart.tsx | 21 +- .../SmartChart/Components/top-widgets.tsx | 4 +- .../__tests__/purchase-button.spec.tsx | 13 +- .../__tests__/purchase-fieldset.spec.tsx | 14 +- .../Components/Elements/purchase-button.tsx | 99 ++++----- .../Components/Elements/purchase-fieldset.tsx | 26 +-- .../__tests__/contract-type-dialog.spec.tsx | 11 +- .../ContractType/contract-type-dialog.tsx | 57 +++--- .../ContractType/contract-type-display.tsx | 13 +- .../Purchase/__tests__/contract-info.spec.tsx | 9 +- .../Form/Purchase/contract-info.tsx | 58 +++--- .../TradeParams/Turbos/barrier-selector.tsx | 75 +++---- .../TradeParams/__tests__/strike.spec.tsx | 18 +- .../Components/Form/TradeParams/strike.tsx | 190 +++++++++--------- .../Form/__tests__/form-layout.spec.tsx | 15 +- .../Trading/Components/Form/form-layout.tsx | 32 +-- .../Containers/__tests__/trade.spec.tsx | 29 ++- .../Trading/Containers/chart-widgets.tsx | 6 +- .../Trading/Containers/trade-chart.tsx | 26 +-- .../src/Modules/Trading/Containers/trade.tsx | 72 +++---- .../src/Stores/Modules/Trading/trade-store.ts | 8 +- .../components/contract-type-widget.scss | 8 +- .../_common/components/number-selector.scss | 2 +- .../_common/components/positions-toggle.scss | 7 + .../_common/components/purchase-button.scss | 16 +- .../app/_common/drawer/contract-drawer.scss | 6 +- .../app/_common/layout/trader-layouts.scss | 83 ++++---- .../modules/contract/accumulators-stats.scss | 26 ++- .../src/sass/app/modules/contract/digits.scss | 6 + .../src/sass/app/modules/trading-mobile.scss | 2 +- .../trader/src/sass/app/modules/trading.scss | 30 +-- packages/tradershub/package.json | 2 +- 87 files changed, 1011 insertions(+), 850 deletions(-) diff --git a/__mocks__/globals.js b/__mocks__/globals.js index 8fa59529a33e..0212b14ee21c 100644 --- a/__mocks__/globals.js +++ b/__mocks__/globals.js @@ -20,6 +20,20 @@ jest.mock('@deriv-com/analytics', () => ({ }, })); +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + const mock_onfido = { init: jest.fn().mockResolvedValue({}), }; diff --git a/jest.config.base.js b/jest.config.base.js index a9a7339ee322..f607d781205e 100644 --- a/jest.config.base.js +++ b/jest.config.base.js @@ -15,7 +15,9 @@ module.exports = { coverageDirectory: './coverage/', testRegex: '(/__tests__/.*|(\\.)(test|spec))\\.(js|jsx|tsx|ts)?$', // This is needed to transform es modules imported from node_modules of the target component. - transformIgnorePatterns: ['/node_modules/(?!(@enykeev/react-virtualized|@simplewebauthn/browser)).+\\.js$'], + transformIgnorePatterns: [ + '/node_modules/(?!(@enykeev/react-virtualized|@simplewebauthn/browser|@deriv/quill-design|@deriv/quill-icons|@deriv-com/ui)).+\\.js$', + ], setupFiles: ['/../../jest.setup.js'], setupFilesAfterEnv: ['/../../setupTests.js'], testPathIgnorePatterns: ['/integration-tests/', '/component-tests/'], diff --git a/jest.config.js b/jest.config.js index da5d1f35c404..ceb9daa8fe7b 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,5 @@ +const baseConfig = require('./jest.config.base'); + module.exports = { collectCoverage: false, collectCoverageFrom: [ @@ -17,6 +19,6 @@ module.exports = { '^.+\\.(ts|tsx)?$': 'ts-jest', }, testRegex: '(/__tests__/.*|(\\.)(test|spec))\\.(js|jsx|tsx|ts)?$', - transformIgnorePatterns: ['/node_modules/(?!(@enykeev/react-virtualized|@simplewebauthn/browser)).+\\.js$'], + transformIgnorePatterns: baseConfig.transformIgnorePatterns, testPathIgnorePatterns: ['/integration-tests/'], }; diff --git a/package-lock.json b/package-lock.json index 355208a25e8b..fc23230111f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@datadog/browser-logs": "^5.11.0", "@datadog/browser-rum": "^5.11.0", "@deriv-com/analytics": "1.4.13", - "@deriv-com/ui": "^1.12.17", + "@deriv-com/ui": "^1.14.2", "@deriv-com/utils": "^0.0.14", "@deriv/api-types": "^1.0.172", "@deriv/deriv-api": "^1.0.15", @@ -2960,9 +2960,9 @@ } }, "node_modules/@deriv-com/ui": { - "version": "1.12.17", - "resolved": "https://registry.npmjs.org/@deriv-com/ui/-/ui-1.12.17.tgz", - "integrity": "sha512-dCV53ugag3dApg/HX+XgIpUFxsi3Y7UUkLObjXqcue/kABzBii5aNxA01561JgUEO8EkjHNxSEHk7i7wi8Po8g==", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/@deriv-com/ui/-/ui-1.14.2.tgz", + "integrity": "sha512-7O06rLPPtWMsyQRI6pIxbAME3+KYathbhmraHCgwAct7dUG1yAmAMGSgIWZuF55psi5San77cYVEb2Ui8GnckQ==", "dependencies": { "@types/react-modal": "^3.16.3" }, diff --git a/packages/account-v2/package.json b/packages/account-v2/package.json index 99dd5634f458..645a1b643e44 100644 --- a/packages/account-v2/package.json +++ b/packages/account-v2/package.json @@ -11,7 +11,7 @@ "start": "rimraf dist && npm run test && npm run serve" }, "dependencies": { - "@deriv-com/ui": "^1.12.17", + "@deriv-com/ui": "^1.14.2", "@deriv-com/utils": "^0.0.14", "@deriv/api-types": "^1.0.172", "@deriv/api-v2": "^1.0.0", diff --git a/packages/account-v2/src/modules/package.json b/packages/account-v2/src/modules/package.json index f1205e812e22..e3315d348b4c 100644 --- a/packages/account-v2/src/modules/package.json +++ b/packages/account-v2/src/modules/package.json @@ -24,7 +24,7 @@ "README.md" ], "peerDependencies": { - "@deriv-com/ui": "1.11.2", + "@deriv-com/ui": "^1.14.2", "@deriv/quill-icons": "^1.21.1", "@deriv/api-v2": "1.0.0", "yup": "^0.32.11", diff --git a/packages/account/jest.config.js b/packages/account/jest.config.js index 11898a71490e..d90c74ceb728 100644 --- a/packages/account/jest.config.js +++ b/packages/account/jest.config.js @@ -3,6 +3,7 @@ const baseConfigForPackages = require('../../jest.config.base'); module.exports = { ...baseConfigForPackages, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^Assets/(.*)$': '/src/Assets/$1', diff --git a/packages/appstore/jest.config.js b/packages/appstore/jest.config.js index 1ec8c6bd0270..d1c21db9f242 100644 --- a/packages/appstore/jest.config.js +++ b/packages/appstore/jest.config.js @@ -3,6 +3,7 @@ const baseConfigForPackages = require('../../jest.config.base'); module.exports = { ...baseConfigForPackages, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/fileMock.js', '^Assets/(.*)$': '/src/assets/$1', diff --git a/packages/bot-skeleton/jest.config.js b/packages/bot-skeleton/jest.config.js index 26391d325ed4..8e7440519763 100644 --- a/packages/bot-skeleton/jest.config.js +++ b/packages/bot-skeleton/jest.config.js @@ -4,6 +4,7 @@ module.exports = { ...baseConfigForPackages, clearMocks: true, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^Constants/(.*)$': '/src/constants/$1', diff --git a/packages/bot-web-ui/jest.config.js b/packages/bot-web-ui/jest.config.js index 779f8f2cbf1a..c364accf2803 100644 --- a/packages/bot-web-ui/jest.config.js +++ b/packages/bot-web-ui/jest.config.js @@ -4,6 +4,7 @@ module.exports = { ...baseConfigForPackages, clearMocks: true, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^App/(.*)$': '/src/app/$1', diff --git a/packages/cashier-v2/package.json b/packages/cashier-v2/package.json index 1529a2015f73..91629a0fb648 100644 --- a/packages/cashier-v2/package.json +++ b/packages/cashier-v2/package.json @@ -12,7 +12,7 @@ "start": "rimraf dist && npm run test && npm run serve" }, "dependencies": { - "@deriv-com/ui": "^1.12.17", + "@deriv-com/ui": "^1.14.2", "@deriv-com/utils": "^0.0.14", "@deriv/api-v2": "^1.0.0", "@deriv/integration": "^1.0.0", diff --git a/packages/cashier-v2/src/lib/Transfer/components/TransferForm/components/TransferAccountSelection/components/TransferDropdown/TransferDropdown.tsx b/packages/cashier-v2/src/lib/Transfer/components/TransferForm/components/TransferAccountSelection/components/TransferDropdown/TransferDropdown.tsx index a05959c2fcbb..89f9079e51a2 100644 --- a/packages/cashier-v2/src/lib/Transfer/components/TransferForm/components/TransferAccountSelection/components/TransferDropdown/TransferDropdown.tsx +++ b/packages/cashier-v2/src/lib/Transfer/components/TransferForm/components/TransferAccountSelection/components/TransferDropdown/TransferDropdown.tsx @@ -1,7 +1,8 @@ import React, { useRef, useState } from 'react'; import clsx from 'clsx'; +import { useOnClickOutside } from 'usehooks-ts'; import { LabelPairedChevronDownMdRegularIcon } from '@deriv/quill-icons'; -import { Text, useOnClickOutside } from '@deriv-com/ui'; +import { Text } from '@deriv-com/ui'; import { TTransferableAccounts, TTransferFormikContext } from '../../../../../../types'; import { TransferAccountTile, TransferDropdownList } from './components'; import styles from './TransferDropdown.module.scss'; diff --git a/packages/cashier/jest.config.js b/packages/cashier/jest.config.js index 843126c3f631..bf61b987be3a 100644 --- a/packages/cashier/jest.config.js +++ b/packages/cashier/jest.config.js @@ -4,6 +4,7 @@ module.exports = { ...baseConfigForPackages, clearMocks: true, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^Stores/(.*)$': '/src/stores/$1', diff --git a/packages/cfd/jest.config.js b/packages/cfd/jest.config.js index fac0fd629654..806c2fa643a9 100644 --- a/packages/cfd/jest.config.js +++ b/packages/cfd/jest.config.js @@ -3,6 +3,7 @@ const baseConfigForPackages = require('../../jest.config.base'); module.exports = { ...baseConfigForPackages, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^_common/(.*)$': '/src/_common/$1', diff --git a/packages/components/jest.config.js b/packages/components/jest.config.js index 06fb2b038ab5..3a99f439df05 100644 --- a/packages/components/jest.config.js +++ b/packages/components/jest.config.js @@ -3,8 +3,10 @@ const baseConfigForPackages = require('../../jest.config.base'); module.exports = { ...baseConfigForPackages, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', }, modulePathIgnorePatterns: ['/icon/', '/.out/'], + transformIgnorePatterns: ['/node_modules/(?!(@deriv-com/ui)).+\\.js$'], }; diff --git a/packages/components/package.json b/packages/components/package.json index 7e34cbe9a8fd..999cf43fc7ea 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -73,6 +73,7 @@ }, "dependencies": { "@contentpass/zxcvbn": "^4.4.3", + "@deriv-com/ui": "^1.14.2", "@deriv/shared": "^1.0.0", "@deriv/stores": "^1.0.0", "@deriv/translations": "^1.0.0", diff --git a/packages/components/src/components/date-picker/date-picker.tsx b/packages/components/src/components/date-picker/date-picker.tsx index 9a75522dc5f6..b003c4621c98 100644 --- a/packages/components/src/components/date-picker/date-picker.tsx +++ b/packages/components/src/components/date-picker/date-picker.tsx @@ -1,13 +1,12 @@ import React from 'react'; -import { addDays, daysFromTodayTo, toMoment, convertDateFormat, getPosition, isMobile } from '@deriv/shared'; +import { addDays, daysFromTodayTo, toMoment, convertDateFormat, getPosition } from '@deriv/shared'; import Input from './date-picker-input'; import Calendar from './date-picker-calendar'; import Native from './date-picker-native'; -import MobileWrapper from '../mobile-wrapper'; -import DesktopWrapper from '../desktop-wrapper'; import { useOnClickOutside } from '../../hooks/use-onclickoutside'; import moment, { MomentInput } from 'moment'; import { TDatePickerOnChangeEvent } from '../types'; +import { useDevice } from '@deriv-com/ui'; type TDatePicker = Omit< React.ComponentProps & React.ComponentProps & React.ComponentProps, @@ -72,6 +71,7 @@ const DatePicker = React.memo((props: TDatePicker) => { const [duration, setDuration] = React.useState(daysFromTodayTo(value)); const [is_datepicker_visible, setIsDatepickerVisible] = React.useState(false); const [is_placeholder_visible, setIsPlaceholderVisible] = React.useState(!!placeholder && !value); + const { isMobile } = useDevice(); useOnClickOutside( datepicker_ref, @@ -197,7 +197,7 @@ const DatePicker = React.memo((props: TDatePicker) => { const getInputValue = (): string | number => (mode === 'duration' ? duration || 0 : date); const getCalendarValue = (new_date: string | null): string | null => { - if (!new_date) return isMobile() ? null : toMoment(start_date || max_date).format(date_format); + if (!new_date) return isMobile ? null : toMoment(start_date || max_date).format(date_format); return convertDateFormat(new_date, display_format, date_format); }; @@ -216,60 +216,58 @@ const DatePicker = React.memo((props: TDatePicker) => { ...other_props, }; + if (isMobile) { + return ( + + ); + } + return ( - - - +
+ + - - -
-
- - -
-
-
- +
+ ); }); diff --git a/packages/components/src/components/dropdown/dropdown.scss b/packages/components/src/components/dropdown/dropdown.scss index 86595f7dee11..8a676979506e 100644 --- a/packages/components/src/components/dropdown/dropdown.scss +++ b/packages/components/src/components/dropdown/dropdown.scss @@ -273,7 +273,8 @@ min-width: 15rem; width: 100%; - &:not(.cfd-personal-details-modal__form *):not(.trade-container__multiplier-dropdown):not(.dc-dropdown--left):not(.contract-type-info__dropdown) { + &:not(.cfd-personal-details-modal__form *):not(.trade-container__multiplier-dropdown):not( + .dc-dropdown--left):not(.contract-type-info__dropdown) { margin-top: unset; } diff --git a/packages/components/src/components/modal/modal.scss b/packages/components/src/components/modal/modal.scss index 5e4c3807d82e..f72e38956090 100644 --- a/packages/components/src/components/modal/modal.scss +++ b/packages/components/src/components/modal/modal.scss @@ -1,7 +1,7 @@ /** @define dc-modal; weak */ .dc-modal { &__container { - @include tablet { + @include tablet-screen { width: unset !important; right: 0; } @@ -31,7 +31,7 @@ &--is-vertical-top { top: $HEADER_HEIGHT; position: absolute; - @include mobile { + @include mobile-screen { top: $MOBILE_HEADER_HEIGHT; left: 1.6rem; width: calc(100vw - 3.2rem) !important; @@ -40,7 +40,7 @@ &--is-vertical-bottom { bottom: $FOOTER_HEIGHT; position: absolute; - @include mobile { + @include mobile-screen { left: 1.6rem; width: calc(100vw - 3.2rem) !important; } @@ -83,11 +83,11 @@ } } } - @include desktop { + @include desktop-screen { min-width: 440px !important; max-height: calc(100vh - #{$HEADER_HEIGHT} - #{$FOOTER_HEIGHT}) !important; } - @include mobile { + @include mobile-screen { max-width: calc(100vw - 3.2rem) !important; } } diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js index 2256e6598ed4..f56d8aa34c71 100644 --- a/packages/core/jest.config.js +++ b/packages/core/jest.config.js @@ -3,6 +3,7 @@ const baseConfigForPackages = require('../../jest.config.base'); module.exports = { ...baseConfigForPackages, moduleNameMapper: { + '\\.css$': '/../../__mocks__/styleMock.js', '\\.s(c|a)ss$': '/../../__mocks__/styleMock.js', '^.+\\.svg$': '/../../__mocks__/styleMock.js', '^_common/(.*)$': '/src/_common/$1', diff --git a/packages/core/package.json b/packages/core/package.json index 28c805f337bb..ae65ad24bf5a 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -95,6 +95,7 @@ "@datadog/browser-rum": "^5.11.0", "@deriv-com/analytics": "1.4.13", "@deriv-com/utils": "^0.0.14", + "@deriv-com/ui": "^1.14.2", "@deriv/account": "^1.0.0", "@deriv/account-v2": "^1.0.0", "@deriv/api": "^1.0.0", diff --git a/packages/core/src/App/AppContent.tsx b/packages/core/src/App/AppContent.tsx index 13e3dd458d1b..28e3941779cc 100644 --- a/packages/core/src/App/AppContent.tsx +++ b/packages/core/src/App/AppContent.tsx @@ -1,8 +1,8 @@ import React from 'react'; import Cookies from 'js-cookie'; import { useRemoteConfig } from '@deriv/api'; -import { DesktopWrapper } from '@deriv/components'; import { useFeatureFlags } from '@deriv/hooks'; +import { useDevice } from '@deriv-com/ui'; import { getAppId, LocalStore, useIsMounted } from '@deriv/shared'; import { observer, useStore } from '@deriv/stores'; import { getLanguage } from '@deriv/translations'; @@ -25,7 +25,7 @@ import initDatadog from '../Utils/Datadog'; const AppContent: React.FC<{ passthrough: unknown }> = observer(({ passthrough }) => { const { is_next_wallet_enabled } = useFeatureFlags(); const store = useStore(); - + const { isDesktop } = useDevice(); const isMounted = useIsMounted(); const { data } = useRemoteConfig(isMounted()); const { marketing_growthbook, tracking_datadog, tracking_rudderstack } = data; @@ -79,9 +79,7 @@ const AppContent: React.FC<{ passthrough: unknown }> = observer(({ passthrough } - -