From 718b50b577287b955f8947d8d386539c5d2d9413 Mon Sep 17 00:00:00 2001 From: Jim Daniels Wasswa Date: Tue, 31 Jan 2023 15:06:48 +0800 Subject: [PATCH 1/3] refactor: migrate contract-card to ts --- packages/components/package.json | 1 + ...t-card-body.jsx => contract-card-body.tsx} | 85 ++++++++++--------- .../contract-card-dialog.jsx | 54 ------------ .../contract-card-dialog.tsx | 59 +++++++++++++ ...rd-footer.jsx => contract-card-footer.tsx} | 35 ++++---- ...rd-header.jsx => contract-card-header.tsx} | 35 ++++---- ...t-card-item.jsx => contract-card-item.tsx} | 27 +++--- .../contract-card-sell.jsx | 45 ---------- .../contract-card-sell.tsx | 44 ++++++++++ ...t-type-cell.jsx => contract-type-cell.tsx} | 18 ++-- ...date-form.jsx => contract-update-form.tsx} | 59 +++++++------ ...tions.jsx => multiplier-close-actions.tsx} | 29 ++++--- ...card-dialog.jsx => toggle-card-dialog.tsx} | 59 ++++++------- ...rd-loader.jsx => contract-card-loader.tsx} | 7 +- .../contract-card-loader/index.js | 3 - .../contract-card-loader/index.ts | 3 + .../{contract-card.jsx => contract-card.tsx} | 46 +++++----- .../contract-card/{index.js => index.ts} | 2 +- .../result-overlay/{index.js => index.ts} | 2 +- ...{result-overlay.jsx => result-overlay.tsx} | 38 +++++---- .../progress-slider-mobile.tsx | 10 +-- .../progress-ticks-mobile.tsx | 2 +- .../progress-slider/progress-slider.tsx | 13 +-- .../progress-slider/progress-ticks.tsx | 7 +- .../tick-progress/tick-progress.tsx | 4 +- .../src/components/types/common.types.ts | 4 +- .../src/components/types/contract.types.ts | 14 +++ .../components/src/components/types/index.ts | 7 +- .../src/hooks/use-onclickoutside.ts | 7 +- packages/shared/package.json | 1 + .../src/utils/contract/contract-types.ts | 63 ++------------ .../shared/src/utils/contract/contract.ts | 58 +++++-------- packages/shared/src/utils/helpers/logic.ts | 10 +-- .../src/utils/helpers/validation-rules.ts | 10 +-- packages/stores/types.ts | 21 ++++- 35 files changed, 432 insertions(+), 450 deletions(-) rename packages/components/src/components/contract-card/contract-card-items/{contract-card-body.jsx => contract-card-body.tsx} (84%) delete mode 100644 packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.jsx create mode 100644 packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.tsx rename packages/components/src/components/contract-card/contract-card-items/{contract-card-footer.jsx => contract-card-footer.tsx} (81%) rename packages/components/src/components/contract-card/contract-card-items/{contract-card-header.jsx => contract-card-header.tsx} (87%) rename packages/components/src/components/contract-card/contract-card-items/{contract-card-item.jsx => contract-card-item.tsx} (61%) delete mode 100644 packages/components/src/components/contract-card/contract-card-items/contract-card-sell.jsx create mode 100644 packages/components/src/components/contract-card/contract-card-items/contract-card-sell.tsx rename packages/components/src/components/contract-card/contract-card-items/{contract-type-cell.jsx => contract-type-cell.tsx} (73%) rename packages/components/src/components/contract-card/contract-card-items/{contract-update-form.jsx => contract-update-form.tsx} (82%) rename packages/components/src/components/contract-card/contract-card-items/{multiplier-close-actions.jsx => multiplier-close-actions.tsx} (76%) rename packages/components/src/components/contract-card/contract-card-items/{toggle-card-dialog.jsx => toggle-card-dialog.tsx} (84%) rename packages/components/src/components/contract-card/contract-card-loader/{contract-card-loader.jsx => contract-card-loader.tsx} (89%) delete mode 100644 packages/components/src/components/contract-card/contract-card-loader/index.js create mode 100644 packages/components/src/components/contract-card/contract-card-loader/index.ts rename packages/components/src/components/contract-card/{contract-card.jsx => contract-card.tsx} (75%) rename packages/components/src/components/contract-card/{index.js => index.ts} (55%) rename packages/components/src/components/contract-card/result-overlay/{index.js => index.ts} (55%) rename packages/components/src/components/contract-card/result-overlay/{result-overlay.jsx => result-overlay.tsx} (82%) create mode 100644 packages/components/src/components/types/contract.types.ts diff --git a/packages/components/package.json b/packages/components/package.json index 459a9895a14b..ed739aab2e4e 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -74,6 +74,7 @@ "gh-pages": "^2.1.1", "glob": "^7.1.5", "lodash.throttle": "^4.1.1", + "moment": "^2.29.2", "prop-types": "^15.7.2", "react-content-loader": "^6.2.0", "react-div-100vh": "^0.3.8", diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx similarity index 84% rename from packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx rename to packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx index c94eee65b526..4f8cbbd7538f 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-body.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-body.tsx @@ -1,5 +1,4 @@ import classNames from 'classnames'; -import PropTypes from 'prop-types'; import React from 'react'; import { isCryptocurrency, @@ -13,15 +12,45 @@ import { isValidToSell, shouldShowCancellation, } from '@deriv/shared'; -import ContractCardItem from './contract-card-item.jsx'; -import ToggleCardDialog from './toggle-card-dialog.jsx'; +import ContractCardItem from './contract-card-item'; +import ToggleCardDialog from './toggle-card-dialog'; import CurrencyBadge from '../../currency-badge'; import DesktopWrapper from '../../desktop-wrapper'; import Icon from '../../icon'; import MobileWrapper from '../../mobile-wrapper'; import Money from '../../money'; -import { ResultStatusIcon } from '../result-overlay/result-overlay.jsx'; +import { ResultStatusIcon } from '../result-overlay/result-overlay'; import ProgressSliderMobile from '../../progress-slider-mobile'; +import { TContractInfo, TContractStore } from '@deriv/shared/src/utils/contract/contract-types'; +import { TGetCardLables, TToastConfig } from '../../types'; +import { ContractUpdate } from '@deriv/api-types'; + +export type TGeneralContractCardBodyProps = { + addToast: (toast_config: TToastConfig) => void; + contract_info: TContractInfo; + contract_update: ContractUpdate; + connectWithContractUpdate: (contract_update_form: React.ElementType) => React.ElementType; + currency: string; + current_focus?: string; + error_message_alignment: string; + getCardLabels: TGetCardLables; + getContractById: (contract_id?: number) => TContractStore; + should_show_cancellation_warning: boolean; + has_progress_slider: boolean; + is_mobile: boolean; + is_sold: boolean; + onMouseLeave: () => void; + removeToast: (toast_id: string) => void; + setCurrentFocus: (name: string) => void; + status: string; + toggleCancellationWarning: () => void; + progress_slider: React.ReactNode; +}; + +export type TContractCardBodyProps = { + is_multiplier: boolean; + server_time: moment.Moment; +} & TGeneralContractCardBodyProps; const MultiplierCardBody = ({ addToast, @@ -43,7 +72,7 @@ const MultiplierCardBody = ({ should_show_cancellation_warning, status, toggleCancellationWarning, -}) => { +}: TGeneralContractCardBodyProps) => { const { buy_price, bid_price, profit, limit_order, underlying } = contract_info; const total_profit = getTotalProfit(contract_info); @@ -62,13 +91,13 @@ const MultiplierCardBody = ({ })} > - +
0, - 'dc-contract-card--loss': +profit < 0, + 'dc-contract-card--profit': Number(profit) > 0, + 'dc-contract-card--loss': Number(profit) < 0, })} > @@ -168,7 +197,7 @@ const ContractCardBody = ({ should_show_cancellation_warning, status, toggleCancellationWarning, -}) => { +}: TContractCardBodyProps) => { const indicative = getIndicativePrice(contract_info); const { buy_price, sell_price, payout, profit, tick_count, date_expiry, purchase_time } = contract_info; const current_tick = tick_count ? getCurrentTick(contract_info) : null; @@ -213,8 +242,8 @@ const ContractCardBody = ({ 0} + is_loss={Number(profit) < 0} + is_won={Number(profit) > 0} >
- +
{card_body}
{card_body}
@@ -279,27 +305,4 @@ const ContractCardBody = ({ ); }; -ContractCardBody.propTypes = { - addToast: PropTypes.func, - connectWithContractUpdate: PropTypes.func, - contract_info: PropTypes.object, - contract_update: PropTypes.object, - currency: PropTypes.string, - current_focus: PropTypes.string, - error_message_alignment: PropTypes.string, - getCardLabels: PropTypes.func, - getContractById: PropTypes.func, - is_mobile: PropTypes.bool, - is_multiplier: PropTypes.bool, - is_sold: PropTypes.bool, - onMouseLeave: PropTypes.func, - removeToast: PropTypes.func, - server_time: PropTypes.object, - setCurrentFocus: PropTypes.func, - should_show_cancellation_warning: PropTypes.bool, - status: PropTypes.string, - toggleCancellationWarning: PropTypes.func, - has_progress_slider: PropTypes.bool, -}; - export default ContractCardBody; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.jsx deleted file mode 100644 index 817aee4bb145..000000000000 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { CSSTransition } from 'react-transition-group'; -import './sass/contract-card-dialog.scss'; -import { useOnClickOutside } from '../../../hooks/use-onclickoutside'; - -const ContractCardDialog = React.forwardRef(({ children, is_visible, left, toggleDialog, toggle_ref, top }, ref) => { - const validateClickOutside = event => is_visible && !toggle_ref.current.contains(event.target); - - useOnClickOutside(ref, toggleDialog, validateClickOutside); - - const dialog = ( - -
- {children} -
-
- ); - - return ReactDOM.createPortal( - dialog, // use portal to render dialog above ThemedScrollbars container - document.getElementById('deriv_app') - ); -}); - -ContractCardDialog.displayName = 'ContractCardDialog'; - -ContractCardDialog.propTypes = { - children: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.node), PropTypes.node]), - is_visible: PropTypes.bool, - left: PropTypes.number, - toggleDialog: PropTypes.func, - toggle_ref: PropTypes.object, - top: PropTypes.number, -}; - -export default ContractCardDialog; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.tsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.tsx new file mode 100644 index 000000000000..f2961c61bdd9 --- /dev/null +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-dialog.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { CSSTransition } from 'react-transition-group'; +import './sass/contract-card-dialog.scss'; +import { IClickEvent, useOnClickOutside } from '../../../hooks/use-onclickoutside'; + +export type TContractCardDialogProps = { + children: React.ReactNode; + is_visible: boolean; + left: number; + toggleDialog: (e: any) => void; // This function accomodates events for various HTML elements, which have no overlap, so typing it to any + toggle_ref?: React.RefObject; + top: number; +}; + +const ContractCardDialog = React.forwardRef( + ( + { children, is_visible, left, toggleDialog, toggle_ref, top }: TContractCardDialogProps, + ref: React.ForwardedRef + ) => { + const validateClickOutside = (event: IClickEvent) => + is_visible && !toggle_ref?.current?.contains(event.target as Node); + + useOnClickOutside(ref, toggleDialog, validateClickOutside); + + const dialog = ( + +
+ {children} +
+
+ ); + const deriv_app_element = document.getElementById('deriv_app'); + return ReactDOM.createPortal( + dialog, // use portal to render dialog above ThemedScrollbars container + deriv_app_element || document.body + ); + } +); + +ContractCardDialog.displayName = 'ContractCardDialog'; + +export default ContractCardDialog; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.tsx similarity index 81% rename from packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx rename to packages/components/src/components/contract-card/contract-card-items/contract-card-footer.tsx index b9a9084a7765..0e036df03929 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-footer.tsx @@ -1,10 +1,24 @@ import classNames from 'classnames'; -import PropTypes from 'prop-types'; import React from 'react'; import { CSSTransition } from 'react-transition-group'; import { isValidToCancel, hasContractEntered, isOpen, useNewRowTransition } from '@deriv/shared'; -import ContractCardSell from './contract-card-sell.jsx'; -import MultiplierCloseActions from './multiplier-close-actions.jsx'; +import ContractCardSell from './contract-card-sell'; +import MultiplierCloseActions from './multiplier-close-actions'; +import { TContractInfo } from '@deriv/shared/src/utils/contract/contract-types'; +import { TGetCardLables } from '../../types'; + +export type TCardFooterPropTypes = { + contract_info: TContractInfo; + getCardLabels: TGetCardLables; + is_multiplier?: boolean; + is_positions: boolean; + is_sell_requested: boolean; + onClickCancel: (contract_id?: number) => void; + onClickSell: (contract_id?: number) => void; + onFooterEntered: () => void; + server_time: moment.Moment; + should_show_transition: boolean; +}; const CardFooter = ({ contract_info, @@ -17,7 +31,7 @@ const CardFooter = ({ onFooterEntered, server_time, should_show_transition, -}) => { +}: TCardFooterPropTypes) => { const { in_prop } = useNewRowTransition(should_show_transition); const is_valid_to_cancel = isValidToCancel(contract_info); @@ -79,17 +93,4 @@ const CardFooter = ({ ); }; -CardFooter.propTypes = { - contract_info: PropTypes.object, - getCardLabels: PropTypes.func, - is_multiplier: PropTypes.bool, - is_positions: PropTypes.bool, - is_sell_requested: PropTypes.bool, - onClickCancel: PropTypes.func, - onClickSell: PropTypes.func, - onFooterEntered: PropTypes.func, - server_time: PropTypes.object, - should_show_transition: PropTypes.bool, -}; - export default CardFooter; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-header.tsx similarity index 87% rename from packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx rename to packages/components/src/components/contract-card/contract-card-items/contract-card-header.tsx index 89e4f80e6d65..f255655b774f 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-header.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-header.tsx @@ -1,15 +1,30 @@ import classNames from 'classnames'; -import PropTypes from 'prop-types'; import React from 'react'; import { CSSTransition } from 'react-transition-group'; import { isHighLow, getCurrentTick, isBot } from '@deriv/shared'; -import ContractTypeCell from './contract-type-cell.jsx'; +import ContractTypeCell from './contract-type-cell'; import Button from '../../button'; import Icon from '../../icon'; import Text from '../../text'; import ProgressSlider from '../../progress-slider'; import DesktopWrapper from '../../desktop-wrapper'; import MobileWrapper from '../../mobile-wrapper'; +import { TContractInfo } from '@deriv/shared/src/utils/contract/contract-types'; +import { TGetCardLables, TGetContractTypeDisplay } from '../../types'; + +export type TContractCardHeaderProps = { + contract_info: TContractInfo; + display_name: string; + getCardLabels: TGetCardLables; + getContractTypeDisplay: TGetContractTypeDisplay; + has_progress_slider: boolean; + is_mobile: boolean; + is_sell_requested: boolean; + is_valid_to_sell: boolean; + onClickSell: (contract_id?: number) => void; + server_time: moment.Moment; + id: number; +}; const ContractCardHeader = ({ contract_info, @@ -23,7 +38,7 @@ const ContractCardHeader = ({ is_valid_to_sell, onClickSell, server_time, -}) => { +}: TContractCardHeaderProps) => { const current_tick = contract_info.tick_count ? getCurrentTick(contract_info) : null; const { underlying, multiplier, contract_type, shortcode, purchase_time, date_expiry, tick_count, is_sold } = contract_info; @@ -99,18 +114,4 @@ const ContractCardHeader = ({ ); }; -ContractCardHeader.propTypes = { - contract_info: PropTypes.object, - display_name: PropTypes.string, - getCardLabels: PropTypes.func, - getContractTypeDisplay: PropTypes.func, - has_progress_slider: PropTypes.bool, - is_mobile: PropTypes.bool, - is_sell_requested: PropTypes.bool, - is_valid_to_sell: PropTypes.bool, - onClickSell: PropTypes.func, - server_time: PropTypes.object, - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), -}; - export default ContractCardHeader; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-item.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-item.tsx similarity index 61% rename from packages/components/src/components/contract-card/contract-card-items/contract-card-item.jsx rename to packages/components/src/components/contract-card/contract-card-items/contract-card-item.tsx index d993abbf328d..9f804d9cac71 100644 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-item.jsx +++ b/packages/components/src/components/contract-card/contract-card-items/contract-card-item.tsx @@ -1,8 +1,22 @@ import classNames from 'classnames'; import React from 'react'; -import PropTypes from 'prop-types'; -const ContractCardItem = ({ className, children, header, is_crypto, is_loss, is_won }) => { +export type TContractCardItemProps = { + className: string; + header: string; + is_crypto: boolean; + is_loss: boolean; + is_won: boolean; +}; + +const ContractCardItem = ({ + className, + children, + header, + is_crypto, + is_loss, + is_won, +}: React.PropsWithChildren>) => { return (
{header}
@@ -19,13 +33,4 @@ const ContractCardItem = ({ className, children, header, is_crypto, is_loss, is_ ); }; -ContractCardItem.propTypes = { - className: PropTypes.string, - children: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.node), PropTypes.node]), - header: PropTypes.string, - is_crypto: PropTypes.bool, - is_loss: PropTypes.bool, - is_won: PropTypes.bool, -}; - export default ContractCardItem; diff --git a/packages/components/src/components/contract-card/contract-card-items/contract-card-sell.jsx b/packages/components/src/components/contract-card/contract-card-items/contract-card-sell.jsx deleted file mode 100644 index e18c107d2fd4..000000000000 --- a/packages/components/src/components/contract-card/contract-card-items/contract-card-sell.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import { isOpen, isValidToSell, hasContractEntered } from '@deriv/shared'; -import Button from '../../button'; - -const ContractCardSell = ({ contract_info, getCardLabels, is_sell_requested, onClickSell }) => { - const is_valid_to_sell = isValidToSell(contract_info); - const should_show_sell = hasContractEntered(contract_info) && isOpen(contract_info); - - const onClick = ev => { - onClickSell(contract_info.contract_id); - ev.stopPropagation(); - ev.preventDefault(); - }; - - return ( - should_show_sell && ( - - {is_valid_to_sell ? ( -