diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b40465371db3..2563643202fb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -73,7 +73,7 @@ # deriv-app/account # ============================================================== -/packages/account/**/* @matin-deriv @amina-deriv @maryia-deriv +/packages/account/**/* @matin-deriv @amina-deriv # ============================================================== @@ -118,13 +118,13 @@ # ============================================================== /packages/api/**/* @ali-hosseini-deriv @matin-deriv -/packages/core/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv -/packages/shared/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv -/packages/components/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv -/packages/translations/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv -/packages/utils/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv +/packages/core/**/* @ali-hosseini-deriv @matin-deriv +/packages/shared/**/* @ali-hosseini-deriv @matin-deriv +/packages/components/**/* @ali-hosseini-deriv @matin-deriv +/packages/translations/**/* @ali-hosseini-deriv @matin-deriv +/packages/utils/**/* @ali-hosseini-deriv @matin-deriv /packages/hooks/**/* @ali-hosseini-deriv @matin-deriv -/packages/stores/**/* @ali-hosseini-deriv @matin-deriv @maryia-deriv +/packages/stores/**/* @ali-hosseini-deriv @matin-deriv # ============================================================== diff --git a/package-lock.json b/package-lock.json index aef2a19e6b57..60d6071a6059 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,7 @@ "@datadog/browser-rum": "^4.37.0", "@deriv/api-types": "^1.0.94", "@deriv/deriv-api": "^1.0.11", - "@deriv/deriv-charts": "1.3.2", + "@deriv/deriv-charts": "1.3.1", "@deriv/js-interpreter": "^3.0.0", "@deriv/ui": "^0.6.0", "@livechat/customer-sdk": "^2.0.4", @@ -2894,9 +2894,9 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/@deriv/deriv-charts": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.3.2.tgz", - "integrity": "sha512-j1xgloqF9jVPiCsfQJGKduivU7r42vQCeT+URCKz82dltlJAw7dmfxY3GgQHjBobkG+SK7ANG/rBzK1vyZn7bA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.3.1.tgz", + "integrity": "sha512-pjtaePIMhe1R5MkbOwnhAFAXGKZb3WI9JtNpgVS3uL8j07kzAzk2SsFOBSNDggwUX1GW1SI/4bPjcDyXTtA2sA==", "dependencies": { "@welldone-software/why-did-you-render": "^3.3.8", "classnames": "^2.3.1", @@ -51290,9 +51290,9 @@ } }, "@deriv/deriv-charts": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.3.2.tgz", - "integrity": "sha512-j1xgloqF9jVPiCsfQJGKduivU7r42vQCeT+URCKz82dltlJAw7dmfxY3GgQHjBobkG+SK7ANG/rBzK1vyZn7bA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@deriv/deriv-charts/-/deriv-charts-1.3.1.tgz", + "integrity": "sha512-pjtaePIMhe1R5MkbOwnhAFAXGKZb3WI9JtNpgVS3uL8j07kzAzk2SsFOBSNDggwUX1GW1SI/4bPjcDyXTtA2sA==", "requires": { "@welldone-software/why-did-you-render": "^3.3.8", "classnames": "^2.3.1", diff --git a/packages/account/package.json b/packages/account/package.json index e05b3edcab01..4e8c7a4c4c3b 100644 --- a/packages/account/package.json +++ b/packages/account/package.json @@ -28,11 +28,11 @@ }, "dependencies": { "@binary-com/binary-document-uploader": "^2.4.8", - "@deriv/api-types": "^1.0.116", + "@deriv/api-types": "^1.0.94", "@deriv/components": "^1.0.0", "@deriv/hooks": "^1.0.0", "@deriv/shared": "^1.0.0", - "@deriv/stores": "^1.0.0", + "@deriv/stores":"^1.0.0", "@deriv/translations": "^1.0.0", "bowser": "^2.9.0", "classnames": "^2.2.6", diff --git a/packages/account/src/App.tsx b/packages/account/src/App.tsx index 23cbccb72a8e..f658afe8facd 100644 --- a/packages/account/src/App.tsx +++ b/packages/account/src/App.tsx @@ -17,11 +17,8 @@ const App = ({ passthrough }: TAppProps) => { const { root_store, WS } = passthrough; setWebsocket(WS); - const { notification_messages_ui: Notifications } = root_store.ui; - return ( - {Notifications && } diff --git a/packages/account/src/Components/account-limits/account-limits-article.tsx b/packages/account/src/Components/account-limits/account-limits-article.tsx index 212ffb2c747c..ab843d110855 100644 --- a/packages/account/src/Components/account-limits/account-limits-article.tsx +++ b/packages/account/src/Components/account-limits/account-limits-article.tsx @@ -1,3 +1,4 @@ +import PropTypes from 'prop-types'; import * as React from 'react'; import { StaticUrl } from '@deriv/components'; import { Localize, localize } from '@deriv/translations'; @@ -28,4 +29,8 @@ const AccountLimitsArticle = ({ is_from_derivgo }: TAccountLimitsArticle) => { return ; }; +AccountLimitsArticle.propTypes = { + is_from_derivgo: PropTypes.bool, +}; + export default AccountLimitsArticle; diff --git a/packages/account/src/Components/forms/idv-form.tsx b/packages/account/src/Components/forms/idv-form.tsx index 961802b60799..48a5a5fd0c1d 100644 --- a/packages/account/src/Components/forms/idv-form.tsx +++ b/packages/account/src/Components/forms/idv-form.tsx @@ -1,11 +1,35 @@ import React from 'react'; import classNames from 'classnames'; -import { Field, FieldProps } from 'formik'; +import { Field, FormikProps, FormikHandlers, FieldProps } from 'formik'; +import { ResidenceList } from '@deriv/api-types'; import { localize } from '@deriv/translations'; -import { formatInput, getIDVNotApplicableOption } from '@deriv/shared'; +import { formatInput, IDV_NOT_APPLICABLE_OPTION } from '@deriv/shared'; import { Autocomplete, DesktopWrapper, Input, MobileWrapper, SelectNative, Text } from '@deriv/components'; import { getDocumentData, preventEmptyClipboardPaste, generatePlaceholderText, getExampleFormat } from 'Helpers/utils'; -import { TDocumentList, TIDVForm } from 'Types'; + +type TDocumentList = Array<{ + id: string; + text: string; + value?: string; + sample_image?: string; + example_format?: string; + additional?: any; +}>; + +type TFormProps = { + document_type: TDocumentList[0]; + document_number: string; + document_additional?: string; + error_message?: string; +}; + +type TIDVForm = { + selected_country: ResidenceList[0]; + hide_hint?: boolean; + class_name?: string; + can_skip_document_verification: boolean; +} & Partial & + FormikProps; const IDVForm = ({ errors, @@ -19,7 +43,7 @@ const IDVForm = ({ hide_hint, can_skip_document_verification = false, }: TIDVForm) => { - const [document_list, setDocumentList] = React.useState([]); + const [document_list, setDocumentList] = React.useState([]); const [document_image, setDocumentImage] = React.useState(null); const [selected_doc, setSelectedDoc] = React.useState(''); @@ -33,8 +57,6 @@ const IDVForm = ({ sample_image: '', }; - const IDV_NOT_APPLICABLE_OPTION = React.useMemo(() => getIDVNotApplicableOption(), []); - React.useEffect(() => { if (document_data && selected_country && selected_country.value) { const document_types = Object.keys(document_data); @@ -78,7 +100,7 @@ const IDVForm = ({ setDocumentList([...new_document_list]); } } - }, [document_data, selected_country, can_skip_document_verification, IDV_NOT_APPLICABLE_OPTION]); + }, [document_data, selected_country, can_skip_document_verification]); const resetDocumentItemSelected = () => { setFieldValue('document_type', default_document, true); @@ -98,7 +120,7 @@ const IDVForm = ({ setFieldValue(document_name, current_input, true); }; - const bindDocumentData = (item: TDocumentList) => { + const bindDocumentData = (item: TDocumentList[0]) => { setFieldValue('document_type', item, true); setSelectedDoc(item?.id); if (item?.id === IDV_NOT_APPLICABLE_OPTION.id) { @@ -149,7 +171,7 @@ const IDVForm = ({ } }} onChange={handleChange} - onItemSelection={(item: TDocumentList) => { + onItemSelection={(item: TDocumentList[0]) => { if ( item.text === 'No results found' || !item.text diff --git a/packages/account/src/Components/personal-details/personal-details.jsx b/packages/account/src/Components/personal-details/personal-details.jsx index 4d2823e1e0b4..dfd5045bee50 100644 --- a/packages/account/src/Components/personal-details/personal-details.jsx +++ b/packages/account/src/Components/personal-details/personal-details.jsx @@ -13,7 +13,7 @@ import { isDesktop, isMobile, PlatformContext, - getIDVNotApplicableOption, + IDV_NOT_APPLICABLE_OPTION, removeEmptyPropertiesFromObject, } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; @@ -83,7 +83,6 @@ const PersonalDetails = ({ residence_list, real_account_signup_target, }); - const IDV_NOT_APPLICABLE_OPTION = React.useMemo(() => getIDVNotApplicableOption(), []); const validateIDV = values => { const errors = {}; diff --git a/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx b/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx index c81e867290ea..347cb848e396 100644 --- a/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx +++ b/packages/account/src/Components/poi/idv-document-submit/idv-document-submit.tsx @@ -1,16 +1,16 @@ import React from 'react'; +import PropTypes from 'prop-types'; import classNames from 'classnames'; import { Button } from '@deriv/components'; import { Formik } from 'formik'; import { localize } from '@deriv/translations'; import { WS, - getIDVNotApplicableOption, + IDV_NOT_APPLICABLE_OPTION, toMoment, filterObjProperties, isDesktop, removeEmptyPropertiesFromObject, - formatIDVFormValues, } from '@deriv/shared'; import { documentAdditionalError, getRegex, validate, makeSettingsRequest, validateName } from 'Helpers/utils'; import FormFooter from 'Components/form-footer'; @@ -18,17 +18,6 @@ import BackButtonIcon from 'Assets/ic-poi-back-btn.svg'; import IDVForm from 'Components/forms/idv-form'; import PersonalDetailsForm from 'Components/forms/personal-details-form'; import FormSubHeader from 'Components/form-sub-header'; -import { GetSettings, IdentityVerificationAddDocumentResponse, ResidenceList } from '@deriv/api-types'; -import { TIDVFormValues, TInputFieldValues, TDocumentList } from 'Types'; - -type TIDVDocumentSubmitProps = { - account_settings: GetSettings; - getChangeableFields: () => Array; - handleBack: React.MouseEventHandler; - handleViewComplete: () => void; - is_from_external: boolean; - selected_country: ResidenceList[0]; -}; const IdvDocumentSubmit = ({ handleBack, @@ -37,7 +26,7 @@ const IdvDocumentSubmit = ({ is_from_external, account_settings, getChangeableFields, -}: TIDVDocumentSubmitProps) => { +}) => { const visible_settings = ['first_name', 'last_name', 'date_of_birth']; const form_initial_values = filterObjProperties(account_settings, visible_settings) || {}; @@ -59,21 +48,20 @@ const IdvDocumentSubmit = ({ ...form_initial_values, }; - const getExampleFormat = (example_format: string) => { + const getExampleFormat = example_format => { return example_format ? localize('Example: ') + example_format : ''; }; - const IDV_NOT_APPLICABLE_OPTION = React.useMemo(() => getIDVNotApplicableOption(), []); - const shouldHideHelperImage = (document_id: string) => document_id === IDV_NOT_APPLICABLE_OPTION.id; + const shouldHideHelperImage = document_id => document_id === IDV_NOT_APPLICABLE_OPTION.id; - const isDocumentTypeValid = (document_type: TDocumentList) => { + const isDocumentTypeValid = document_type => { if (!document_type?.text) { return localize('Please select a document type.'); } return undefined; }; - const isAdditionalDocumentValid = (document_type: TDocumentList, document_additional: string) => { + const isAdditionalDocumentValid = (document_type, document_additional) => { const error_message = documentAdditionalError(document_additional, document_type.additional?.format); if (error_message) { return localize(error_message) + getExampleFormat(document_type.additional?.example_format); @@ -81,7 +69,7 @@ const IdvDocumentSubmit = ({ return undefined; }; - const isDocumentNumberValid = (document_number: string, document_type: Required) => { + const isDocumentNumberValid = (document_number, document_type) => { const is_document_number_invalid = document_number === document_type.example_format; if (!document_number) { return localize('Please enter your document number. ') + getExampleFormat(document_type.example_format); @@ -95,8 +83,8 @@ const IdvDocumentSubmit = ({ return undefined; }; - const validateFields = (values: TIDVFormValues) => { - const errors: Partial = {}; + const validateFields = values => { + const errors = {}; const { document_type, document_number, document_additional } = values; const needs_additional_document = !!document_type.additional; @@ -139,22 +127,25 @@ const IdvDocumentSubmit = ({ setSubmitting(false); return; } - const submit_data = { identity_verification_document_add: 1, - ...formatIDVFormValues(values, selected_country.value), + document_number: values.document_number, + document_additional: values.document_additional || '', + document_type: values.document_type.id, + issuing_country: selected_country.value, }; - WS.send(submit_data).then( - (response: IdentityVerificationAddDocumentResponse & { error: { message: string } }) => { - setSubmitting(false); - if (response.error) { - setErrors({ error_message: response.error.message }); - return; - } - handleViewComplete(); + if (submit_data.document_type === IDV_NOT_APPLICABLE_OPTION.id) { + return; + } + WS.send(submit_data).then(response => { + setSubmitting(false); + if (response.error) { + setErrors({ error_message: response.error.message }); + return; } - ); + handleViewComplete(); + }); }; return ( @@ -234,4 +225,13 @@ const IdvDocumentSubmit = ({ ); }; +IdvDocumentSubmit.propTypes = { + account_settings: PropTypes.object, + getChangeableFields: PropTypes.func, + handleBack: PropTypes.func, + handleViewComplete: PropTypes.func, + is_from_external: PropTypes.bool, + selected_country: PropTypes.object, +}; + export default IdvDocumentSubmit; diff --git a/packages/account/src/Constants/idv-document-config.ts b/packages/account/src/Constants/idv-document-config.ts deleted file mode 100644 index 2202ab910848..000000000000 --- a/packages/account/src/Constants/idv-document-config.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { getUrlBase } from '@deriv/shared'; -import { localize } from '@deriv/translations'; - -const getImageLocation = (image_name: string) => getUrlBase(`/public/images/common/${image_name}`); - -// Note: Ensure that the object keys matches BE API's keys. This is simply a mapping for FE templates - -export const getIDVDocumentConfig = () => ({ - ke: { - alien_card: { - new_display_name: '', - example_format: '123456', - sample_image: getImageLocation('ke_alien_card.png'), - }, - national_id: { - new_display_name: '', - example_format: '12345678', - sample_image: getImageLocation('ke_national_identity_card.png'), - }, - passport: { - new_display_name: '', - example_format: 'A12345678', - sample_image: getImageLocation('ke_passport.png'), - }, - }, - za: { - national_id: { - new_display_name: localize('National ID'), - example_format: '1234567890123', - sample_image: getImageLocation('za_national_identity_card.png'), - }, - national_id_no_photo: { - new_display_name: localize('National ID (No Photo)'), - example_format: '1234567890123', - sample_image: '', - }, - }, - ng: { - bvn: { - new_display_name: localize('Bank Verification Number'), - example_format: '12345678901', - sample_image: '', - }, - cac: { - new_display_name: localize('Corporate Affairs Commission'), - example_format: '12345678', - sample_image: '', - }, - drivers_license: { - new_display_name: '', - example_format: 'ABC123456789', - sample_image: getImageLocation('ng_drivers_license.png'), - }, - nin: { - new_display_name: localize('National Identity Number'), - example_format: '12345678901', - sample_image: '', - }, - nin_slip: { - new_display_name: localize('National Identity Number Slip'), - example_format: '12345678901', - sample_image: getImageLocation('ng_nin_slip.png'), - }, - tin: { - new_display_name: localize('Taxpayer identification number'), - example_format: '12345678-1234', - sample_image: '', - }, - voter_id: { - new_display_name: localize('Voter ID'), - example_format: '1234567890123456789', - sample_image: getImageLocation('ng_voter_id.png'), - }, - }, - gh: { - drivers_license: { - new_display_name: '', - example_format: 'B1234567', - sample_image: '', - }, - national_id: { - new_display_name: localize('National ID'), - example_format: 'GHA-123456789-1', - sample_image: '', - }, - passport: { - new_display_name: localize('Passport'), - example_format: 'G1234567', - sample_image: '', - }, - ssnit: { - new_display_name: localize('Social Security and National Insurance Trust'), - example_format: 'C123456789012', - sample_image: '', - }, - voter_id: { - new_display_name: localize('Voter ID'), - example_format: '01234567890', - sample_image: '', - }, - }, - br: { - cpf: { - new_display_name: localize('CPF'), - example_format: '123.456.789-12', - sample_image: '', - }, - }, - ug: { - national_id: { - new_display_name: localize('National ID'), - example_format: 'CM12345678PE1D', - sample_image: getImageLocation('ug_national_identity_card.png'), - }, - national_id_no_photo: { - new_display_name: localize('National ID (No Photo)'), - example_format: 'CM12345678PE1D', - sample_image: '', - }, - }, - zw: { - national_id: { - new_display_name: localize('National ID'), - example_format: '081234567F53', - sample_image: getImageLocation('zw_national_identity_card.png'), - }, - }, -}); diff --git a/packages/account/src/Helpers/utils.ts b/packages/account/src/Helpers/utils.ts index 581e4ae4b117..68484b8ec624 100644 --- a/packages/account/src/Helpers/utils.ts +++ b/packages/account/src/Helpers/utils.ts @@ -1,8 +1,16 @@ -import { filterObjProperties, toMoment, validLength, validName, getIDVNotApplicableOption } from '@deriv/shared'; +import { + getUrlBase, + filterObjProperties, + toMoment, + validLength, + validName, + IDV_NOT_APPLICABLE_OPTION, +} from '@deriv/shared'; import { localize } from '@deriv/translations'; import { ResidenceList, GetSettings, GetAccountStatus } from '@deriv/api-types'; -import { FormikValues } from 'formik'; -import { getIDVDocumentConfig } from '../Constants/idv-document-config'; +import { FormikErrors, FormikValues } from 'formik'; + +const getImageLocation = (image_name: string) => getUrlBase(`/public/images/common/${image_name}`); export const documentAdditionalError = (document_additional: string, document_additional_format: string) => { let error_message = null; @@ -27,7 +35,128 @@ const regex = [ }, ]; -const IDV_NOT_APPLICABLE_OPTION = getIDVNotApplicableOption(); +// Note: Ensure that the object keys matches BE API's keys. This is simply a mapping for FE templates +const idv_document_data = Object.freeze({ + ke: { + alien_card: { + new_display_name: '', + example_format: '123456', + sample_image: getImageLocation('ke_alien_card.png'), + }, + national_id: { + new_display_name: '', + example_format: '12345678', + sample_image: getImageLocation('ke_national_identity_card.png'), + }, + passport: { + new_display_name: '', + example_format: 'A12345678', + sample_image: getImageLocation('ke_passport.png'), + }, + }, + za: { + national_id: { + new_display_name: localize('National ID'), + example_format: '1234567890123', + sample_image: getImageLocation('za_national_identity_card.png'), + }, + national_id_no_photo: { + new_display_name: localize('National ID (No Photo)'), + example_format: '1234567890123', + sample_image: '', + }, + }, + ng: { + bvn: { + new_display_name: localize('Bank Verification Number'), + example_format: '12345678901', + sample_image: '', + }, + cac: { + new_display_name: localize('Corporate Affairs Commission'), + example_format: '12345678', + sample_image: '', + }, + drivers_license: { + new_display_name: '', + example_format: 'ABC123456789', + sample_image: getImageLocation('ng_drivers_license.png'), + }, + nin: { + new_display_name: localize('National Identity Number'), + example_format: '12345678901', + sample_image: '', + }, + nin_slip: { + new_display_name: localize('National Identity Number Slip'), + example_format: '12345678901', + sample_image: getImageLocation('ng_nin_slip.png'), + }, + tin: { + new_display_name: localize('Taxpayer identification number'), + example_format: '12345678-1234', + sample_image: '', + }, + voter_id: { + new_display_name: localize('Voter ID'), + example_format: '1234567890123456789', + sample_image: getImageLocation('ng_voter_id.png'), + }, + }, + gh: { + drivers_license: { + new_display_name: '', + example_format: 'B1234567', + sample_image: '', + }, + national_id: { + new_display_name: localize('National ID'), + example_format: 'GHA-123456789-1', + sample_image: '', + }, + passport: { + new_display_name: localize('Passport'), + example_format: 'G1234567', + sample_image: '', + }, + ssnit: { + new_display_name: localize('Social Security and National Insurance Trust'), + example_format: 'C123456789012', + sample_image: '', + }, + voter_id: { + new_display_name: localize('Voter ID'), + example_format: '01234567890', + sample_image: '', + }, + }, + br: { + cpf: { + new_display_name: localize('CPF'), + example_format: '123.456.789-12', + sample_image: '', + }, + }, + ug: { + national_id: { + new_display_name: localize('National ID'), + example_format: 'CM12345678PE1D', + sample_image: getImageLocation('ug_national_identity_card.png'), + }, + national_id_no_photo: { + new_display_name: localize('National ID (No Photo)'), + example_format: 'CM12345678PE1D', + sample_image: '', + }, + }, + zw: { + national_id: { + new_display_name: localize('National ID'), + example_format: '081234567F53', + sample_image: getImageLocation('zw_national_identity_card.png'), + }, + }, +}); type TIDVSupportCheck = { residence_list: ResidenceList; @@ -54,10 +183,9 @@ export const shouldShowIdentityInformation = ({ }; export const getDocumentData = (country_code: string, document_type: string) => { - const IDV_DOCUMENT_DATA = getIDVDocumentConfig(); return ( - (Object.keys(IDV_DOCUMENT_DATA).includes(country_code) && - (IDV_DOCUMENT_DATA as any)[country_code][document_type]) || { + (Object.keys(idv_document_data).includes(country_code) && + (idv_document_data as any)[country_code][document_type]) || { new_display_name: '', example_format: '', sample_image: '', @@ -133,7 +261,7 @@ export const validateName = (name: string) => { return ''; }; -export const getExampleFormat = (example_format: string | undefined) => +export const getExampleFormat = (example_format: string) => example_format ? localize('Example: ') + example_format : ''; export const isDocumentTypeValid = (document_type: FormikValues) => { diff --git a/packages/account/src/Sections/Profile/PersonalDetails/personal-details.jsx b/packages/account/src/Sections/Profile/PersonalDetails/personal-details.jsx index 8b45270125a4..9632ae82057b 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/personal-details.jsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/personal-details.jsx @@ -104,7 +104,7 @@ export const PersonalDetailsForm = observer(({ history }) => { const [is_btn_loading, setIsBtnLoading] = React.useState(false); const [is_submit_success, setIsSubmitSuccess] = useStateCallback(false); - const { client, notifications, common } = useStore(); + const { client, notifications, ui, common } = useStore(); const { authentication_status, @@ -132,6 +132,7 @@ export const PersonalDetailsForm = observer(({ history }) => { showPOAAddressMismatchFailureNotification, } = notifications; + const { Notifications } = ui; const { is_language_changing } = common; const is_mf = landing_company_shortcode === 'maltainvest'; const has_poa_address_mismatch = account_status.status?.includes('poa_address_mismatch'); @@ -560,6 +561,7 @@ export const PersonalDetailsForm = observer(({ history }) => { dirty, }) => ( + {Notifications && } {show_form && (
{ /(?[0-9a-zA-Z-]+\s[0-9:]+GMT)[\s](IP=)(?[\w:.]+)\sIP_COUNTRY=(?([a-zA-Z]{2}))\s(User_AGENT=)(\w.*)(?iPhone|Android)([\W\w]+)\s(?Deriv P2P|Deriv GO)(?[\w\W]+)\s(LANG=)([\w]{2})/ ); const date = environment_split[0]; - const time = environment_split[1].replace('GMT', ' GMT'); - data[i].date = `${moment(date).format('YYYY-MM-DD')} ${time}`; + const time = environment_split[1].replace('GMT', ''); + const date_time = convertDateFormat(`${date} ${time}`, 'D-MMMM-YY hh:mm:ss', 'YYYY-MM-DD hh:mm:ss'); + data[i].date = `${date_time} GMT`; data[i].action = login_history[i].action === 'login' ? localize('Login') : localize('Logout'); const user_agent = environment.substring(environment.indexOf('User_AGENT'), environment.indexOf('LANG')); const ua = mobile_app_UA ? mobile_app_UA.groups : Bowser.getParser(user_agent)?.getBrowser(); diff --git a/packages/account/src/Sections/Security/TwoFactorAuthentication/two-factor-authentication.jsx b/packages/account/src/Sections/Security/TwoFactorAuthentication/two-factor-authentication.jsx index e9663fed49ac..afada8e544c8 100644 --- a/packages/account/src/Sections/Security/TwoFactorAuthentication/two-factor-authentication.jsx +++ b/packages/account/src/Sections/Security/TwoFactorAuthentication/two-factor-authentication.jsx @@ -19,10 +19,11 @@ import TwoFactorAuthenticationArticle from './two-factor-authentication-article. import { observer, useStore } from '@deriv/stores'; const TwoFactorAuthentication = observer(() => { - const { client, common } = useStore(); + const { client, ui, common } = useStore(); const { email_address, getTwoFAStatus, has_enabled_two_fa, is_switching, setTwoFAStatus, setTwoFAChangedStatus } = client; const { is_language_changing } = common; + const { notification_messages_ui: Notifications } = ui; const [is_loading, setLoading] = React.useState(true); const [is_qr_loading, setQrLoading] = React.useState(false); const [error_message, setErrorMessage] = React.useState(''); @@ -197,6 +198,7 @@ const TwoFactorAuthentication = observer(() => { 'two-factor__wrapper-dashboard': is_appstore, })} > + {Notifications && } {has_enabled_two_fa ? TwoFactorEnabled : TwoFactorDisabled} diff --git a/packages/account/src/Sections/Verification/ProofOfIdentity/__tests__/proof-of-identity-container.spec.js b/packages/account/src/Sections/Verification/ProofOfIdentity/__tests__/proof-of-identity-container.spec.js deleted file mode 100644 index 8603b4187173..000000000000 --- a/packages/account/src/Sections/Verification/ProofOfIdentity/__tests__/proof-of-identity-container.spec.js +++ /dev/null @@ -1,304 +0,0 @@ -import React from 'react'; -import { render, screen, act, waitFor } from '@testing-library/react'; -import ProofOfIdentityContainer from '../proof-of-identity-container'; -import { populateVerificationStatus } from '../../Helpers/verification.js'; -import { identity_status_codes, service_code } from '../proof-of-identity-utils'; - -jest.mock('@deriv/shared', () => ({ - ...jest.requireActual('@deriv/shared'), - WS: { - authorized: { - getAccountStatus: jest.fn().mockResolvedValue({ get_account_status: 1 }), - }, - }, -})); - -jest.mock('@deriv/components', () => ({ - ...jest.requireActual('@deriv/components'), - Loading: jest.fn(() => 'mockedLoading'), -})); - -jest.mock('onfido-sdk-ui', () => ({ - init: jest.fn().mockResolvedValue({}), -})); - -jest.mock('../../Helpers/verification.js', () => ({ - populateVerificationStatus: jest.fn().mockReturnValue({ - is_age_verified: false, - }), -})); - -jest.mock('Components/demo-message', () => jest.fn(() => 'mockedDemoMessage')); -jest.mock('Sections/Verification/ProofOfIdentity/idv.jsx', () => jest.fn(() => 'mockedIDV')); -jest.mock('Sections/Verification/ProofOfIdentity/onfido.jsx', () => jest.fn(() => 'mockedOnfido')); -jest.mock('Sections/Verification/ProofOfIdentity/proof-of-identity-submission.jsx', () => - jest.fn(() => 'mockedProofOfIdentitySubmission') -); -jest.mock('Components/poi/status/unsupported', () => jest.fn(() => 'mockedUnsupported')); -jest.mock('Components/poi/status/not-required', () => jest.fn(() => 'mockedNotRequired')); -jest.mock('Components/error-component', () => jest.fn(() => 'mockedErrorMessage')); -jest.mock('Components/poi/status/upload-complete', () => jest.fn(() => 'mockedUploadComplete')); -jest.mock('Components/poi/status/verified', () => jest.fn(() => 'mockedVerified')); -jest.mock('Components/poi/status/limited', () => jest.fn(() => 'mockedLimited')); -jest.mock('Components/poi/status/expired', () => jest.fn(() => 'mockedExpired')); - -const mock_props = { - account_settings: {}, - account_status: { - authentication: { - attempts: { - count: 1, - history: [ - { - country_code: 'id', - id: '8919', - service: 'manual', - status: 'verified', - timestamp: 1674633681, - }, - ], - latest: { - country_code: 'id', - id: '8919', - service: 'manual', - status: 'verified', - timestamp: 1674633681, - }, - }, - document: { - status: 'verified', - }, - - identity: { - services: { - idv: { - last_rejected: [], - reported_properties: {}, - status: 'none', - submissions_left: 3, - }, - manual: { - status: 'none', - }, - onfido: { - country_code: 'IDN', - documents_supported: [ - 'Driving Licence', - 'National Identity Card', - 'Passport', - 'Residence Permit', - ], - is_country_supported: 1, - last_rejected: [], - reported_properties: {}, - status: 'none', - submissions_left: 3, - }, - }, - status: 'verified', - }, - income: { - status: 'none', - }, - needs_verification: [], - ownership: { - requests: [], - status: 'none', - }, - }, - currency_config: { - USD: { - is_deposit_suspended: 0, - is_withdrawal_suspended: 0, - }, - }, - p2p_status: 'none', - prompt_client_to_authenticate: 0, - risk_classification: 'low', - status: [ - 'age_verification', - 'allow_document_upload', - 'authenticated', - 'dxtrade_password_not_set', - 'financial_information_not_complete', - 'idv_disallowed', - 'mt5_password_not_set', - 'trading_experience_not_complete', - ], - }, - app_routing_history: [ - { - pathname: '/account/proof-of-identity', - }, - ], - fetchResidenceList: jest.fn().mockResolvedValue({ - residence_list: [], - }), - getChangeableFields: [], - is_from_external: false, - is_switching: false, - is_virtual: false, - is_high_risk: false, - is_withdrawal_lock: false, - onStateChange: jest.fn(), - refreshNotifications: jest.fn(), - routeBackInApp: jest.fn(), - should_allow_authentication: false, - setIsCfdPoiCompleted: jest.fn(), - updateAccountStatus: jest.fn(), -}; - -describe('ProofOfIdentityContainer', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - it('should render proof of identity container with loader', async () => { - const new_props = { - ...mock_props, - is_switching: true, - }; - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedLoading')).toBeInTheDocument(); - }); - - it('should render message when account is virtual', async () => { - const new_props = { - ...mock_props, - is_virtual: true, - }; - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedDemoMessage')).toBeInTheDocument(); - }); - - it('should render API error message returned in response', async () => { - const new_props = { - ...mock_props, - fetchResidenceList: jest.fn().mockResolvedValue({ - error: { - message: 'API error', - }, - }), - }; - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedErrorMessage')).toBeInTheDocument(); - }); - - it('should render messages that POA is not required', async () => { - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedNotRequired')).toBeInTheDocument(); - }); - - it('should render POI submission section when status is none', async () => { - populateVerificationStatus.mockReturnValue({ - identity_status: identity_status_codes.none, - is_age_verified: true, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedProofOfIdentitySubmission')).toBeInTheDocument(); - }); - - it('should render POI submission section when allow_poi_resubmission is set', async () => { - populateVerificationStatus.mockReturnValue({ - allow_poi_resubmission: true, - is_age_verified: true, - identity_status: identity_status_codes.verified, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedProofOfIdentitySubmission')).toBeInTheDocument(); - }); - - it('should render Upload complete section when status is pending', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: null, - is_age_verified: true, - identity_status: identity_status_codes.pending, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedUploadComplete')).toBeInTheDocument(); - }); - - it('should render Verified section when status is verified', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: null, - is_age_verified: true, - identity_status: identity_status_codes.verified, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedVerified')).toBeInTheDocument(); - }); - - it('should render Expired section when status is expired', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: null, - is_age_verified: true, - identity_status: identity_status_codes.expired, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedExpired')).toBeInTheDocument(); - }); - - it('should render Limited section when status is rejected', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: null, - is_age_verified: true, - identity_status: identity_status_codes.rejected, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedLimited')).toBeInTheDocument(); - }); - - it('should render Onfido section when there was a previous onfido submission', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: { service: service_code.onfido }, - is_age_verified: true, - identity_status: identity_status_codes.rejected, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedOnfido')).toBeInTheDocument(); - }); - - it('should render IDV section when there was a previous IDV submission', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: { service: service_code.idv }, - is_age_verified: true, - identity_status: identity_status_codes.rejected, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedIDV')).toBeInTheDocument(); - }); - - it('should render Manual section when there was a previous manual submission', async () => { - populateVerificationStatus.mockReturnValue({ - identity_last_attempt: { service: service_code.manual }, - is_age_verified: true, - identity_status: identity_status_codes.rejected, - }); - - render(); - await waitFor(() => {}); - expect(screen.getByText('mockedUnsupported')).toBeInTheDocument(); - }); -}); diff --git a/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-container.jsx b/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-container.jsx index f9fc84bb6fe4..a77b3ea5d4d9 100644 --- a/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-container.jsx +++ b/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-container.jsx @@ -98,6 +98,9 @@ const ProofOfIdentityContainer = ({ needs_poa, onfido, } = verification_status; + const last_attempt_status = identity_last_attempt?.status; + const is_last_attempt_idv = identity_last_attempt?.service === 'idv'; + const is_last_attempt_onfido = identity_last_attempt?.service === 'onfido'; const should_ignore_idv = is_high_risk && is_withdrawal_lock; if (!should_allow_authentication && !is_age_verified) { @@ -121,7 +124,13 @@ const ProofOfIdentityContainer = ({ ); - if (identity_status === identity_status_codes.none || has_require_submission || allow_poi_resubmission) { + if ( + identity_status === identity_status_codes.none || + has_require_submission || + allow_poi_resubmission || + (should_ignore_idv && is_last_attempt_idv && manual?.status !== 'verified' && manual?.status !== 'pending') || + (should_ignore_idv && is_last_attempt_onfido && last_attempt_status === 'rejected') + ) { return ( { setSubmitting(true); + const { document_number, document_type } = values; const request = makeSettingsRequest(values, [...getChangeableFields()]); @@ -70,9 +72,16 @@ const POISubmissionForMT5 = ({ const submit_data = { identity_verification_document_add: 1, - ...formatIDVFormValues(values, citizen_data.value), + document_number, + document_type: document_type.id, + issuing_country: citizen_data.value, }; + if (submit_data.document_type === IDV_NOT_APPLICABLE_OPTION.id) { + handlePOIComplete(); + return; + } + WS.send(submit_data).then(response => { setSubmitting(false); if (response.error) { diff --git a/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-submission.jsx b/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-submission.jsx index 3f4efcae812f..81e2c69d245f 100644 --- a/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-submission.jsx +++ b/packages/account/src/Sections/Verification/ProofOfIdentity/proof-of-identity-submission.jsx @@ -1,3 +1,4 @@ +/* eslint-disable react-hooks/exhaustive-deps */ import React from 'react'; import { WS } from '@deriv/shared'; import CountrySelector from 'Components/poi/poi-country-selector'; diff --git a/packages/account/src/Types/common-prop.type.ts b/packages/account/src/Types/common-prop.type.ts index 5298105baa8b..204e11a8985e 100644 --- a/packages/account/src/Types/common-prop.type.ts +++ b/packages/account/src/Types/common-prop.type.ts @@ -1,6 +1,6 @@ /** Add types that are shared between components */ -import { FormikHandlers, FormikProps, FormikValues } from 'formik'; -import { Authorize, IdentityVerificationAddDocumentResponse, ResidenceList } from '@deriv/api-types'; +import { FormikProps, FormikValues } from 'formik'; +import { Authorize, ResidenceList } from '@deriv/api-types'; import { Redirect } from 'react-router-dom'; export type TToken = { @@ -150,54 +150,6 @@ export type TPersonalDetailsForm = { export type TInputFieldValues = Record; -export type TIDVVerificationResponse = IdentityVerificationAddDocumentResponse & { error: { message: string } }; - -export type TDocumentList = { - id: string; - text: string; - value?: string; - sample_image?: string; - example_format?: string; - additional?: { - display_name?: string; - example_format?: string; - }; -}; - -type TFormProps = { - document_type: TDocumentList; - document_number: string; - document_additional?: string; - error_message?: string; -}; - -export type TIDVForm = { - selected_country: ResidenceList[0]; - hide_hint?: boolean; - class_name?: string; - can_skip_document_verification: boolean; -} & Partial & - FormikProps; - export type TVerificationStatus = Readonly< Record<'none' | 'pending' | 'rejected' | 'verified' | 'expired' | 'suspected', string> >; - -type TDocumentList = Array<{ - id: string; - text: string; - value?: string; - sample_image?: string; - example_format?: string; - additional?: { - display_name: string; - format: string; - }; -}>; - -export type TIDVFormValues = { - document_type: TDocumentList[0]; - document_number: string; - document_additional?: string; - error_message?: string; -}; diff --git a/packages/api/package.json b/packages/api/package.json index 3e0a17020cf0..603e827785a0 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -10,7 +10,7 @@ "@tanstack/react-query-devtools": "^4.28.0" }, "devDependencies": { - "@deriv/api-types": "^1.0.116", + "@deriv/api-types": "^1.0.94", "@testing-library/react": "^12.0.0", "@testing-library/react-hooks": "^7.0.2", "@testing-library/user-event": "^13.5.0", diff --git a/packages/api/src/__tests__/usePaginatedFetch.spec.tsx b/packages/api/src/__tests__/usePaginatedFetch.spec.tsx deleted file mode 100644 index 70943d802d3c..000000000000 --- a/packages/api/src/__tests__/usePaginatedFetch.spec.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; -import { TSocketResponse } from '../../types'; -import APIProvider from '../APIProvider'; -import usePaginatedFetch from '../usePaginatedFetch'; - -jest.mock('@deriv/shared', () => ({ - WS: { - send: jest.fn(() => - Promise.resolve>({ - p2p_advert_list: { - list: [ - // @ts-expect-error need to come up with a way to mock the return type of useFetch - { - account_currency: 'USD', - amount: 50, - amount_display: '50.00', - }, - ], - }, - echo_req: {}, - msg_type: 'p2p_advert_list', - req_id: 1, - }) - ), - }, -})); - -describe('usePaginatedFetch', () => { - it('should call p2p_advert_list and get data in response', async () => { - const wrapper = ({ children }: { children: JSX.Element }) => {children}; - - const { result, waitFor } = renderHook(() => usePaginatedFetch('p2p_advert_list'), { wrapper }); - - await waitFor(() => result.current.isSuccess, { timeout: 10000 }); - - const adverts_list = result.current.data?.p2p_advert_list?.list; - - expect(adverts_list).toHaveLength(1); - expect(adverts_list?.[0].amount).toBe(50); - expect(adverts_list?.[0].account_currency).toBe('USD'); - expect(adverts_list?.[0].amount_display).toBe('50.00'); - }); -}); diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index c57ebbc8d920..f0ccb910ded4 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -2,5 +2,4 @@ export { default as APIProvider } from './APIProvider'; export { default as useFetch } from './useFetch'; export { default as useInvalidateQuery } from './useInvalidateQuery'; export { default as useRequest } from './useRequest'; -export { default as usePaginatedFetch } from './usePaginatedFetch'; export { default as useSubscription } from './useSubscription'; diff --git a/packages/api/src/usePaginatedFetch.ts b/packages/api/src/usePaginatedFetch.ts deleted file mode 100644 index 98e57cc90ef3..000000000000 --- a/packages/api/src/usePaginatedFetch.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { useCallback, useState } from 'react'; -import useFetch from './useFetch'; -import { - TSocketAcceptableProps, - TSocketRequestPayload, - TSocketRequestQueryOptions, - TSocketPaginateableEndpointNames, -} from '../types'; - -const usePaginatedFetch = ( - name: T, - ...props: TSocketAcceptableProps -) => { - const prop = props?.[0]; - const payload = prop && 'payload' in prop ? (prop.payload as TSocketRequestPayload) : undefined; - const options = prop && 'options' in prop ? (prop.options as TSocketRequestQueryOptions) : undefined; - - // @ts-expect-error The `limit` parameter is always present in - // the `payload` for the paginateable endpoints. - const limit: number = payload?.payload?.limit || 10; - // @ts-expect-error The `offset` parameter is always present in - // the `payload` for the paginateable endpoints. - const [offset, setOffset] = useState(payload?.payload?.offset || 0); - - // @ts-expect-error It's safe to ignore the TS error here since the - // exact type of the payload is not determined at this point. - const { remove, ...rest } = useFetch(name, { - payload: { ...payload, offset, limit }, - options: { ...options, keepPreviousData: !!offset }, - }); - - const loadMore = useCallback(() => setOffset(prev => prev + limit), [limit]); - - const reset = useCallback(() => { - remove(); - setOffset(0); - }, [remove]); - - return { - ...rest, - remove, - loadMore, - reset, - }; -}; - -export default usePaginatedFetch; diff --git a/packages/api/types.ts b/packages/api/types.ts index 500ba46ebe9f..dacad83af719 100644 --- a/packages/api/types.ts +++ b/packages/api/types.ts @@ -863,8 +863,3 @@ export type TSocketAcceptableProps> extends TSocketRequestProps ? [TSocketRequestProps?] : [TSocketRequestProps]; - -export type TSocketPaginateableEndpointNames = KeysMatching< - TSocketEndpoints, - { request: { limit?: number; offset?: number } } ->; diff --git a/packages/appstore/package.json b/packages/appstore/package.json index 68143a7d4bd4..c41dc858fab8 100644 --- a/packages/appstore/package.json +++ b/packages/appstore/package.json @@ -25,7 +25,7 @@ "license": "Apache-2.0", "dependencies": { "@deriv/account": "^1.0.0", - "@deriv/api-types": "^1.0.116", + "@deriv/api-types": "^1.0.94", "@deriv/cashier": "^1.0.0", "@deriv/components": "^1.0.0", "@deriv/cfd": "^1.0.0", diff --git a/packages/appstore/src/components/cfds-listing/__tests__/index.spec.tsx b/packages/appstore/src/components/cfds-listing/__tests__/index.spec.tsx deleted file mode 100644 index bdd7c41d2589..000000000000 --- a/packages/appstore/src/components/cfds-listing/__tests__/index.spec.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; -import { StoreProvider, mockStore } from '@deriv/stores'; -import CFDsListing from '../index'; - -jest.mock('Components/containers/listing-container', () => - jest.fn(({ children }) =>
{children}
) -); - -describe('CFDsListing', () => { - const mock = mockStore({ - traders_hub: { - selected_region: 'NON-EU', - has_any_real_account: true, - is_real: true, - can_get_more_cfd_mt5_accounts: true, - no_MF_account: true, - is_demo_low_risk: true, - }, - client: { - is_landing_company_loaded: true, - real_account_creation_unlock_date: '2022-02-02', - }, - modules: { - cfd: { - toggleCompareAccountsModal: jest.fn(), - setAccountType: jest.fn(), - }, - }, - }); - - it('should render the component', () => { - const wrapper = ({ children }: { children: JSX.Element }) => ( - {children} - ); - - render(, { wrapper }); - expect(screen.getByTestId('listing-container')).toBeInTheDocument(); - }); -}); diff --git a/packages/appstore/src/components/cfds-listing/index.tsx b/packages/appstore/src/components/cfds-listing/index.tsx index bbe800358463..2b2986b48f75 100644 --- a/packages/appstore/src/components/cfds-listing/index.tsx +++ b/packages/appstore/src/components/cfds-listing/index.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { observer, useStore } from '@deriv/stores'; +import { observer } from 'mobx-react-lite'; import { Text, StaticUrl } from '@deriv/components'; import { isMobile, formatMoney, getAuthenticationStatusInfo, Jurisdiction } from '@deriv/shared'; import { localize, Localize } from '@deriv/translations'; @@ -10,6 +10,7 @@ import PlatformLoader from 'Components/pre-loader/platform-loader'; import GetMoreAccounts from 'Components/get-more-accounts'; import { Actions } from 'Components/containers/trading-app-card-actions'; import { getHasDivider } from 'Constants/utils'; +import { useStores } from 'Stores/index'; import { AvailableAccount, TDetailsOfEachMT5Loginid } from 'Types'; import './cfds-listing.scss'; @@ -19,14 +20,14 @@ type TDetailedExistingAccount = AvailableAccount & key: string; }; -const CFDsListing = observer(() => { +const CFDsListing = () => { const { client, modules: { cfd }, traders_hub, common, ui, - } = useStore(); + } = useStores(); const { available_dxtrade_accounts, available_derivez_accounts, @@ -61,12 +62,8 @@ const CFDsListing = observer(() => { const accounts_sub_text = !is_eu_user || is_demo_low_risk ? localize('Compare accounts') : localize('Account Information'); - const { - poi_pending_for_bvi_labuan_vanuatu, - poi_resubmit_for_bvi_labuan_vanuatu, - poa_resubmit_for_labuan, - is_idv_revoked, - } = getAuthenticationStatusInfo(account_status); + const { poi_pending_for_bvi_labuan, poi_resubmit_for_bvi_labuan, poa_resubmit_for_labuan, is_idv_revoked } = + getAuthenticationStatusInfo(account_status); const getAuthStatus = (status_list: boolean[]) => status_list.some(status => status); @@ -77,16 +74,13 @@ const CFDsListing = observer(() => { if ( getAuthStatus([ is_idv_revoked, - poi_resubmit_for_bvi_labuan_vanuatu, + poi_resubmit_for_bvi_labuan, current_acc_status === 'proof_failed', ]) ) { return 'failed'; } else if ( - getAuthStatus([ - poi_pending_for_bvi_labuan_vanuatu, - current_acc_status === 'verification_pending', - ]) + getAuthStatus([poi_pending_for_bvi_labuan, current_acc_status === 'verification_pending']) ) { return 'pending'; } @@ -97,27 +91,20 @@ const CFDsListing = observer(() => { getAuthStatus([ poa_resubmit_for_labuan, is_idv_revoked, - poi_resubmit_for_bvi_labuan_vanuatu, + poi_resubmit_for_bvi_labuan, current_acc_status === 'proof_failed', ]) ) { return 'failed'; } else if ( - getAuthStatus([ - poi_pending_for_bvi_labuan_vanuatu, - current_acc_status === 'verification_pending', - ]) + getAuthStatus([poi_pending_for_bvi_labuan, current_acc_status === 'verification_pending']) ) { return 'pending'; } return null; } default: - if (current_acc_status === 'proof_failed') { - return 'failed'; - } else if (current_acc_status === 'verification_pending') { - return 'pending'; - } + return null; } } return null; @@ -196,7 +183,7 @@ const CFDsListing = observer(() => { existing_account.status || is_idv_revoked ? getMT5AccountAuthStatus( existing_account.status, - existing_account?.landing_company_short + existing_account?.short_code_and_region?.toLowerCase() ) : null; @@ -402,6 +389,6 @@ const CFDsListing = observer(() => { : !is_real && } */} ); -}); +}; -export default CFDsListing; +export default observer(CFDsListing); diff --git a/packages/appstore/src/constants/platform-config.ts b/packages/appstore/src/constants/platform-config.ts index cba13cf731b9..961a11fb1326 100644 --- a/packages/appstore/src/constants/platform-config.ts +++ b/packages/appstore/src/constants/platform-config.ts @@ -41,7 +41,6 @@ export const getAppstorePlatforms = (): PlatformConfig[] => [ name: getPlatformSettingsAppstore('dbot').name, app_desc: localize('Automate your trading, no coding needed.'), link_to: routes.bot, - is_external: true, }, { name: getPlatformSettingsAppstore('smarttrader').name, diff --git a/packages/bot-skeleton/src/scratch/blocks/Binary/Trade Definition/trade_definition_multiplier.js b/packages/bot-skeleton/src/scratch/blocks/Binary/Trade Definition/trade_definition_multiplier.js index 7c7da79c804e..2f95f7ea648e 100644 --- a/packages/bot-skeleton/src/scratch/blocks/Binary/Trade Definition/trade_definition_multiplier.js +++ b/packages/bot-skeleton/src/scratch/blocks/Binary/Trade Definition/trade_definition_multiplier.js @@ -80,20 +80,6 @@ Blockly.Blocks.trade_definition_multiplier = { const block_types_in_multiplier = []; blocks_in_multiplier.forEach(block => { block_types_in_multiplier.push(block.type); - const block_multiplier_take_profit = block.childValueToCode('multiplier_take_profit', 'AMOUNT'); - const block_multiplier_stop_loss = block.childValueToCode('multiplier_stop_loss', 'AMOUNT'); - if (block_multiplier_take_profit <= 0 || block_multiplier_stop_loss <= 0) { - block.setDisabled(true); - } - - if (block.type === 'multiplier_stop_loss' && block_multiplier_stop_loss > 0) { - block.setDisabled(false); - } - - if (block.type === 'multiplier_take_profit' && block_multiplier_take_profit > 0) { - block.setDisabled(false); - } - if ( !/^multiplier_.+$/.test(block.type) || new Set(block_types_in_multiplier).size !== block_types_in_multiplier.length diff --git a/packages/bot-skeleton/src/services/api/active-symbols.js b/packages/bot-skeleton/src/services/api/active-symbols.js index 3d0bd2bbe3c2..acde7caa0e8c 100644 --- a/packages/bot-skeleton/src/services/api/active-symbols.js +++ b/packages/bot-skeleton/src/services/api/active-symbols.js @@ -7,7 +7,7 @@ export default class ActiveSymbols { this.active_symbols = []; this.disabled_markets = []; this.disabled_symbols = ['frxGBPNOK', 'frxUSDNOK', 'frxUSDNEK', 'frxUSDSEK']; // These are only forward-starting. - this.disabled_submarkets = ['energy', 'step_index']; + this.disabled_submarkets = ['energy', 'step_index', 'crash_index']; this.init_promise = new PendingPromise(); this.is_initialised = false; this.processed_symbols = {}; diff --git a/packages/bot-web-ui/package.json b/packages/bot-web-ui/package.json index 532c9240f475..57765bbc5db1 100644 --- a/packages/bot-web-ui/package.json +++ b/packages/bot-web-ui/package.json @@ -70,7 +70,7 @@ "@datadog/browser-logs": "^4.36.0", "@deriv/bot-skeleton": "^1.0.0", "@deriv/components": "^1.0.0", - "@deriv/deriv-charts": "1.3.2", + "@deriv/deriv-charts": "1.3.1", "@deriv/shared": "^1.0.0", "@deriv/stores": "^1.0.0", "@deriv/translations": "^1.0.0", diff --git a/packages/bot-web-ui/src/app/__tests__/dbot-providers.spec.tsx b/packages/bot-web-ui/src/app/__tests__/dbot-providers.spec.tsx deleted file mode 100644 index 67e57037bb6d..000000000000 --- a/packages/bot-web-ui/src/app/__tests__/dbot-providers.spec.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react'; -import { mockStore, useStore } from '@deriv/stores'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { render, screen } from '@testing-library/react'; -import { mock_ws } from '../../utils/mock'; -import DBotProviders from '../dbot-providers'; - -jest.mock('@deriv/bot-skeleton/src/scratch/blockly', () => jest.fn()); -jest.mock('@deriv/bot-skeleton/src/scratch/dbot', () => ({ - saveRecentWorkspace: jest.fn(), - unHighlightAllBlocks: jest.fn(), -})); -jest.mock('@deriv/bot-skeleton/src/scratch/hooks/block_svg', () => jest.fn()); - -const TestStoreComponent = () => { - const { common } = useStore(); - const { platform } = common; - return
{platform}
; -}; - -describe('DBotProviders', () => { - let wrapper: ({ children }: { children: JSX.Element }) => JSX.Element; - - beforeAll(() => { - const mock_store = mockStore({ common: { platform: 'ctrader' } }); - wrapper = ({ children }: { children: JSX.Element }) => ( - - {children} - - ); - }); - - it('should render DBotProviders with children', () => { - render(
Test
, { - wrapper, - }); - expect(screen.getByText('Test')).toBeInTheDocument(); - }); - - it('should access useStore platform value from component', () => { - render(, { - wrapper, - }); - expect(screen.getByText('ctrader')).toBeInTheDocument(); - }); -}); diff --git a/packages/bot-web-ui/src/app/app-content.jsx b/packages/bot-web-ui/src/app/app-content.jsx index dd3fd3d50e07..745e1aa9aadb 100644 --- a/packages/bot-web-ui/src/app/app-content.jsx +++ b/packages/bot-web-ui/src/app/app-content.jsx @@ -4,7 +4,6 @@ import { Loading } from '@deriv/components'; import { observer, useStore } from '@deriv/stores'; import { Audio, BotNotificationMessages, Dashboard, NetworkToastPopup, RoutePromptDialog } from 'Components'; import BotBuilder from 'Components/dashboard/bot-builder'; -import TransactionDetailsModal from 'Components/transaction-details'; import GTM from 'Utils/gtm'; import { useDBotStore } from 'Stores/useDBotStore'; import BlocklyLoading from '../components/blockly-loading'; @@ -108,7 +107,6 @@ const AppContent = observer(() => { - ); diff --git a/packages/bot-web-ui/src/app/app.scss b/packages/bot-web-ui/src/app/app.scss index 9348e176719c..69d3a1efdb22 100644 --- a/packages/bot-web-ui/src/app/app.scss +++ b/packages/bot-web-ui/src/app/app.scss @@ -11,7 +11,4 @@ --tab-content-height: calc(100vh - 16.6rem); --tab-content-height-mobile: calc(100vh - 12.6rem); - - --zindex-drawer: 5; - --zindex-modal: 6; } diff --git a/packages/bot-web-ui/src/components/audio/__tests__/audio.spec.tsx b/packages/bot-web-ui/src/components/audio/__tests__/audio.spec.tsx deleted file mode 100644 index 8384cc3f15c6..000000000000 --- a/packages/bot-web-ui/src/components/audio/__tests__/audio.spec.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import exp from 'constants'; -import { render, screen } from '@testing-library/react'; -import Audio from '../audio'; - -describe('Audio', () => { - it('should render Audio', () => { - const { container } = render(