diff --git a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js index ff125ca64f61..17266feb1eae 100644 --- a/packages/cfd/src/Stores/Modules/CFD/cfd-store.js +++ b/packages/cfd/src/Stores/Modules/CFD/cfd-store.js @@ -1,48 +1,96 @@ -import { action, computed, observable, runInAction } from 'mobx'; +import { action, computed, observable, runInAction, makeObservable, override } from 'mobx'; import { getAccountListKey, getAccountTypeFields, CFD_PLATFORMS, WS } from '@deriv/shared'; import BaseStore from 'Stores/base-store'; import { getDxCompanies, getMtCompanies } from './Helpers/cfd-config'; export default class CFDStore extends BaseStore { - @observable is_compare_accounts_visible = false; - @observable account_type = { + is_compare_accounts_visible = false; + account_type = { category: undefined, type: undefined, }; - @observable new_account_response = {}; - @observable map_type = {}; - @observable has_cfd_error = false; - @observable error_message = ''; + new_account_response = {}; + map_type = {}; + has_cfd_error = false; + error_message = ''; - @observable is_cfd_success_dialog_enabled = false; - @observable is_mt5_financial_stp_modal_open = false; - @observable is_cfd_password_modal_enabled = false; - @observable is_cfd_reset_password_modal_enabled = false; + is_cfd_success_dialog_enabled = false; + is_mt5_financial_stp_modal_open = false; + is_cfd_password_modal_enabled = false; + is_cfd_reset_password_modal_enabled = false; - @observable is_cfd_pending_dialog_open = false; + is_cfd_pending_dialog_open = false; - @observable current_account = undefined; // this is a tmp value, don't rely on it, unless you set it first. + current_account = undefined; // this is a tmp value, don't rely on it, unless you set it first. - @observable error_type = undefined; + error_type = undefined; constructor({ root_store }) { super({ root_store }); + + makeObservable(this, { + is_compare_accounts_visible: observable, + account_type: observable, + new_account_response: observable, + map_type: observable, + has_cfd_error: observable, + error_message: observable, + is_cfd_success_dialog_enabled: observable, + is_mt5_financial_stp_modal_open: observable, + is_cfd_password_modal_enabled: observable, + is_cfd_reset_password_modal_enabled: observable, + is_cfd_pending_dialog_open: observable, + current_account: observable, + error_type: observable, + has_cfd_account: computed, + account_title: computed, + current_list: computed, + onMount: action.bound, + onUnmount: override, + checkShouldOpenAccount: action.bound, + realAccountSignupEndListener: action.bound, + resetFormErrors: action.bound, + clearCFDError: action.bound, + createCFDAccount: action.bound, + disableCFDPasswordModal: action.bound, + enableCFDPasswordModal: action.bound, + getName: action.bound, + openMT5Account: action.bound, + openCFDAccount: action.bound, + beginRealSignupForMt5: action.bound, + enableMt5FinancialStpModal: action.bound, + setAccountType: action.bound, + setCurrentAccount: action.bound, + setError: action.bound, + setCFDNewAccount: action.bound, + setCFDSuccessDialog: action.bound, + storeProofOfAddress: action.bound, + getAccountStatus: action.bound, + creatMT5Password: action.bound, + submitMt5Password: action.bound, + createCFDPassword: action.bound, + submitCFDPassword: action.bound, + toggleCompareAccountsModal: action.bound, + disableMt5FinancialStpModal: action.bound, + topUpVirtual: action.bound, + closeCFDPendingDialog: action.bound, + openPendingDialog: action.bound, + sendVerifyEmail: action.bound, + setCFDPasswordResetModal: action.bound, + }); } - @computed get has_cfd_account() { return this.current_list.length > 0; } - @computed get account_title() { return this.account_type.category ? getMtCompanies(this.root_store.client.is_eu)[this.account_type.category][this.account_type.type].title : ''; } - @computed get current_list() { const list = []; @@ -73,14 +121,12 @@ export default class CFDStore extends BaseStore { return getDxCompanies(); } - @action.bound onMount() { this.checkShouldOpenAccount(); this.onRealAccountSignupEnd(this.realAccountSignupEndListener); this.root_store.ui.is_cfd_page = true; } - @action.bound onUnmount() { this.disposeRealAccountSignupEnd(); this.root_store.ui.is_cfd_page = false; @@ -88,7 +134,6 @@ export default class CFDStore extends BaseStore { // other platforms can redirect to here using account switcher's `Add` account button // so in that case we should open the corresponding account opening modal on load/component update - @action.bound checkShouldOpenAccount() { const account_type = sessionStorage.getItem('open_cfd_account_type'); if (account_type) { @@ -98,7 +143,6 @@ export default class CFDStore extends BaseStore { } } - @action.bound realAccountSignupEndListener() { const post_signup = JSON.parse(sessionStorage.getItem('post_real_account_signup')); if (post_signup && post_signup.category && post_signup.type) { @@ -108,20 +152,17 @@ export default class CFDStore extends BaseStore { return Promise.resolve(); } - @action.bound resetFormErrors() { this.error_message = ''; this.error_type = undefined; this.has_cfd_error = false; } - @action.bound clearCFDError() { this.resetFormErrors(); this.is_cfd_password_modal_enabled = false; } - @action.bound createCFDAccount({ category, type, set_password }) { this.clearCFDError(); this.setAccountType({ @@ -140,17 +181,14 @@ export default class CFDStore extends BaseStore { this.enableCFDPasswordModal(); } - @action.bound disableCFDPasswordModal() { this.is_cfd_password_modal_enabled = false; } - @action.bound enableCFDPasswordModal() { this.is_cfd_password_modal_enabled = true; } - @action.bound getName() { const { first_name } = this.root_store.client.account_settings && this.root_store.client.account_settings; const title = this.mt5_companies[this.account_type.category][this.account_type.type].title; @@ -159,7 +197,6 @@ export default class CFDStore extends BaseStore { return first_name ? [first_name, title].join(' ') : title; } - @action.bound openMT5Account(values) { const name = this.getName(); const leverage = this.mt5_companies[this.account_type.category][this.account_type.type].leverage; @@ -175,7 +212,6 @@ export default class CFDStore extends BaseStore { }); } - @action.bound openCFDAccount(values) { return WS.tradingPlatformNewAccount({ password: values.password, @@ -185,7 +221,6 @@ export default class CFDStore extends BaseStore { }); } - @action.bound beginRealSignupForMt5() { sessionStorage.setItem('post_real_account_signup', JSON.stringify(this.account_type)); this.root_store.ui.openRealAccountSignup(); @@ -211,19 +246,16 @@ export default class CFDStore extends BaseStore { } } - @action.bound enableMt5FinancialStpModal() { if (this.account_type.category === 'real' && this.account_type.type === 'financial_stp') { this.is_mt5_financial_stp_modal_open = true; } } - @action.bound setAccountType(account_type) { this.account_type = account_type; } - @action.bound setCurrentAccount(data, meta) { this.current_account = { ...meta, @@ -231,24 +263,20 @@ export default class CFDStore extends BaseStore { }; } - @action.bound setError(state, obj) { this.has_cfd_error = state; this.error_message = obj ? obj.message : ''; this.error_type = obj?.code ?? undefined; } - @action.bound setCFDNewAccount(cfd_new_account) { this.new_account_response = cfd_new_account; } - @action.bound setCFDSuccessDialog(value) { this.is_cfd_success_dialog_enabled = !!value; } - @action.bound storeProofOfAddress(file_uploader_ref, values, { setStatus }) { return new Promise((resolve, reject) => { setStatus({ msg: '' }); @@ -284,7 +312,6 @@ export default class CFDStore extends BaseStore { }); } - @action.bound async getAccountStatus(platform) { const should_load_account_status = (platform === CFD_PLATFORMS.MT5 && this.root_store.client.is_mt5_password_not_set) || @@ -295,7 +322,6 @@ export default class CFDStore extends BaseStore { } } - @action.bound async creatMT5Password(values, actions) { const response = await WS.tradingPlatformPasswordChange({ new_password: values.password, @@ -311,7 +337,6 @@ export default class CFDStore extends BaseStore { return false; } - @action.bound async submitMt5Password(values, actions) { if (this.root_store.client.is_mt5_password_not_set) { const has_error = await this.creatMT5Password(values, actions); @@ -342,7 +367,6 @@ export default class CFDStore extends BaseStore { } } - @action.bound async createCFDPassword(values, actions) { const response = await WS.tradingPlatformPasswordChange({ new_password: values.password, @@ -359,7 +383,6 @@ export default class CFDStore extends BaseStore { return false; } - @action.bound async submitCFDPassword(values, actions) { if (this.root_store.client.is_dxtrade_password_not_set) { const has_error = await this.createCFDPassword(values, actions); @@ -388,17 +411,14 @@ export default class CFDStore extends BaseStore { } } - @action.bound toggleCompareAccountsModal() { this.is_compare_accounts_visible = !this.is_compare_accounts_visible; } - @action.bound disableMt5FinancialStpModal() { this.is_mt5_financial_stp_modal_open = false; } - @action.bound async topUpVirtual(platform) { this.root_store.ui.setTopUpInProgress(true); let response; @@ -465,12 +485,10 @@ export default class CFDStore extends BaseStore { this.root_store.ui.setTopUpInProgress(false); } - @action.bound closeCFDPendingDialog() { this.is_cfd_pending_dialog_open = false; } - @action.bound openPendingDialog() { setTimeout( runInAction(() => { @@ -480,12 +498,10 @@ export default class CFDStore extends BaseStore { ); } - @action.bound sendVerifyEmail() { return WS.verifyEmail(this.root_store.client.email, 'trading_platform_investor_password_reset'); } - @action.bound setCFDPasswordResetModal(val) { this.is_cfd_reset_password_modal_enabled = !!val; } diff --git a/packages/cfd/src/Stores/base-store.js b/packages/cfd/src/Stores/base-store.js index 3a803f0c2a40..7d601c440e10 100644 --- a/packages/cfd/src/Stores/base-store.js +++ b/packages/cfd/src/Stores/base-store.js @@ -1,4 +1,4 @@ -import { action, intercept, observable, reaction, toJS, when } from 'mobx'; +import { action, intercept, observable, reaction, toJS, when, makeObservable } from 'mobx'; import { isProduction, isEmptyObject } from '@deriv/shared'; import Validator from '../Utils/Validator'; @@ -17,10 +17,8 @@ export default class BaseStore { SESSION_STORAGE: Symbol('SESSION_STORAGE'), }); - @observable validation_errors = {}; - @observable validation_rules = {}; preSwitchAccountDisposer = null; @@ -44,7 +42,7 @@ export default class BaseStore { realAccountSignupEndedDisposer = null; real_account_signup_ended_listener = null; - @observable partial_fetch_time = 0; + partial_fetch_time = 0; /** * Constructor of the base class that gets properties' name of child which should be saved in storages @@ -57,6 +55,34 @@ export default class BaseStore { * @property {String} store_name - Explicit store name for browser application storage (to bypass minification) */ constructor(options = {}) { + makeObservable(this, { + validation_errors: observable, + validation_rules: observable, + partial_fetch_time: observable, + retrieveFromStorage: action, + setValidationErrorMessages: action, + setValidationRules: action, + addRule: action, + validateProperty: action, + validateAllProperties: action, + onSwitchAccount: action.bound, + onPreSwitchAccount: action.bound, + onLogout: action.bound, + onClientInit: action.bound, + onNetworkStatusChange: action.bound, + onThemeChange: action.bound, + onRealAccountSignupEnd: action.bound, + disposePreSwitchAccount: action.bound, + disposeSwitchAccount: action.bound, + disposeLogout: action.bound, + disposeClientInit: action.bound, + disposeNetworkStatusChange: action.bound, + disposeThemeChange: action.bound, + disposeRealAccountSignupEnd: action.bound, + onUnmount: action.bound, + assertHasValidCache: action.bound, + }); + const { root_store, local_storage_properties, session_storage_properties, validation_rules, store_name } = options; @@ -172,7 +198,6 @@ export default class BaseStore { * Retrieves saved snapshot of the store and assigns to the current instance. * */ - @action retrieveFromStorage() { const local_storage_snapshot = JSON.parse(localStorage.getItem(this.store_name, {})); const session_storage_snapshot = JSON.parse(sessionStorage.getItem(this.store_name, {})); @@ -189,7 +214,6 @@ export default class BaseStore { * @param [{String}] messages - An array of strings that contains validation error messages for the particular property. * */ - @action setValidationErrorMessages(propertyName, messages) { const is_different = () => !!this.validation_errors[propertyName] @@ -206,7 +230,6 @@ export default class BaseStore { * @param {object} rules * */ - @action setValidationRules(rules = {}) { Object.keys(rules).forEach(key => { this.addRule(key, rules[key]); @@ -220,7 +243,6 @@ export default class BaseStore { * @param {String} rules * */ - @action addRule(property, rules) { this.validation_rules[property] = rules; @@ -237,7 +259,6 @@ export default class BaseStore { * @param {object} value - The value of the property, it can be undefined. * */ - @action validateProperty(property, value) { const trigger = this.validation_rules[property].trigger; const inputs = { [property]: value !== undefined ? value : this[property] }; @@ -261,7 +282,6 @@ export default class BaseStore { * Validates all properties which validation rule has been set for. * */ - @action validateAllProperties() { const validation_rules = Object.keys(this.validation_rules); const validation_errors = Object.keys(this.validation_errors); @@ -278,7 +298,6 @@ export default class BaseStore { }); } - @action.bound onSwitchAccount(listener) { if (listener) { this.switch_account_listener = listener; @@ -308,7 +327,6 @@ export default class BaseStore { } } - @action.bound onPreSwitchAccount(listener) { if (listener) { this.pre_switch_account_listener = listener; @@ -337,7 +355,6 @@ export default class BaseStore { } } - @action.bound onLogout(listener) { this.logoutDisposer = when( () => this.root_store.client.has_logged_out, @@ -364,7 +381,6 @@ export default class BaseStore { this.logout_listener = listener; } - @action.bound onClientInit(listener) { this.clientInitDisposer = when( () => this.root_store.client.initialized_broadcast, @@ -391,7 +407,6 @@ export default class BaseStore { this.client_init_listener = listener; } - @action.bound onNetworkStatusChange(listener) { this.networkStatusChangeDisposer = reaction( () => this.root_store.common.is_network_online, @@ -411,7 +426,6 @@ export default class BaseStore { this.network_status_change_listener = listener; } - @action.bound onThemeChange(listener) { this.themeChangeDisposer = reaction( () => this.root_store.ui.is_dark_mode_on, @@ -431,7 +445,6 @@ export default class BaseStore { this.theme_change_listener = listener; } - @action.bound onRealAccountSignupEnd(listener) { this.realAccountSignupEndedDisposer = when( () => this.root_store.ui.has_real_account_signup_ended, @@ -459,7 +472,6 @@ export default class BaseStore { this.real_account_signup_ended_listener = listener; } - @action.bound disposePreSwitchAccount() { if (typeof this.preSwitchAccountDisposer === 'function') { this.preSwitchAccountDisposer(); @@ -467,7 +479,6 @@ export default class BaseStore { this.pre_switch_account_listener = null; } - @action.bound disposeSwitchAccount() { if (typeof this.switchAccountDisposer === 'function') { this.switchAccountDisposer(); @@ -475,7 +486,6 @@ export default class BaseStore { this.switch_account_listener = null; } - @action.bound disposeLogout() { if (typeof this.logoutDisposer === 'function') { this.logoutDisposer(); @@ -483,7 +493,6 @@ export default class BaseStore { this.logout_listener = null; } - @action.bound disposeClientInit() { if (typeof this.clientInitDisposer === 'function') { this.clientInitDisposer(); @@ -491,7 +500,6 @@ export default class BaseStore { this.client_init_listener = null; } - @action.bound disposeNetworkStatusChange() { if (typeof this.networkStatusChangeDisposer === 'function') { this.networkStatusChangeDisposer(); @@ -499,7 +507,6 @@ export default class BaseStore { this.network_status_change_listener = null; } - @action.bound disposeThemeChange() { if (typeof this.themeChangeDisposer === 'function') { this.themeChangeDisposer(); @@ -507,7 +514,6 @@ export default class BaseStore { this.theme_change_listener = null; } - @action.bound disposeRealAccountSignupEnd() { if (typeof this.realAccountSignupEndedDisposer === 'function') { this.realAccountSignupEndedDisposer(); @@ -515,7 +521,6 @@ export default class BaseStore { this.real_account_signup_ended_listener = null; } - @action.bound onUnmount() { this.disposePreSwitchAccount(); this.disposeSwitchAccount(); @@ -526,7 +531,6 @@ export default class BaseStore { this.disposeRealAccountSignupEnd(); } - @action.bound assertHasValidCache(loginid, ...reactions) { // account was changed when this was unmounted. if (this.root_store.client.loginid !== loginid) {