diff --git a/packages/account/src/Configs/employment-tax-info-config.ts b/packages/account/src/Configs/employment-tax-info-config.ts index 71b025fb3dad..971632c02898 100644 --- a/packages/account/src/Configs/employment-tax-info-config.ts +++ b/packages/account/src/Configs/employment-tax-info-config.ts @@ -36,7 +36,7 @@ const generateEmploymentTaxInfoFormValues = ({ }, }); -const getEmploymentTaxIfoConfig = ( +const getEmploymentTaxInfoConfig = ( { account_settings, residence_list, @@ -60,4 +60,4 @@ const getEmploymentTaxIfoConfig = ( }; }; -export default getEmploymentTaxIfoConfig; +export default getEmploymentTaxInfoConfig; diff --git a/packages/account/src/Configs/user-profile-validation-config.ts b/packages/account/src/Configs/user-profile-validation-config.ts index 6e2fdb1a70f7..e16773fc3ac4 100644 --- a/packages/account/src/Configs/user-profile-validation-config.ts +++ b/packages/account/src/Configs/user-profile-validation-config.ts @@ -2,7 +2,6 @@ import { localize } from '@deriv-com/translations'; import * as Yup from 'yup'; import { ValidationConstants } from '@deriv-com/utils'; import dayjs from 'dayjs'; -import { TinValidations } from '@deriv/api/types'; import { TEmployeeDetailsTinValidationConfig } from '../Types'; const { @@ -25,6 +24,7 @@ type TINDepdendents = { * This flag indicates that tin was skipped before and was set by BE */ is_tin_auto_set?: boolean; + is_employment_status_tin_mandatory?: boolean; }; Yup.addMethod(Yup.string, 'validatePhoneNumberLength', function (message) { @@ -38,10 +38,20 @@ Yup.addMethod(Yup.string, 'validatePhoneNumberLength', function (message) { }); }); -const makeTinOptional = ({ is_mf, is_real, tin_skipped, is_tin_auto_set }: TINDepdendents) => { +const makeTinOptional = ({ + is_mf, + is_real, + tin_skipped, + is_tin_auto_set, + is_employment_status_tin_mandatory, +}: TINDepdendents) => { const check_if_tin_skipped = tin_skipped && !is_tin_auto_set; if (is_real) { - return check_if_tin_skipped; + // Students and unemployed are not required to provide TIN to have a regulated MT5 jurisdiction + if (is_tin_auto_set && is_employment_status_tin_mandatory) { + return true; + } + return check_if_tin_skipped || !is_employment_status_tin_mandatory; } // Check For Virtual account if (is_mf) { @@ -56,9 +66,14 @@ export const getEmploymentAndTaxValidationSchema = ({ is_real = false, is_tin_auto_set = false, is_duplicate_account = false, + is_employment_status_tin_mandatory = false, }: TEmployeeDetailsTinValidationConfig) => { return Yup.object({ - employment_status: Yup.string().required(localize('Employment status is required.')), + employment_status: Yup.string().when('is_employment_status_tin_mandatory', { + is: () => is_employment_status_tin_mandatory, + then: Yup.string().required(localize('Employment status is required.')), + otherwise: Yup.string().notRequired(), + }), tax_residence: Yup.string().when('is_mf', { is: () => is_mf, then: Yup.string().required(localize('Tax residence is required.')), @@ -73,7 +88,14 @@ export const getEmploymentAndTaxValidationSchema = ({ }), tax_identification_number: Yup.string() .when(['tin_skipped'], { - is: (tin_skipped: boolean) => makeTinOptional({ is_mf, is_real, tin_skipped, is_tin_auto_set }), + is: (tin_skipped: boolean) => + makeTinOptional({ + is_mf, + is_real, + tin_skipped, + is_tin_auto_set, + is_employment_status_tin_mandatory, + }), then: Yup.string().notRequired(), otherwise: Yup.string().required(localize('Tax identification number is required.')), }) diff --git a/packages/account/src/Containers/employment-tax-details-container/employment-tax-details-container.tsx b/packages/account/src/Containers/employment-tax-details-container/employment-tax-details-container.tsx index ad06305ab640..ff53accab6bf 100644 --- a/packages/account/src/Containers/employment-tax-details-container/employment-tax-details-container.tsx +++ b/packages/account/src/Containers/employment-tax-details-container/employment-tax-details-container.tsx @@ -39,11 +39,19 @@ const EmploymentTaxDetailsContainer = observer( const { data: residence_list } = useResidenceList(); const { client } = useStore(); - const { is_virtual, account_settings } = client; + const { is_virtual, account_settings, account_status } = client; const { tin_employment_status_bypass } = tin_validation_config; - const is_tin_required = !is_virtual && !tin_employment_status_bypass?.includes(values.employment_status); + const is_employment_status_mandatory = is_virtual + ? true + : Boolean(account_status?.status?.includes('mt5_additional_kyc_required')); + + const is_tin_required = + !is_virtual && + values.employment_status && + !tin_employment_status_bypass?.includes(values.employment_status) && + is_employment_status_mandatory; const [is_tax_residence_popover_open, setIsTaxResidencePopoverOpen] = useState(false); const [is_tin_popover_open, setIsTinPopoverOpen] = useState(false); @@ -132,15 +140,11 @@ const EmploymentTaxDetailsContainer = observer( const isFieldDisabled = (field_name: string) => isFieldImmutable(field_name, editable_fields); - // [TODO] - This should come from BE - const should_disable_employment_status = - isFieldDisabled('employment_status') || Boolean(is_virtual && client.account_settings.employment_status); - return (
diff --git a/packages/account/src/Containers/employment-tax-info/employment-tax-info.tsx b/packages/account/src/Containers/employment-tax-info/employment-tax-info.tsx index bba318b6e101..6aa2af7c6bc0 100644 --- a/packages/account/src/Containers/employment-tax-info/employment-tax-info.tsx +++ b/packages/account/src/Containers/employment-tax-info/employment-tax-info.tsx @@ -65,6 +65,7 @@ const EmploymentTaxInfo = observer( is_duplicate_account: client.account_settings.immutable_fields?.includes('tax_identification_number') || client.account_settings.immutable_fields?.includes('tax_residence'), + is_employment_status_tin_mandatory: true, // Override the value to true as we need to make Employment status mandatory for Real account creation }); const handleCancel = (values: FormikValues) => { diff --git a/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx b/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx index 0e7c44a4e96c..a662fce805d1 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx +++ b/packages/account/src/Sections/Profile/PersonalDetails/personal-details-form.tsx @@ -300,12 +300,15 @@ const PersonalDetailsForm = observer(() => { const is_tin_auto_set = Boolean(account_settings?.tin_skipped); + const is_employment_status_tin_mandatory = Boolean(account_status?.status?.includes('mt5_additional_kyc_required')); + const PersonalDetailSchema = getPersonalDetailsValidationSchema( is_virtual, is_svg, tin_validation_config, is_tin_auto_set, - account_settings?.immutable_fields + account_settings?.immutable_fields, + is_employment_status_tin_mandatory ); const displayErrorMessage = (status: { code: string; msg: string }) => { if (status?.code === 'PhoneNumberTaken') { diff --git a/packages/account/src/Sections/Profile/PersonalDetails/validation.ts b/packages/account/src/Sections/Profile/PersonalDetails/validation.ts index 3e93de1394f1..00396bfebc57 100644 --- a/packages/account/src/Sections/Profile/PersonalDetails/validation.ts +++ b/packages/account/src/Sections/Profile/PersonalDetails/validation.ts @@ -133,7 +133,8 @@ export const getPersonalDetailsValidationSchema = ( is_svg?: boolean, tin_validation_config?: TinValidations, is_tin_auto_set?: boolean, - immutable_fields?: string[] + immutable_fields?: string[], + is_employment_status_tin_mandatory?: boolean ) => { if (is_virtual) return Yup.object(); @@ -154,6 +155,7 @@ export const getPersonalDetailsValidationSchema = ( is_tin_auto_set, is_duplicate_account: immutable_fields?.includes('tax_identification_number') || immutable_fields?.includes('tax_residence'), + is_employment_status_tin_mandatory, }); return personal_details_schema.concat(address_detail_schema).concat(employment_tin_schema); diff --git a/packages/account/src/Types/common.type.ts b/packages/account/src/Types/common.type.ts index a3010b1835fc..9e9603bb3033 100644 --- a/packages/account/src/Types/common.type.ts +++ b/packages/account/src/Types/common.type.ts @@ -163,7 +163,7 @@ export type TIDVFormValues = { error_message?: string; }; -export type TPlatforms = typeof Platforms[keyof typeof Platforms]; +export type TPlatforms = (typeof Platforms)[keyof typeof Platforms]; export type TServerError = { code?: string; @@ -172,7 +172,7 @@ export type TServerError = { details?: { [key: string]: string }; fields?: string[]; }; -export type TCFDPlatform = typeof CFD_PLATFORMS[keyof typeof CFD_PLATFORMS]; +export type TCFDPlatform = (typeof CFD_PLATFORMS)[keyof typeof CFD_PLATFORMS]; export type TClosingAccountFormValues = { 'financial-priorities': boolean; @@ -250,7 +250,7 @@ export type TAutoComplete = { value: boolean; text: string; }; -export type TPaymentMethodIdentifier = typeof IDENTIFIER_TYPES[keyof typeof IDENTIFIER_TYPES]; +export type TPaymentMethodIdentifier = (typeof IDENTIFIER_TYPES)[keyof typeof IDENTIFIER_TYPES]; export type TPaymentMethodInfo = { documents_required: number; @@ -285,11 +285,11 @@ export type TProofOfOwnershipErrors = Record< export type TFinancialInformationForm = Omit; -export type TAuthStatusCodes = typeof AUTH_STATUS_CODES[keyof typeof AUTH_STATUS_CODES]; +export type TAuthStatusCodes = (typeof AUTH_STATUS_CODES)[keyof typeof AUTH_STATUS_CODES]; export type TMT5AccountStatus = - | typeof MT5_ACCOUNT_STATUS[keyof typeof MT5_ACCOUNT_STATUS] - | typeof TRADING_PLATFORM_STATUS[keyof typeof TRADING_PLATFORM_STATUS]; + | (typeof MT5_ACCOUNT_STATUS)[keyof typeof MT5_ACCOUNT_STATUS] + | (typeof TRADING_PLATFORM_STATUS)[keyof typeof TRADING_PLATFORM_STATUS]; export type TFilesDescription = { descriptions: { id: string; value: JSX.Element }[]; @@ -343,6 +343,7 @@ export type TEmployeeDetailsTinValidationConfig = { is_real?: boolean; is_tin_auto_set?: boolean; is_duplicate_account?: boolean; + is_employment_status_tin_mandatory?: boolean; }; type ReqRule = ['req', React.ReactNode]; diff --git a/packages/cashier/src/components/cashier-container/virtual/virtual.tsx b/packages/cashier/src/components/cashier-container/virtual/virtual.tsx index 289c933f3fa8..edd70cee9233 100644 --- a/packages/cashier/src/components/cashier-container/virtual/virtual.tsx +++ b/packages/cashier/src/components/cashier-container/virtual/virtual.tsx @@ -42,7 +42,13 @@ const Virtual = observer(() => { i18n_default_text='You need to switch to a real money account to use this feature.<0/>You can do this by selecting a real account from the <1>Account Switcher.' components={[
, - , + { + toggleAccountsDialog(); + }} + />, ]} /> diff --git a/packages/core/build/config.js b/packages/core/build/config.js index a45d93da626d..2fbc7ebd1cb9 100644 --- a/packages/core/build/config.js +++ b/packages/core/build/config.js @@ -63,9 +63,6 @@ const copyConfig = base => { { from: path.resolve(__dirname, '../../../node_modules/@deriv/cashier/dist/cashier/public'), to: 'cashier/public', - transform(_content, transform_path) { - return transform_path.split('node_modules/@deriv/cashier/dist/')[1]; - }, }, { from: path.resolve(__dirname, '../../../node_modules/@deriv/trader/dist/trader'), diff --git a/packages/core/src/App/Components/Layout/Header/__tests__/account-info-wallets.spec.tsx b/packages/core/src/App/Components/Layout/Header/__tests__/account-info-wallets.spec.tsx index a9c96c0841b6..a7e0e438c15b 100644 --- a/packages/core/src/App/Components/Layout/Header/__tests__/account-info-wallets.spec.tsx +++ b/packages/core/src/App/Components/Layout/Header/__tests__/account-info-wallets.spec.tsx @@ -35,7 +35,7 @@ describe('AccountInfoWallets component', () => { }, }; - it('should show "disabled_message" when "is_disabled" property is "true"', () => { + it('should show "disabled_message" when "is_disabled" property is "true"', async () => { const mock = mockStore({ client: { accounts: { @@ -64,7 +64,7 @@ describe('AccountInfoWallets component', () => { render(, { wrapper: wrapper(mock) }); const popover = screen.getByTestId('dt_popover_wrapper'); - userEvent.hover(popover); + await userEvent.hover(popover); const disabled_message = screen.getByText(/test disabled message/i); expect(disabled_message).toBeInTheDocument(); }); @@ -108,7 +108,7 @@ describe('AccountInfoWallets component', () => { expect(div_element).not.toHaveClass('acc-info--show'); }); - it('can not "toggleDialog" when "is_disabled" property is "true"', () => { + it('can not "toggleDialog" when "is_disabled" property is "true"', async () => { const mock = mockStore({ client: { accounts: { @@ -134,7 +134,7 @@ describe('AccountInfoWallets component', () => { render(, { wrapper: wrapper(mock) }); const div_element = screen.getByTestId('dt_acc_info'); - userEvent.click(div_element); + await userEvent.click(div_element); expect(toggleDialog).toHaveBeenCalledTimes(0); }); @@ -185,35 +185,6 @@ describe('AccountInfoWallets component', () => { expect(screen.queryByText('SVG')).not.toBeInTheDocument(); }); - it('should render "MALTA" label', () => { - const mock = mockStore({ - client: { - accounts: { - CRW909900: { - account_category: 'wallet', - currency: 'USD', - is_virtual: 0, - is_disabled: 0, - landing_company_name: 'maltainvest', - linked_to: [{ loginid: 'CR123', platform: 'dtrade' }], - }, - CR123: { - account_category: 'trading', - currency: 'USD', - is_virtual: 0, - is_disabled: 0, - }, - }, - loginid: 'CR123', - }, - }); - - const toggleDialog = jest.fn(); - render(, { wrapper: wrapper(mock) }); - - expect(screen.queryByText('MALTA')).toBeInTheDocument(); - }); - it('should render "IcLock" icon when "is_disabled" property is "true"', () => { const mock = mockStore({ client: { diff --git a/packages/core/src/App/Components/Layout/Header/wallets/account-info-wallets.tsx b/packages/core/src/App/Components/Layout/Header/wallets/account-info-wallets.tsx index 0c3ad88f4d92..8b3c1e3b1ee6 100644 --- a/packages/core/src/App/Components/Layout/Header/wallets/account-info-wallets.tsx +++ b/packages/core/src/App/Components/Layout/Header/wallets/account-info-wallets.tsx @@ -138,7 +138,7 @@ const AccountInfoWallets = observer(({ is_dialog_on, toggleDialog }: TAccountInf if (!linked_wallet) return ; - const show_badge = linked_wallet.is_malta_wallet || linked_wallet.is_virtual; + const show_badge = linked_wallet.is_virtual; return (
diff --git a/packages/core/src/App/Containers/AccountSwitcherWallet/__tests__/account-switcher-wallet-item.spec.tsx b/packages/core/src/App/Containers/AccountSwitcherWallet/__tests__/account-switcher-wallet-item.spec.tsx index 3b76a191ead8..ce83375254ae 100644 --- a/packages/core/src/App/Containers/AccountSwitcherWallet/__tests__/account-switcher-wallet-item.spec.tsx +++ b/packages/core/src/App/Containers/AccountSwitcherWallet/__tests__/account-switcher-wallet-item.spec.tsx @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event'; import { StoreProvider, mockStore } from '@deriv/stores'; import { AccountSwitcherWalletItem } from '../account-switcher-wallet-item'; +// @ts-expect-error - This is a mock account const account: React.ComponentProps['account'] = { currency: 'USD', dtrade_balance: 100, @@ -45,31 +46,20 @@ const AccountSwitcherWalletItemComponent = ({ }; describe('AccountSwitcherWalletItem', () => { - it('should render the component', () => { + it('renders the component', () => { const store = mockStore({}); render(); expect(screen.getByText('USD Wallet')).toBeInTheDocument(); expect(screen.getByText('100.00 USD')).toBeInTheDocument(); }); - it('should NOT show SVG badge', () => { + it('does not show SVG badge', () => { const store = mockStore({}); render(); expect(screen.queryByText('SVG')).not.toBeInTheDocument(); }); - it('should show MALTA badge if show_badge is true', () => { - const store = mockStore({}); - const tempProps = { - ...props, - account: { ...account, is_malta_wallet: true, landing_company_name: 'malta' }, - show_badge: true, - }; - render(); - expect(screen.getByText('MALTA')).toBeInTheDocument(); - }); - - it('should render Demo Badge if show_badge is true', () => { + it('renders Demo Badge if show_badge is true', () => { const store = mockStore({}); const tempProps = { ...props, account: { ...account, is_virtual: true }, show_badge: true }; render(); @@ -78,28 +68,50 @@ describe('AccountSwitcherWalletItem', () => { expect(screen.getByText('Demo')).toBeInTheDocument(); }); - it('should call closeAccountsDialog when clicked', () => { + it('calls closeAccountsDialog when clicked', async () => { const store = mockStore({}); render(); - userEvent.click(screen.getByTestId('account-switcher-wallet-item')); + await userEvent.click(screen.getByTestId('account-switcher-wallet-item')); expect(props.closeAccountsDialog).toHaveBeenCalled(); }); - it('should call switchAccount when clicked not selected', async () => { + it('calls switchAccount when clicked not selected', async () => { const switchAccount = jest.fn(); const store = mockStore({ client: { switchAccount, loginid: 'CR008' } }); render(); - userEvent.click(screen.getByTestId('account-switcher-wallet-item')); + await userEvent.click(screen.getByTestId('account-switcher-wallet-item')); expect(switchAccount).toHaveBeenCalledWith('CR007'); expect(props.closeAccountsDialog).toHaveBeenCalled(); }); - it('should not call switchAccount when clicked the already selected', async () => { + it('does not call switchAccount when clicked the already selected', async () => { const switchAccount = jest.fn(); const store = mockStore({ client: { switchAccount, loginid: 'CR007' } }); render(); - userEvent.click(screen.getByTestId('account-switcher-wallet-item')); + await userEvent.click(screen.getByTestId('account-switcher-wallet-item')); expect(switchAccount).not.toHaveBeenCalled(); expect(props.closeAccountsDialog).toHaveBeenCalled(); }); + + it('shows Options when is_eu is false', () => { + const store = mockStore({ + client: { + is_eu: false, + }, + }); + const tempProps = { ...props, account }; + render(); + expect(screen.getByText('Options')).toBeInTheDocument(); + }); + + it('shows Multipliers when is_eu is true', () => { + const store = mockStore({ + client: { + is_eu: true, + }, + }); + const tempProps = { ...props, account }; + render(); + expect(screen.getByText('Multipliers')).toBeInTheDocument(); + }); }); diff --git a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx index 67478d64b452..ed3cca542431 100644 --- a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx +++ b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-item.tsx @@ -30,7 +30,7 @@ export const AccountSwitcherWalletItem = observer( const { ui: { is_dark_mode_on }, - client: { switchAccount, loginid: active_loginid }, + client: { switchAccount, loginid: active_loginid, is_eu }, } = useStore(); const theme = is_dark_mode_on ? 'dark' : 'light'; @@ -70,7 +70,11 @@ export const AccountSwitcherWalletItem = observer(
- + {is_eu ? ( + + ) : ( + + )} {is_virtual ? ( diff --git a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-list.tsx b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-list.tsx index 9ff6b564f915..a7bac152449a 100644 --- a/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-list.tsx +++ b/packages/core/src/App/Containers/AccountSwitcherWallet/account-switcher-wallet-list.tsx @@ -12,13 +12,12 @@ export const AccountSwitcherWalletList = ({ wallets, closeAccountsDialog }: TAcc
{wallets?.map(account => { if (account.is_dtrader_account_disabled) return null; - const show_badge = account?.is_malta_wallet || account?.is_virtual; return ( ); })} diff --git a/packages/core/src/Stores/client-store.js b/packages/core/src/Stores/client-store.js index 06ab601c1a1f..21467d6b1527 100644 --- a/packages/core/src/Stores/client-store.js +++ b/packages/core/src/Stores/client-store.js @@ -1407,7 +1407,6 @@ export default class ClientStore extends BaseStore { if (this.accounts && this.accounts[this.loginid]) { return this.accounts[this.loginid].email; } - return ''; } @@ -2068,6 +2067,7 @@ export default class ClientStore extends BaseStore { async logout() { // makes sure to clear the cached traders-hub data when logging out localStorage.removeItem('traders_hub_store'); + localStorage.removeItem('trade_store'); // TODO: [add-client-action] - Move logout functionality to client store const response = await requestLogout(); diff --git a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/__tests__/barrier-input.spec.tsx b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/__tests__/barrier-input.spec.tsx index 6d9a2466dcbd..70bd281b2bb2 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/__tests__/barrier-input.spec.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/__tests__/barrier-input.spec.tsx @@ -66,7 +66,7 @@ describe('BarrierInput', () => { expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '-10' } }); await userEvent.click(fixedPriceChip); - expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '10' } }); + expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '' } }); await userEvent.click(aboveSpotChip); expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '+10' } }); @@ -145,7 +145,7 @@ describe('BarrierInput', () => { const fixedPriceChip = screen.getByText('Fixed barrier'); await userEvent.click(fixedPriceChip); - expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '0.6' } }); + expect(onChange).toHaveBeenCalledWith({ target: { name: 'barrier_1', value: '' } }); }); it('handles chip selection correctly for Above spot when initial barrier is fixed price', async () => { diff --git a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier-input.tsx b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier-input.tsx index dc57ec544a11..90c6bb1c8a23 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier-input.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier-input.tsx @@ -29,6 +29,7 @@ const BarrierInput = observer( const { barrier_1, onChange, validation_errors, tick_data, setV2ParamsInitialValues } = useTraderStore(); const [option, setOption] = React.useState(0); const [should_show_error, setShouldShowError] = React.useState(false); + const [previous_value, setPreviousValue] = React.useState(barrier_1); const [is_focused, setIsFocused] = React.useState(false); const { pip_size } = tick_data ?? {}; const barrier_ref = React.useRef(null); @@ -69,12 +70,16 @@ const BarrierInput = observer( const handleChipSelect = (index: number) => { setOption(index); - let newValue = barrier_1.replace(/^[+-]/, ''); + const current_value = barrier_1.replace(/^[+-]/, ''); + let newValue = previous_value.replace(/^[+-]/, ''); if (index === 0) { newValue = `+${newValue}`; } else if (index === 1) { newValue = `-${newValue}`; + } else if (index === 2) { + newValue = ''; + setPreviousValue(current_value); } if ((newValue.startsWith('+') || newValue.startsWith('-')) && newValue.charAt(1) === '.') { @@ -92,6 +97,7 @@ const BarrierInput = observer( if (option === 1) value = `-${value}`; onChange({ target: { name: 'barrier_1', value } }); setV2ParamsInitialValues({ name: 'barrier_1', value }); + setPreviousValue(value); }; return ( diff --git a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier.tsx b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier.tsx index 70f849dfaa8f..8fb754275b3b 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/Barrier/barrier.tsx @@ -45,12 +45,6 @@ const Barrier = observer(({ is_minimized }: TTradeParametersProps) => { [initialBarrierValue, is_open] ); - React.useEffect(() => { - if (v2_params_initial_values.barrier_1?.toString() !== barrier_1) { - setV2ParamsInitialValues({ value: barrier_1, name: 'barrier_1' }); - } - }, [barrier_1]); - React.useEffect(() => { const has_error = proposal_info?.[trade_type_tab]?.has_error; const error_field = proposal_info?.[trade_type_tab]?.error_field; diff --git a/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/__tests__/payout-info.spec.tsx b/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/__tests__/payout-info.spec.tsx index 92c1ea605d01..dcec939071d2 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/__tests__/payout-info.spec.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/__tests__/payout-info.spec.tsx @@ -36,17 +36,6 @@ describe('', () => { ); - it('does not render if there is an API error ', () => { - default_mock_store.modules.trade.proposal_info = { - ONETOUCH: { - has_error: true, - }, - }; - const { container } = mockedPayoutInfo(); - - expect(container).toBeEmptyDOMElement(); - }); - it('renders loader if payout is falsy but there is no API error', () => { default_mock_store.modules.trade.proposal_info = {}; mockedPayoutInfo(); diff --git a/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/payout-info.tsx b/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/payout-info.tsx index 44310e68a9fd..aab09b56cb7e 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/payout-info.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/PayoutInfo/payout-info.tsx @@ -11,8 +11,6 @@ const PayoutInfo = observer(() => { const { value: payout } = proposal_info[trade_type_tab]?.obj_contract_basis || {}; const has_error = proposal_info[trade_type_tab]?.has_error; - if (has_error) return null; - return (
@@ -22,6 +20,10 @@ const PayoutInfo = observer(() => { + ) : has_error ? ( + + - {currency} + ) : ( )} diff --git a/packages/trader/src/AppV2/Components/TradeParameters/Stake/__tests__/stake.spec.tsx b/packages/trader/src/AppV2/Components/TradeParameters/Stake/__tests__/stake.spec.tsx index 51666ae5fbd8..f2ab352154d4 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/Stake/__tests__/stake.spec.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/Stake/__tests__/stake.spec.tsx @@ -100,12 +100,12 @@ describe('Stake', () => { expect(screen.getByRole('textbox')).toHaveValue(`${amount} ${currency}`); }); - it('opens ActionSheet with input, details and "Save" button if user clicks on "Stake" trade param', () => { + it('opens ActionSheet with input, details and "Save" button if user clicks on "Stake" trade param', async () => { render(); expect(screen.queryByTestId('dt-actionsheet-overlay')).not.toBeInTheDocument(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.getByTestId('dt-actionsheet-overlay')).toBeInTheDocument(); expect(screen.getByPlaceholderText(input_placeholder)).toBeInTheDocument(); @@ -113,37 +113,37 @@ describe('Stake', () => { expect(screen.getByRole('button', { name: save_button_label })).toBeInTheDocument(); }); - it('calls onChange when stake input changes', () => { + it('calls onChange when stake input changes', async () => { render(); - userEvent.click(screen.getByText(stake_param_label)); - userEvent.type(screen.getByPlaceholderText(input_placeholder), '0'); + await userEvent.click(screen.getByText(stake_param_label)); + await userEvent.type(screen.getByPlaceholderText(input_placeholder), '0'); expect(default_mock_store.modules.trade.onChange).toHaveBeenCalledWith({ target: { name: 'amount', value: '100' }, }); }); - it('does not render payout details for Accumulators', () => { + it('does not render payout details for Accumulators', async () => { default_mock_store.modules.trade.is_accumulator = true; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.queryByText(/payout/i)).not.toBeInTheDocument(); }); - it('does not render payout details for Turbos', () => { + it('does not render payout details for Turbos', async () => { default_mock_store.modules.trade.is_turbos = true; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.queryByText(/payout/i)).not.toBeInTheDocument(); }); - it('does not render payout details for Vanillas', () => { + it('does not render payout details for Vanillas', async () => { default_mock_store.modules.trade.is_vanilla = true; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.queryByText(/payout/i)).not.toBeInTheDocument(); }); - it('renders Stop out and Commission details instead of payout details for Multipliers', () => { + it('renders Stop out and Commission details instead of payout details for Multipliers', async () => { render( { /> ); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.getByText('Acceptable range: 1.00 to 2,000.00 USD')).toBeInTheDocument(); expect(screen.getByText('Stop out')).toBeInTheDocument(); expect(screen.getByText('Commission')).toBeInTheDocument(); }); - it('calls setV2ParamsInitialValues if v2_params_initial_values.stake !== amount on mount and on Save button click if no error', () => { + it('calls setV2ParamsInitialValues if v2_params_initial_values.stake !== amount on mount and on Save button click if no error', async () => { default_mock_store.modules.trade.amount = '30'; render(); - userEvent.click(screen.getByText(stake_param_label)); - userEvent.type(screen.getByPlaceholderText(input_placeholder), '0'); + await userEvent.click(screen.getByText(stake_param_label)); + await userEvent.type(screen.getByPlaceholderText(input_placeholder), '0'); - expect(default_mock_store.modules.trade.setV2ParamsInitialValues).toHaveBeenCalledTimes(1); - - userEvent.click(screen.getByRole('button', { name: save_button_label })); expect(default_mock_store.modules.trade.setV2ParamsInitialValues).toHaveBeenCalledTimes(2); + + await userEvent.click(screen.getByRole('button', { name: save_button_label })); + expect(default_mock_store.modules.trade.setV2ParamsInitialValues).toHaveBeenCalledTimes(3); }); it('calls onChange on component mount if v2_params_initial_values.stake is not equal to amount', () => { @@ -222,7 +222,7 @@ describe('Stake', () => { }); }); - it('shows error in case of a validation error if input is non-empty', () => { + it('shows error in case of a validation error if input is non-empty', async () => { const error_text = "Please enter a stake amount that's at least 0.35."; default_mock_store.modules.trade.proposal_info = { PUT: { id: '', has_error: true, message: error_text }, @@ -232,12 +232,12 @@ describe('Stake', () => { default_mock_store.modules.trade.amount = 0; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.getByText(error_text)).toBeInTheDocument(); expect(screen.getAllByText('- USD')).toHaveLength(2); }); - it('shows max payout error with the least current payout when both of the 2 contract types exceed max payout', () => { + it('shows max payout error with the least current payout when both of the 2 contract types exceed max payout', async () => { const error_text_rise = 'Minimum stake of 0.35 and maximum payout of 50000.00. Current payout is 50631.97.'; const error_text_fall = 'Minimum stake of 0.35 and maximum payout of 50000.00. Current payout is 50513.21.'; default_mock_store.modules.trade.proposal_info = { @@ -248,13 +248,13 @@ describe('Stake', () => { default_mock_store.modules.trade.amount = '26500'; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.getByText(error_text_fall)).toBeInTheDocument(); expect(screen.queryByText('- USD')).not.toBeInTheDocument(); }); - it('does not show max payout error if one of the 2 contract types satisfies max payout', () => { + it('does not show max payout error if one of the 2 contract types satisfies max payout', async () => { const error_text_rise = 'Minimum stake of 0.35 and maximum payout of 50000.00. Current payout is 50058.77.'; const success_text_fall = 'Win payout if Volatility 100 (1s) Index is strictly lower than entry spot at 5 minutes after contract start time.'; @@ -270,7 +270,7 @@ describe('Stake', () => { default_mock_store.modules.trade.amount = '26200'; render(); - userEvent.click(screen.getByText(stake_param_label)); + await userEvent.click(screen.getByText(stake_param_label)); expect(screen.queryByText(error_text_rise)).not.toBeInTheDocument(); }); diff --git a/packages/trader/src/AppV2/Components/TradeParameters/Stake/stake.tsx b/packages/trader/src/AppV2/Components/TradeParameters/Stake/stake.tsx index 90e82371bd7a..c513ccbd0673 100644 --- a/packages/trader/src/AppV2/Components/TradeParameters/Stake/stake.tsx +++ b/packages/trader/src/AppV2/Components/TradeParameters/Stake/stake.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import clsx from 'clsx'; import { observer } from 'mobx-react'; import { useStore } from '@deriv/stores'; @@ -38,7 +38,7 @@ const Stake = observer(({ is_minimized }: TTradeParametersProps) => { validation_params, } = useTraderStore(); const { - client: { is_logged_in }, + client: { is_logged_in, currency: client_currency }, } = useStore(); const { addSnackbar } = useSnackbar(); const [is_open, setIsOpen] = React.useState(false); @@ -53,6 +53,16 @@ const Stake = observer(({ is_minimized }: TTradeParametersProps) => { ? Number(v2_params_initial_values.stake) : available_contract_types?.[contract_type]?.config?.default_stake; + useEffect(() => { + if (client_currency !== currency) { + onChange({ target: { name: 'currency', value: client_currency } }); + if (!isCryptocurrency(client_currency ?? '')) { + onChange({ target: { name: 'amount', value: default_stake } }); + setV2ParamsInitialValues({ value: default_stake as number, name: 'stake' }); + } + } + }, [client_currency]); + const displayed_error = React.useRef(false); const contract_types = getDisplayedContractTypes(trade_types, contract_type, trade_type_tab); // first contract type data: diff --git a/packages/trader/src/AppV2/Containers/Trade/trade.tsx b/packages/trader/src/AppV2/Containers/Trade/trade.tsx index 7cbb18b8ae11..b24280e655c8 100644 --- a/packages/trader/src/AppV2/Containers/Trade/trade.tsx +++ b/packages/trader/src/AppV2/Containers/Trade/trade.tsx @@ -32,12 +32,12 @@ const Trade = observer(() => { active_symbols, contract_type, has_cancellation, - symbol, is_accumulator, is_market_closed, - onMount, onChange, + onMount, onUnmount, + symbol, } = useTraderStore(); const { trade_types } = useContractsForCompany(); const [guide_dtrader_v2] = useLocalStorageData>('guide_dtrader_v2', { diff --git a/packages/trader/src/Stores/Modules/Trading/trade-store.ts b/packages/trader/src/Stores/Modules/Trading/trade-store.ts index 53fad1e5028f..c5b82502599b 100644 --- a/packages/trader/src/Stores/Modules/Trading/trade-store.ts +++ b/packages/trader/src/Stores/Modules/Trading/trade-store.ts @@ -622,7 +622,7 @@ export default class TradeStore extends BaseStore { reaction( () => this.is_equal, () => { - this.onAllowEqualsChange(); + this.contract_type?.includes(TRADE_TYPES.RISE_FALL) && this.onAllowEqualsChange(); } ); reaction( @@ -1374,7 +1374,7 @@ export default class TradeStore extends BaseStore { const is_crypto = isCryptocurrency(this.currency ?? ''); const default_crypto_value = getMinPayout(this.currency ?? '') ?? ''; this.setV2ParamsInitialValues({ - value: is_crypto ? default_crypto_value : this.default_stake ?? '', + value: is_crypto ? default_crypto_value : (this.default_stake ?? ''), name: 'stake', }); obj_new_values.amount = is_crypto ? default_crypto_value : this.default_stake; diff --git a/packages/translations/src/translations/de.json b/packages/translations/src/translations/de.json index f8a17dd09e96..fac9db1f3ddf 100644 --- a/packages/translations/src/translations/de.json +++ b/packages/translations/src/translations/de.json @@ -3105,7 +3105,7 @@ "-2131851017": "Wachstumsrate", "-1073566768": "Ihr Einsatz wächst mit dem angegebenen Wachstumsprozentsatz pro Tick, solange der aktuelle Spotpreis innerhalb des Bereichs des vorherigen Spotpreises bleibt.", "-447853970": "Verlustschwelle", - "-1850439039": "Die Einheit, mit der der Einsatz nach einem Verlustgeschäft für das nächste Geschäft multipliziert wird.", + "-1850439039": "Die Einheit, mit der der Einsatz nach einem Verlustgeschäft für den nächsten Handel multipliziert wird.", "-33106112": "Die Größe, die verwendet wird, um den Einsatz nach einem erfolgreichen Handel für den nächsten Handel zu multiplizieren.", "-1503301801": "Der Wert muss gleich oder größer als {{ min }} sein", "-1596504046": "Anzahl der Einheit(en), die nach einem erfolgreichen Handel zum nächsten Handel hinzugefügt werden. Eine Einheit entspricht dem Betrag des ursprünglichen Einsatzes.", @@ -3864,7 +3864,7 @@ "-694027125": "take Profit", "-1302593482": "Bitte geben Sie einen {{field_label}} Betrag ein.", "-426023176": "Bitte geben Sie einen {{field_label}} Betrag ein, der mindestens {{min_value}} beträgt.", - "-774366508": "Maximaler {{field_label}} ist {{max_value}}.", + "-774366508": "Das maximal zulässige {{field_label}} ist {{max_value}}.", "-376450619": "Es ist ein Fehler aufgetreten.", "-843831637": "Stop-loss", "-509210647": "Versuchen Sie, nach etwas anderem zu suchen.", diff --git a/packages/translations/src/translations/km.json b/packages/translations/src/translations/km.json index da3fc8c465e3..351de36c8108 100644 --- a/packages/translations/src/translations/km.json +++ b/packages/translations/src/translations/km.json @@ -16,7 +16,7 @@ "14365404": "សំណើបានបរាជ័យសម្រាប់៖ {{ message_type }} ព្យាយាមម្តងទៀតក្នុង {{ delay }} វិនាទី", "14874020": "តម្លៃមិនអាចអវិជ្ជមានបានទេ។ តម្លៃដែលបានផ្តល់៖ {{ input_value }} ។", "15377251": "ចំនួនប្រាក់ចំណេញ៖ {{profit}}", - "15794287": "ត្រូវការជនជាតិ។", + "15794287": "តម្រូវ​ឱ្យ​បញ្ជាក់​សញ្ជាតិ​។", "17843034": "ពិនិត្យស្ថានភាពនៃការផ្ទៀងផ្ទាត់អត្តសញ្ញាណតាមរយៈឯកសារ", "19424289": "ឈ្មោះអ្នកប្រើប្រាស់", "19552684": "USD Basket", @@ -3735,106 +3735,106 @@ "-78895143": "សមតុល្យទឹកប្រាក់បច្ចុប្បន្ន", "-149993085": "សមតុល្យទឹកប្រាក់ថ្មីបច្ចុប្បន្ន", "-1615126227": "គ្រប់គ្រងគណនី Deriv cTrader បានរហូតដល់ {{max_count}} ។ ខណៈពេលដែលអ្នកអាចបំប្លែងគណនី Deriv cTrader ណាមួយរបស់អ្នកទៅជាគណនីយុទ្ធសាស្រ្ត សូមចំណាំដូចខាងក្រោម៖", - "-1547739386": "ដើម្បីធានាថាអ្នកអាចបង្កើតនិងគ្រប់គ្រងយុទ្ធសាស្ត្រដែលមានកម្រៃជាថ្មី គឺ <0>ត្រូវរក្សាគណនីខ្ញុំទេមួយយ៉ាងយ៉ាងកន្លែងកាន់ជាproviders strategy ។", - "-2145356061": "ទាញយក {{ platform }} ទៅកាន់ទូរស័ព្ទរបស់អ្នកដើម្បីជួញដូរ​ជាមួយគណនី {{ platform }} {{ account }}។", - "-1547458328": "ប្រតិបត្តិការ cTrader លើថ្លៃចូលរួមរាល់ពេលដែលក្នុងទីតាំងវារបស់អ្នក", - "-747382643": "ទទួលការគ្រប់គ្រងគណនី cTrader ផ្សេងទៀត", - "-1986258847": "សេវាកម្មថ្វីមុនវេលាចាប់ផ្តើមនៅ 01:00​ GMT​ នៅថ្ងៃទីសួរគ្រាប់​តុ ហើយវាអាចចររបស់សេវាកម្មនេះថយចុះបានពេលនេះ។", - "-499504077": "ជ្រើសរើសគណនី cTrader ដើម្បីផ្ទេរ", - "-251202291": "សហប្រតិបត្តិការអ្នកជំនួសការផ្ទាល់ប័ត្ររបស់អ្នក", + "-1547739386": "ដើម្បីធានាថាអ្នកតែងតែអាចបង្កើត និងគ្រប់គ្រងយុទ្ធសាស្រ្តជាមួយនឹងថ្លៃសេវាបាន ត្រូវ<0>រក្សាគណនីយ៉ាងហោចណាស់មួយចេញពីការក្លាយជាអ្នកផ្តល់សេវាយុទ្ធសាស្រ្ត។ វិធីនេះអ្នកនឹងតែងតែមានគណនីរួចរាល់សម្រាប់ការប្រមូលថ្លៃសេវា ដែលអនុញ្ញាតឱ្យអ្នកមាន រហូតដល់ទៅបួនយុទ្ធសាស្រ្តដែលអ្នកអាចដាក់ថ្លៃសេវាបាន។", + "-2145356061": "ទាញយក Deriv X នៅលើទូរសព្ទរបស់អ្នកដើម្បីធ្វើការជួញដូរជាមួយគណនី Deriv X", + "-1547458328": "ដំណើរការ cTrader នៅលើកម្មវិធីរុករករបស់អ្នក", + "-747382643": "ទទួលបានគណនី cTrader ផ្សេងទៀត", + "-1986258847": "ការថែទាំម៉ាស៊ីនមេចាប់ផ្តើមនៅម៉ោង 01:00 GMT រៀងរាល់ថ្ងៃអាទិត្យ ហើយដំណើរការនេះអាចចំណាយពេលរហូតដល់ 2 ម៉ោងដើម្បីបញ្ចប់។ សេវាកម្មអាចនឹងត្រូវបានរំខានក្នុងអំឡុងពេលនេះ។", + "-499504077": "ជ្រើសរើសគណនី cTrader ដើម្បីផ្ទេរប្រាក់", + "-251202291": "ឈ្មួញកណ្តាល", "-678964540": "ដល់", - "-206829624": "(១:x)", - "-616293830": "ទ្រង់ទ្រាយរួមពេក <0>រហ័សទៅ ១:១៥០០ ពោរបិស័យនៅពេលដែលអ្នកកាន់អោយអាត្រាក្នុងទីវិលនិងផ្កាវលីគូរ ប្រៃគ្រប់គ្រងផលិតផល CFD របស់ Deriv។ រហ័សទិញដោយផ្លាស់ប្តូរដោយស្វ័យប្រវត្តិនឹងប្រភេទទាក់ទងនិងលេខសម្គាល់អ្នកកំពុងកាន់ចំនួន។", - "-2042845290": "អ្នកគួរតែបញ្ចូលតួអក្សរ {{min_number}}-{{max_number}}។", - "-1882295407": "ពាក្យសំងាត់របស់អ្នកបានផ្លាស់ប្ដូររួចហើយ.", - "-254497873": "ប្រើពាក្យសម្ងាត់នេះដើម្បីផ្ដល់កំណត់ភាពក្នុងការមើលទៅអ្នកប្រើទៀត។", + "-206829624": "(1:x)", + "-616293830": "សូមរីករាយជាមួយអានុភាពថាមវន្តឬឌីណាមីកនៃ <0>រហូតដល់ 1:1500 នៅពេលដែលការជួញដូរឧបករណ៍ដែលបានជ្រើសរើសនៅក្នុងទីផ្សារ Forex, ទំនិញ, cryptocurrencies និងទីផ្សារភាគហ៊ុន។ អានុភាពថាមវន្តរបស់យើងកែតម្រូវដោយស្វ័យប្រវត្តិទៅនឹងទីតាំងជួញដូររបស់អ្នក ដោយផ្អែកលើប្រភេទទ្រព្យសកម្ម និងបរិមាណជួញដូរ។", + "-2042845290": "ពាក្យសម្ងាត់វិនិយោគិនរបស់អ្នកត្រូវបានផ្លាស់ប្តូររួចហើយ។", + "-1882295407": "ពាក្យសម្ងាត់របស់អ្នកត្រូវបានផ្លាស់ប្តូររួចហើយ។", + "-254497873": "ប្រើ​ពាក្យ​សម្ងាត់​នេះ​ដើម្បី​ផ្តល់​សិទ្ធិ​ចូល​មើល​ដល់​អ្នក​ប្រើ​ផ្សេង​ទៀត។ ខណៈពេលដែលពួកគេអាចមើលគណនីជួញដូររបស់អ្នក ពួកគេនឹងមិនអាចធ្វើការជួញដូរ ឬធ្វើសកម្មភាពផ្សេងទៀតបានទេ។", "-161656683": "ពាក្យសម្ងាត់អ្នកវិនិយោគបច្ចុប្បន្ន", - "-374736923": "ពាក្យសម្ងាត់វិនិយោគថ្មី", - "-1793894323": "បង្កើតឬផ្លាស់ប្តូពាក្យសម្ងាត់វិនិយោគ", - "-918069465": "គណនីមិនអាចប្រើបាន", + "-374736923": "ពាក្យសម្ងាត់អ្នកវិនិយោគថ្មី", + "-1793894323": "បង្កើត ឬកំណត់ពាក្យសម្ងាត់របស់អ្នកវិនិយោគឡើងវិញ", + "-918069465": "គណនីមិនអាចប្រើបានទេ", "-643795646": "បង្កើតពាក្យសម្ងាត់សម្រាប់គណនី {{platform}} របស់អ្នក៖", - "-1593684005": "ពាក្យសម្ងាត់នេះអាចប្រើបានសម្រាប់គណនី Deriv MT5 របស់អ្នកទាំងអស់។", + "-1593684005": "ពាក្យសម្ងាត់នេះដំណើរការសម្រាប់គណនី Deriv MT5 របស់អ្នកទាំងអស់។", "-417711545": "បង្កើតគណនី", - "-637537305": "ទាញយក {{ platform }} នៅលើទូរស័ព្ទរបស់អ្នកដើម្បីជួញដូរ​ជាមួយគណនី {{ platform }} {{ account }}។", + "-637537305": "ទាញយក {{ platform }} នៅលើទូរសព្ទរបស់អ្នកដើម្បីធ្វើការជួញដូរជាមួយគណនី {{ platform }} {{ account }}", "-964130856": "{{existing_account_title}}", - "-879259635": "បញ្ចូលពាក្យសម្ងាត់គណនីរៀនរបស់ក្រុមហ៊ន MT5 ដើម្បីធ្វើឲ្យគណនីរៀនរបស់អ្នកបានបង្កើត។", - "-361998267": "យើងបានណែនាំសមាជិកនូវតម្រូវការពាក្យសម្ងាត់បន្ថែម ដើម្បីបង្កើនសុវត្ថិភាពគណនីរបស់អ្នក។ ពាក្យសម្ងាត់របស់អ្នកគួរតែ:", + "-879259635": "បញ្ចូលពាក្យសម្ងាត់ Deriv MT5 របស់អ្នក ដើម្បីអាប់ក្រេដគណនីរបស់អ្នក។", + "-361998267": "យើងបានណែនាំតម្រូវការពាក្យសម្ងាត់បន្ថែមដើម្បីបង្កើនសុវត្ថិភាពគណនីរបស់អ្នក។ ពាក្យសម្ងាត់របស់អ្នកគួរតែ៖", "-996995493": "មានចន្លោះពី 8 ទៅ 16 តួអក្សរ។", - "-219163415": "មានយ៉ាងហោចណាស់តួអក្សរពិសេសមួយ", - "-1446636186": "ដោយចុច <0>បន្ទាប់ អ្នកយល់ព្រមផ្លាស់ប្តូរគណនី {{platform}} {{type_1}} និង {{type_2}} {{from_account}} របស់អ្នកទៅ Deriv {{account_to_migrate}} Ltd ’s <1>terms and conditions។", - "-1766387013": "ធ្វើបច្ចុប្បន្នភាពគណនី MT5 របស់អ្នក", - "-990927225": "បញ្ចូលពាក្យសម្ងាត់គណនីរៀនរបស់ក្រុមហ៊ន MT5", - "-1486399361": "ទិញការទូលាយជាមួយកម្មវិធីទូលាយ MT5", - "-301350824": "សូមប្តូរយកកម្មវិធី MT5? ចុចលើប៊ូតុង <0>ទិញការទូលាយជាមួយកម្មវិធីទូលាយ MT5 ដើម្បីទាញយក។ បន្ទាប់ពីដែលអ្នកបានតំឡើងកម្មវិធីត្រូវទាញយក អញ្ចឹងទៅលើអេក្រងៈនេះហើយចុចលើប៊ូតុងដើម្បីចូលទៅគណនីរបស់លោកអ្នក។", - "-648956272": "ប្រើពាក្យសម្ងាត់នេះ ដើម្បីចូលទៅក្នុងគណនី Deriv X របស់អ្នកនៅលើវែបសាយ និងកម្មវិធីទូរស័ព្ទ។", - "-1814308691": "សូមចុចលើតំណនៅក្នុងអ៊ីមែលដើម្បីផ្លាស់ប្តូរពាក្យសម្ងាត់ {{platform}} របស់អ្នក។", - "-601303096": "ស្កានបញ្ជូនរបស់អ្នកសម្រាប់ទាញយក Deriv {{ platform }}។", - "-1357917360": "ធ្វើជាបន្ថែក្រចក្រនាមអ័ក្សញ៉ូម៉ូតាប៉ុណ្ណ", - "-1282933308": "មិន {{barrier}}", + "-219163415": "មានយ៉ាងហោចណាស់តួអក្សរពិសេសមួយ។", + "-1446636186": "ដោយចុចលើ <0>បន្ទាប់ អ្នកយល់ព្រមផ្លាស់ទី {{platform}} {{type_1}} និង {{type_2}} គណនី {{from_account}} របស់អ្នកនៅក្រោម Deriv {{account_to_migrate}} Ltd's < 1>លក្ខខណ្ឌ។", + "-1766387013": "អាប់ក្រេដគណនី MT5 របស់អ្នក", + "-990927225": "បញ្ចូលពាក្យសម្ងាត់ Deriv MT5 របស់អ្នក", + "-1486399361": "ធ្វើការជួញដូរជាមួយកម្មវិធីទូរស័ព្ទ MT5", + "-301350824": "ចំណាំ៖ មិនមានកម្មវិធី MT5 មែនទេ? ចុចប៊ូតុង <0>ជួញដូរជាមួយកម្មវិធីទូរស័ព្ទ MT5 ដើម្បីទាញយក។ នៅពេលដែលអ្នកបាន\n បានដំឡើងកម្មវិធី ត្រឡប់ទៅអេក្រង់នេះ ហើយចុចប៊ូតុងដដែលដើម្បីចូលប្រព័ន្ធ។", + "-648956272": "ប្រើពាក្យសម្ងាត់នេះដើម្បីចូលគណនី Deriv X របស់អ្នកនៅលើគេហទំព័រ និងកម្មវិធីទូរស័ព្ទ។", + "-1814308691": "សូមចុចលើតំណក្នុងអ៊ីមែល ដើម្បីផ្លាស់ប្តូរពាក្យសម្ងាត់ {{platform}} របស់អ្នក។", + "-601303096": "ស្កេនកូដ QR ដើម្បីទាញយក Deriv {{ platform }} ។", + "-1357917360": "ស្ថានីយគេហទំព័រ", + "-1282933308": "មិនមែន {{barrier}}", "-968190634": "ស្មើ {{barrier}}", - "-1747377543": "ក្រោម {{barrier}}", - "-256210543": "ការជួញដូរមិនអាចប្រើបាននៅពេលនេះទេ។", - "-1418742026": "របាំងខ្ពស់ត្រូវតែខ្ពស់ជាងរបាំងទាប", - "-92007689": "របាំងទាបត្រូវតែទាបជាងរបាំងខ្ពស់", - "-1095538960": "សូមបញ្ចូលពេលដែលចាប់ផ្ដើមក្នុងទ្រង់ទ្រាយ “HH:MM”។", - "-1975910372": "នាទីត្រូវតែចន្លោះពី 0 ទៅ 59", - "-866277689": "ពេលវេលាយឹងថ្មីមិនអាចមានបាននៅក្នុងអតីតកាលទេ។", + "-1747377543": "នៅក្រោម {{barrier}}", + "-256210543": "ការជួញដូរមិនអាចធ្វើទៅបានទេនៅពេលនេះ។", + "-1418742026": "បន្ទាត់តម្លៃគោលដៅខាងលើត្រូវតែខ្ពស់ជាងបន្ទាត់ខាងក្រោម។", + "-92007689": "បន្ទាត់តម្លៃគោលដៅខាងក្រោមត្រូវតែទាបជាងបន្ទាត់តម្លៃខាងលើ។", + "-1095538960": "សូមបញ្ចូលម៉ោងចាប់ផ្តើមក្នុងទម្រង់ \"HH:MM\"។", + "-1975910372": "នាទីត្រូវតែស្ថិតនៅចន្លោះពី 0 ដល់ 59។", + "-866277689": "ពេលវេលាផុតកំណត់មិនអាចជាពេលវេលាអតីតកាលបានទេ។", "-1455298001": "ឥឡូវនេះ", - "-1150099396": "យើងកំពុងធ្វើការដើម្បីធ្វើឱ្យមានសម្រាប់អ្នកឆាប់ៗនេះ។ ប្រសិនបើអ្នកមានគណនីផ្សេងទៀត សូមប្តូរទៅគណនីនោះ ដើម្បីបន្តការពាណិជ្ជកម្ម។ អ្នកអាចបន្ថែម Deriv MT5 Financial បាន។", + "-1150099396": "យើងកំពុងធ្វើការដើម្បីឱ្យវាអាចប្រើប្រាស់បានសម្រាប់អ្នកក្នុងពេលឆាប់ៗនេះ។ ប្រសិនបើអ្នកមានគណនីផ្សេងទៀត សូមប្តូរទៅគណនីនោះដើម្បីបន្តការជួញដូរ។ អ្នកអាចបន្ថែម Deriv MT5 Financial ។", "-28115241": "{{platform_name_trader}} មិនអាចប្រើបានសម្រាប់គណនីនេះទេ", - "-453920758": "ចូលទៅផ្ទាំងគណនី {{platform_name_mt5}}", + "-453920758": "ចូលទៅកាន់ផ្ទាំងគ្រប់គ្រង {{platform_name_mt5}}", "-402175529": "ប្រវត្តិ", - "-1013917510": "ពេលកំណត់បញ្ចូល {{ reset_time }}", - "-925402280": "កន្លងមិត្តក្រោម", - "-1075414250": "កន្លងមិត្តលើរបស់ក្រោយ", - "-902712434": "ការលុបចោលកិច្ចព្រមព្រៀង។", - "-988484646": "បោះបង់កិច្ចការ (បើបានអនុញ្ញាត)", - "-444882676": "បោះបង់កិច្ចការ (ដែលកំពុងដំណើរការ)", - "-13423018": "លេខយោង", - "-1371082433": "កំណត់ជញ្ជាំងឡើងវិញ", + "-1013917510": "ពេលវេលាកំណត់ឡើងវិញគឺ {{ reset_time }}", + "-925402280": "ចំណុចសូចនាករទាប", + "-1075414250": "ចំណុចខ្ពស់", + "-902712434": "ការលុបចោលកិច្ចព្រមព្រៀង", + "-988484646": "ការលុបចោលកិច្ចព្រមព្រៀង (ដំណើរការហើយ)", + "-444882676": "ការលុបចោលកិច្ចព្រមព្រៀង (នៅដំណើរការ)", + "-13423018": "លេខសម្គាល់ឯកសារយោង", + "-1371082433": "កំណត់តម្លៃបន្ទាត់តម្លៃគោលដៅឡើងវិញ", "-1402197933": "កំណត់ពេលវេលាឡើងវិញ", "-2035315547": "បន្ទាត់កម្រិតតម្លៃគោលដៅខាងក្រោម", - "-1745835713": "ជ្រើសពិន្ទុ", - "-1551639437": "គ្មានប៉វត្តិប្រជាប់", - "-1214703885": "អ្នកមិនទាន់បានធ្វើបច្ចុប្បន្នភាពទាំង Take Profit ឬ Stop Loss", - "-504849554": "វានឹងបើកឡើងនៅម៉ោង។", - "-59803288": "ក្នុងពេលនេះ សូមសាកល្បងសន្ទស្សន៍សំយោគរបស់យើង។ ពួកគេក្លែងធ្វើការប្រែប្រួលទីផ្សារពិតប្រាកដ ហើយបើក 24/7 ។", - "-1278109940": "មើលទីផ្សារធ្វើការដែលបានបើក", - "-694105443": "ទីផ្សារនេះបានបិទហើយ", - "-104603605": "អ្នកមិនអាចវិលបន្ទាន់ប្រាក់បានតែក្នុងការពិនិត្យមើលឯកសាររបស់អ្នកទេ។ យើងនឹងផ្ញើអ៊ីម៉ែលពេលវេលា រួមកាលបរិច្ឆេទ ពីរ ថ្ងៃតក្រឡូថ្ងៃបន្ទាប់ក្រោយបញ្ចេញជាមុន។", - "-439389714": "យើងកំពុងធ្វើការ", - "-770929448": "ចូលទៅ {{platform_name_smarttrader}}", - "-347156282": "ដាក់រូបសំណាក់", - "-138538812": "ចូលប្រើគណនីរបស់អ្នក ឬបង្កើតគណនីដោយឥតគិតថ្លៃ ដើម្បីធ្វើការជួញដូរ។", - "-2036388794": "បង្កើតគណនីដោយឥតគិតថ្លៃ។", - "-1813736037": "មិនអនុញ្ញាតឲ្យធ្វើការជួញដូរបន្ថែមទេនៅលើប្រភេទកិច្ចសន្យានេះសម្រាប់វគ្គជួញដូរបច្ចុប្បន្ន។ សម្រាប់ព័ត៌មានបន្ថែម សូមអញ្ជើញមើលលក្ខខណ្ឌនិងកាលបរិច្ឆេទរបស់យើង។", - "-1043795232": "ទីតាំងថ្មីៗ។", - "-153220091": "{{display_value}} សរសេរ", + "-1745835713": "ចំណុច Tick ដែលបានជ្រើសរើស", + "-1551639437": "គ្មានប្រវត្តិ", + "-1214703885": "អ្នកមិនទាន់បានធ្វើការអាប់ដេតទាំង Take profit ឬ Stop loss", + "-504849554": "វានឹងបើកឡើងវិញនៅ", + "-59803288": "ក្នុងពេលនេះ សូមសាកល្បងសន្ទស្សន៍ Synthetic របស់យើង។ ពួកគេក្លែងធ្វើការប្រែប្រួលទីផ្សារពិតប្រាកដ ហើយបើក 24/7 ។", + "-1278109940": "មើលទីផ្សារបើក", + "-694105443": "ទីផ្សារនេះត្រូវបានបិទហើយ", + "-104603605": "អ្នកមិនអាចធ្វើការជួញដូរបានទេ ដោយសារឯកសាររបស់អ្នកកំពុងស្ថិតក្រោមការត្រួតពិនិត្យនៅឡើយ។ យើងនឹងជូនដំណឹងដល់អ្នកតាមអ៊ីមែល នៅពេលដែលការផ្ទៀងផ្ទាត់របស់អ្នកត្រូវបានអនុតម័ត។", + "-439389714": "យើងកំពុងដំណើរការ", + "-770929448": "ចូលទៅកាន់ {{platform_name smarttrader}}", + "-347156282": "បញ្ជូនភស្តុតាង", + "-138538812": "ចូលប្រព័ន្ធ ឬបង្កើតគណនីឥតគិតថ្លៃ ដើម្បីធ្វើការជួញដូរ។", + "-2036388794": "បង្កើតគណនីដោយឥតគិតថ្លៃ", + "-1813736037": "មិនអនុញ្ញាតឲ្យមានការជួញដូរបន្ថែមទៀតទេលើប្រភេទកិច្ចសន្យានេះសម្រាប់វគ្គជួញដូរបច្ចុប្បន្ន។ សម្រាប់ព័ត៌មានបន្ថែម សូមមើល <0>លក្ខខណ្ឌ របស់យើង។", + "-1043795232": "មុខតំណែងថ្មីៗ", + "-153220091": "ចំណុច Tick {{display_value}} ចំណុច", "-802374032": "ម៉ោង", - "-1700010072": "មុខងារនេះមិនមានសម្រាប់ចន្លោះពេលធីកទេ។ ប្តូរទៅជានាទី ម៉ោង ឬថ្ងៃ។", - "-2017825013": "យល់ដឹង", - "-112444942": "ប្រវត្តិនៃការរាប់សញ្ញាធីក", - "-1145293111": "ផ្សារ​នេះ​នឹង​បើក​វិញ​នៅ​ម៉ោង", - "-1782608357": "ចាប់ផ្ដើមនៅ {{formatted_date}}, {{formatted_time}}", - "-1341681145": "នៅពេលនេះសកម្ម អ្នកអាចលុបចោលការបោះឆ្នោតរបស់អ្នកក្នុងរយៈពេលដែលបានជ្រើស។ ភាគចំណែករបស់អ្នកនឹងត្រូវបានវិលត្រឡប់ដោយគ្មានការបាត់បង់។", - "-2069438609": "រកមិនឃើញការប្រកួត", - "-647454892": "មិនមានមុខតំណែងជួញដូរបិទជិតទេ។", - "-1474415836": "មុខតំណែងជួញដូរដែលបានបិទនឹងបង្ហាញនៅទីនេះ។", - "-576924961": "មុខតំណែងជួញដូរដែលបើកនឹងបង្ហាញនៅទីនេះ។", - "-225500551": "ព័ត៌មានលម្អិតអំពីកន្លែងចូល និងច្រកចេញ", + "-1700010072": "មុខងារនេះមិនអាចប្រើបានទេសម្រាប់ចន្លោះពេលបែបចំណុច Tick ។ សូមប្តូរទៅនាទី ម៉ោង ឬថ្ងៃ។", + "-2017825013": "យល់ហើយ", + "-112444942": "ប្រវត្តិនៃការរាប់ចំណុច Tick", + "-1145293111": "ទីផ្សារនេះនឹងបើកឡើងវិញនៅម៉ោង", + "-1782608357": "ចាប់ផ្តើមនៅថ្ងៃ {{formatted_date}}, {{formatted_time}}", + "-1341681145": "នៅពេលបើកដំណើរការហើយ អ្នកអាចលុបចោលការជួញដូររបស់អ្នកក្នុងរយៈពេលដែលបានជ្រើសរើស។ ភាគហ៊ុនរបស់អ្នកនឹងត្រូវបានត្រឡប់មកវិញដោយមិនបាត់បង់។", + "-2069438609": "រកមិនឃើញការផ្គូផ្គងដែលដូចគ្នាទេ", + "-647454892": "គ្មានមុខតំណែងដែលបិទទេ", + "-1474415836": "មុខតំណែងដែលបិទរបស់អ្នកនឹងត្រូវបានបង្ហាញនៅទីនេះ។", + "-576924961": "មុខតំណែងដែលបើករបស់អ្នកនឹងបង្ហាញនៅទីនេះ។", + "-225500551": "ព័ត៌មានលម្អិតអំពីការចូលជួញដូរ និងចេញ", "-1022682526": "ទីផ្សារដែលអ្នកចូលចិត្តនឹងបង្ហាញនៅទីនេះ។", - "-232254547": "ផ្ទាល់ខ្លួន", + "-232254547": "កំណត់ខ្លួនឯង", "-1251526905": "7 ថ្ងៃចុងក្រោយ", "-1539223392": "90 ថ្ងៃចុងក្រោយ", - "-1123299427": "ភាគហ៊ុនរបស់អ្នកនឹងបន្តកើនឡើង ដរាបណាតម្លៃកន្លែងបច្ចុប្បន្ននៅតែស្ថិតក្នុង <0>ជួរ ដែលបានបញ្ជាក់ពី <1>តម្លៃកន្លែងមុន។ បើមិនដូច្នោះទេ អ្នកបាត់បង់ភាគហ៊ុនរបស់អ្នក ហើយការជួញដូរត្រូវបានបញ្ចប់។", - "-1052279158": "<0>ការបង់ប្រាក់ របស់អ្នកគឺសរុបនៃភ្នាល់ដំបូង និងចំណេញរបស់អ្នក", - "-274058583": "<0>Take profit គឺជាលក្ខណៈបន្ថែមដែលអនុញ្ញាតឱ្យអ្នកគ្រប់គ្រងហានិភ័យរបស់អ្នក ដោយបិទពាណិជ្ជកម្មដោយស្វ័យប្រវត្តិនៅពេលចំណេញរបស់អ្នកឈានដល់ចំនួនប្រាក់ដែលបានកំណត់ទុក។ លក្ខណៈសម្បត្ដិនេះមិនមានសម្រាប់កិច្ចសន្យាសន្សំពិន្ទុណៅលើកម្មវិធីដែលដំណើរការបន្តទេ។", - "-1819891401": "អ្នកអាចបិទការពាណិជ្ជកម្មរបស់អ្នកនៅពេលណាក៏បាន។ ប៉ុន្តែ, សូមប្រយ័ត្នពី <0>ហានិភ័យនៃការរអិល។", - "-859589563": "ប្រសិនបើអ្នកជ្រើសរើស “<0>Odd” អ្នកនឹងឈ្នះការបង់ប្រាក់ ប្រសិនបើខ្ទង់ចុងក្រោយនៃសញ្ញាធីកចុងក្រោយគឺជាលេខសេស (ឧ. 1, 3, 5, 7, ឬ 9)។", - "-1911850849": "ប្រសិនបើកន្លែងចេញគឺស្មើនឹងរបាំង នោះអ្នកមិនឈ្នះការបង់ប្រាក់នោះទេ។", - "-618782785": "ប្រើ Multipliers ដើម្បីបង្កើនលទ្ធភាពចំណេញរបស់អ្នក។ ទស្សនាតម្លៃទ្រព្យសម្បត្តិថានឹងឡើង (bullish) ឬធ្លាក់ (bearish)។ យើងនឹងគិតថ្លៃកម្រៃពេលអ្នកបើកការជួញដូរ Multipliers។", - "-565391674": "ប្រសិនបើអ្នកជ្រើសរើស \"<0>Up\" ប្រាក់ចំណេញ/ការខាតបង់សរុបរបស់អ្នកនឹងជាភាគរយនៃការកើនឡើងនៃតម្លៃទ្រព្យសកម្មមូលដ្ឋាន គុណនឹង Multiplier និងភាគហ៊ុន ដកកំរៃជើងសារ។", - "-2132756399": "មានមុខងារបន្ថែមមានសម្រាប់គ្រប់គ្រងមុខតំណែងរបស់អ្នក៖ <0>បិទ​ការ​ជួញដូរ​យក​ចំណេញ​, <1>បញ្ឈប់ការខាតបង់ និង <2>ការលុបចោលកិច្ចព្រមព្រៀង អនុញ្ញាតឱ្យអ្នកកែតម្រូវកម្រិតនៃការបដិសេធហានិភ័យរបស់អ្នកបាន។", + "-1123299427": "ភាគហ៊ុនរបស់អ្នកនឹងបន្តកើនឡើង ដរាបណាតម្លៃ spot បច្ចុប្បន្ននៅតែស្ថិតក្នុង <0>ជួរ ដែលបានបញ្ជាក់ពី <1>តម្លៃ spot មុន។ បើមិនដូច្នោះទេ អ្នកនឹងបាត់បង់ប្រាក់ដើមរបស់អ្នក ហើយការជួញដូរត្រូវបានបញ្ចប់។", + "-1052279158": "<0>ប្រាក់សំណង របស់អ្នកគឺជាផលបូកនៃប្រាក់ដើមទុនដំបូង និងប្រាក់ចំណេញរបស់អ្នក។", + "-274058583": "<0>Take profit គឺជាមុខងារបន្ថែមដែលអនុញ្ញាតឱ្យអ្នកគ្រប់គ្រងហានិភ័យរបស់អ្នកដោយការបិទការជួញដូរដោយស្វ័យប្រវត្តិ នៅពេលដែលប្រាក់ចំណេញរបស់អ្នកឈានដល់ចំនួនគោលដៅ។ មុខងារនេះមិនអាចប្រើបានសម្រាប់កិច្ចសន្យា Accumulator ដែលកំពុងបន្តដំណើរការទេ។", + "-1819891401": "អ្នកអាចបិទការជួញដូររបស់អ្នកបានគ្រប់ពេល។ ទោះយ៉ាងណាក៏ដោយ សូមប្រយ័ត្នចំពោះ <0>ហានិភ័យនៃភាពមិនស៊ីសង្វាក់គ្នា។", + "-859589563": "ប្រសិនបើអ្នកជ្រើសរើស “<0>Odd” អ្នកនឹងឈ្នះប្រាក់សំណង ប្រសិនបើខ្ទង់ចុងក្រោយនៃចំណុច Tick ចុងក្រោយគឺជាលេខសេស (ឧ. 1, 3, 5, 7, ឬ 9)។", + "-1911850849": "ប្រសិនបើចំណុចចេញគឺស្មើនឹងបន្ទាត់តម្លៃគោលដៅ អ្នកនឹងមិនទទួលបានប្រាក់សំណងទេ។", + "-618782785": "ប្រើ Multiplier ​ដើម្បី​បង្កើន​ផល​ចំណេញ​របស់​អ្នក។ ទស្សន៍ទាយថាតើតម្លៃទ្រព្យសកម្មនឹងឡើងលើ (bullish) ឬធ្លាក់ចុះ (bearish)។ យើងនឹងគិតប្រាក់កម្រៃជើងសារនៅពេលអ្នកបើកការជួញដូរបែប Multiplier។", + "-565391674": "ប្រសិនបើអ្នកជ្រើសរើស \"<0>Up\" នោះ ប្រាក់ចំណេញ/ការខាតបង់សរុបរបស់អ្នកនឹងជាភាគរយនៃការកើនឡើងនៃតម្លៃទ្រព្យសកម្មមូលដ្ឋាន គុណនឹង Multiplier និងប្រាក់ដើម ដកកំរៃជើងសារ។", + "-2132756399": "មុខងារបន្ថែមមានសម្រាប់គ្រប់គ្រងមុខតំណែងរបស់អ្នក៖ <0>Take profit, <1>Stop loss និង <2>ការលុបចោលកិច្ចព្រមព្រៀង អនុញ្ញាតឱ្យអ្នកកែតម្រូវកម្រិតនៃហានិភ័យរបស់អ្នក។", "-1158764468": "ប្រសិនបើអ្នកជ្រើសរើស “<0>Over” អ្នកនឹងឈ្នះការបង់ប្រាក់ ប្រសិនបើខ្ទង់ចុងក្រោយនៃសញ្ញាធីកចុងក្រោយគឺធំជាងការព្យាករណ៍របស់អ្នក។", "-1268105691": "ប្រសិនបើអ្នកជ្រើសរើស “<0>Under” អ្នកនឹងឈ្នះការបង់ប្រាក់ ប្រសិនបើលេខចុងក្រោយនៃសញ្ញាធីកចុងក្រោយគឺតិចជាងការព្យាករណ៍របស់អ្នក។", "-444119935": "ប្រសិនបើអ្នកជ្រើសរើស \"<0>Rise\" អ្នកនឹងឈ្នះការបង់ប្រាក់ ប្រសិនបើកន្លែងចេញគឺខ្ពស់ជាងកន្លែងចូល។", diff --git a/packages/translations/src/translations/pt.json b/packages/translations/src/translations/pt.json index 23e66f41546d..09fb507b26d3 100644 --- a/packages/translations/src/translations/pt.json +++ b/packages/translations/src/translations/pt.json @@ -3,7 +3,7 @@ "2091451": "Deriv Bot - o seu parceiro de negociação automatizado", "3215342": "Últimos 30 dias", "3420069": "Para evitar atrasos, insira o seu <0>nome e a <0>data de nascimento exatamente como constam do seu documento de identidade.", - "3939620": "O seu comprovativo de identidade está a ser analisado. Entraremos em contacto consigo dentro de 1 a 3 dias úteis.", + "3939620": "O seu comprovativo de identidade está em análise. Entraremos em contacto consigo no prazo de 1 a 3 dias úteis.", "4547840": "<0>Para proceder à transferência de fundos, é necessário validar a sua conta. <1>Validar agora", "5149403": "Saiba mais sobre os tipos de negociação", "7100308": "A hora deve situar-se entre 0 e 23.", @@ -16,7 +16,7 @@ "14365404": "O pedido falhou para: {{ message_type }}, tentar novamente em {{ delay }}s", "14874020": "Os valores não podem ser negativos. Valor fornecido: {{ input_value }}.", "15377251": "Valor do lucro: {{profit}}", - "15794287": "A cidadania é obrigatória.", + "15794287": "O campo da cidadania é obrigatório.", "17843034": "Consultar o estado de validação do documento de identidade", "19424289": "Nome de utilizador", "19552684": "Cesta de USD", @@ -40,7 +40,7 @@ "46523711": "O seu comprovativo de identidade foi validado", "47525080": "O montante que irá receber na data de expiração por cada ponto de variação abaixo da barreira.", "49404821": "Se comprar uma opção \"<0>{{trade_type}}\", recebe um pagamento no vencimento se o preço final for {{payout_status}} o preço de exercício. Caso contrário, a sua opção \"<0>{{trade_type}}\" expira sem valor.", - "50717678": "Guardar a estratégia atualizada para reimportações mais rápidas.", + "50717678": "Guarde a estratégia atualizada para agilizar as reimportações.", "53801223": "Hong Kong 50", "53964766": "5. Clique em Guardar para transferir o seu bot. Pode transferir o bot para o seu dispositivo ou para o Google Drive.", "54185751": "Menos de 100.000 dólares", @@ -96,7 +96,7 @@ "99306476": "A importação falhou devido a um ficheiro inválido. Carregue um ficheiro completo no formato XML.", "100239694": "Carregue a frente do cartão a partir do seu computador", "102226908": "O campo não pode estar vazio", - "102929937": "Certifique-se de copiar o endereço da conta Deriv {{currency}} acima e colá-lo na sua carteira de criptomoedas.", + "102929937": "Certifique-se de copiar o endereço da conta Deriv em {{currency}} acima e colá-lo na sua carteira de criptomoedas.", "105871033": "A idade que consta no documento que forneceu é inferior a 18 anos. Só estamos autorizados a oferecer os nossos serviços a clientes com mais de 18 anos, o que implica que teremos de encerrar a sua conta. Se tiver saldo na conta, contacte-nos através do live chat e iremos ajudá-lo a retirar os seus fundos antes do encerramento da sua conta.", "107537692": "Estes limites aplicam-se apenas às suas transações de opções. Por exemplo, a <0>perda total máxima refere-se às perdas acumuladas em todas as suas transações nas plataformas de negociação de opções.", "108916570": "Duração: {{duration}} dias", @@ -132,7 +132,7 @@ "133536621": "e", "133655768": "Caso deseje saber mais sobre o Bot Builder, entre no separador <0>Tutoriais.", "134126193": "Tente pesquisar por mercados ou palavras-chave", - "135698857": "<0>Siga estes passos para transferir as suas estratégias sem problemas:", + "135698857": "<0>Siga os seguintes passos para transferir as suas estratégias sem dificuldades:", "136790425": "Tente alterar ou remover os filtros para ver as posições disponíveis.", "137589354": "Para avaliar a sua experiência de negociação e determinar se os nossos produtos são adequados para si, por favor forneça respostas precisas e completas, pois estas podem afetar o resultado desta avaliação.", "138055021": "Índices sintéticos", @@ -140,7 +140,7 @@ "141265840": "Informações sobre a transferência de fundos", "141626595": "Certifique-se de que o seu dispositivo tem uma câmara funcional", "142050447": "defina {{ variable }} para criar texto com", - "142075981": "Acesso direto a preços de mercado.", + "142075981": "Acesso direto aos preços de mercado.", "142390699": "Ligado ao seu telemóvel", "143970826": "Problemas de pagamento?", "145511192": "s representa a entrada inicial.", @@ -199,7 +199,7 @@ "201091938": "30 dias", "203271702": "Tente novamente", "203297887": "A Estratégia Rápida que acabou de criar será carregada para a área de trabalho.", - "203337807": "<0>Fatura de serviços públicos: Eletricidade, água, gás ou fatura de telefone fixo.", + "203337807": "<0>Fatura de serviços públicos: Eletricidade, água, gás ou telefone fixo.", "203924654": "Clique no botão <0>Iniciar para começar e seguir o tutorial.", "204797764": "Transferência para o cliente", "204863103": "Hora de fecho", @@ -301,7 +301,7 @@ "294305803": "Gerir definições da conta", "294335229": "Vender ao preço de mercado", "296017162": "Voltar ao Bot", - "299867329": "Para mais informações, consulte esta publicação do blogue sobre os princípios básicos da criação de um bot de negociação.", + "299867329": "Para mais informações, consulte esta publicação no blogue sobre os princípios básicos da criação de um bot de negociação.", "301315130": "O montante que escolhe receber no vencimento por cada ponto de variação entre o preço final e a barreira.", "301441673": "Selecione a cidadania/nacionalidade tal como consta no seu passaporte ou outro documento de identificação emitido pelo governo.", "304309961": "Estamos a analisar o seu pedido de levantamento. Ainda pode cancelar esta transação se assim o desejar. Assim que iniciarmos o processamento, não será possível cancelar.", @@ -341,7 +341,7 @@ "343194622": "O montante que irá receber na data de expiração por cada ponto de variação acima da barreira", "343873723": "Este bloco apresenta uma mensagem. Pode especificar a cor da mensagem e escolher entre 6 Options de som diferentes.", "344418897": "Estes limites de negociação e autoexclusão ajudam-no a controlar a quantidade de dinheiro e tempo que gasta em {{brand_website_name}} e a exercer a <0>negociação responsável.", - "345171716": "Insira o seu endereço", + "345171716": "Introduza a sua morada", "345320063": "Carimbo de data/hora inválido", "345818851": "Desculpe, ocorreu um erro interno. Clique na caixa de seleção acima para tentar novamente.", "346070861": "Zero Spread", @@ -371,7 +371,7 @@ "367978153": "Removido dos favoritos", "368160866": "na lista", "369035361": "<0>• Número da conta", - "369409629": "Atualizámos o nosso sistema Blockly na Deriv Bot de <0>versão 3 para versão 10. Isto traz:", + "369409629": "Atualizámos o nosso sistema Blockly na Deriv Bot da <0>versão 3 para versão 10. Esta atualização traz:", "371151609": "Última utilização", "371710104": "Este âmbito permite que as aplicações de terceiros comprem e vendam contratos por si, renovem as suas compras expiradas e carreguem as suas contas demo.", "372291654": "A hora de exclusão deve ser posterior a hoje.", @@ -407,7 +407,7 @@ "411482865": "Adicionar conta {{deriv_account}}", "412433839": "Concordo com os <0>termos e condições.", "413594348": "Só são permitidas letras, números, espaços, hífenes, pontos finais e barras oblíquas.", - "415677940": "Desempenho mais rápido.", + "415677940": "Melhor desempenho.", "417864079": "Não é possível mudar de moeda após efetuar um depósito.", "419485005": "Spot", "419496000": "O seu contrato é fechado automaticamente quando o seu lucro é superior ou igual a este montante. Este bloco só pode ser utilizado com o tipo de negociação \"Multipliers\".", @@ -432,7 +432,7 @@ "433616983": "2. Fase de investigação", "434548438": "Definição da função de destaque", "434896834": "Funções personalizadas", - "436218994": "Não tenho informações fiscais", + "436218994": "Não possuo informações fiscais", "436364528": "A sua conta será aberta com {{legal_entity_name}} e estará sujeita às leis de São Vicente e Granadinas.", "436534334": "<0>Enviámos-lhe um e-mail.", "437138731": "Criar uma nova palavra-passe {{platform}}", @@ -478,7 +478,7 @@ "475492878": "Experimente os Índices Sintéticos", "476023405": "Não recebeu o e-mail?", "477557241": "Os blocos remotos a carregar devem ser uma coleção.", - "477744930": "Eliminar Todos os Blocos", + "477744930": "Eliminar todos os blocos", "478280278": "Este bloco exibe uma caixa de diálogo que utiliza uma mensagem personalizada para solicitar uma entrada. A entrada pode ser uma sequência de texto ou um número e pode ser atribuída a uma variável. Quando a caixa de diálogo é exibida, a sua estratégia é interrompida e só será retomada após introduzir uma resposta e clicar em “OK”.", "479420576": "Terciário", "480356486": "*Índice Boom 300 e Crash 300", @@ -580,7 +580,7 @@ "587577347": "Take Profit (Accumulator)", "587577425": "Proteger a minha conta", "587856857": "Quer saber mais sobre APIs?", - "588811360": "Devido a alterações na atividade comercial, as contas dos clientes no seu país serão encerradas. Levante os seus fundos até {{date}}.", + "588811360": "Devido a alterações na atividade comercial, as contas dos clientes no seu país serão encerradas. Por favor, levante os seus fundos até {{date}}.", "592087722": "O estatuto profissional é obrigatório.", "592381383": "Chave de acesso removida com sucesso", "592964176": "Junte-se a mais de 2,5 milhões de traders", @@ -625,7 +625,7 @@ "629003252": "Se a sua palavra-passe atual não cumprir estes requisitos, terá de criar uma nova palavra-passe no passo seguinte.", "629145209": "Se for selecionada a operação \"AND\", o bloco só devolve \"True\" se ambos os valores fornecidos forem \"True\"", "629395043": "Todas as taxas de crescimento", - "631355440": "O seu comprovativo de identidade está a ser analisado. Entraremos em contacto consigo dentro de 5 minutos.", + "631355440": "O seu comprovativo de identidade está em análise. Entraremos em contacto consigo no prazo de 5 minutos.", "632398049": "Esse bloco atribui um valor nulo a um item ou a um extrato.", "632897893": "Se o exposto acima se aplicar a si, selecione <0>Sim. Caso contrário, selecione <0>Não.", "632942644": "Contrato de arrendamento", @@ -698,7 +698,7 @@ "696870196": "- Open time: hora de inicio", "698037001": "Número de Identificação Civil", "698151231": "Não recebeu um código?", - "698440637": "Compare contas de CFDs {{title}}", + "698440637": "Compare as contas de CFDs {{title}}", "699159918": "1. Apresentação de reclamações", "699646180": "É necessário um valor mínimo de depósito de <0>{{minimum_deposit}} {{currency}}. Caso contrário, os fundos serão perdidos e não poderão ser recuperados.", "700259824": "Moeda da conta", @@ -900,7 +900,7 @@ "876826584": "Introduza um número de telefone válido, incluindo o código do país (ex.: +5511991234567).", "879014472": "Atingiu o número máximo de casas decimais", "879647892": "Pode vender o contrato até 60 segundos antes da expiração. Se o fizer, pagaremos o <0>valor do contrato.", - "880552407": "Declaração de residência oficial ou declaração juramentada", + "880552407": "Declaração oficial de residência ou affidavit", "881963105": "(XAUUSD, XAGUSD)", "882423592": "O montante que investe na primeira negociação. Note que este é o montante mínimo de entrada.", "885065431": "Criar uma conta Deriv", @@ -913,7 +913,7 @@ "894191608": "<0>c.O acordo deve ser concedido no prazo de 28 dias a contar da data em que a decisão é tomada.", "896790627": "Local de nascimento nos EUA", "897597439": "Alterações guardadas.", - "898167937": "Total levantado (Durante a vida)", + "898167937": "Total levantado (ao longo da vida)", "898457777": "Adicionou uma conta Deriv Financeira.", "898904393": "Barreira:", "899342595": "NIN", @@ -956,7 +956,7 @@ "938500877": "{{ text }}. <0>Pode visualizar o resumo da transação no seu e-mail.", "938947787": "Levantamento {{currency}}", "938988777": "Barreira alta", - "940624996": "Transferindo estratégias para a Deriv Bot", + "940624996": "Transferir estratégias para a Deriv Bot", "942015028": "Índice Step 500", "944499219": "Máximo de posições abertas", "945532698": "Contrato vendido", @@ -1103,7 +1103,7 @@ "1065766135": "Tem {{remaining_transfers}} {{transfer_text}} disponíveis para hoje.", "1066235879": "Será necessário criar uma segunda conta para transferir fundos.", "1066459293": "4.3. Reconhecimento da reclamação", - "1069336791": "Revisão em andamento", + "1069336791": "Revisão em curso", "1069347258": "O link de validação que utilizou já não é válido ou expirou. Por favor, solicite um novo link.", "1070323991": "6. Se ocorrerem negociações consecutivas bem sucedidas, a entrada deve seguir uma sequência de ajustamento de 1 para 3, depois 2 e 6 unidades da entrada inicial. Após 4 negociações bem sucedidas consecutivas, completa-se um ciclo e a estratégia repete-se para outro ciclo. Se qualquer negociação resultar em perdas, a sua entrada volta ao montante inicial da entrada para a negociação seguinte.", "1070624871": "Verifique o estado de validação do comprovativo de morada", @@ -1179,7 +1179,7 @@ "1140585027": "Entrada Inválida {{ input_value }}.", "1142023511": "Selecione o tipo de documento:", "1143730031": "A direção é {{ direction_type }}", - "1143854257": "Os serviços Deriv P2P e Agente de Pagamento estão atualmente indisponíveis para Wallets.", + "1143854257": "Os serviços Deriv P2P e Agentes de Pagamento estão atualmente indisponíveis para a Wallets.", "1144028300": "Matriz do Índice de Força Relativa (RSIA)", "1144740912": "Cancelar a validação do número de telefone?", "1145927365": "Execute os blocos após um determinado número de segundos", @@ -1324,9 +1324,9 @@ "1274819385": "3. Reclamações e Litígios", "1276660852": "Envie o seu comprovativo de identidade", "1276973471": "Os produtos oferecidos no nosso site são produtos derivados complexos que comportam um risco significativo de perda potencial. Os CFDs são instrumentos complexos que apresentam um elevado risco de perda rápida de dinheiro devido à alavancagem. 70,84% das contas de investidores não profissionais perdem dinheiro ao negociar CFDs com este fornecedor. Deve considerar se compreende o funcionamento destes produtos e se pode correr o risco elevado de perder o seu dinheiro.", - "1279003709": "A posição encerra após os lucros e perdas ultrapassarem o valor do take profit.", - "1279197529": "O Número de Identificação Fiscal é obrigatório.", - "1279937041": "<0>Nota: Algumas estratégias complexas podem enfrentar problemas no Bot Builder. Se tiver dúvidas, contacte-nos via <1/>.", + "1279003709": "A posição encerra após os lucros e perdas ultrapassarem o valor de take profit.", + "1279197529": "O campo do Número de Identificação Fiscal é obrigatório.", + "1279937041": "<0>Nota: Algumas estratégias complexas podem apresentar problemas no Bot Builder. Em caso de dúvidas, contacte-nos via <1/>.", "1281045211": "Classifica os itens em uma determinada lista, por seu valor numérico ou alfabético, em ordem crescente ou decrescente.", "1281290230": "Selecionar", "1282951921": "Only Downs", @@ -1347,7 +1347,7 @@ "1294756261": "Este bloco cria uma função, que é um grupo de instruções que podem ser executadas em qualquer altura. Coloque outros blocos aqui para executar qualquer tipo de ação que necessite na sua estratégia. Quando todas as instruções de uma função tiverem sido executadas, o teu bot continuará com os restantes blocos da tua estratégia. Clique no campo \"fazer algo\" para dar um nome à sua escolha. Clique no ícone \"mais\" para enviar um valor (como uma variável designada) para a sua função.", "1295284664": "Aceite os nossos <0>Termos e Condições actualizados para prosseguir.", "1296380713": "Encerrar o meu contrato", - "1299451470": "Total de levantamento autorizado (Durante a vida)", + "1299451470": "Total de levantamento autorizado (ao longo da vida)", "1299479533": "8 horas", "1300576911": "Volte a apresentar o seu comprovativo de morada ou poderemos restringir a sua conta.", "1302691457": "Ocupação", @@ -1366,7 +1366,7 @@ "1313167179": "Iniciar sessão", "1313302450": "O bot interrompe a negociação se a sua perda total exceder este valor.", "1314572331": "O seu documento não passou nos nossos controlos de verificação.", - "1315463257": "Máximos fundos disponíveis para levantamento.", + "1315463257": "Montante máximo disponível para levantamento.", "1316216284": "Pode utilizar esta palavra-passe para todas as suas contas {{platform}}.", "1319217849": "Verificar o seu telemóvel", "1320715220": "<0>Conta encerrada", @@ -1514,7 +1514,7 @@ "1445592224": "Acidentalmente, deu-nos outro endereço de e-mail o (normalmente um endereço de trabalho ou pessoal, em vez daquele que pretendia).", "1447698999": "Os levantamentos podem ser cancelados se ainda estiverem no estado \"Pedido\" (pode verificar o estado em Pagamento pendente). Quando o estado muda para \"Autorizado\", em \" Em curso\" ou \"Processado\", já não é possível efetuar o cancelamento.", "1449462402": "Em análise", - "1451838304": "Novas funcionalidades para desenvolvedores.", + "1451838304": "Novas funcionalidades para os programadores.", "1452260922": "Demasiadas tentativas falhadas", "1452941569": "Este bloco atrasa a execução durante um determinado número de segundos. É possível colocar quaisquer blocos dentro deste bloco. A execução de outros blocos na sua estratégia será interrompida até que as instruções deste bloco sejam executadas.", "1453317405": "Este bloco apresenta-lhe o saldo da sua conta sob a forma de um número ou de uma cadeia de texto.", @@ -1558,7 +1558,7 @@ "1491392301": "<0>Vendido por: {{sold_for}}", "1493673429": "Alterar e-mail", "1493866481": "Executar a Deriv X no seu navegador", - "1494535716": "Contagem de Ticks: ", + "1494535716": "Contagem de ticks: ", "1495294225": "Barreira estabelecida a um preço específico.", "1496810530": "GBP/AUD", "1497773819": "Contas Deriv MT5", @@ -1666,7 +1666,7 @@ "1622662457": "Data de", "1622944161": "Agora, vá para o bloco <0>Reiniciar condições de negociação.", "1623706874": "Utilize este bloco quando pretender utilizar Multipliers como tipo de transação.", - "1623723710": "<0>Fortaleça a sua estratégia de negociação com os \"Accumulators\"", + "1623723710": "<0>Fortaleça a sua estratégia de negociação com os Accumulators", "1628981793": "Posso negociar criptomoedas na Deriv Bot?", "1630317389": "Se selecionar \"<0>No Touch\", recebe o pagamento se o mercado nunca atingir a barreira em nenhum momento durante o período do contrato.", "1630417358": "Aceda às definições da sua conta e preencha os seus dados pessoais para permitir levantamentos.", @@ -1775,7 +1775,7 @@ "1723589564": "Representa o número máximo de contratos pendentes na sua carteira. Cada linha na sua carteira conta para uma posição aberta. Uma vez atingido o máximo, não será possível abrir novas posições sem fechar primeiro uma posição existente.", "1724367774": "Assim que a validação da sua conta estiver concluída, poderá proceder à transferência de fundos.", "1724696797": "Está limitado a uma única conta fiduciária.", - "1725141550": "Contando o número de ticks antes de vender a posição.", + "1725141550": "A contar o número de ticks antes de vender a posição.", "1725873563": "Negociação desativada", "1725958461": "Número da conta", "1726472773": "Função sem valor de retorno", @@ -1813,7 +1813,7 @@ "1747674345": "Utilize `.` como separador decimal para números fraccionários.", "1747682136": "O contrato foi anulado.", "1748754976": "Executar", - "1750980485": "Confirmo que as informações fiscais fornecidas são verdadeiras e completas. Também informarei {{legal_entity_name}} sobre quaisquer alterações a essas informações.", + "1750980485": "Confirmo que as informações fiscais fornecidas são verdadeiras e completas. Irei também comunicar à entidade {{legal_entity_name}} qualquer alteração a essas informações.", "1753082252": "Este artigo explora a estratégia integrada na Deriv Bot, um bot de negociação versátil desenvolvido para negociar ativos como Forex, Matérias-primas e Índices Derivados. Vamos analisar os principais parâmetros da estratégia, com aplicar e fornecer dicas essenciais para os traders que pretendem utilizar o bot de forma eficiente.", "1753183432": "Levamos todas as queixas a sério e procuramos resolvê-las da forma mais rápida e justa possível. Se não estiver satisfeito com algum aspeto do nosso serviço, informe-nos apresentando uma queixa utilizando as orientações abaixo:", "1753226544": "remover", @@ -1866,7 +1866,7 @@ "1794815502": "Descarregue o seu histórico de transações.", "1796270910": "{{days}} dias atrás", "1796787905": "Carregue o(s) seguinte(s) documento(s).", - "1797139903": "Descarregue a sua estratégia em formato XML e importe-a para a Deriv Bot.", + "1797139903": "Transfira a sua estratégia em formato XML e importe-a para a Deriv Bot.", "1798943788": "Só é possível efetuar depósitos.", "1801093206": "Obter lista de velas", "1801270786": "Pronto para automatizar a sua estratégia de negociação sem escrever qualquer código? Está no sítio certo.", @@ -2038,7 +2038,7 @@ "1958788790": "Este é o montante que irá receber no termo do contrato por cada ponto de variação do preço subjacente, isto se o preço à vista nunca atingir ou ultrapassar a barreira durante a duração do contrato.", "1958807602": "4. 'Table' pega numa matriz de dados, como uma lista de velas, e apresenta-a num formato de tabela.", "1959678342": "Highs e Lows", - "1960005187": "Siga estes passos para transferir as suas estratégias sem problemas", + "1960005187": "Siga os seguintes passos para transferir as suas estratégias sem dificuldades", "1960240336": "primeira letra", "1964165648": "Conexão perdida", "1965358881": "Passo 2 de 3: Confirme o seu número de telefone", @@ -2208,7 +2208,7 @@ "2114766645": "Alguns tipos de negociação não estão disponíveis para {{symbol}}.", "2115223095": "Perda", "2117165122": "1. Crie um bot do Telegram e obtenha o seu token da API do Telegram. Leia mais sobre como criar bots no Telegram aqui: https://core.telegram.org/bots#6-botfather", - "2117454014": "Na sua Wallet de criptomoedas, selecione a rede <0>{{network_name}} network ao transferir para a Deriv. Transferências incorretas podem resultar na perda de fundos.", + "2117454014": "Na sua carteira de criptomoedas, selecione a rede <0>{{network_name}} ao transferir para a Deriv. Transferências incorretas podem resultar na perda de fundos.", "2117489390": "Atualização automática em {{ remaining }} segundos", "2118292085": "<0>Nota: Irá receber um e-mail quando o seu depósito começar a ser processado.", "2119449126": "O exemplo de saída do exemplo abaixo será:", @@ -2216,7 +2216,7 @@ "2121227568": "NEO/USD", "2122152120": "Ativos", "2127564856": "As retiradas estão bloqueadas", - "2128250969": "Utilize o mesmo endereço que aparece no seu comprovativo de morada (fatura de serviços públicos, extrato bancário, etc.).", + "2128250969": "Utilize a mesma morada que aparece no seu comprovativo de morada (fatura de serviços públicos, extrato bancário, etc.).", "2129807378": "Atualizar perfil", "2133075559": "Isto significa que após 10 rondas de perdas consecutivas, este trader vai perder 100 USD. Esta perda atinge o limite de perdas de 100 USD, o que faz com que o bot pare.", "2133451414": "Duração", @@ -2376,7 +2376,7 @@ "-1024240099": "Morada", "-1534917661": "Selecione a moeda pretendida", "-1635962020": "Preencha os seus dados de emprego e informações fiscais", - "-1413855395": "Informações de emprego e fiscais", + "-1413855395": "Dados de emprego e fiscais", "-1027595143": "Menos de $25.000", "-40491332": "$25.000 - $50.000", "-1139806939": "$50.001 - $100.000", @@ -2418,8 +2418,8 @@ "-1696856986": "Deve introduzir entre 9 a 20 números.", "-1974444881": "O Número de Identificação Fiscal não pode ter mais de 25 caracteres.", "-919191810": "Por favor, preencha o domicílio fiscal.", - "-253057270": "Apenas 99 caracteres, por favor.", - "-2123345566": "Apenas 70 caracteres, por favor.", + "-253057270": "Por favor, apenas 99 caracteres.", + "-2123345566": "Por favor, apenas 70 caracteres.", "-1566700751": "Utilizar apenas os seguintes caracteres especiais:", "-807278899": "Por favor, introduza um Código Postal/CEP com menos de 20 caracteres.", "-1161338910": "O primeiro nome é obrigatório.", @@ -2499,7 +2499,7 @@ "-251603364": "O seu comprovativo de morada expirou. <0/>Por favor, envie novamente.", "-1425489838": "Não é necessária a validação do comprovativo de morada", "-1008641170": "De momento, a sua conta não necessita de validação de endereço. De futuro, caso seja necessário, iremos informá-lo da necessidade de proceder à validação do endereço.", - "-1053859245": "O seu comprovativo de morada está a ser analisado. Entraremos em contacto consigo dentro de 1 a 3 dias úteis.", + "-1053859245": "O seu comprovativo de morada está em análise. Entraremos em contacto consigo no prazo de 1 a 3 dias úteis.", "-1951115137": "Para começar a negociar, precisa também de validar a sua identidade.", "-60204971": "Não foi possível validar o seu comprovativo de morada", "-1944264183": "Para continuar a negociar, deve também apresentar um comprovativo de identidade.", @@ -2633,8 +2633,8 @@ "-231863107": "Não", "-1858215754": "O documento deve estar atualizado e ser assinado pela autoridade emissora.", "-718917527": "Os documentos inválidos ou incompletos serão rejeitados.", - "-682267922": "<0>Documento financeiro, jurídico ou governamental: Extrato bancário recente, declaração juramentada ou carta emitida pelo governo.", - "-214582149": "Fatura de serviços públicos (eletricidade, água, gás)", + "-682267922": "<0>Documento financeiro, legal ou governamental: Extrato bancário recente, affidavit ou carta emitida por uma entidade governamental.", + "-214582149": "Fatura de serviços públicos (eletricidade, água e gás)", "-506510414": "Data e hora", "-1708927037": "Endereço IP", "-189310067": "Conta encerrada", @@ -2767,7 +2767,7 @@ "-2113555886": "Só são permitidas letras, números, espaço e hífen.", "-1310832072": "Este é o endereço de e-mail associado à sua conta na Deriv. <0>{{ email }}", "-1504907646": "Palavra-passe Deriv MT5", - "-804004994": "Senha da Deriv X", + "-804004994": "Palavra-passe Deriv X", "-310459824": "Utilize a <0>palavra-passe Deriv X para iniciar sessão nas suas contas Deriv X na página Web e nas aplicações móveis.", "-1193118628": "Utilize a <0>palavra-passe Deriv para iniciar sessão na {{brand_website_name}} e na {{platform_name_trader}}.", "-1154366280": "Utilize a <0>palavra-passe Deriv para iniciar sessão em {{brand_website_name}}, {{platform_name_trader}} e {{platform_name_go}}.", @@ -2792,7 +2792,7 @@ "-403552929": "Para desativar o 2FA, introduza abaixo o código de autenticação de seis dígitos gerado pela sua aplicação 2FA:", "-890084320": "Salvar e enviar", "-1043340733": "O carregamento do comprovativo de morada falhou", - "-1242877737": "O tipo de documento é obrigatório.", + "-1242877737": "O campo do tipo de documento é obrigatório.", "-30772747": "Os seus dados pessoais foram guardados com sucesso.", "-2021135479": "Esse campo é obrigatório.", "-1002044401": "Selecione o seu documento*", @@ -2845,8 +2845,8 @@ "-1807332199": "Crie uma conta real", "-1839156429": "Confirme os seus dados para abrir a conta. Após a validação, poderá começar a negociar.", "-2063877443": "A sua conta necessita de validação.", - "-874707603": "Complete o seu perfil", - "-1450834745": "A validação é necessária", + "-874707603": "Conclua o seu perfil", + "-1450834745": "Validação requerida", "-1002556560": "Não foi possível concluir o upgrade da Wallet. Tente novamente mais tarde ou contacte-nos através do live chat.", "-90090878": "Utilize as Wallets para gerir os seus fundos em diferentes moedas sem qualquer dificuldade.", "-280236366": "Ativar agora", @@ -3145,7 +3145,7 @@ "-792737139": "Oferecemos os nossos serviços em todos os países, exceto nos mencionados nos nossos termos e condições.", "-352345777": "Quais são as estratégias mais populares para negociação automatizada?", "-552392096": "Três das estratégias mais usadas na negociação automatizada são Martingale, D'Alembert e Oscar's Grind - pode encontrá-las prontas e esperando por si na Deriv Bot.", - "-1036999457": "Assista ao seguinte vídeo para saber como criar um bot de negociação na Deriv Bot. Além disso, verifique esta publicação no blogue sobre como criar um bot de negociação.", + "-1036999457": "Assista ao seguinte vídeo para saber como criar um bot de negociação na Deriv Bot. Além disso, consulte esta publicação no blogue sobre como criar um bot de negociação.", "-1630262763": "Sobre Martingale", "-413928457": "Sobre Oscar's Grind", "-1497015866": "Sobre o Reverse D’Alembert", @@ -3334,7 +3334,7 @@ "-1646497683": "Loops", "-251326965": "Diversos", "-1136893592": "Anúncios", - "-195234787": "<0>Nota: O upload de estratégias complexas pode demorar algum tempo. Guardá-las na Deriv Bot garante um acesso mais rápido posteriormente. Se tiver dúvidas, contacte-nos via <1/>.", + "-195234787": "<0>Nota: O carregamento de estratégias complexas pode demorar algum tempo. Guardá-las na Deriv Bot garante um acesso mais rápido posteriormente. Se tiver dúvidas, contacte-nos via <1/>.", "-206059150": "Atualização do Google Blockly v10", "-523557619": "Maior segurança.", "-1317334545": "Os \"Accumulators\" chegaram à Deriv Bot", @@ -3653,7 +3653,7 @@ "-1271218821": "Conta adicionada", "-197631101": "Os seus fundos estarão disponíveis para negociação assim que a validação da sua conta estiver concluída.", "-2055364427": "Atualização dos Termos e Condições", - "-356910979": "Ao continuar, você entende e aceita as mudanças.", + "-356910979": "Ao continuar, compreende e aceita as alterações.", "-835056719": "Recebemos os seus documentos", "-55435892": "Vamos precisar de 1 a 3 dias para analisar os seus documentos e notificá-lo por e-mail. Entretanto, pode praticar com contas demo.", "-554054753": "Iniciar", @@ -3708,15 +3708,15 @@ "-700260448": "demo", "-1769158315": "real", "-1922462747": "Trader's hub", - "-1218651003": "Digite sua senha da {{platform}} para adicionar uma conta da {{platform}}{{account}}.", - "-1190393389": "Digite sua senha da {{platform}} para adicionar uma conta da {{platform}}{{account}}.", + "-1218651003": "Introduza a palavra-passe da {{platform}} para adicionar uma conta {{platform}}{{account}}.", + "-1190393389": "Introduza a palavra-passe da {{platform}} para adicionar uma conta {{platform}}{{account}}.", "-16858060": "Tem uma nova palavra-passe Deriv MT5 para iniciar sessão nas suas contas Deriv MT5 na Web e nas aplicações móveis.", "-1868608634": "Palavra-passe atual", "-2092058806": "8 a 16 caracteres", "-2051033705": "Caracteres especiais como ( _ @ ? ! / # )", "-1762249687": "Letras minúsculas", - "-2034549226": "Está a adicionar a sua conta {{product}} da {{platform}} na {{company}}.", - "-1449526710": "Crie uma conta {{platform_name}}", + "-2034549226": "Está a adicionar a sua conta {{product}} {{platform}} sob a {{company}}.", + "-1449526710": "Criar conta {{platform_name}}", "-610575301": "Adicionar conta {{platform_name}}", "-184453418": "Insira a sua senha {{platform}}", "-2057918502": "Sugestão: Pode ter introduzido a sua senha Deriv, que difere da sua senha {{platform}}.", @@ -3727,7 +3727,7 @@ "-1969916895": "A sua palavra-passe deve conter entre 8 e 16 caracteres, incluindo letras maiúsculas e minúsculas, e pelo menos um número e um carácter especial ( _ @ ? ! / # ).", "-1087845020": "principal", "-1950683866": "investidor", - "-1150741791": "Para continuar, forneça as informações necessárias na secção de Dados pessoais.", + "-1150741791": "Para continuar, forneça as informações requeridas na secção de Dados pessoais.", "-588451627": "Manutenção do servidor em curso", "-1874242353": "Reforçar fundos", "-89838213": "Pode carregar a sua conta demo com <0> adicionais se o seu saldo for <1> ou inferior.", @@ -3752,7 +3752,7 @@ "-374736923": "Nova senha de investidor", "-1793894323": "Criar ou redefinir a senha do investidor", "-918069465": "Conta indisponível", - "-643795646": "Crie uma senha para a sua conta {{platform}}:", + "-643795646": "Crie uma palavra-passe para a sua conta {{platform}} :", "-1593684005": "Esta palavra-passe funciona para todas as suas contas Deriv MT5.", "-417711545": "Criar conta", "-637537305": "Instale {{ platform }} no seu telemóvel para negociar com a conta {{ platform }} {{ account }}", @@ -3873,7 +3873,7 @@ "-2062696378": "Acima do preço atual:", "-1858102926": "Barreira estabelecida abaixo do preço à vista.", "-635746838": "Abaixo do preço atual", - "-1838512476": "Escolha uma hora de término", + "-1838512476": "Selecione uma hora de fim.", "-1977959027": "horas", "-591705950": "Termina a", "-1855256857": "h", @@ -4388,7 +4388,7 @@ "-1488537825": "Se tiver uma conta, inicie sessão para continuar.", "-2079171087": "Não foi possível enviar códigos via {{ current_carrier }} de momento. Obtenha o seu código por {{other_carriers}}.", "-1366327411": "Código expirado. Obtenha um novo.", - "-987182219": "Tente novamente. Tem 1 tentativa restante.", + "-987182219": "Tente novamente. Resta 1 tentativa.", "-227482563": "Código expirado. Obtenha um novo código.", "-1867522447": "Código inválido. Tente novamente ou obtenha um novo código.", "-886317740": "A <0>data de nascimento do seu documento de identidade não corresponde à data de nascimento que consta no seu perfil.", @@ -4414,7 +4414,7 @@ "-624316211": "O seu documento parece ser uma fotografia do ecrã de um dispositivo.", "-570380023": "Total de levantamento autorizado ({{num_of_days}} dias).", "-1139619402": "Total levantado ({{num_of_days}} dias)", - "-521471074": "Total que pode levantar ao longo da vida desta conta.", + "-521471074": "Total que pode levantar ao longo da vida útil desta conta.", "-387918462": "Total que pode levantar durante este período.", "-1466380443": "Total levantado desde a abertura da conta.", "-1730384411": "Total levantado durante este período.", diff --git a/packages/translations/src/translations/zh_cn.json b/packages/translations/src/translations/zh_cn.json index cab9caf59c6d..12faa22305f2 100644 --- a/packages/translations/src/translations/zh_cn.json +++ b/packages/translations/src/translations/zh_cn.json @@ -19,7 +19,7 @@ "15794287": "国籍是必填项。", "17843034": "查看身份证明文件验证状态", "19424289": "用户名", - "19552684": "美元 Basket", + "19552684": "USD Basket", "21035405": "请告诉我们您为什么要离开。(最多选择{{ allowed_reasons }} 个原因。)", "23745193": "前往演示账户", "24900606": "黄金 Basket", @@ -63,7 +63,7 @@ "67923436": "不,当网络浏览器关闭时 Deriv Bot将停止运行。", "68885999": "遇到错误时重复前次交易。", "69005593": "以下例子中的1分钟烛线价位开始后30秒或更久,交易重新开始。", - "71016232": "嫩模币/美元", + "71016232": "OMG/USD", "71180364": "继续验证", "71232823": "基金管理", "71445658": "开盘", @@ -105,7 +105,7 @@ "111718006": "结束日期", "111931529": "7天内最大总投注金额", "113091401": "可接受范围:{{min_stake}} 到 {{max_stake}} {{currency}}", - "113378532": "以太币/美元", + "113378532": "ETH/USD", "115032488": "买入价和损益", "116005488": "指标", "117056711": "正在更新网站", @@ -221,7 +221,7 @@ "221261209": "Deriv 账户允许为差价合约账户注资(和提款)。", "223120514": "此例子中,简单移动平均线(SMA)的每一点是前50天收盘价的算术平均数。", "223607908": "{{underlying_name}} 最新1000 跳点的最后统计数字", - "224650827": "IOT/美元", + "224650827": "IOT/USD", "225887649": "此程序块是强制性的。当您创建新策略时它已默认加入策略中。您不能在画布中加入超过一个程序块副本。", "227591929": "至时间戳 {{ input_datetime }} {{ dummy }}", "227903202": "Deriv 法定货币和 {{platform_name_mt5}} 账户之间的不同货币转账,我们将收取 1% 转账费。", @@ -335,7 +335,7 @@ "337023006": "开始时间不可为过去式。", "339449279": "剩余时间", "339610914": "Spread Up/Spread Down", - "339879944": "英镑/美元", + "339879944": "GBP/USD", "340807218": "找不到说明。", "342181776": "取消交易", "343194622": "到期时将在大于障碍的每一个变动点收到的金额。", @@ -643,7 +643,7 @@ "642393128": "输入金额", "642546661": "从电脑上传执照的背面", "644150241": "上次清除统计记录至今的获利合约数。", - "645902266": "欧元/纽元", + "645902266": "EUR/NZD", "646773081": "利润阈值: 如果总利润超过此值, Bot将停止交易。", "647039329": "需要地址证明", "647745382": "输入列表 {{ input_list }}", @@ -667,11 +667,11 @@ "662953503": "达到<0>强制平仓水平时,合约将被关闭。", "664779910": "3. 如果第一笔交易获利,下一笔交易的投注额不会减少,仍为初始投注额。该策略以 1 美元的初始投注额进行最小交易。参见 A1。", "665089217": "请提交<0>身份证明以验证账户并访问收银台。", - "665777772": "恒星币/美元", + "665777772": "XLM/USD", "665872465": "下例中,先选定开盘价,然后分配予称为\"op\"的变量。", "666158951": "达到<0>强制平仓水平时,合约将被关闭。", "666724936": "请输入有效的身份证号码。", - "672008428": "大零币/美元", + "672008428": "ZEC/USD", "673915530": "管辖和法律规定", "674973192": "用此密码登录桌面、网络和手机应用上的 Deriv MT5 账户。", "676159329": "无法转换至默认账户。", @@ -741,7 +741,7 @@ "729251105": "范围: {{min}} - {{max}} {{duration_unit_text}} ", "729651741": "选择照片", "730473724": "此程序块对给定数字执行\"与\" 或 \"或\"逻辑操作。", - "731382582": "币安币/美元", + "731382582": "BNB/USD", "732828463": "向在美国开立的账户转账的长期指示,或定期从美国地址收到的指示", "734298230": "只是提醒", "734390964": "余额不足", @@ -778,7 +778,7 @@ "771570279": "按时间筛选", "772520934": "可以在到期前 24 小时内卖出该合约。如果这样做,我们将支付<0>合约价值。", "773091074": "投注资金:", - "773309981": "原油/美元", + "773309981": "Oil/USD", "773336410": "Tether是启用了区块链的平台,旨在促进以数字方式使用法定货币。", "775679302": "{{pending_withdrawals}} 待取款", "775706054": "交易 Bot有卖吗?", @@ -831,7 +831,7 @@ "824797920": "列表为空?", "825042307": "让我们再试一次", "825179913": "此文件编号已为另一个账户提交。看来您已有账户,不需要进一步验证。如果需要帮助,请通过<0>实时聊天联系我们。", - "826511719": "美元/瑞典克朗", + "826511719": "USD/SEK", "827688195": "禁用程序块", "828219890": "然后", "828602451": "以字符串格式返回跳动点值的列表", @@ -1008,7 +1008,7 @@ "988361781": "您还没有交易活动。", "988934465": "出现提示时,须启用相机访问权限以继续操作", "989840364": "未到法定年龄。", - "991654042": "通过更改您的初始投注和/或止盈。", + "991654042": "通过更改初始投注和/或止盈。", "992294492": "邮政编码无效", "992677950": "在其他设备注销", "995563717": "不是{{ boolean }}", @@ -1053,7 +1053,7 @@ "1031602624": "已发送安全链接至%{number}", "1031731167": "英镑", "1032173180": "Deriv", - "1032907147": "澳元/纽元", + "1032907147": "AUD/NZD", "1033253221": "确认身份以便提款.", "1035893169": "删除", "1036116144": "不实际拥有资产的情况下推测资产的价格走势。", @@ -1246,7 +1246,7 @@ "1204202371": "无未平仓头寸", "1204223111": "此例中,烛线列表中的开盘价被分配予称为\"candle_list\"的变量。", "1204459171": "仍然可以继续访问现有的 <0>{{platform}} {{type_1}} <1/>和<0>{{type_2}}{{from_account}}账户。", - "1205194941": "更新您的初始投注。", + "1205194941": "更新初始投注。", "1206227936": "如何掩盖卡片?", "1206821331": "武装部队", "1208729868": "跳动点", @@ -1309,7 +1309,7 @@ "1258097139": "我们可以做些什么改善措施?", "1258198117": "正", "1259145708": "请重试。选择另一份文件并输入相应的详细信息。", - "1259598687": "英镑/日元", + "1259598687": "GBP/JPY", "1260321794": "有效", "1262255038": "Step 300 指数", "1264096613": "搜索给定的字符串", @@ -1317,7 +1317,7 @@ "1266728508": "收入证明已通过验证", "1269296089": "让我们建造 Bot吧!", "1270581106": "如果选择“No Touch”期权,假设市场在合约期限内一直没有触及障碍水平,将获得赔付。", - "1272012156": "英镑/瑞士法郎", + "1272012156": "GBP/CHF", "1272337240": "日", "1272681097": "小时", "1274380814": "赔付额等于<0>每点赔付额乘以最终价格与行权价格之间的差额(<1>以点为单位)。只有当赔付高于初始投注时,才会赚取利润。", @@ -1560,7 +1560,7 @@ "1493866481": "在浏览器运行 Deriv X", "1494535716": "跳动点数: ", "1495294225": "障碍设置于特定价格。", - "1496810530": "英镑/澳元", + "1496810530": "GBP/AUD", "1497773819": "Deriv MT5 账户", "1499080621": "尝试执行无效的操作。", "1499733992": "已验证为您的电话号码。", @@ -1574,7 +1574,7 @@ "1509559328": "cTrader", "1509570124": "{{buy_value}} (买入)", "1509678193": "教育", - "1510075920": "黄金/美元", + "1510075920": "Gold/USD", "1510357015": "税务居住地为必填项.", "1510735345": "此程序块提供最近1000个跳动点的最后数字的列表。", "1512469749": "以上示例假定在其他程序块中的某处处理了Candle_open_price变量。", @@ -1604,7 +1604,7 @@ "1544642951": "如果您选择“Only Ups”期权,只要入市现价后的价格持续上涨,您将获得赔付。如果期间内的价格有任何下跌或相等于之前的价格, 您将不会获得赔付。", "1547148381": "文件太大了(最多只允许 8MB)。请上传另一文件。", "1548185597": "Step 200 指数", - "1551172020": "澳元 Basket", + "1551172020": "AUD Basket", "1551689907": "升级 <0/> <1>{{platform}} {{type}} {{from_account}} 账户,增强交易体验。", "1553026987": "如果现货价格在合约期内从未突破<0>障碍,则将在<0>到期时获得<0>赔付。否则,合约将提前终止。", "1556391770": "由于文件仍在审核中,不能提款。一旦审核通过,将在 3 天内通过电子邮件通知。", @@ -1670,7 +1670,7 @@ "1628981793": "Deriv Bot可以交易加密货币吗?", "1630317389": "如果选择“<0>No Touch”,假设市场在合约期限内一直没有触及障碍水平,将获得赔付。", "1630417358": "请前往账户设置并填写个人详细信息,以启用取款。", - "1631281562": "英镑 Basket", + "1631281562": "GBP Basket", "1633661992": "跳动点 {{current_tick}}/{{tick_count}}", "1634016345": "2. 如果交易获利,该策略会自动将下一笔交易的投注额调整为初始投注额的 3 个单位。在本例中,投注额调整为 3 个单位,初始投注额为 1 美元,因此下一笔交易将以 3 美元开始。", "1634594289": "选择语言", @@ -1907,7 +1907,7 @@ "1839021527": "请输入有效的账号。示例:CR123456789", "1840721160": "Deriv MT5 最新密码要求", "1840865068": "设置{{ variable }} 为简单移动平均线数组{{ dummy }}", - "1841788070": "钯金/美元", + "1841788070": "Palladium/USD", "1841996888": "每日亏损限额", "1842266423": "返回", "1843336754": "选择文件", @@ -1991,7 +1991,7 @@ "1908023954": "对不起,处理请求时发生错误。", "1908239019": "确保所有文档都在照片中", "1908686066": "合适性测试警告", - "1909647105": "波场币/美元", + "1909647105": "TRX/USD", "1909769048": "中值", "1910533633": "注册真实账户存款并开始交易。", "1910990442": "使用 <0>Deriv 密码登录 {{brand_website_name}}、{{platform_name_go}}、{{platform_name_trader}}、{{platform_name_smarttrader}}、{{platform_name_dbot}} 和 {{platform_name_ctrader}}。", @@ -2015,7 +2015,7 @@ "1924365090": "以后再说", "1924765698": "出生地*", "1927316982": "检查头寸 (6/6)", - "1928930389": "英镑/挪威克罗钠", + "1928930389": "GBP/NOK", "1929694162": "账户比较", "1930899934": "Tether", "1931659123": "每一跳动点皆运行", @@ -2030,7 +2030,7 @@ "1944204227": "此程序块返回当前账户余额。", "1947527527": "1. 此链接是您发送的", "1947826019": "已达 OTP 限额", - "1948092185": "英镑/加拿大元", + "1948092185": "GBP/CAD", "1949719666": "以下是可能的原因:", "1950413928": "提交身份证明文件", "1955219734": "城镇/城市*", @@ -2071,7 +2071,7 @@ "1985366224": "每天,您最多可以在 Deriv 账户之间进行 {{ allowed_internal }} 次转账,以及 Deriv 和 {{platform_name_mt5}} 账户之间最多 {{ allowed_mt5 }} 次转账.", "1985637974": "放置在此程序块内的任何程序块都将在每个跳动点处执行。如果在“交易参数”根程序块中将默认烛线间隔设置为1分钟,则此程序块中的指令将每分钟执行一次。将此程序块放置在任何根程序块之外。", "1986322868": "当亏损达到或超过此金额时,交易将自动平仓。", - "1986498784": "比特币/莱特币", + "1986498784": "BTC/LTC", "1987080350": "演示", "1987447369": "收银台已锁定", "1988153223": "电子邮件地址", @@ -2115,7 +2115,7 @@ "2027441253": "我们为什么要收集这个?", "2027625329": "简单移动平均线数组 (SMAA)", "2027638150": "升级", - "2028163119": "EOS/美元", + "2028163119": "EOS/USD", "2029237955": "纳闽", "2030018735": "RSI是可帮助您确定市场趋势的技术分析工具。它将为您提供0到100之间的数值。RSI值大于等于70表示资产已超买,当前趋势可能会反转,而RSI值小于等于30则意味着资产超卖。", "2030045667": "消息", @@ -2125,7 +2125,7 @@ "2035258293": "开始通过我们交易", "2035925727": "排序 {{ sort_type }} {{ sort_direction }} {{ input_list }}", "2036578466": "必须是{{value}}", - "2037050619": "止盈: ", + "2037050619": "止盈: ", "2037906477": "从# 项获取子列表", "2039198937": "最大投注额: 您愿意为单笔交易支付的最大金额。如果超过此值,下一笔交易的投注额将重置为初始投注额。这是可选的风险管理参数。", "2042050260": "-买入价格:合约的买入价格(投注额)", @@ -2213,7 +2213,7 @@ "2118292085": "<0>注意:存款开始处理时,您将收到一封电子邮件。", "2119449126": "以下例子的输出示例将是:", "2119710534": "常见问题", - "2121227568": "小蚁币/美元", + "2121227568": "NEO/USD", "2122152120": "资产", "2127564856": "提款已被锁定", "2128250969": "使用与地址证明 (如水电煤费单、银行对账单等) 上相同的地址。", @@ -3103,9 +3103,9 @@ "-138833194": " Bot将使用此策略交易的标的市场。", "-410856998": "如利润总额超出此金额, Bot将停止交易。", "-2131851017": "增长率", - "-1073566768": "只要当前入市现价保持在前一个现货价的范围内,您的投注将以每一跳动价的指定增长率增长。", + "-1073566768": "只要当前入市现价保持在前一个现货价的范围内,投注将以每一跳动价的指定增长率增长。", "-447853970": "亏损阈值", - "-1850439039": "亏损交易后用于乘以下一笔交易的投注的大小。", + "-1850439039": "亏损交易后用于乘以下一笔交易的投注的单位。", "-33106112": "成功交易后用于乘以下一笔交易的投注的大小。", "-1503301801": "该值必须等于或大于 {{ min }}", "-1596504046": "交易成功后要添加到下一笔交易的单位数。一个单位等于初始投注额。", @@ -3237,7 +3237,7 @@ "-1190046167": "此程序块显示带有自定义消息的对话框。显示对话框时,策略将暂停,并且仅在单击“确定”后才会恢复。", "-859028989": "此示例中,日期和时间将显示在绿色的通知框中。", "-1452086215": "此示例中,2019年8月1日午夜将买入 Rise 合约。", - "-2078588404": "选择所需的市场和资产类型。例如,外汇>主要货币对> 澳元/日元", + "-2078588404": "选择所需的市场和资产类型。例如,外汇>主要货币对> AUD/JPY", "-2037446013": "2. 交易类型", "-533927844": "选择所需的交易类型。例如,Up/Down> Rise/Fall", "-1192411640": "4. 默认烛线间隔", @@ -4329,26 +4329,26 @@ "-1818650227": "交易取消费用", "-706219815": "指示性价格", "-112601585": "已执行", - "-1669418686": "澳元/加元", - "-1548588249": "澳元/瑞士法郎", - "-1552890620": "澳元/日元", - "-681231560": "澳元/波兰兹罗提", - "-64938413": "澳元/美元", - "-1430522808": "欧元/澳元", - "-2020477069": "欧元/加元", - "-1201853162": "欧元/瑞士法郎", - "-1318070255": "欧元/英镑", - "-1197505739": "欧元/日元", - "-405907358": "欧元/美元", - "-1536293064": "纽元/日元", - "-79700881": "纽元/美元", - "-642323838": "美元/加元", - "-428199705": "美元/瑞士法郎", - "-424108348": "美元/日元", - "-548255282": "美元/挪威克朗", - "-1834131208": "美元/波兰兹罗提", - "-524302516": "白银/美元", - "-764731776": "白金/美元", + "-1669418686": "AUD/CAD", + "-1548588249": "AUD/CHF", + "-1552890620": "AUD/JPY", + "-681231560": "AUD/PLN", + "-64938413": "AUD/USD", + "-1430522808": "EUR/AUD", + "-2020477069": "EUR/CAD", + "-1201853162": "EUR/CHF", + "-1318070255": "EUR/GBP", + "-1197505739": "EUR/JPY", + "-405907358": "EUR/USD", + "-1536293064": "NZD/JPY", + "-79700881": "NZD/USD", + "-642323838": "USD/CAD", + "-428199705": "USD/CHF", + "-424108348": "USD/JPY", + "-548255282": "USD/NOK", + "-1834131208": "USD/PLN", + "-524302516": "Silver/USD", + "-764731776": "Platinum/USD", "-853582174": "法国 40", "-1096386695": "英国 100", "-617646862": "德国 40", @@ -4356,7 +4356,7 @@ "-512194910": "美国技术 100", "-381746202": "美国 500", "-1935463381": "瑞士 20", - "-1941767726": "欧盟 50", + "-1941767726": "Euro 50", "-1925264914": "Volatility 25 指数", "-708579504": "Volatility 50 指数", "-975255670": "Volatility 75 指数", @@ -4364,7 +4364,7 @@ "-342128411": "Crash 500 指数", "-9704319": "Crash 1000 指数", "-465860988": "Bull Market 指数", - "-280323742": "欧元 Basket", + "-280323742": "EUR Basket", "-563812039": "Volatility 10 (1s) 指数", "-82971929": "Volatility 25 (1s) 指数", "-433962508": "Volatility 75 (1s) 指数", @@ -4373,13 +4373,13 @@ "-1374309449": "Volatility 200 (1s) 指数", "-1288044380": "Volatility 250 (1s) 指数", "-1164978320": "Jump 10 指数", - "-575272887": "比特币现金/美元", + "-575272887": "BCH/USD", "-295406873": "比特币/以太币", - "-1713556301": "ZMR/美元", - "-2046638412": "瑞波币/美元", - "-1263203461": "比特币/美元", - "-1112522776": "DSH/美元", - "-460689370": "莱特币/美元", + "-1713556301": "ZMR/USD", + "-2046638412": "XRP/USD", + "-1263203461": "BTC/USD", + "-1112522776": "DSH/USD", + "-460689370": "LTC/USD", "-132112961": "Sharkfin", "-175164838": "{{seconds_passed}}秒钟前", "-514136557": "{{minutes_passed}}分钟前", diff --git a/packages/translations/src/translations/zh_tw.json b/packages/translations/src/translations/zh_tw.json index af1f9724d81b..7b9970a08c96 100644 --- a/packages/translations/src/translations/zh_tw.json +++ b/packages/translations/src/translations/zh_tw.json @@ -19,10 +19,10 @@ "15794287": "國籍為必填欄位。", "17843034": "查看身份證明文件驗證狀態", "19424289": "使用者名稱", - "19552684": "美元 Basket", + "19552684": "USD Basket", "21035405": "請告訴我們您為什麼要離開。(最多選擇{{ allowed_reasons }} 個原因。)", "23745193": "前往示範帳戶", - "24900606": "黃金 Basket", + "24900606": "Gold Basket", "25854018": "此區塊在開發人員主控台中顯示消息,輸入內容可以是文字串、數字、布爾值或資料陣列。", "26566655": "摘要", "26596220": "金融", @@ -63,7 +63,7 @@ "67923436": "不,當網頁瀏覽器關閉時,Deriv Bot將停止運行。", "68885999": "遇到錯誤時重覆前次交易。", "69005593": "以下例子中的1分鐘燭線價位開始後30秒或更久,交易重新開始。", - "71016232": "嫩模幣/美元", + "71016232": "OMG/USD", "71180364": "繼續驗證", "71232823": "基金管理", "71445658": "開盤", @@ -105,7 +105,7 @@ "111718006": "結束日期", "111931529": "7天內最大總投注金額", "113091401": "可接受的範圍: {{min_stake}} 至 {{max_stake}} {{currency}}", - "113378532": "以太幣/美元", + "113378532": "ETH/USD", "115032488": "買入價和損益", "116005488": "指標", "117056711": "正在更新網站", @@ -221,7 +221,7 @@ "221261209": "Deriv 帳戶允許為差價合約帳戶注資(和提款)。", "223120514": "此例子中,簡單移動平均線(SMA)的每一點是前50天收盤價的算術平均數。", "223607908": "{{underlying_name}} 最新1000跳點之最後統計數字", - "224650827": "IOT/美元", + "224650827": "IOT/USD", "225887649": "此區塊是強制性的。建立新策略時它已預設加入策略中。不能在畫布中加入超過一個區塊複製。", "227591929": "到時間戳記 {{ input_datetime }} {{ dummy }}", "227903202": "Deriv 法定貨幣和{{platform_name_mt5}} 帳戶之間的不同貨幣轉帳,我們將收取 1% 轉帳費。", @@ -335,7 +335,7 @@ "337023006": "開始時間不可為過去式。", "339449279": "剩餘時間", "339610914": "Spread Up/Spread Down", - "339879944": "英鎊/美元", + "339879944": "GBP/USD", "340807218": "找不到說明。", "342181776": "取消交易", "343194622": "到期時將在大於障礙的每一個變動點收到的金額。", @@ -643,7 +643,7 @@ "642393128": "輸入金額", "642546661": "從電腦上傳執照的背面", "644150241": "上次清除統計記錄至今的獲利合約數。", - "645902266": "歐元/紐元", + "645902266": "EUR/NZD", "646773081": "利潤限額: 如果總利潤超過此金額, Bot將停止交易。", "647039329": "需要地址證明", "647745382": "輸入清單 {{ input_list }}", @@ -667,11 +667,11 @@ "662953503": "達到<0>強制平倉水平時,合約將會關閉。", "664779910": "3. 如果第一筆交易獲利,則下一筆交易的投注額將不減少,而保持在初始投注額。該策略最低交易的初始投注額為 1 美元。請參閱 A1。", "665089217": "請提交 <0>身份證明以驗證帳戶並存取收銀台。", - "665777772": "恆星幣/美元", + "665777772": "XLM/USD", "665872465": "下例中,先選定開盤價,然後分配予稱為「op」的變數。", "666158951": "達到<0>強制平倉水平時,合約將會關閉。", "666724936": "請輸入有效的身份證件號碼。", - "672008428": "大零幣/美元", + "672008428": "ZEC/USD", "673915530": "管轄和法律規定", "674973192": "使用此密碼登入桌面、網絡和手機應用上的 Deriv MT5 帳戶.", "676159329": "無法轉換至預設帳戶。", @@ -741,7 +741,7 @@ "729251105": "範圍: {{min}} - {{max}} {{duration_unit_text}} ", "729651741": "選擇照片", "730473724": "此區塊對指定數字執行「與」或「或」邏輯操作。", - "731382582": "幣安幣/美元", + "731382582": "BNB/USD", "732828463": "將資金轉移到美國開立的帳戶的常規指示,或經常從美國地址收到的指示", "734298230": "只是提醒", "734390964": "餘額不足", @@ -778,7 +778,7 @@ "771570279": "按時間篩選", "772520934": "可以在到期前 24 小時內賣出該合約。 如果這樣做,我們將支付<0>合約價值。", "773091074": "投注資金:", - "773309981": "原油/美元", + "773309981": "Oil/USD", "773336410": "Tether是啟用了區塊鏈的平台,旨在促進以數字方式使用法定貨幣。", "775679302": "{{pending_withdrawals}} 待取款", "775706054": "交易 Bot是否有出售?", @@ -831,7 +831,7 @@ "824797920": "清單為空?", "825042307": "讓我們再試一次", "825179913": "此文件號碼已為其他帳戶提交。似乎您已擁有帳戶,不需要進一步驗證。如果需要幫助,請透過<0>即時聊天與我們聯繫。", - "826511719": "美元/瑞典克朗", + "826511719": "USD/SEK", "827688195": "禁用區塊", "828219890": "然後", "828602451": "以字串格式返回跳動點數值清單", @@ -1008,7 +1008,7 @@ "988361781": "還沒有交易活動。", "988934465": "出現提示時,須啟用相機存取權限以繼續操作", "989840364": "未滿法定年齡。", - "991654042": "透過更改您的初始投注額和/或止盈。", + "991654042": "透過更改初始投注額和/或止盈。", "992294492": "郵遞區號無效", "992677950": "登出其他裝置", "995563717": "不是 {{ boolean }}", @@ -1053,7 +1053,7 @@ "1031602624": "已傳送安全連結至%{number}", "1031731167": "英鎊", "1032173180": "Deriv", - "1032907147": "澳元/紐元", + "1032907147": "AUD/NZD", "1033253221": "確認身份以進行提款.", "1035893169": "刪除", "1036116144": "沒有實際擁有資產的情況下推測資產的價格變動。", @@ -1246,7 +1246,7 @@ "1204202371": "無未平倉頭寸", "1204223111": "此例中,燭線清單中的開盤價被分配予稱為\"candle_list\"的變數。", "1204459171": "仍然可以繼續存取現有的 <0>{{platform}}{{type_1}}<1/> 和 <0>{{type_2}}{{from_account}} 帳戶。", - "1205194941": "更新您的初始投注額。", + "1205194941": "更新初始投注額。", "1206227936": "如何掩蓋卡片?", "1206821331": "武裝部隊", "1208729868": "Ticks", @@ -1309,7 +1309,7 @@ "1258097139": "我們可以做些什麼改善措施?", "1258198117": "正值", "1259145708": "請重試。 選擇另一份文件並輸入相應的詳細資訊。", - "1259598687": "英鎊/日圓\n", + "1259598687": "GBP/JPY", "1260321794": "有效", "1262255038": "Step 300 指數", "1264096613": "搜尋指定的字串", @@ -1317,14 +1317,14 @@ "1266728508": "收入證明驗證透過", "1269296089": "讓我們建立 Bot!", "1270581106": "如果選擇「No Touch」期權,假設市場在合約期限內一直沒有觸及障礙水平,將獲得賠付。", - "1272012156": "英鎊/瑞士法郎", + "1272012156": "GBP/CHF", "1272337240": "日", "1272681097": "小時", "1274380814": "賠付額等於<0>每點賠付額乘以最終價格與行權價之間的差額(<1>以點為單位)。只有當賠付高於初始投注時,才會賺取利潤。", "1274819385": "3. 投訴與糾紛", "1276660852": "提交身份證明", "1276973471": "網站上提供的產品是複雜的衍生產品,可能虧損的風險很高。差價合約是複雜的工具,並且由於槓桿作用,具有快速虧損的高風險。 70.84% 的零售投資者帳戶在與該供應商交易差價合約時損失。您必須考慮自己是否了解這些產品的運作方式,以及是否有能力承擔損失資金的高風險。", - "1279003709": "當盈虧金額超過止盈金額後,持倉將被平倉。", + "1279003709": "當盈虧金額超過止盈金額後,持倉頭寸將被平倉。", "1279197529": "稅務識別號碼為必填欄位。", "1279937041": "<0>注意:某些複雜策略可能會在 Bot Builder 遇到問題。如果有任何問題,請透過<1/>聯繫我們。", "1281045211": "在提供清單中將項目按其數字或字母值以升序或降序排序。", @@ -1558,9 +1558,9 @@ "1491392301": "<0>賣價: {{sold_for}}", "1493673429": "更改電子郵件地址", "1493866481": "在瀏覽器運行 Deriv X", - "1494535716": "跳動次數: ", + "1494535716": "跳動次數: ", "1495294225": "障礙設定在特定價格。", - "1496810530": "英鎊/澳元", + "1496810530": "GBP/AUD", "1497773819": "Deriv MT5 帳戶", "1499080621": "嘗試執行無效的操作。", "1499733992": "已驗證為您的電話號碼。", @@ -1574,7 +1574,7 @@ "1509559328": "cTrader", "1509570124": "{{buy_value}} (買入)", "1509678193": "教育", - "1510075920": "黃金/美元", + "1510075920": "Gold/USD", "1510357015": "稅務居住地為必填欄位。", "1510735345": "此區塊提供最近1000個跳動點的最後數字的清單。", "1512469749": "以上例子假定在其他區塊中的某處處理了Candle_open_price變數。", @@ -1604,7 +1604,7 @@ "1544642951": "如果選擇「Only Ups」期權,只要入市現價後的價格持續上漲,將獲得賠付。如果期間內的價格有任何下跌或相等於之前的價格, 將不會獲得賠付。", "1547148381": "該文件太大(最多只允許 8MB)。請上傳另一文件。", "1548185597": "Step 200 指數", - "1551172020": "澳元 Basket", + "1551172020": "AUD Basket", "1551689907": "升級 <0/> <1>{{platform}} {{type}} {{from_account}} 帳戶,增強交易體驗。", "1553026987": "如果現貨價格在合約期間從未突破<0>障礙,則將在<0>到期時獲得<0>賠付。 否則,合約將提前終止。", "1556391770": "無法提款,因為文件仍在審查中。核准驗證後,將在 3 天內透過電子郵件通知您。", @@ -1670,7 +1670,7 @@ "1628981793": "Deriv Bot可以交易加密貨幣嗎?", "1630317389": "如果選擇“<0>No Touch”,假設市場在合約期限內一直沒有觸及障礙水平,將獲得賠付。", "1630417358": "請前往帳戶設定並填寫個人詳細資料,以啟用取款。", - "1631281562": "英鎊 Basket", + "1631281562": "GBP Basket", "1633661992": "跳動點 {{current_tick}}/{{tick_count}}", "1634016345": "2. 如果交易獲利,該策略會自動將下一筆交易的投注額調整為初始投注額的 3 個單位。 在本例中,投注額調整為 3 個單位,初始投注額為 1 美元,因此下一筆交易將以 3 美元開始。", "1634594289": "選擇語言", @@ -1907,7 +1907,7 @@ "1839021527": "請輸入有效的帳號。範例:CR123456789", "1840721160": "Deriv MT5 最新密碼要求", "1840865068": "設定 {{ variable }} 為簡單移動平均線陣列 {{ dummy }}", - "1841788070": "鈀金/美元", + "1841788070": "Palladium/USD", "1841996888": "每日虧損限額", "1842266423": "返回", "1843336754": "選擇文件", @@ -1991,7 +1991,7 @@ "1908023954": "對不起,處理請求時發生錯誤。", "1908239019": "確保所有文檔都在照片中", "1908686066": "合適性測試警告", - "1909647105": "波場幣/美元", + "1909647105": "TRX/USD", "1909769048": "中值", "1910533633": "取得真實帳戶存入資金並開始交易。", "1910990442": "使用 <0>Deriv 密碼登入 {{brand_website_name}}、{{platform_name_go}}、{{platform_name_trader}}、{{platform_name_smarttrader}}、{{platform_name_dbot}} 和 {{platform_name_ctrader}}。", @@ -2015,7 +2015,7 @@ "1924365090": "以後再說", "1924765698": "出生地*", "1927316982": "檢查頭寸 (6/6)", - "1928930389": "英鎊/挪威克羅鈉", + "1928930389": "GBP/NOK", "1929694162": "帳戶比較", "1930899934": "Tether", "1931659123": "每一跳動點皆運行", @@ -2030,7 +2030,7 @@ "1944204227": "此區塊返回目前帳戶餘額。", "1947527527": "1. 此連結是您傳送的", "1947826019": "已達 OTP 上限", - "1948092185": "英鎊/加拿大元", + "1948092185": "GBP/CAD", "1949719666": "以下是可能的原因:", "1950413928": "提交身份證明文件", "1955219734": "城鎮/城市*", @@ -2071,7 +2071,7 @@ "1985366224": "每天,最多可以在 Deriv 帳戶之間進行 {{ allowed_internal }} 次轉帳,以及 Deriv 和 {{platform_name_mt5}} 帳戶之間最多 {{ allowed_mt5 }} 次轉帳 .", "1985637974": "放置在此區塊內的任何區塊都將在每個跳動點處執行。如果在「交易參數」根區塊中將預設燭線間隔設定為1分鐘,則此區塊中的指令將每分鐘執行一次。將此區塊放置在任何根區塊之外。", "1986322868": "當虧損達到或超過此金額時,交易將自動平倉。", - "1986498784": "比特幣/萊特幣", + "1986498784": "BTC/LTC", "1987080350": "示範", "1987447369": "收銀台已鎖定", "1988153223": "電子郵件地址", @@ -2115,7 +2115,7 @@ "2027441253": "我們為什麼要收集這些?", "2027625329": "簡單移動平均線陣列 (SMAA)", "2027638150": "升級", - "2028163119": "EOS/美元", + "2028163119": "EOS/USD", "2029237955": "納閩", "2030018735": "RSI 是可幫助確定市場趨勢的技術分析工具。它將提供0到100之間的數值。RSI 值大於等於70表示資產已超買,當前趨勢可能會反轉,而 RSI 值小於等於30則意味著資產超賣。", "2030045667": "消息", @@ -2125,7 +2125,7 @@ "2035258293": "開始透過我們交易", "2035925727": "排序 {{ sort_type }} {{ sort_direction }} {{ input_list }}", "2036578466": "必須是 {{value}}", - "2037050619": "止盈: ", + "2037050619": "止盈: ", "2037906477": "從 # 取得子清單", "2039198937": "最大投注額: 您願意為單筆交易支付的最大金額。 如果超過此值,下一筆交易的投注額將重設為初始投注額。 這是可選的風險管理參數。", "2042050260": "- 買入價格:合約的買入價格(投注額)", @@ -2213,7 +2213,7 @@ "2118292085": "<0>注意:存款開始處理時,您將收到一封電子郵件。", "2119449126": "以下例子的輸出例將是:", "2119710534": "常見問題集", - "2121227568": "小蟻幣/美元", + "2121227568": "NEO/USD", "2122152120": "資產", "2127564856": "提款已被鎖定", "2128250969": "使用與地址證明上顯示的相同地址 (如水電煤費單、銀行對帳單等)。", @@ -2810,7 +2810,7 @@ "-1089385344": "Deriv (SVG) 有限責任公司", "-2019617323": "Deriv (BVI) 有限公司", "-112814932": "Deriv (FX) 有限公司", - "-1131400885": "Deriv 投資 (歐洲) 有限公司", + "-1131400885": "Deriv Investments (Europe) Limited", "-1471207907": "所有資產", "-781132577": "槓桿", "-1591882610": "綜合", @@ -3237,7 +3237,7 @@ "-1190046167": "此區塊顯示帶有自訂消息的對話方塊。顯示對話方塊時,策略將暫停,並且僅在點選「確定」後才會恢復。", "-859028989": "此例中,日期和時間將顯示在綠色的通知方塊中。", "-1452086215": "此例中,2019年8月1日午夜將買入 Rise 合約。", - "-2078588404": "選擇所需的市場和資產類型。例如,外匯>主要貨幣對> 澳元/日元", + "-2078588404": "選擇所需的市場和資產類型。例如,外匯>主要貨幣對> AUD/JPY", "-2037446013": "2. 交易類型", "-533927844": "選擇所需的交易類型。例如,Up/Down> Rise/Fall", "-1192411640": "4. 預設燭線間隔", @@ -4329,26 +4329,26 @@ "-1818650227": "交易取消費用", "-706219815": "指示性價格", "-112601585": "已執行", - "-1669418686": "澳元/加元", - "-1548588249": "澳元/瑞士法郎", - "-1552890620": "澳元/日圓", - "-681231560": "澳元/波蘭茲羅提", - "-64938413": "澳元/美元", - "-1430522808": "歐元/澳元", - "-2020477069": "歐元/加元", - "-1201853162": "歐元/瑞士法郎", - "-1318070255": "歐元/英鎊", - "-1197505739": "歐元/日圓", - "-405907358": "歐元/美元", - "-1536293064": "紐元/日圓", - "-79700881": "紐元/美元", - "-642323838": "美元/加元", - "-428199705": "美元/瑞士法郎", - "-424108348": "美元/日圓", - "-548255282": "美元/挪威克朗", - "-1834131208": "美元/波蘭茲羅提", - "-524302516": "白銀/美元", - "-764731776": "白金/美元", + "-1669418686": "AUD/CAD", + "-1548588249": "AUD/CHF", + "-1552890620": "AUD/JPY", + "-681231560": "AUD/PLN", + "-64938413": "AUD/USD", + "-1430522808": "EUR/AUD", + "-2020477069": "EUR/CAD", + "-1201853162": "EUR/CHF", + "-1318070255": "EUR/GBP", + "-1197505739": "EUR/JPY", + "-405907358": "EUR/USD", + "-1536293064": "NZD/JPY", + "-79700881": "NZD/USD", + "-642323838": "USD/CAD", + "-428199705": "USD/CHF", + "-424108348": "USD/JPY", + "-548255282": "USD/NOK", + "-1834131208": "USD/PLN", + "-524302516": "Silver/USD", + "-764731776": "Platinum/USD", "-853582174": "法國 40", "-1096386695": "英國 100", "-617646862": "德國 40", @@ -4356,7 +4356,7 @@ "-512194910": "美國技術 100", "-381746202": "美國 500", "-1935463381": "瑞士 20", - "-1941767726": "歐盟 50", + "-1941767726": "Euro 50", "-1925264914": "Volatility 25 指數", "-708579504": "Volatility 50 指數", "-975255670": "Volatility 75 指數", @@ -4364,7 +4364,7 @@ "-342128411": "Crash 500 指數", "-9704319": "Crash 1000 指數", "-465860988": "Bull Market 指數", - "-280323742": "歐元 Basket", + "-280323742": "EUR Basket", "-563812039": "Volatility 10 (1s) 指數", "-82971929": "Volatility 25 (1s) 指數", "-433962508": "Volatility 75 (1s) 指數", @@ -4373,13 +4373,13 @@ "-1374309449": "Volatility 200 (1s) 指數", "-1288044380": "Volatility250 (1s) 指數", "-1164978320": "Jump 10 指數", - "-575272887": "比特幣現金/美元", - "-295406873": "比特幣/以太幣", - "-1713556301": "ZMR/美元", - "-2046638412": "瑞波幣/美元", - "-1263203461": "比特幣/美元", - "-1112522776": "DSH/美元", - "-460689370": "萊特幣/美元", + "-575272887": "BCH/USD", + "-295406873": "BTC/ETH", + "-1713556301": "ZMR/USD", + "-2046638412": "XRP/USD", + "-1263203461": "BTC/USD", + "-1112522776": "DSH/USD", + "-460689370": "LTC/USD", "-132112961": "Sharkfin", "-175164838": "{{seconds_passed}} 秒鐘前", "-514136557": "{{minutes_passed}}分鐘前", diff --git a/packages/wallets/src/AppContent.scss b/packages/wallets/src/AppContent.scss index e3839bd9332f..086569fa8baf 100644 --- a/packages/wallets/src/AppContent.scss +++ b/packages/wallets/src/AppContent.scss @@ -9,7 +9,11 @@ height: calc(100vh - 8.4rem); // 100vh - (4.8rem header + 3.6rem footer) /* stylelint-disable-next-line declaration-no-important */ overflow-y: auto !important; //override overflow: initial from core app content - + &--with-banner { + @include desktop-screen { + height: 100vh; + } + } @include mobile-or-tablet-screen { height: calc(var(--wallets-vh, 1vh) * 100 - 4rem); // 100vh - 4rem (header) min-height: calc(var(--wallets-vh, 1vh) * 100 - 8.4rem); // 100vh - (4.8rem header + 3.6rem footer) diff --git a/packages/wallets/src/AppContent.tsx b/packages/wallets/src/AppContent.tsx index bae664f3b6c7..55b63493d832 100644 --- a/packages/wallets/src/AppContent.tsx +++ b/packages/wallets/src/AppContent.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useRef } from 'react'; -import { useDerivAccountsList, useSettings } from '@deriv/api-v2'; +import classNames from 'classnames'; +import { useActiveWalletAccount, useDerivAccountsList, useIsEuRegion, useSettings } from '@deriv/api-v2'; import { Analytics } from '@deriv-com/analytics'; import useAllBalanceSubscription from './hooks/useAllBalanceSubscription'; import { defineViewportHeight } from './utils/utils'; @@ -15,8 +16,10 @@ type AppContentProps = { const AppContent: React.FC = ({ isWalletsOnboardingTourGuideVisible, setPreferredLanguage }) => { const { isSubscribed, subscribeToAllBalance, unsubscribeFromAllBalance } = useAllBalanceSubscription(); const { data: derivAccountList } = useDerivAccountsList(); - const previousDerivAccountListLenghtRef = useRef(0); + const previousDerivAccountListLengthRef = useRef(0); const appRef = useRef(null); + const { data: isEuRegion } = useIsEuRegion(); + const { data: activeWallet } = useActiveWalletAccount(); const { data: { preferred_language: preferredLanguage }, } = useSettings(); @@ -31,9 +34,9 @@ const AppContent: React.FC = ({ isWalletsOnboardingTourGuideVis useEffect(() => { if (!derivAccountList?.length) return; - if (previousDerivAccountListLenghtRef.current !== derivAccountList.length || !isSubscribed) { + if (previousDerivAccountListLengthRef.current !== derivAccountList.length || !isSubscribed) { subscribeToAllBalance(); - previousDerivAccountListLenghtRef.current = derivAccountList.length; + previousDerivAccountListLengthRef.current = derivAccountList.length; } return () => { if (isSubscribed) { @@ -64,7 +67,12 @@ const AppContent: React.FC = ({ isWalletsOnboardingTourGuideVis }, [isWalletsOnboardingTourGuideVisible]); return ( -
+
diff --git a/packages/wallets/src/components/AccountsList/AccountsList.tsx b/packages/wallets/src/components/AccountsList/AccountsList.tsx index 949f2f60e66b..9432de212ad6 100644 --- a/packages/wallets/src/components/AccountsList/AccountsList.tsx +++ b/packages/wallets/src/components/AccountsList/AccountsList.tsx @@ -1,8 +1,10 @@ import React, { FC, useCallback } from 'react'; +import { useIsEuRegion } from '@deriv/api-v2'; import { useTranslations } from '@deriv-com/translations'; import { Divider, Tab, Tabs, useDevice } from '@deriv-com/ui'; import { CFDPlatformsList } from '../../features'; import { OptionsAndMultipliersListing } from '../OptionsAndMultipliersListing'; +import { WalletsTabsLoader } from '../SkeletonLoader'; import './AccountsList.scss'; type TProps = { @@ -13,7 +15,11 @@ type TProps = { const AccountsList: FC = ({ accountsActiveTabIndex, onTabClickHandler }) => { const { isDesktop } = useDevice(); const { localize } = useTranslations(); - const tabs = [localize('CFDs'), localize('Options')]; + const { data: isEuRegion, isLoading: isEuRegionLoading } = useIsEuRegion(); + + const optionsAndMultipliersTabTitle = isEuRegion ? localize('Multipliers') : localize('Options'); + + const tabs = [localize('CFDs'), optionsAndMultipliersTabTitle]; const onChangeTabHandler = useCallback((activeTab: number) => onTabClickHandler?.(activeTab), [onTabClickHandler]); @@ -29,6 +35,14 @@ const AccountsList: FC = ({ accountsActiveTabIndex, onTabClickHandler })
); + if (isEuRegionLoading && !isDesktop) { + return ( +
+ +
+ ); + } + return ( = ({ accountsActiveTabIndex, onTabClickHandler }) - + diff --git a/packages/wallets/src/components/AccountsList/__tests__/AccountsList.spec.tsx b/packages/wallets/src/components/AccountsList/__tests__/AccountsList.spec.tsx index 20bd8532b12f..f60651097cd4 100644 --- a/packages/wallets/src/components/AccountsList/__tests__/AccountsList.spec.tsx +++ b/packages/wallets/src/components/AccountsList/__tests__/AccountsList.spec.tsx @@ -1,6 +1,6 @@ import React, { ComponentProps, PropsWithChildren } from 'react'; import { WalletTourGuide } from 'src/components/WalletTourGuide'; -import { APIProvider } from '@deriv/api-v2'; +import { APIProvider, useIsEuRegion } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; import { render, screen } from '@testing-library/react'; import WalletsAuthProvider from '../../../AuthProvider'; @@ -26,6 +26,11 @@ jest.mock( } ); +jest.mock('@deriv/api-v2', () => ({ + ...jest.requireActual('@deriv/api-v2'), + useIsEuRegion: jest.fn(), +})); + const wrapper = ({ children }: PropsWithChildren) => ( @@ -37,13 +42,17 @@ const wrapper = ({ children }: PropsWithChildren) => ( describe('AccountsList', () => { beforeEach(() => { (useDevice as jest.Mock).mockReturnValue({ isDesktop: true }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + isLoading: false, + }); }); afterAll(() => { jest.clearAllMocks(); }); - it('should render account list in mobile view', () => { + it('renders account list in mobile view', () => { (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); render(, { wrapper, @@ -54,7 +63,7 @@ describe('AccountsList', () => { expect(screen.getByText('Compare accounts')).toBeInTheDocument(); }); - it('should show Options tab in mobile view when the tab active', () => { + it('shows Options tab in mobile view when the tab active', () => { (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); const { rerender } = render(, { @@ -72,7 +81,42 @@ describe('AccountsList', () => { expect(screen.getByText('Deriv GO')).toBeInTheDocument(); }); - it('should trigger `onTabClickHandler` with proper tab index when the user switches the tab', () => { + it('shows Multipliers tab when is_eu is true', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: true, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByText('Multipliers')).toBeInTheDocument(); + expect(screen.queryByText('Options')).not.toBeInTheDocument(); + expect( + screen.getByText('Trade bigger positions with less capital on a wide range of global markets.') + ).toBeInTheDocument(); + }); + + it('shows Options tab when is_eu is false', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.queryByText('Multipliers')).not.toBeInTheDocument(); + expect(screen.getByText('Options')).toBeInTheDocument(); + }); + + it('show the loader when isEuRegion is loading', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + isLoading: true, + }); + render(, { wrapper }); + expect(screen.getByTestId('dt_wallets_tabs_loader')).toBeInTheDocument(); + }); + + it('triggers `onTabClickHandler` with proper tab index when the user switches the tab', () => { const onTabClickHandler = jest.fn(); (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); @@ -84,7 +128,7 @@ describe('AccountsList', () => { expect(onTabClickHandler).toHaveBeenCalledWith(1); }); - it('should render account list in desktop view', () => { + it('renders account list in desktop view', () => { (useDevice as jest.Mock).mockReturnValue({ isDesktop: true }); render(, { wrapper }); @@ -93,7 +137,7 @@ describe('AccountsList', () => { expect(screen.getAllByText('Options')[0]).toBeInTheDocument(); }); - it('should render wallet tour guide in mobile view with isWalletSettled set to false', () => { + it('renders wallet tour guide in mobile view with isWalletSettled set to false', () => { (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); render(, { @@ -103,7 +147,7 @@ describe('AccountsList', () => { expect(mockWalletTourGuide); }); - it('should render wallet tour guide in mobile view with isWalletSettled set to true', () => { + it('renders wallet tour guide in mobile view with isWalletSettled set to true', () => { (useDevice as jest.Mock).mockReturnValue({ isMobile: true }); render(, { diff --git a/packages/wallets/src/components/DerivAppsSection/DerivAppsGetAccount.tsx b/packages/wallets/src/components/DerivAppsSection/DerivAppsGetAccount.tsx index 1aea6f365c53..7381d2f31f6e 100644 --- a/packages/wallets/src/components/DerivAppsSection/DerivAppsGetAccount.tsx +++ b/packages/wallets/src/components/DerivAppsSection/DerivAppsGetAccount.tsx @@ -4,6 +4,7 @@ import { useActiveWalletAccount, useCreateNewRealAccount, useInvalidateQuery, + useIsEuRegion, useSettings, } from '@deriv/api-v2'; import { displayMoney } from '@deriv/api-v2/src/utils'; @@ -39,6 +40,7 @@ const DerivAppsGetAccount: React.FC = () => { const { data: balanceData } = useAllBalanceSubscription(); const { localize } = useTranslations(); + const { data: isEuRegion } = useIsEuRegion(); const createTradingAccount = async () => { if (!activeWallet?.is_virtual) { @@ -84,11 +86,18 @@ const DerivAppsGetAccount: React.FC = () => { } description={localize( - 'Transfer funds from your {{walletCurrencyType}} Wallet to your Options account to start trading.', - { walletCurrencyType: activeWallet?.wallet_currency_type } + 'Transfer funds from your {{walletCurrencyType}} Wallet to your {{accountType}} account to start trading.', + { + accountType: isEuRegion ? localize('Multipliers') : localize('Options'), + walletCurrencyType: activeWallet?.wallet_currency_type, + } )} displayBalance={displayBalance} - title={localize('Your Options account is ready')} + title={ + isEuRegion + ? localize('Your Multipliers account is ready') + : localize('Your Options account is ready') + } /> , { @@ -107,10 +116,18 @@ const DerivAppsGetAccount: React.FC = () => { - + {isEuRegion ? ( + + ) : ( + + )} - + {isEuRegion ? ( + + ) : ( + + )} diff --git a/packages/wallets/src/components/DerivAppsSection/DerivAppsTradingAccount.tsx b/packages/wallets/src/components/DerivAppsSection/DerivAppsTradingAccount.tsx index 984d18aa7789..6c1fdc88a0d3 100644 --- a/packages/wallets/src/components/DerivAppsSection/DerivAppsTradingAccount.tsx +++ b/packages/wallets/src/components/DerivAppsSection/DerivAppsTradingAccount.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import classNames from 'classnames'; import { useHistory } from 'react-router-dom'; -import { useActiveLinkedToTradingAccount, useActiveWalletAccount } from '@deriv/api-v2'; +import { useActiveLinkedToTradingAccount, useActiveWalletAccount, useIsEuRegion } from '@deriv/api-v2'; import { displayMoney } from '@deriv/api-v2/src/utils'; import { LabelPairedArrowUpArrowDownSmBoldIcon } from '@deriv/quill-icons'; import { Localize, useTranslations } from '@deriv-com/translations'; @@ -20,6 +20,7 @@ const DerivAppsTradingAccount = () => { const history = useHistory(); const { data: activeWallet } = useActiveWalletAccount(); const { data: activeLinkedToTradingAccount } = useActiveLinkedToTradingAccount(); + const { data: isEuRegion } = useIsEuRegion(); const { data: balanceData, isLoading: isBalanceLoading } = useAllBalanceSubscription(); const balance = balanceData?.[activeLinkedToTradingAccount?.loginid ?? '']?.balance; @@ -50,7 +51,11 @@ const DerivAppsTradingAccount = () => { >
- + {isEuRegion ? ( + + ) : ( + + )} {activeWallet?.is_virtual && }
diff --git a/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsGetAccount.spec.tsx b/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsGetAccount.spec.tsx index f0257459fa72..4f9110d6c0da 100644 --- a/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsGetAccount.spec.tsx +++ b/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsGetAccount.spec.tsx @@ -5,6 +5,7 @@ import { useActiveWalletAccount, useCreateNewRealAccount, useInvalidateQuery, + useIsEuRegion, } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; import { render, screen, waitFor } from '@testing-library/react'; @@ -21,6 +22,7 @@ jest.mock('@deriv/api-v2', () => ({ })), useCreateNewRealAccount: jest.fn(() => ({ isLoading: false })), useInvalidateQuery: jest.fn(() => Promise.resolve({})), + useIsEuRegion: jest.fn(() => ({ isLoading: false })), })); jest.mock('../../../hooks/useSyncLocalStorageClientAccounts', () => @@ -135,4 +137,26 @@ describe('DerivAppsGetAccount', () => { await userEvent.click(button); await waitFor(() => expect(mockMutateAsync).not.toBeCalled()); }); + + it('shows Options tab when is_eu is false', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByText('Options')).toBeInTheDocument(); + expect(screen.queryByText('One options account for all platforms.')).toBeInTheDocument(); + }); + + it('shows Multipliers tab when is_eu is true', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: true, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByText('Multipliers')).toBeInTheDocument(); + expect(screen.queryByText('Expand your potential gains; risk only what you put in.')).toBeInTheDocument(); + }); }); diff --git a/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsTradingAccount.spec.tsx b/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsTradingAccount.spec.tsx index 7698b8542366..ac203f1fd009 100644 --- a/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsTradingAccount.spec.tsx +++ b/packages/wallets/src/components/DerivAppsSection/__tests__/DerivAppsTradingAccount.spec.tsx @@ -1,5 +1,5 @@ import React, { PropsWithChildren } from 'react'; -import { APIProvider, useActiveLinkedToTradingAccount, useActiveWalletAccount } from '@deriv/api-v2'; +import { APIProvider, useActiveLinkedToTradingAccount, useActiveWalletAccount, useIsEuRegion } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; import { render, screen } from '@testing-library/react'; import WalletsAuthProvider from '../../../AuthProvider'; @@ -28,6 +28,10 @@ jest.mock('@deriv/api-v2', () => ({ useActiveWalletAccount: jest.fn(() => ({ data: { currency_config: { display_code: 'USD' }, is_virtual: false, loginid: 'CRW1' }, })), + useIsEuRegion: jest.fn(() => ({ + data: false, + isLoading: false, + })), })); jest.mock('../../../hooks/useAllBalanceSubscription', () => @@ -107,4 +111,23 @@ describe('DerivAppsTradingAccount', () => { toAccountLoginId: 'CRW1', }); }); + it('shows Options tab when is_eu is false', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByText('Options')).toBeInTheDocument(); + }); + + it('shows Multipliers tab when is_eu is true', () => { + (useDevice as jest.Mock).mockReturnValue({ isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: true, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByText('Multipliers')).toBeInTheDocument(); + }); }); diff --git a/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.scss b/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.scss index a134d2fc6c0a..e90ec92577a3 100644 --- a/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.scss +++ b/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.scss @@ -1,7 +1,11 @@ .wallets-desktop-wallets-list { max-width: 123.2rem; width: 100%; - height: max-content; + &--with-banner { + @include desktop-screen { + max-height: 63rem; + } + } display: flex; flex-direction: column; gap: 2.4rem; diff --git a/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.tsx b/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.tsx index 175293136738..a8844dd75147 100644 --- a/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.tsx +++ b/packages/wallets/src/components/DesktopWalletsList/DesktopWalletsList.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { useActiveWalletAccount } from '@deriv/api-v2'; +import classNames from 'classnames'; +import { useActiveWalletAccount, useIsEuRegion } from '@deriv/api-v2'; import { AccountsList } from '../AccountsList'; import { WalletsCardLoader } from '../SkeletonLoader'; import { WalletListCard } from '../WalletListCard'; @@ -8,9 +9,14 @@ import './DesktopWalletsList.scss'; const DesktopWalletsList = () => { const { data: activeWallet, isInitializing } = useActiveWalletAccount(); - + const { data: isEuRegion } = useIsEuRegion(); return ( -
+
{isInitializing && } {!isInitializing && ( ({ ...jest.requireActual('@deriv/api-v2'), useActiveWalletAccount: jest.fn(), + useIsEuRegion: jest.fn(() => ({ + data: false, + isLoading: false, + })), })); const wrapper = ({ children }: PropsWithChildren) => { @@ -52,4 +56,13 @@ describe('DesktopWalletsList', () => { render(, { wrapper }); expect(screen.getByTestId('dt_wallets_card_loader')).toBeInTheDocument(); }); + it('applies the with-banner class when is_eu is true and is_virtual is false', () => { + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: true, + isLoading: false, + }); + (useActiveWalletAccount as jest.Mock).mockReturnValue(() => ({ is_vertual: false })); + render(, { wrapper }); + expect(screen.getByTestId('dt_desktop-wallets-list')).toHaveClass('wallets-desktop-wallets-list--with-banner'); + }); }); diff --git a/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.scss b/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.scss index 47dfc6ced34b..829b152c5a9e 100644 --- a/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.scss +++ b/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.scss @@ -1,3 +1,5 @@ +@import '../SkeletonLoader/SkeletonLoader.scss'; + .wallets-options-and-multipliers-listing { width: 100%; height: 100%; @@ -22,6 +24,11 @@ flex-direction: column; align-items: flex-start; width: 100%; + + &__loader { + width: 12.1rem; + height: 2.4rem; + } } @include mobile-or-tablet-screen { @@ -37,6 +44,11 @@ color: var(--brand-coral, #ff444f); text-underline-offset: 0.3rem; } + &__loader { + margin-top: 0.2rem; + width: 42.6rem; + height: 2.4rem; + } } } @@ -48,6 +60,9 @@ @include mobile-or-tablet-screen { grid-template-rows: repeat(5, 1fr); + &--eu { + grid-template-rows: repeat(1, 1fr); + } grid-template-columns: auto; gap: 0; } diff --git a/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.tsx b/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.tsx index 80e4c6950ba8..85b94a4a35dd 100644 --- a/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.tsx +++ b/packages/wallets/src/components/OptionsAndMultipliersListing/OptionsAndMultipliersListing.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { useHistory } from 'react-router-dom'; -import { useActiveLinkedToTradingAccount } from '@deriv/api-v2'; +import { useActiveLinkedToTradingAccount, useIsEuRegion } from '@deriv/api-v2'; import { LabelPairedChevronLeftCaptionRegularIcon, LabelPairedChevronRightCaptionRegularIcon, @@ -12,79 +12,133 @@ import useIsRtl from '../../hooks/useIsRtl'; import { TRoute } from '../../routes/Router'; import { WalletLink } from '../Base'; import { DerivAppsSection } from '../DerivAppsSection'; +import { TradingAppCardLoader } from '../SkeletonLoader'; import { TradingAccountCard } from '../TradingAccountCard'; import LinkTitle from './LinkTitle'; import './OptionsAndMultipliersListing.scss'; +import classNames from 'classnames'; -const OptionsAndMultipliersListing = () => { - const { isDesktop } = useDevice(); +const OptionsAndMultipliersListingContentLoader = () => { + return ( + <> + {Array.from({ length: 3 }).map((_, idx) => ( + + ))} + + ); +}; + +const OptionsAndMultipliersListingContent: React.FC<{ isEuRegion: boolean }> = ({ isEuRegion }) => { const { localize } = useTranslations(); - const history = useHistory(); const isRtl = useIsRtl(); + const history = useHistory(); const { data: activeLinkedToTradingAccount } = useActiveLinkedToTradingAccount(); + return ( + <> + {getOptionsAndMultipliersContent(localize, isEuRegion).map(account => { + const { availability, description, key, redirect, title } = account; + if (availability === 'Non-EU' && isEuRegion) return; + return ( + { + if (!activeLinkedToTradingAccount?.loginid) return; + account.isExternal ? window.open(redirect, '_blank') : history.push(redirect as TRoute); + }} + > + + + + + + + {title} + + + {description} + + + {activeLinkedToTradingAccount?.loginid && ( + + {isRtl ? ( + + ) : ( + + )} + + )} + + + ); + })} + + ); +}; + +const OptionsAndMultipliersListing = () => { + const { isDesktop } = useDevice(); + const { data: isEuRegion, isLoading: isEuRegionLoading } = useIsEuRegion(); + const isLoading = isEuRegionLoading; + + const title = isEuRegion ? : ; + const subtitle = isEuRegion ? ( + <> + {' '} + + + + + ) : ( + <> + {' '} + + + + + ); + return (
{isDesktop && ( - + {isLoading ? ( +
+ ) : ( + title + )} )} - {' '} - - - + {isLoading ? ( +
+ ) : ( + subtitle + )}
- + {isLoading ? : }
-
- {getOptionsAndMultipliersContent(localize).map(account => { - const { description, key, redirect, title } = account; - return ( - { - if (!activeLinkedToTradingAccount?.loginid) return; - account.isExternal ? window.open(redirect, '_blank') : history.push(redirect as TRoute); - }} - > - - - - - - - {title} - - - {description} - - - {activeLinkedToTradingAccount?.loginid && ( - - {isRtl ? ( - - ) : ( - - )} - - )} - - - ); +
+ {isLoading ? ( + + ) : ( + + )}
); diff --git a/packages/wallets/src/components/OptionsAndMultipliersListing/__test__/OptionsAndMultipliersListing.spec.tsx b/packages/wallets/src/components/OptionsAndMultipliersListing/__test__/OptionsAndMultipliersListing.spec.tsx index f36fb156f81d..2e1e633547be 100644 --- a/packages/wallets/src/components/OptionsAndMultipliersListing/__test__/OptionsAndMultipliersListing.spec.tsx +++ b/packages/wallets/src/components/OptionsAndMultipliersListing/__test__/OptionsAndMultipliersListing.spec.tsx @@ -1,5 +1,5 @@ import React, { PropsWithChildren } from 'react'; -import { APIProvider, AuthProvider, useActiveLinkedToTradingAccount } from '@deriv/api-v2'; +import { APIProvider, AuthProvider, useActiveLinkedToTradingAccount, useIsEuRegion } from '@deriv/api-v2'; import { render, screen, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ModalProvider } from '../../ModalProvider'; @@ -16,6 +16,9 @@ jest.mock('react-router-dom', () => ({ jest.mock('@deriv/api-v2', () => ({ ...jest.requireActual('@deriv/api-v2'), useActiveLinkedToTradingAccount: jest.fn(), + useIsEuRegion: jest.fn(() => ({ + data: false, + })), })); jest.mock('../../DerivAppsSection', () => ({ @@ -42,24 +45,24 @@ describe('OptionsAndMultipliersListing', () => { expect(screen.getAllByTestId('dt_label_paired_chevron')[0]).toBeInTheDocument(); }); - it('handles onclick for the TradingAccountCard when loginid is undefined', () => { + it('handles onclick for the TradingAccountCard when loginid is undefined', async () => { (useActiveLinkedToTradingAccount as jest.Mock).mockReturnValue({ data: { loginid: undefined }, }); render(, { wrapper }); const tradingAccountCard = screen.getAllByTestId('dt_wallets_trading_account_card')[0]; - userEvent.click(tradingAccountCard); + await userEvent.click(tradingAccountCard); expect(screen.queryByTestId('dt_label_paired_chevron')).not.toBeInTheDocument(); expect(mockHistoryPush).not.toHaveBeenCalled(); }); - it('handles onclick for the TradingAccountCard when loginid is defined', () => { + it('handles onclick for the TradingAccountCard when loginid is defined', async () => { (useActiveLinkedToTradingAccount as jest.Mock).mockReturnValue({ data: { loginid: 'CR1' }, }); render(, { wrapper }); const tradingAccountCard = screen.getAllByTestId('dt_wallets_trading_account_card')[0]; - userEvent.click(tradingAccountCard); + await userEvent.click(tradingAccountCard); const icon = within(tradingAccountCard).queryByTestId('dt_label_paired_chevron'); expect(icon).toBeInTheDocument(); expect(mockHistoryPush).toHaveBeenCalled(); @@ -76,4 +79,18 @@ describe('OptionsAndMultipliersListing', () => { const icon = within(tradingAccountCard).queryByTestId('dt_label_paired_chevron'); expect(icon).toBeInTheDocument(); }); + + it('renders only accounts with availability EU when is_eu is true', () => { + (useActiveLinkedToTradingAccount as jest.Mock).mockReturnValue({ + data: { loginid: 'MF-1' }, + }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: true, + isLoading: false, + }); + render(, { wrapper }); + expect(screen.getByTestId('dt_wallets_trading_account_card')).toBeInTheDocument(); + expect(screen.queryByText('Deriv Trader')).toBeInTheDocument(); + expect(screen.queryByText('Custom charts, low-entry costs.')).toBeInTheDocument(); + }); }); diff --git a/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.scss b/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.scss index ff7451446e8f..cd622bbfd82e 100644 --- a/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.scss +++ b/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.scss @@ -1,5 +1,3 @@ -@import '../SkeletonLoader.scss'; - .wallets-responsive-loader { width: 100%; display: flex; @@ -7,30 +5,4 @@ align-items: center; gap: 1.6rem; overflow-x: hidden; - - &__content { - width: 100%; - display: flex; - flex-direction: column; - align-items: center; - gap: 1.6rem; - padding: 0 1.6rem 1.6rem; - - & > div { - width: 100%; - border-radius: 6px; - } - } - - &__content-tabs { - height: 5rem; - } - - &__content-description { - height: 7.6rem; - } - - &__content-list { - height: 8rem; - } } diff --git a/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.tsx b/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.tsx index ca4a23faabfd..cfd51e833d4a 100644 --- a/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.tsx +++ b/packages/wallets/src/components/SkeletonLoader/WalletsResponsiveLoader/WalletsResponsiveLoader.tsx @@ -1,16 +1,13 @@ import React from 'react'; import WalletsCarouselLoader from '../WalletsCarouselLoader/WalletsCarouselLoader'; +import WalletsTabsLoader from '../WalletsTabsLoader/WalletsTabsLoader'; import './WalletsResponsiveLoader.scss'; const WalletsResponsiveLoader: React.FC = () => { return (
-
-
-
-
-
+
); }; diff --git a/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.scss b/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.scss new file mode 100644 index 000000000000..2563507f598d --- /dev/null +++ b/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.scss @@ -0,0 +1,28 @@ +@import '../SkeletonLoader.scss'; + +.wallets-tabs-loader { + &__wrapper { + width: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 1.6rem; + padding: 0 1.6rem 1.6rem; + & > div { + width: 100%; + border-radius: 6px; + } + } + + &__tabs { + height: 5rem; + } + + &__description { + height: 7.6rem; + } + + &__list { + height: 8rem; + } +} diff --git a/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.tsx b/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.tsx new file mode 100644 index 000000000000..53bc3ff8dcb1 --- /dev/null +++ b/packages/wallets/src/components/SkeletonLoader/WalletsTabsLoader/WalletsTabsLoader.tsx @@ -0,0 +1,14 @@ +import React from 'react'; +import './WalletsTabsLoader.scss'; + +const WalletsTabsLoader: React.FC = () => { + return ( +
+
+
+
+
+ ); +}; + +export default WalletsTabsLoader; diff --git a/packages/wallets/src/components/SkeletonLoader/index.ts b/packages/wallets/src/components/SkeletonLoader/index.ts index 365252a9ec9f..ef6e5ebf03ea 100644 --- a/packages/wallets/src/components/SkeletonLoader/index.ts +++ b/packages/wallets/src/components/SkeletonLoader/index.ts @@ -4,3 +4,4 @@ export { default as WalletsCardLoader } from './WalletsCardLoader/WalletsCardLoa export { default as WalletsCarouselLoader } from './WalletsCarouselLoader/WalletsCarouselLoader'; export { default as WalletsPriorityCryptoWithdrawLoader } from './WalletsPriorityCryptoWithdrawLoader/WalletsPriorityCryptoWithdrawLoader'; export { default as WalletsResponsiveLoader } from './WalletsResponsiveLoader/WalletsResponsiveLoader'; +export { default as WalletsTabsLoader } from './WalletsTabsLoader/WalletsTabsLoader'; diff --git a/packages/wallets/src/components/WalletsContainer/WalletsContainer.scss b/packages/wallets/src/components/WalletsContainer/WalletsContainer.scss index d98f66cbbc1e..93c062b9a978 100644 --- a/packages/wallets/src/components/WalletsContainer/WalletsContainer.scss +++ b/packages/wallets/src/components/WalletsContainer/WalletsContainer.scss @@ -3,6 +3,7 @@ background: var(--system-light-8-primary-background, #fff); border-radius: 1.6rem; position: relative; + height: 100%; &__header { width: 100%; diff --git a/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.scss b/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.scss new file mode 100644 index 000000000000..1fc6440f4c62 --- /dev/null +++ b/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.scss @@ -0,0 +1,47 @@ +.wallets-disclaimer-banner { + display: flex; + justify-content: center; + width: 100%; + @include desktop-screen { + height: fit-content; + } + + position: fixed; + @include desktop-screen { + z-index: 3; + bottom: 3.6rem; + left: 0; + right: 0; + padding: 0 10rem; + } + + @include mobile-or-tablet-screen { + bottom: 0; + } + + &__container { + width: 100%; + max-width: 123.2rem; + padding: 0.8rem 4rem; + position: relative; + background-color: var(--system-light-7, #f2f3f4); + border-top: 1px solid var(--system-light-6-hover-background, #e6e9e9); + + &:hover { + background-color: var(--system-light-6, #e6e9e9); + } + + @include mobile-or-tablet-screen { + padding: 0.8rem 1.6rem; + } + } + + &__content { + @include mobile-or-tablet-screen { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + } + } +} diff --git a/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.tsx b/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.tsx new file mode 100644 index 000000000000..770a02b20045 --- /dev/null +++ b/packages/wallets/src/components/WalletsDisclaimerBanner/WalletsDisclaimerBanner.tsx @@ -0,0 +1,58 @@ +import React, { useState } from 'react'; +import { LabelPairedChevronDownLgBoldIcon, LabelPairedChevronUpLgBoldIcon } from '@deriv/quill-icons'; +import { Localize } from '@deriv-com/translations'; +import { Text, useDevice } from '@deriv-com/ui'; +import './WalletsDisclaimerBanner.scss'; + +const WalletsMobileDisclaimerBannerContent = () => { + const [isOpen, setIsOpen] = useState(false); + if (isOpen) { + return ( + <> + + ]} + i18n_default_text='The products offered on our website are complex derivative products that carry a significant risk of potential loss. CFDs are complex instruments with a high risk of losing money rapidly due to leverage. <0>70.78% of retail investor accounts lose money when trading CFDs with this provider. You should consider whether you understand how these products work and whether you can afford to take the high risk of losing your money.' + /> + +
+ setIsOpen(false)} width={16} /> +
+ + ); + } + return ( + <> + + + +
+ setIsOpen(true)} width={16} /> +
+ + ); +}; + +const WalletsDisclaimerBanner = () => { + const { isDesktop } = useDevice(); + return ( +
+
+
+ {isDesktop ? ( + + ]} + i18n_default_text='The products offered on our website are complex derivative products that carry a significant risk of potential loss. CFDs are complex instruments with a high risk of losing money rapidly due to leverage. <0>70.78% of retail investor accounts lose money when trading CFDs with this provider. You should consider whether you understand how these products work and whether you can afford to take the high risk of losing your money.' + /> + + ) : ( + + )} +
+
+
+ ); +}; + +export default WalletsDisclaimerBanner; diff --git a/packages/wallets/src/components/WalletsDisclaimerBanner/index.ts b/packages/wallets/src/components/WalletsDisclaimerBanner/index.ts new file mode 100644 index 000000000000..b2daed3f15ba --- /dev/null +++ b/packages/wallets/src/components/WalletsDisclaimerBanner/index.ts @@ -0,0 +1 @@ +export { default as WalletsDisclaimerBanner } from './WalletsDisclaimerBanner'; diff --git a/packages/wallets/src/components/index.ts b/packages/wallets/src/components/index.ts index 1111940abbba..05a17d433e64 100644 --- a/packages/wallets/src/components/index.ts +++ b/packages/wallets/src/components/index.ts @@ -38,6 +38,7 @@ export * from './WalletsCarouselContent'; export * from './WalletsCarouselHeader'; export * from './WalletsContainer'; export * from './WalletsDisabledAccountsBanner'; +export * from './WalletsDisclaimerBanner'; export * from './WalletsErrorScreen'; export * from './WalletsPercentageSelector'; export * from './WalletsResetMT5Password'; diff --git a/packages/wallets/src/constants/constants.tsx b/packages/wallets/src/constants/constants.tsx index 9ffa2dd081a8..f4b13f23fd78 100644 --- a/packages/wallets/src/constants/constants.tsx +++ b/packages/wallets/src/constants/constants.tsx @@ -1,20 +1,37 @@ import { useTranslations } from '@deriv-com/translations'; import { getStaticUrl, getUrlSmartTrader } from '../helpers/urls'; -export const getOptionsAndMultipliersContent = (localize: ReturnType['localize']) => [ +type TOptionsAndMultipliersContent = { + availability: 'All' | 'EU' | 'Non-EU'; + description: string; + isExternal?: boolean; + key: string; + redirect: string; + title: string; +}; + +export const getOptionsAndMultipliersContent = ( + localize: ReturnType['localize'], + isEU?: boolean +): TOptionsAndMultipliersContent[] => [ { - description: localize('The options and multipliers trading platform.'), + availability: 'All', + description: isEU + ? localize('Custom charts, low-entry costs.') + : localize('The options and multipliers trading platform.'), key: 'trader', redirect: '/dtrader', title: 'Deriv Trader', }, { + availability: 'Non-EU', description: localize('The ultimate bot trading platform.'), key: 'bot', redirect: '/bot', title: 'Deriv Bot', }, { + availability: 'Non-EU', description: localize('The legacy options trading platform.'), isExternal: true, key: 'smarttrader', @@ -22,6 +39,7 @@ export const getOptionsAndMultipliersContent = (localize: ReturnType = ({ isDesktop, isEuRegion }) => { + const history = useHistory(); + + return isDesktop ? ( + +
+ + + + +
+ + ]} + i18n_default_text='Trade bigger positions with less capital on a wide range of global markets. <0>Learn more' + /> + +
+ ) : ( +
+ + , + ]} + i18n_default_text='Trade bigger positions with less capital on a wide range of global markets. <0>Learn more' + /> + + +
+ ); +}; + const CFDPlatformsList: React.FC = () => { const { data: activeWallet } = useActiveWalletAccount(); const { isDesktop } = useDevice(); - const history = useHistory(); + const { data: isEuRegion, isLoading } = useIsEuRegion(); return (
- {isDesktop ? ( - -
- - - - -
- - ]} - i18n_default_text='Trade bigger positions with less capital on a wide range of global markets. <0>Learn more' - /> - -
+ {isLoading ? ( +
) : ( -
- - , - ]} - i18n_default_text='Trade bigger positions with less capital on a wide range of global markets. <0>Learn more' - /> - - -
+ )}
{activeWallet?.currency_config?.is_crypto ? : } diff --git a/packages/wallets/src/features/cfd/__tests__/CFDPlatformsList.spec.tsx b/packages/wallets/src/features/cfd/__tests__/CFDPlatformsList.spec.tsx index 81d81e790365..e4cb70f7c44a 100644 --- a/packages/wallets/src/features/cfd/__tests__/CFDPlatformsList.spec.tsx +++ b/packages/wallets/src/features/cfd/__tests__/CFDPlatformsList.spec.tsx @@ -1,8 +1,9 @@ import React from 'react'; -import { useActiveWalletAccount } from '@deriv/api-v2'; +import { APIProvider, useActiveWalletAccount, useIsEuRegion } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import WalletsAuthProvider from '../../../AuthProvider'; import CFDPlatformsList from '../CFDPlatformsList'; jest.mock('@deriv/api-v2', () => ({ @@ -14,6 +15,7 @@ jest.mock('@deriv/api-v2', () => ({ }, }, })), + useIsEuRegion: jest.fn(), })); jest.mock('@deriv-com/ui', () => ({ @@ -39,12 +41,22 @@ jest.mock('../components', () => ({ const mockUseActiveWalletAccount = useActiveWalletAccount as jest.MockedFunction; const mockUseDevice = useDevice as jest.MockedFunction; +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + describe('CFDPlatformsList', () => { describe('Mobile/Tablet view', () => { it('renders proper content', () => { //@ts-expect-error we only need partial action types mockUseDevice.mockReturnValueOnce({ isMobile: true }); - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); expect( screen.getByText('Trade bigger positions with less capital on a wide range of global markets.') @@ -56,7 +68,11 @@ describe('CFDPlatformsList', () => { it('opens proper link when the user is clicking on `Learn more` text', () => { //@ts-expect-error we only need partial action types mockUseDevice.mockReturnValueOnce({ isMobile: true }); - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); const learnMoreEl = screen.getByRole('link', { name: 'Learn more' }); @@ -66,7 +82,11 @@ describe('CFDPlatformsList', () => { it('redirects to `/compare-accounts` route when the user is clicking on `Compare accounts` button', async () => { //@ts-expect-error we only need partial action types mockUseDevice.mockReturnValueOnce({ isMobile: true }); - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); const compareAccountsBtn = screen.getByText('Compare accounts'); await userEvent.click(compareAccountsBtn); @@ -77,7 +97,11 @@ describe('CFDPlatformsList', () => { describe('Desktop view', () => { it('renders proper content', () => { - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); expect(screen.getByText('CFDs')).toBeInTheDocument(); expect( @@ -88,7 +112,15 @@ describe('CFDPlatformsList', () => { }); it('opens proper link when the user is clicking on `Learn more` text', () => { - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); const learnMoreEl = screen.getByRole('link', { name: 'Learn more' }); @@ -96,7 +128,11 @@ describe('CFDPlatformsList', () => { }); it('redirects to `/compare-accounts` route when the user is clicking on `Compare accounts` button', async () => { - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); const compareAccountsBtn = screen.getByText('Compare accounts'); await userEvent.click(compareAccountsBtn); @@ -106,12 +142,20 @@ describe('CFDPlatformsList', () => { }); it('renders proper content for fiat accounts', () => { - render(); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); + render(, { wrapper }); expect(screen.getByText('CFDPlatformsListAccounts')).toBeInTheDocument(); }); it('renders proper content for crypto accounts', () => { + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); mockUseActiveWalletAccount.mockReturnValueOnce({ data: { //@ts-expect-error we only need partial action types @@ -120,7 +164,7 @@ describe('CFDPlatformsList', () => { }, }, }); - render(); + render(, { wrapper }); expect(screen.getByText('CFDPlatformsListEmptyState')).toBeInTheDocument(); }); diff --git a/packages/wallets/src/features/cfd/components/CFDPlatformsListAccounts/CFDPlatformsListAccounts.tsx b/packages/wallets/src/features/cfd/components/CFDPlatformsListAccounts/CFDPlatformsListAccounts.tsx index 0a3ea97a7b3c..626ed0f36f64 100644 --- a/packages/wallets/src/features/cfd/components/CFDPlatformsListAccounts/CFDPlatformsListAccounts.tsx +++ b/packages/wallets/src/features/cfd/components/CFDPlatformsListAccounts/CFDPlatformsListAccounts.tsx @@ -1,5 +1,11 @@ import React from 'react'; -import { useCtraderAccountsList, useDxtradeAccountsList, useLandingCompany, useSortedMT5Accounts } from '@deriv/api-v2'; +import { + useCtraderAccountsList, + useDxtradeAccountsList, + useIsEuRegion, + useLandingCompany, + useSortedMT5Accounts, +} from '@deriv/api-v2'; import { TradingAppCardLoader } from '../../../../components/SkeletonLoader'; import { AddedCTraderAccountsList, @@ -29,6 +35,7 @@ const CFDPlatformsListAccounts: React.FC = () => { isLoading: isDxtradeLoading, } = useDxtradeAccountsList(); const { data: landingCompany, isLoading: isLandingCompanyLoading } = useLandingCompany(); + const { data: isEuRegion } = useIsEuRegion(); const isLoading = isMT5Loading || isCTraderLoading || isDxtradeLoading || isLandingCompanyLoading; const isFetchedAfterMount = isMT5FetchedAfterMount || isCtraderFetchedAfterMount || isDxtradeFetchedAfterMount; @@ -70,7 +77,7 @@ const CFDPlatformsListAccounts: React.FC = () => { /> ); })} - {!isRestricted && ( + {!isRestricted && !isEuRegion && ( <> {hasCTraderAccount ? : } {hasDxtradeAccount ? : } diff --git a/packages/wallets/src/features/cfd/constants.tsx b/packages/wallets/src/features/cfd/constants.tsx index d74137d0ca37..c81968919e5a 100644 --- a/packages/wallets/src/features/cfd/constants.tsx +++ b/packages/wallets/src/features/cfd/constants.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { AccountsDerivCtraderIcon, AccountsDerivXIcon, + AccountsDmt5CfdsIcon, AccountsDmt5FinancialIcon, AccountsDmt5StandardIcon, AccountsDmt5SwfIcon, @@ -18,46 +19,82 @@ import { THooks, TPlatforms } from '../../types'; import { ctraderLinks, whiteLabelLinks } from './screens/MT5TradeScreen/MT5TradeLink/urlConfig'; const zeroSpreadDetails = (localize: ReturnType['localize']) => ({ + availability: 'Non-EU', description: localize('Zero spread CFDs on financial and derived instruments'), icon: , title: 'Zero Spread', }); const swapFreeDetails = (localize: ReturnType['localize']) => ({ + availability: 'Non-EU', description: localize('Swap-free CFDs on selected financial and derived instruments'), icon: , title: 'Swap-Free', }); +const getMarketTypeDetailsDescription = ( + localize: ReturnType['localize'], + product?: THooks.AvailableMT5Accounts['product'] | 'stp', + isEuRegion?: boolean +) => { + if (isEuRegion && product !== 'stp') { + return localize('Your all-in-one access to financial and derived instruments.'); + } + + if (product === 'stp') { + return localize('Direct access to market prices'); + } + + return localize('CFDs on financial instruments'); +}; + +const getMarketTypeDetailsTitle = (product?: THooks.AvailableMT5Accounts['product'] | 'stp', isEuRegion?: boolean) => { + if (isEuRegion && product !== 'stp') { + return 'CFDs'; + } + + if (product === 'stp') { + return 'Financial STP'; + } + + return 'Financial'; +}; + export const getMarketTypeDetails = ( localize: ReturnType['localize'], - product?: THooks.AvailableMT5Accounts['product'] | 'stp' + product?: THooks.AvailableMT5Accounts['product'] | 'stp', + isEuRegion?: boolean ) => ({ all: product === PRODUCT.ZEROSPREAD ? zeroSpreadDetails(localize) : swapFreeDetails(localize), financial: { - description: - product === 'stp' - ? localize('Direct access to market prices') - : localize('CFDs on financial instruments'), - icon: , - title: product === 'stp' ? 'Financial STP' : 'Financial', + availability: 'All', + description: getMarketTypeDetailsDescription(localize, product, isEuRegion), + icon: isEuRegion ? ( + + ) : ( + + ), + title: getMarketTypeDetailsTitle(product, isEuRegion), }, synthetic: { + availability: 'Non-EU', description: localize('CFDs on derived and financial instruments'), icon: , title: 'Standard', }, - } as const); + }) as const; export const PlatformDetails = { ctrader: { + availability: 'Non-EU', icon: , link: 'https://onelink.to/5jgj8z', platform: 'ctrader' as TPlatforms.OtherAccounts, title: 'Deriv cTrader', }, dxtrade: { + availability: 'Non-EU', icon: , link: 'https://onelink.to/grmtyx', platform: 'dxtrade' as TPlatforms.OtherAccounts, @@ -121,7 +158,7 @@ export const getAppToContentMapper = (localize: ReturnType, @@ -139,7 +176,7 @@ export const getServiceMaintenanceMessages = (localize: ReturnType { expect(badge).toBeInTheDocument(); expect(mockPropsFn).toBeCalledWith('mockKycStatus'); - userEvent.click(badge); + await userEvent.click(badge); await waitFor(() => { expect(screen.getByText('ClientVerificationModal')).toBeInTheDocument(); @@ -209,8 +209,8 @@ describe('AddedMT5AccountsList', () => { // @ts-expect-error - since this is a mock, we only need partial properties of the account render(, { wrapper }); - await waitFor(() => { - userEvent.click(screen.getByText('WalletStatusBadge')); + await waitFor(async () => { + await userEvent.click(screen.getByText('WalletStatusBadge')); }); await waitFor(() => { diff --git a/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.ts b/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.tsx similarity index 79% rename from packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.ts rename to packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.tsx index 0d7af35c6215..69a9d330886b 100644 --- a/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.ts +++ b/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/__tests__/useAddedMT5Account.spec.tsx @@ -1,6 +1,8 @@ -import { useTradingPlatformStatus } from '@deriv/api-v2'; +import React, { PropsWithChildren } from 'react'; +import { APIProvider, useTradingPlatformStatus } from '@deriv/api-v2'; import { cleanup } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; +import WalletsAuthProvider from '../../../../../../../AuthProvider'; import { getMarketTypeDetails } from '../../../../../constants'; import { TAddedMT5Account } from '../../../../../types'; import useAddedMT5Account from '../useAddedMT5Account'; @@ -21,6 +23,12 @@ const mockAccount = { status: '', } as TAddedMT5Account; +const wrapper = ({ children }: PropsWithChildren) => ( + + {children} + +); + describe('useAddedMT5Account', () => { beforeEach(() => { (useTradingPlatformStatus as jest.Mock).mockReturnValue({ @@ -32,7 +40,7 @@ describe('useAddedMT5Account', () => { it('provides correct account details based on the market type', () => { (getMarketTypeDetails as jest.Mock).mockReturnValue({ financial: 'mock-account-details' }); - const { result } = renderHook(() => useAddedMT5Account(mockAccount)); + const { result } = renderHook(() => useAddedMT5Account(mockAccount), { wrapper }); expect(result.current.accountDetails).toEqual('mock-account-details'); }); @@ -42,37 +50,45 @@ describe('useAddedMT5Account', () => { getPlatformStatus: jest.fn(() => 'maintenance'), }); - const { result } = renderHook(() => useAddedMT5Account(mockAccount)); + const { result } = renderHook(() => useAddedMT5Account(mockAccount), { wrapper }); expect(result.current.isServerMaintenance).toEqual(true); }); it('isServerMaintenance is `true` when account status is `under_maintenance`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'under_maintenance' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'under_maintenance' }), { + wrapper, + }); expect(result.current.isServerMaintenance).toEqual(true); }); it('kycStatus is `failed` when status received for account is `proof_failed`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'proof_failed' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'proof_failed' }), { + wrapper, + }); expect(result.current.kycStatus).toEqual('failed'); }); it('kycStatus is `failed` when status received for account is `poa_failed`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'poa_failed' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'poa_failed' }), { wrapper }); expect(result.current.kycStatus).toEqual('failed'); }); it('kycStatus is `in_review` when status received for account is `verification_pending`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'verification_pending' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'verification_pending' }), { + wrapper, + }); expect(result.current.kycStatus).toEqual('in_review'); }); it('kycStatus is `needs_verification` when status received for account is `needs_verification`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'needs_verification' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'needs_verification' }), { + wrapper, + }); expect(result.current.kycStatus).toEqual('needs_verification'); }); @@ -82,19 +98,21 @@ describe('useAddedMT5Account', () => { getPlatformStatus: jest.fn(() => 'active'), }); - const { result } = renderHook(() => useAddedMT5Account(mockAccount)); + const { result } = renderHook(() => useAddedMT5Account(mockAccount), { wrapper }); expect(result.current.showMT5TradeModal).toEqual(true); }); it('showPlatformStatus is `true` when account status is `unavailable`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'unavailable' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'unavailable' }), { wrapper }); expect(result.current.showPlatformStatus).toEqual(true); }); it('showPlatformStatus is `true` when account status is `under_maintenance`', () => { - const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'under_maintenance' })); + const { result } = renderHook(() => useAddedMT5Account({ ...mockAccount, status: 'under_maintenance' }), { + wrapper, + }); expect(result.current.showPlatformStatus).toEqual(true); }); @@ -104,7 +122,7 @@ describe('useAddedMT5Account', () => { getPlatformStatus: jest.fn(() => 'maintenance'), }); - const { result } = renderHook(() => useAddedMT5Account(mockAccount)); + const { result } = renderHook(() => useAddedMT5Account(mockAccount), { wrapper }); expect(result.current.showPlatformStatus).toEqual(true); }); diff --git a/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/useAddedMT5Account.ts b/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/useAddedMT5Account.ts index e02189eab358..aeac7000a752 100644 --- a/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/useAddedMT5Account.ts +++ b/packages/wallets/src/features/cfd/flows/MT5/AddedMT5AccountsList/hooks/useAddedMT5Account.ts @@ -1,5 +1,5 @@ import React, { useMemo } from 'react'; -import { useTradingPlatformStatus } from '@deriv/api-v2'; +import { useIsEuRegion, useTradingPlatformStatus } from '@deriv/api-v2'; import { useTranslations } from '@deriv-com/translations'; import { ClientVerificationStatusBadge } from '../../../../components'; import { getMarketTypeDetails, MARKET_TYPE, MT5_ACCOUNT_STATUS, TRADING_PLATFORM_STATUS } from '../../../../constants'; @@ -28,9 +28,11 @@ const useAddedMT5Account = (account: TAddedMT5Account) => { // @ts-expect-error The enabled property exists, but the api-types are invalid const isAccountDisabled = !account.rights?.enabled; + const { data: isEuRegion } = useIsEuRegion(); + const accountDetails = useMemo( - () => getMarketTypeDetails(localize, account.product)[account.market_type ?? MARKET_TYPE.ALL], - [account.market_type, account.product, localize] + () => getMarketTypeDetails(localize, account.product, isEuRegion)[account.market_type ?? MARKET_TYPE.ALL], + [account.market_type, account.product, localize, isEuRegion] ); const { getPlatformStatus } = useTradingPlatformStatus(); diff --git a/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/AvailableMT5AccountsList.tsx b/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/AvailableMT5AccountsList.tsx index 3d6c53ed996e..da1d68369f81 100644 --- a/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/AvailableMT5AccountsList.tsx +++ b/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/AvailableMT5AccountsList.tsx @@ -1,5 +1,5 @@ import React, { useCallback } from 'react'; -import { useActiveWalletAccount, useMT5AccountsList, useTradingPlatformStatus } from '@deriv/api-v2'; +import { useActiveWalletAccount, useIsEuRegion, useMT5AccountsList, useTradingPlatformStatus } from '@deriv/api-v2'; import { LabelPairedChevronLeftCaptionRegularIcon, LabelPairedChevronRightCaptionRegularIcon, @@ -25,7 +25,8 @@ const AvailableMT5AccountsList: React.FC = ({ account }) => { const { localize } = useTranslations(); const isRtl = useIsRtl(); const { setModalState, show } = useModal(); - const { description, title } = getMarketTypeDetails(localize, account.product)[ + const { data: isEuRegion } = useIsEuRegion(); + const { availability, description, icon, title } = getMarketTypeDetails(localize, account.product, isEuRegion)[ account.market_type || MARKET_TYPE.ALL ]; const { data: mt5Accounts } = useMT5AccountsList(); @@ -55,11 +56,11 @@ const AvailableMT5AccountsList: React.FC = ({ account }) => { } }, [hasUnavailableAccount, show, platformStatus, isVirtual, hasClientKycStatus, setModalState, account]); + if (isEuRegion && availability === 'Non-EU') return null; + return ( - - {getMarketTypeDetails(localize, account.product)[account.market_type || MARKET_TYPE.ALL].icon} - + {icon}
diff --git a/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/__test__/AvailableMT5AcountsList.spec.tsx b/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/__test__/AvailableMT5AcountsList.spec.tsx index 9eef6b865cf6..7ca8e8945be9 100644 --- a/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/__test__/AvailableMT5AcountsList.spec.tsx +++ b/packages/wallets/src/features/cfd/flows/MT5/AvailableMT5AccountsList/__test__/AvailableMT5AcountsList.spec.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useActiveWalletAccount, useMT5AccountsList, useTradingPlatformStatus } from '@deriv/api-v2'; +import { useActiveWalletAccount, useIsEuRegion, useMT5AccountsList, useTradingPlatformStatus } from '@deriv/api-v2'; import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { useModal } from '../../../../../../components/ModalProvider'; @@ -7,7 +7,9 @@ import { ClientVerificationModal, MT5PasswordModal, TradingPlatformStatusModal } import AvailableMT5AccountsList from '../AvailableMT5AccountsList'; jest.mock('@deriv/api-v2', () => ({ + ...jest.requireActual('@deriv/api-v2'), useActiveWalletAccount: jest.fn(), + useIsEuRegion: jest.fn(), useMT5AccountsList: jest.fn(), useTradingPlatformStatus: jest.fn(), })); @@ -40,6 +42,9 @@ describe('AvailableMT5AccountsList', () => { setModalState: mockSetModalState, show: mockShow, }); + (useIsEuRegion as jest.Mock).mockReturnValue({ + data: false, + }); }); const nonRegulatedAccount = { @@ -132,7 +137,7 @@ describe('AvailableMT5AccountsList', () => { expect(mockShow).toHaveBeenCalledWith(); }); - it('shows MT5PasswordModal for non-regulated real accounts if client is verified', () => { + it('shows MT5PasswordModal for non-regulated real accounts if client is verified', async () => { (useActiveWalletAccount as jest.Mock).mockReturnValue({ data: undefined, }); @@ -140,13 +145,13 @@ describe('AvailableMT5AccountsList', () => { render(); const button = screen.getByTestId('dt_wallets_trading_account_card'); - userEvent.click(button); + await userEvent.click(button); // @ts-expect-error - since this is a mock, we only need partial properties of the account expect(mockShow).toHaveBeenCalledWith(); }); - it('shows ClientVerificationModal for regulated real accounts if client is unverified', () => { + it('shows ClientVerificationModal for regulated real accounts if client is unverified', async () => { (useActiveWalletAccount as jest.Mock).mockReturnValue({ data: { is_virtual: false, @@ -156,13 +161,13 @@ describe('AvailableMT5AccountsList', () => { render(); const button = screen.getByTestId('dt_wallets_trading_account_card'); - userEvent.click(button); + await userEvent.click(button); // @ts-expect-error - since this is a mock, we only need partial properties of the account expect(mockShow).toHaveBeenCalledWith(); }); - it('shows MT5PasswordModal for demo accounts for verified clients', () => { + it('shows MT5PasswordModal for demo accounts for verified clients', async () => { (useActiveWalletAccount as jest.Mock).mockReturnValue({ data: { is_virtual: true, @@ -172,7 +177,7 @@ describe('AvailableMT5AccountsList', () => { render(); const button = screen.getByTestId('dt_wallets_trading_account_card'); - userEvent.click(button); + await userEvent.click(button); // @ts-expect-error - since this is a mock, we only need partial properties of the account expect(mockShow).toHaveBeenCalledWith(); diff --git a/packages/wallets/src/features/cfd/screens/CFDSuccess/CFDSuccess.tsx b/packages/wallets/src/features/cfd/screens/CFDSuccess/CFDSuccess.tsx index 7da446b08bd9..81b71514386c 100644 --- a/packages/wallets/src/features/cfd/screens/CFDSuccess/CFDSuccess.tsx +++ b/packages/wallets/src/features/cfd/screens/CFDSuccess/CFDSuccess.tsx @@ -1,6 +1,6 @@ import React, { ComponentProps } from 'react'; import classNames from 'classnames'; -import { useActiveWalletAccount } from '@deriv/api-v2'; +import { useActiveWalletAccount, useIsEuRegion } from '@deriv/api-v2'; import { Localize, useTranslations } from '@deriv-com/translations'; import { Text, useDevice } from '@deriv-com/ui'; import { WalletMarketCurrencyIcon, WalletSuccess } from '../../../../components'; @@ -36,13 +36,14 @@ const CFDSuccess: React.FC = ({ const { data } = useActiveWalletAccount(); const { isDesktop } = useDevice(); const { localize } = useTranslations(); + const { data: isEuRegion } = useIsEuRegion(); const isDemo = data?.is_virtual; const isDxtradeOrCtrader = marketType === MARKET_TYPE.ALL && (platform === PlatformDetails.dxtrade.platform || platform === PlatformDetails.ctrader.platform); - let marketTypeTitle = localize('Options'); + let marketTypeTitle = isEuRegion ? localize('Multipliers') : localize('Options'); if (marketType && platform) { const isPlatformValid = Object.keys(PlatformDetails).includes(platform); diff --git a/packages/wallets/src/features/cfd/screens/CFDSuccess/__test__/CFDSuccess.spec.tsx b/packages/wallets/src/features/cfd/screens/CFDSuccess/__test__/CFDSuccess.spec.tsx index c204099ec699..676ef8896c8b 100644 --- a/packages/wallets/src/features/cfd/screens/CFDSuccess/__test__/CFDSuccess.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CFDSuccess/__test__/CFDSuccess.spec.tsx @@ -8,6 +8,9 @@ jest.mock('@deriv/api-v2', () => ({ useActiveWalletAccount: jest.fn(() => ({ data: { currency: 'USD', is_virtual: false }, })), + useIsEuRegion: jest.fn(() => ({ + data: false, + })), })); jest.mock('@deriv-com/ui', () => ({ diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.scss b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.scss index 61edec62e70b..b875359730ee 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.scss +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.scss @@ -13,13 +13,19 @@ @include mobile-or-tablet-screen { width: 18rem; - height: 66.6rem; + height: 47rem; + + &--eu { + height: fit-content; + } } &__eu-clients { position: relative; top: 0.5rem; - text-align: center; + display: flex; + justify-content: flex-start; + padding: 0 2.4rem; } &__banner { diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.tsx index 11d809c5b705..51c381999a8d 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsCard.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import classNames from 'classnames'; import { Localize } from '@deriv-com/translations'; import { Text } from '@deriv-com/ui'; import { THooks, TPlatforms } from '../../../../types'; @@ -12,7 +13,6 @@ import './CompareAccountsCard.scss'; type TCompareAccountsCard = { isDemo: boolean; isEuRegion: boolean; - isEuUser: boolean; marketType: THooks.AvailableMT5Accounts['market_type']; platform: TPlatforms.All; product?: THooks.AvailableMT5Accounts['product']; @@ -22,7 +22,6 @@ type TCompareAccountsCard = { const CompareAccountsCard = ({ isDemo, isEuRegion, - isEuUser, marketType, platform, product, @@ -30,7 +29,11 @@ const CompareAccountsCard = ({ }: TCompareAccountsCard) => { return (
-
+
{product === PRODUCT.ZEROSPREAD && (
@@ -62,7 +65,7 @@ const CompareAccountsCard = ({ product={product} shortCode={shortCode} /> - {isEuUser && ( + {isEuRegion && (
diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.scss b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.scss index 2ab2fc5a102e..7a09e0fe6048 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.scss +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.scss @@ -1,13 +1,22 @@ .wallets-compare-accounts-text-container { - height: 24.5rem; + height: 8.5rem; @include mobile-or-tablet-screen { - height: 21rem; + height: 3rem; + } + + &--eu { + height: fit-content; } &--demo { - height: 13.5rem; + height: 11.5rem; + + @include mobile-or-tablet-screen { + height: 8rem; + } } + &__separator { margin: 0.9rem; } diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.tsx index 56cd087cf149..bb2f6e3b0ee0 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsDescription.tsx @@ -38,7 +38,8 @@ const CompareAccountsDescription = ({ return (
@@ -72,39 +73,6 @@ const CompareAccountsDescription = ({
)} - {!isDemo && ( - -
- - {jurisdictionData.counterparty_company} - - - {jurisdictionData.counterparty_company_description} - -
-
- - {jurisdictionData.jurisdiction} - - - {jurisdictionData.jurisdiction_description} - -
-
- - {jurisdictionData.regulator} - - {jurisdictionData.regulator_license && ( - - {jurisdictionData.regulator_license} - - )} - - {jurisdictionData.regulator_description} - -
-
- )}
); }; diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsHeader.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsHeader.tsx index 580db8ffd8f7..7f82003f59b7 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsHeader.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/CompareAccountsHeader.tsx @@ -8,9 +8,10 @@ import './CompareAccountsHeader.scss'; type TCompareAccountsHeader = { isDemo: boolean; isEuRegion: boolean; + isLoading: boolean; }; -const CompareAccountsHeader = ({ isDemo, isEuRegion }: TCompareAccountsHeader) => { +const CompareAccountsHeader = ({ isDemo, isEuRegion, isLoading }: TCompareAccountsHeader) => { const history = useHistory(); const { localize } = useTranslations(); @@ -32,7 +33,7 @@ const CompareAccountsHeader = ({ isDemo, isEuRegion }: TCompareAccountsHeader) =
- {headerText} + {isLoading ? '' : headerText}
{ const { data: activeWallet } = useActiveWalletAccount(); const isRtl = useIsRtl(); - // Temporary false until we have useIsEuRegion() ready - const isEuRegion = false; - const { is_malta_wallet: isEuUser = false, is_virtual: isDemo = false } = activeWallet || {}; + const { data: isEuRegion, isLoading: isEuRegionLoading } = useIsEuRegion(); + const { is_virtual: isDemo = false } = activeWallet || {}; - const { data: compareAccounts, hasCTraderAccountAvailable, hasDxtradeAccountAvailable } = useCFDCompareAccounts(); + const { + data: compareAccounts, + hasCTraderAccountAvailable, + hasDxtradeAccountAvailable, + } = useCFDCompareAccounts(isEuRegion); const { ctraderAccount, dxtradeAccount, mt5Accounts } = compareAccounts; return (
- +
{mt5Accounts?.map((item, index) => ( { { { if (platform === CFD_PLATFORMS.DXTRADE || platform === CFD_PLATFORMS.CTRADER) { return ACCOUNT_ICONS[platform]; } + if (isEuRegion && marketType === MARKET_TYPE.FINANCIAL) { + return ACCOUNT_ICONS[marketType].Eu; + } + + if (marketType === MARKET_TYPE.FINANCIAL) { + return ACCOUNT_ICONS[marketType].NonEU; + } return ( (product === PRODUCT.ZEROSPREAD && ACCOUNT_ICONS[product]) || (marketType && ACCOUNT_ICONS[marketType]) || @@ -65,12 +74,13 @@ const getAccountCardTitle = (shortCode: TMarketWithShortCode | TPlatforms.OtherA const CompareAccountsTitleIcon = ({ isDemo, marketType, platform, product, shortCode }: TCompareAccountsTitleIcon) => { const { localize } = useTranslations(); + const { data: isEuRegion } = useIsEuRegion(); const marketTypeShortCode: TMarketWithShortCode = platform === CFD_PLATFORMS.MT5 && marketType === MARKET_TYPE.ALL ? `${marketType}_${product}_${shortCode}` : `${marketType}_${shortCode}`; - const jurisdictionCardIcon = getAccountIcon(platform, marketType, product); + const jurisdictionCardIcon = getAccountIcon(platform, marketType, product, isEuRegion); const jurisdictionCardTitle = platform === CFD_PLATFORMS.DXTRADE || platform === CFD_PLATFORMS.CTRADER diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsCard.spec.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsCard.spec.tsx index 2b16f73ae469..4c533c3bf3ec 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsCard.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsCard.spec.tsx @@ -1,8 +1,16 @@ -import React from 'react'; +import React, { PropsWithChildren } from 'react'; +import { APIProvider } from '@deriv/api-v2'; import { render, screen } from '@testing-library/react'; +import WalletsAuthProvider from '../../../../../AuthProvider'; import { CFD_PLATFORMS, PRODUCT } from '../../../constants'; import CompareAccountsCard from '../CompareAccountsCard'; +const wrapper = ({ children }: PropsWithChildren) => ( + + {children} + +); + describe('CompareAccountsCard', () => { const defaultProps = { isDemo: false, @@ -14,7 +22,7 @@ describe('CompareAccountsCard', () => { }; it('renders the component with default props', () => { - render(); + render(, { wrapper }); expect(screen.getByText('MT5 Platform')).toBeInTheDocument(); expect(screen.getByText('CFDs')).toBeInTheDocument(); @@ -22,29 +30,30 @@ describe('CompareAccountsCard', () => { expect(screen.getByText('Maximum leverage')).toBeInTheDocument(); expect(screen.getByText('0.5 pips')).toBeInTheDocument(); expect(screen.getByText('Spreads from')).toBeInTheDocument(); - expect(screen.getByText('Deriv (SVG) LLC')).toBeInTheDocument(); }); it('renders the new banner for Zero Spread platform', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('NEW')).toBeInTheDocument(); }); it('does not render the new banner for non Zero Spread platforms', () => { - render(); + render(, { wrapper }); expect(screen.queryByText('NEW')).not.toBeInTheDocument(); }); it('renders the EU clients disclaimer for EU users', () => { - render(); + render(, { wrapper }); expect(screen.getByText('*Boom 300 and Crash 300 Index')).toBeInTheDocument(); }); it('does not render the EU clients disclaimer for non-EU users', () => { - render(); + render(, { wrapper }); expect(screen.queryByText('*Boom 300 and Crash 300 Index')).not.toBeInTheDocument(); }); diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsDescription.spec.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsDescription.spec.tsx index 253d6eaeec13..657a5e369faf 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsDescription.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsDescription.spec.tsx @@ -10,15 +10,8 @@ jest.mock('../compareAccountsConfig', () => ({ describe('CompareAccountsDescription', () => { const mockJurisdictionData = { - counterparty_company: 'Deriv (SVG) LLC', - counterparty_company_description: 'Counterparty company description', - jurisdiction: 'St. Vincent & Grenadines', - jurisdiction_description: 'Jurisdiction description', leverage: 'Up to 1:1000', leverage_description: 'Leverage description', - regulator: 'Financial Commission', - regulator_description: 'Regulator description', - regulator_license: 'License number', spread: '0.6 pips', spread_description: 'Spread description', }; @@ -42,10 +35,6 @@ describe('CompareAccountsDescription', () => { expect(screen.getByText('Leverage description')).toBeInTheDocument(); expect(screen.getByText('0.6 pips')).toBeInTheDocument(); expect(screen.getByText('Spread description')).toBeInTheDocument(); - expect(screen.getByText('Deriv (SVG) LLC')).toBeInTheDocument(); - expect(screen.getByText('St. Vincent & Grenadines')).toBeInTheDocument(); - expect(screen.getByText('Financial Commission')).toBeInTheDocument(); - expect(screen.getByText('License number')).toBeInTheDocument(); }); it('renders correct compare accounts descriptions for demo accounts', () => { @@ -54,8 +43,6 @@ describe('CompareAccountsDescription', () => { expect(screen.getByText('Up to 1:1000')).toBeInTheDocument(); expect(screen.getByText('Leverage description')).toBeInTheDocument(); expect(screen.getByText('0.6 pips')).toBeInTheDocument(); - expect(screen.queryByText('Deriv (SVG) LLC')).not.toBeInTheDocument(); - expect(screen.queryByText('St. Vincent & Grenadines')).not.toBeInTheDocument(); }); it('renders correct compare accounts descriptions for EU region accounts', () => { diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsHeader.spec.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsHeader.spec.tsx index 118765b4976b..6853c15d3eae 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsHeader.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsHeader.spec.tsx @@ -15,31 +15,31 @@ describe('CompareAccountsHeader', () => { }); it('displays CFDs compare accounts header title for non-demo, non-EU accounts', () => { - render(); + render(); expect(screen.getByText('Compare CFDs accounts')).toBeInTheDocument(); }); it('displays CFDs compare accounts header title for demo, non-EU accounts', () => { - render(); + render(); expect(screen.getByText('Compare CFDs demo accounts')).toBeInTheDocument(); }); it('displays MT5 CFDs compare accounts header title for non-demo, EU accounts', () => { - render(); + render(); expect(screen.getByText('Deriv MT5 CFDs real account')).toBeInTheDocument(); }); it('displays MT5 CFDs compare accounts header title for demo, EU accounts', () => { - render(); + render(); expect(screen.getByText('Deriv MT5 CFDs Demo account')).toBeInTheDocument(); }); it('redirects back to root when close icon is clicked', () => { - render(); + render(); const closeIcon = screen.getByTestId('dt_wallets_compare_accounts_header_close_icon'); fireEvent.click(closeIcon); diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsScreen.spec.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsScreen.spec.tsx index 71ccb0821bd7..0cfba6608b03 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsScreen.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsScreen.spec.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { useActiveWalletAccount, useCFDCompareAccounts } from '@deriv/api-v2'; +import { useActiveWalletAccount, useCFDCompareAccounts, useIsEuRegion } from '@deriv/api-v2'; import { render, screen } from '@testing-library/react'; import CompareAccountsScreen from '../CompareAccountsScreen'; jest.mock('@deriv/api-v2', () => ({ useActiveWalletAccount: jest.fn(), useCFDCompareAccounts: jest.fn(), + useIsEuRegion: jest.fn(), })); jest.mock('../../../components', () => ({ @@ -47,6 +48,10 @@ describe('CompareAccountsScreen', () => { hasCTraderAccountAvailable: true, hasDxtradeAccountAvailable: true, }); + (useIsEuRegion as jest.Mock).mockReturnValue(() => ({ + data: false, + isLoading: false, + })); }); it('renders default components correctly', () => { diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsTitleIcon.spec.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsTitleIcon.spec.tsx index 7f807f7b0cd2..df3070d9b04c 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsTitleIcon.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/CompareAccountsTitleIcon.spec.tsx @@ -1,8 +1,16 @@ import React from 'react'; +import { APIProvider } from '@deriv/api-v2'; import { render, screen } from '@testing-library/react'; +import WalletsAuthProvider from '../../../../../AuthProvider'; import { CFD_PLATFORMS } from '../../../constants'; import CompareAccountsTitleIcon from '../CompareAccountsTitleIcon'; +const wrapper = ({ children }: { children: React.ReactNode }) => ( + + {children} + +); + describe('CompareAccountsTitleIcon', () => { const defaultProps = { isDemo: false, @@ -12,43 +20,47 @@ describe('CompareAccountsTitleIcon', () => { }; it('renders default real account title when isDemo is false', () => { - render(); + render(, { wrapper }); expect(screen.getByText('CFDs')).toBeInTheDocument(); }); it('renders default demo account title when isDemo is true', () => { - render(); + render(, { wrapper }); expect(screen.getByText('CFDs Demo')).toBeInTheDocument(); }); it('renders correct title for Deriv X platform', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Deriv X')).toBeInTheDocument(); }); it('renders correct title for demo Deriv X', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Deriv X Demo')).toBeInTheDocument(); }); it('renders correct title for Deriv cTrader platform', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Deriv cTrader')).toBeInTheDocument(); }); it('renders correct title for Deriv cTrader platform', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Deriv cTrader Demo')).toBeInTheDocument(); }); it('renders tooltip for Labuan jurisdiction', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Financial - Labuan')).toBeInTheDocument(); const tooltip = screen.getByTestId('dt_wallets_compare_accounts_title__tooltip'); @@ -56,13 +68,15 @@ describe('CompareAccountsTitleIcon', () => { }); it('does not render tooltip for non-Labuan jurisdictions', () => { - render(); + render(, { wrapper }); expect(screen.queryByTestId('dt_wallets_compare_accounts_title__tooltip')).not.toBeInTheDocument(); }); it('renders correct title for swap-free accounts', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Swap-Free - SVG')).toBeInTheDocument(); }); @@ -74,14 +88,17 @@ describe('CompareAccountsTitleIcon', () => { marketType='all' product='swap_free' shortCode='svg' - /> + />, + { wrapper } ); expect(screen.getByText('Swap-Free Demo')).toBeInTheDocument(); }); it('renders correct title for Zero Spread accounts', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Zero Spread - BVI')).toBeInTheDocument(); }); @@ -93,56 +110,61 @@ describe('CompareAccountsTitleIcon', () => { marketType='all' product='zero_spread' shortCode='bvi' - /> + />, + { wrapper } ); expect(screen.getByText('Zero Spread Demo')).toBeInTheDocument(); }); it('renders correct title for synthetic SVG accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Standard - SVG')).toBeInTheDocument(); }); it('renders correct title for demo SVG accounts', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Standard Demo')).toBeInTheDocument(); }); it('renders correct title for synthetic BVI accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Standard - BVI')).toBeInTheDocument(); }); it('renders correct title for synthetic Vanuatu accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Standard - Vanuatu')).toBeInTheDocument(); }); it('renders correct title for financial SVG accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Financial - SVG')).toBeInTheDocument(); }); it('renders correct title for demo financial SVG accounts', () => { - render(); + render(, { + wrapper, + }); expect(screen.getByText('Financial Demo')).toBeInTheDocument(); }); it('renders correct title for financial BVI accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Financial - BVI')).toBeInTheDocument(); }); it('renders correct title for financial Vanuatu accounts', () => { - render(); + render(, { wrapper }); expect(screen.getByText('Financial - Vanuatu')).toBeInTheDocument(); }); diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/compareAccountsConfig.spec.ts b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/compareAccountsConfig.spec.ts index 4acb0c749571..a993e2e6e8cf 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/compareAccountsConfig.spec.ts +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/__tests__/compareAccountsConfig.spec.ts @@ -1,17 +1,7 @@ import { localize } from '@deriv-com/translations'; import { CFD_PLATFORMS, MARKET_TYPE } from '../../../constants'; -import { - getAccountVerificationStatus, - getHighlightedIconLabel, - getJurisdictionDescription, - getPlatformType, - isCTraderAccountAdded, - isDxtradeAccountAdded, - isMt5AccountAdded, - shouldRestrictBviAccountCreation, - shouldRestrictVanuatuAccountCreation, -} from '../compareAccountsConfig'; -import { JURISDICTION, MARKET_TYPE_SHORTCODE } from '../constants'; +import { getHighlightedIconLabel, getPlatformType } from '../compareAccountsConfig'; +import { JURISDICTION } from '../constants'; describe('compareAccountsConfig', () => { describe('getHighlightedIconLabel', () => { @@ -73,234 +63,4 @@ describe('compareAccountsConfig', () => { expect(getPlatformType('unknown')).toBe('OtherCFDs'); }); }); - - describe('getJurisdictionDescription', () => { - it('returns correct description for synthetic BVI', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.SYNTHETIC_BVI); - expect(result.jurisdiction).toBe('British Virgin Islands'); - }); - - it('returns correct description for financial BVI', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.FINANCIAL_BVI); - expect(result.jurisdiction).toBe('British Virgin Islands'); - }); - - it('returns correct description for synthetic Vanuatu', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.SYNTHETIC_VANUATU); - expect(result.jurisdiction).toBe('Vanuatu'); - }); - - it('returns correct description for financial Vanuatu', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.FINANCIAL_VANUATU); - expect(result.jurisdiction).toBe('Vanuatu'); - }); - - it('returns correct description for financial Labuan', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.FINANCIAL_LABUAN); - expect(result.jurisdiction).toBe('Labuan'); - }); - - it('returns correct description for financial Maltainvest', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.FINANCIAL_MALTAINVEST); - expect(result.jurisdiction).toBe('Malta'); - }); - - it('returns default description for DerivX', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.ALL_DXTRADE); - expect(result).toEqual( - expect.objectContaining({ - jurisdiction: 'St. Vincent & Grenadines', - }) - ); - }); - - it('returns default description for all SVG', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.ALL_SVG); - expect(result).toEqual( - expect.objectContaining({ - jurisdiction: 'St. Vincent & Grenadines', - }) - ); - }); - - it('returns default description for synthetic SVG', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.SYNTHETIC_SVG); - expect(result).toEqual( - expect.objectContaining({ - jurisdiction: 'St. Vincent & Grenadines', - }) - ); - }); - - it('returns default description for financial SVG', () => { - const result = getJurisdictionDescription(localize, MARKET_TYPE_SHORTCODE.FINANCIAL_SVG); - expect(result).toEqual( - expect.objectContaining({ - jurisdiction: 'St. Vincent & Grenadines', - }) - ); - }); - - it('returns default description for unknown shortcode', () => { - const result = getJurisdictionDescription(localize, 'unknown'); - expect(result).toEqual( - expect.objectContaining({ - jurisdiction: 'St. Vincent & Grenadines', - }) - ); - }); - }); - - describe('getAccountVerificationStatus', () => { - it('returns correct status for SVG jurisdiction', () => { - expect(getAccountVerificationStatus(JURISDICTION.SVG, false, false, true)).toBe(true); - }); - - it('returns correct status for BVI jurisdiction', () => { - const authInfo = { - has_poa_been_attempted: true, - has_poi_been_attempted: true, - identity: { services: { manual: { status: 'verified' } } }, - poa_status: 'verified', - risk_classification: 'low', - }; - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.BVI, false, false, true, authInfo)).toBe(true); - }); - - it('returns correct status for high risk classification', () => { - const authInfo = { - has_poa_been_attempted: true, - has_poi_been_attempted: true, - identity: { services: { manual: { status: 'verified' } } }, - poa_status: 'verified', - risk_classification: 'high', - }; - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.BVI, false, false, true, authInfo)).toBe(false); - }); - - it('returns correct status for Vanuatu jurisdiction', () => { - const authInfo = { - has_poa_been_attempted: true, - has_poi_been_attempted: true, - identity: { services: { manual: { status: 'verified' } } }, - poa_status: 'verified', - risk_classification: 'low', - }; - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.VANUATU, false, false, true, authInfo)).toBe(true); - }); - - it('returns correct status for Labuan jurisdiction', () => { - const authInfo = { - has_poa_been_attempted: true, - has_poi_been_attempted: true, - identity: { services: { manual: { status: 'verified' } } }, - poa_status: 'verified', - risk_classification: 'low', - }; - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.LABUAN, false, false, true, authInfo)).toBe(true); - }); - - it('returns correct status for Maltainvest jurisdiction', () => { - const authInfo = { - has_poa_been_attempted: true, - has_poi_been_attempted: true, - identity: { services: { manual: { status: 'verified' } } }, - poa_status: 'verified', - }; - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.MALTAINVEST, false, false, true, authInfo)).toBe(true); - // @ts-expect-error - since this is a mock, we only need partial properties of authInfo - expect(getAccountVerificationStatus(JURISDICTION.MALTAINVEST, false, false, true, authInfo, true)).toBe( - true - ); - }); - }); - - describe('isMt5AccountAdded', () => { - it('returns true if account is added', () => { - const list = [ - { - account_type: 'real', - landing_company_short: 'svg', - market_type: MARKET_TYPE.FINANCIAL, - platform: CFD_PLATFORMS.MT5, - }, - ]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isMt5AccountAdded(list, MARKET_TYPE.FINANCIAL, 'svg')).toBe(true); - }); - - it('returns false if account is not added', () => { - const list = [ - { - account_type: 'real', - landing_company_short: 'svg', - market_type: MARKET_TYPE.FINANCIAL, - platform: CFD_PLATFORMS.MT5, - }, - ]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isMt5AccountAdded(list, MARKET_TYPE.FINANCIAL, 'svg', true)).toBe(false); - }); - }); - - describe('isDxtradeAccountAdded', () => { - it('returns true if account is added', () => { - const list = [{ account_type: 'real', platform: CFD_PLATFORMS.DXTRADE }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isDxtradeAccountAdded(list)).toBe(true); - }); - - it('returns false if account is not added', () => { - const list = [{ account_type: 'real', platform: CFD_PLATFORMS.DXTRADE }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isDxtradeAccountAdded(list, true)).toBe(false); - }); - }); - - describe('isCTraderAccountAdded', () => { - it('returns true if account is added', () => { - const list = [{ account_type: 'real', platform: CFD_PLATFORMS.CTRADER }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isCTraderAccountAdded(list)).toBe(true); - }); - - it('returns false if account is not added', () => { - const list = [{ account_type: 'real', platform: CFD_PLATFORMS.CTRADER }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the list - expect(isCTraderAccountAdded(list, true)).toBe(false); - }); - }); - - describe('shouldRestrictBviAccountCreation', () => { - it('returns true if BVI account creation should be restricted', () => { - const accounts = [{ landing_company_short: 'bvi', status: 'poa_failed' }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the accounts - expect(shouldRestrictBviAccountCreation(accounts)).toBe(true); - }); - - it('returns false if BVI account creation should not be restricted', () => { - const accounts = [{ landing_company_short: 'bvi', status: 'active' }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the accounts - expect(shouldRestrictBviAccountCreation(accounts)).toBe(false); - }); - }); - - describe('shouldRestrictVanuatuAccountCreation', () => { - it('returns true if Vanuatu account creation should be restricted', () => { - const accounts = [{ landing_company_short: 'vanuatu', status: 'poa_failed' }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the accounts - expect(shouldRestrictVanuatuAccountCreation(accounts)).toBe(true); - }); - - it('returns false if Vanuatu account creation should not be restricted', () => { - const accounts = [{ landing_company_short: 'vanuatu', status: 'active' }]; - // @ts-expect-error - since this is a mock, we only need partial properties of the accounts - expect(shouldRestrictVanuatuAccountCreation(accounts)).toBe(false); - }); - }); }); diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/compareAccountsConfig.ts b/packages/wallets/src/features/cfd/screens/CompareAccounts/compareAccountsConfig.ts index 1f6a8ea16870..02a5c870926b 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/compareAccountsConfig.ts +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/compareAccountsConfig.ts @@ -156,15 +156,8 @@ const getPlatformType = (platform: TPlatforms.All) => { }; const cfdConfig = (localize: ReturnType['localize']) => ({ - counterparty_company: localize('Deriv (SVG) LLC'), - counterparty_company_description: localize('Counterparty company'), - jurisdiction: localize('St. Vincent & Grenadines'), - jurisdiction_description: localize('Jurisdiction'), leverage: localize('Up to 1:1000'), leverage_description: localize('Maximum leverage'), - regulator: localize('Financial Commission'), - regulator_description: localize('Regulator/External dispute resolution'), - regulator_license: '', spread: localize('0.5 pips'), spread_description: localize('Spreads from'), }); @@ -173,54 +166,24 @@ const getJurisdictionDescription = (localize: ReturnType switch (shortcode) { case MARKET_TYPE_SHORTCODE.SYNTHETIC_BVI: case MARKET_TYPE_SHORTCODE.FINANCIAL_BVI: - return { - ...cfdConfig(localize), - counterparty_company: localize('Deriv (BVI) Ltd'), - jurisdiction: localize('British Virgin Islands'), - regulator: localize('British Virgin Islands Financial Services Commission'), - regulator_description: localize('Regulator/External dispute resolution'), - regulator_license: localize('(License no. SIBA/L/18/1114)'), - }; + return { ...cfdConfig(localize) }; case MARKET_TYPE_SHORTCODE.SYNTHETIC_VANUATU: case MARKET_TYPE_SHORTCODE.FINANCIAL_VANUATU: - return { - ...cfdConfig(localize), - counterparty_company: localize('Deriv (V) Ltd'), - jurisdiction: localize('Vanuatu'), - regulator: localize('Vanuatu Financial Services Commission'), - regulator_description: localize('Regulator/External dispute resolution'), - regulator_license: '', - }; + return { ...cfdConfig(localize) }; case MARKET_TYPE_SHORTCODE.FINANCIAL_LABUAN: return { ...cfdConfig(localize), - counterparty_company: localize('Deriv (FX) Ltd'), - jurisdiction: localize('Labuan'), leverage: localize('Up to 1:100'), - regulator: localize('Labuan Financial Services Authority'), - regulator_description: localize('Regulator/External dispute resolution'), - regulator_license: localize('(License no. MB/18/0024)'), spread: localize('0.6 pips'), }; case MARKET_TYPE_SHORTCODE.FINANCIAL_MALTAINVEST: return { ...cfdConfig(localize), - counterparty_company: localize('Deriv Investments (Europe) Limited'), - jurisdiction: localize('Malta'), leverage: localize('Up to 1:30'), - regulator: localize('Financial Commission'), - regulator_description: '', - regulator_license: localize( - 'Regulated by the Malta Financial Services Authority (MFSA) (licence no. IS/70156)' - ), }; case MARKET_TYPE_SHORTCODE.ALL_ZERO_SPREAD_BVI: return { ...cfdConfig(localize), - counterparty_company: localize('Deriv (BVI) Ltd'), - jurisdiction: localize('British Virgin Islands'), - regulator: localize('British Virgin Islands Financial Services Commission'), - regulator_license: localize('(License no. SIBA/L/18/1114)'), spread: localize('0.0 pips'), }; case MARKET_TYPE_SHORTCODE.ALL_DXTRADE: @@ -232,120 +195,4 @@ const getJurisdictionDescription = (localize: ReturnType } }; -const acknowledgedStatus = ['pending', 'verified']; - -const getPoiAcknowledgedForMaltainvest = (authenticationInfo?: THooks.Authentication) => { - const services = authenticationInfo?.identity?.services ?? {}; - const { manual: { status: manualStatus } = {}, onfido: { status: onfidoStatus } = {} } = services; - - return [onfidoStatus, manualStatus].some(status => acknowledgedStatus.includes(status ?? '')); -}; - -const getPoiAcknowledgedForBviLabuanVanuatu = (authenticationInfo?: THooks.Authentication) => { - const services = authenticationInfo?.identity?.services ?? {}; - const riskClassification = authenticationInfo?.risk_classification ?? ''; - const { - idv: { status: idvStatus } = {}, - manual: { status: manualStatus } = {}, - onfido: { status: onfidoStatus } = {}, - } = services; - - if (riskClassification === 'high') { - return Boolean(onfidoStatus && acknowledgedStatus.includes(onfidoStatus)); - } - return [idvStatus, onfidoStatus, manualStatus].some(status => acknowledgedStatus.includes(status ?? '')); -}; - -const shouldRestrictBviAccountCreation = (mt5Accounts: THooks.MT5AccountsList[]) => - !!mt5Accounts.filter(item => item?.landing_company_short === 'bvi' && item?.status === 'poa_failed').length; - -const shouldRestrictVanuatuAccountCreation = (mt5Accounts: THooks.MT5AccountsList[]) => - !!mt5Accounts.filter(item => item?.landing_company_short === 'vanuatu' && item?.status === 'poa_failed').length; - -const getAccountVerificationStatus = ( - shortCode: THooks.AvailableMT5Accounts['shortcode'], - shouldRestrictBviAccountCreation: boolean, - shouldRestrictVanuatuAccountCreation: boolean, - hasSubmittedPersonalDetails: boolean, - authenticationInfo?: THooks.Authentication, - isDemo?: boolean -) => { - const { - has_poa_been_attempted: hasPoaBeenAttempted, - has_poi_been_attempted: hasPoiBeenAttempted, - poa_status: poaStatus, - } = authenticationInfo || {}; - const poiOrPoaNotSubmitted = !hasPoaBeenAttempted || !hasPoiBeenAttempted; - const poaAcknowledged = acknowledgedStatus.includes(poaStatus ?? ''); - - const poiAcknowledgedForMaltainvest = getPoiAcknowledgedForMaltainvest(authenticationInfo); - const poiAcknowledgedForBviLabuanVanuatu = getPoiAcknowledgedForBviLabuanVanuatu(authenticationInfo); - - if (shortCode === JURISDICTION.SVG) { - return true; - } - if (shortCode === JURISDICTION.BVI) { - return ( - poiAcknowledgedForBviLabuanVanuatu && - !poiOrPoaNotSubmitted && - !shouldRestrictBviAccountCreation && - hasSubmittedPersonalDetails && - poaAcknowledged - ); - } - if (shortCode === JURISDICTION.VANUATU) { - return ( - poiAcknowledgedForBviLabuanVanuatu && - !poiOrPoaNotSubmitted && - !shouldRestrictVanuatuAccountCreation && - hasSubmittedPersonalDetails && - poaAcknowledged - ); - } - if (shortCode === JURISDICTION.LABUAN) { - return poiAcknowledgedForBviLabuanVanuatu && poaAcknowledged && hasSubmittedPersonalDetails; - } - if (shortCode === JURISDICTION.MALTAINVEST) { - return (poiAcknowledgedForMaltainvest && poaAcknowledged) || isDemo; - } -}; - -const isMt5AccountAdded = ( - list: THooks.MT5AccountsList[], - marketType: TMarketTypes, - companyShortCode: string, - isDemo?: boolean -) => - list.some(item => { - const currentAccountType = isDemo ? 'demo' : 'real'; - return ( - item.account_type === currentAccountType && - item.market_type === marketType && - item.landing_company_short === companyShortCode && - item.platform === CFD_PLATFORMS.MT5 - ); - }); - -const isDxtradeAccountAdded = (list: THooks.DxtradeAccountsList[], isDemo?: boolean) => - list.some(item => { - const currentAccountType = isDemo ? 'demo' : 'real'; - return item.account_type === currentAccountType && item.platform === CFD_PLATFORMS.DXTRADE; - }); - -const isCTraderAccountAdded = (list: THooks.CtraderAccountsList[], isDemo?: boolean) => - list.some(item => { - const currentAccountType = isDemo ? 'demo' : 'real'; - return item.account_type === currentAccountType && item.platform === CFD_PLATFORMS.CTRADER; - }); - -export { - getAccountVerificationStatus, - getHighlightedIconLabel, - getJurisdictionDescription, - getPlatformType, - isCTraderAccountAdded, - isDxtradeAccountAdded, - isMt5AccountAdded, - shouldRestrictBviAccountCreation, - shouldRestrictVanuatuAccountCreation, -}; +export { getHighlightedIconLabel, getJurisdictionDescription, getPlatformType }; diff --git a/packages/wallets/src/features/cfd/screens/CompareAccounts/constants.tsx b/packages/wallets/src/features/cfd/screens/CompareAccounts/constants.tsx index 2abf13e26a0a..dfa701606a1e 100644 --- a/packages/wallets/src/features/cfd/screens/CompareAccounts/constants.tsx +++ b/packages/wallets/src/features/cfd/screens/CompareAccounts/constants.tsx @@ -13,7 +13,7 @@ import { CFD_PLATFORMS, MARKET_TYPE, PRODUCT } from '../../constants'; export const ACCOUNT_ICONS = { [MARKET_TYPE.SYNTHETIC]: , - [MARKET_TYPE.FINANCIAL]: , + [MARKET_TYPE.FINANCIAL]: { Eu: , NonEU: }, [MARKET_TYPE.ALL]: , [CFD_PLATFORMS.DXTRADE]: , [CFD_PLATFORMS.CTRADER]: , diff --git a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeLink/__tests__/MT5TradeLink.spec.tsx b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeLink/__tests__/MT5TradeLink.spec.tsx index 8d69046d52b9..deef80e05123 100644 --- a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeLink/__tests__/MT5TradeLink.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeLink/__tests__/MT5TradeLink.spec.tsx @@ -7,6 +7,9 @@ import MT5TradeLink from '../MT5TradeLink'; jest.mock('@deriv/api-v2', () => ({ useCtraderServiceToken: jest.fn(), + useIsEuRegion: jest.fn(() => ({ + data: false, + })), })); jest.mock('../../../../../../helpers/urls', () => ({ diff --git a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeScreen.tsx b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeScreen.tsx index 2e4982189039..bac2209a597e 100644 --- a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeScreen.tsx +++ b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/MT5TradeScreen.tsx @@ -1,6 +1,6 @@ import React, { FC, Fragment, useMemo } from 'react'; import { useHistory } from 'react-router-dom'; -import { useActiveWalletAccount, useCtraderAccountsList, useDxtradeAccountsList } from '@deriv/api-v2'; +import { useActiveWalletAccount, useCtraderAccountsList, useDxtradeAccountsList, useIsEuRegion } from '@deriv/api-v2'; import { LabelPairedArrowUpArrowDownMdBoldIcon, LabelPairedCircleExclamationMdFillIcon } from '@deriv/quill-icons'; import { Localize, useTranslations } from '@deriv-com/translations'; import { Button, InlineMessage, Text, useDevice } from '@deriv-com/ui'; @@ -27,6 +27,7 @@ const MT5TradeScreen: FC = ({ mt5Account }) => { const { data: dxtradeAccountsList } = useDxtradeAccountsList(); const { data: ctraderAccountsList } = useCtraderAccountsList(); const { data: activeWalletData } = useActiveWalletAccount(); + const { data: isEuRegion } = useIsEuRegion(); const mt5Platform = CFD_PLATFORMS.MT5; const dxtradePlatform = CFD_PLATFORMS.DXTRADE; @@ -36,9 +37,11 @@ const MT5TradeScreen: FC = ({ mt5Account }) => { const platform = getModalState('platform') ?? mt5Platform; const { icon: platformIcon, title: platformTitle } = PlatformDetails[platform as keyof typeof PlatformDetails]; - const { icon: marketTypeIcon, title: marketTypeTitle } = getMarketTypeDetails(localize, mt5Account?.product)[ - marketType ?? 'all' - ]; + const { icon: marketTypeIcon, title: marketTypeTitle } = getMarketTypeDetails( + localize, + mt5Account?.product, + isEuRegion + )[marketType ?? 'all']; const platformToAccountsListMapper = useMemo( () => ({ @@ -96,7 +99,8 @@ const MT5TradeScreen: FC = ({ mt5Account }) => { 'product' in details && //@ts-expect-error needs backend type details.product !== 'stp' && - details.landing_company_name !== 'labuan'; + details.landing_company_name !== 'labuan' && + !isEuRegion; const migrationMessage = useMemo(() => { if (platform === mt5Platform && !activeWalletData?.is_virtual) { diff --git a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/__test__/MT5TradeScreen.spec.tsx b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/__test__/MT5TradeScreen.spec.tsx index 5fd660388f90..79606d1279b1 100644 --- a/packages/wallets/src/features/cfd/screens/MT5TradeScreen/__test__/MT5TradeScreen.spec.tsx +++ b/packages/wallets/src/features/cfd/screens/MT5TradeScreen/__test__/MT5TradeScreen.spec.tsx @@ -20,6 +20,9 @@ jest.mock('@deriv/api-v2', () => ({ useCtraderAccountsList: jest.fn(), useCtraderServiceToken: jest.fn(), useDxtradeAccountsList: jest.fn(), + useIsEuRegion: jest.fn(() => ({ + data: false, + })), })); jest.mock('@deriv-com/ui', () => ({ diff --git a/packages/wallets/src/routes/CompareAccountsRoute/CompareAccountsRoute.scss b/packages/wallets/src/routes/CompareAccountsRoute/CompareAccountsRoute.scss index 9629bafe61b6..78fe7c75bfc0 100644 --- a/packages/wallets/src/routes/CompareAccountsRoute/CompareAccountsRoute.scss +++ b/packages/wallets/src/routes/CompareAccountsRoute/CompareAccountsRoute.scss @@ -1,5 +1,5 @@ .wallets-compare-accounts-route { width: 100%; - height: calc(100vh - 8.4rem); + height: calc(100vh - 3rem); overflow-x: hidden; } diff --git a/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.scss b/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.scss index 8e8bc893ceb7..6dbf3e8300a4 100644 --- a/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.scss +++ b/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.scss @@ -5,7 +5,7 @@ display: flex; flex-direction: column; align-items: center; - justify-content: center; + justify-content: flex-start; padding: 0 4rem; @include tablet-screen { diff --git a/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.tsx b/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.tsx index 7ebb4a6d452c..174dbff51cfe 100644 --- a/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.tsx +++ b/packages/wallets/src/routes/WalletsListingRoute/WalletsListingRoute.tsx @@ -1,7 +1,13 @@ import React, { lazy } from 'react'; -import { useWalletAccountsList } from '@deriv/api-v2'; +import { useActiveWalletAccount, useAllWalletAccounts, useIsEuRegion } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; -import { WalletListHeader, WalletsAddMoreCarousel, WalletsCardLoader, WalletsResponsiveLoader } from '../../components'; +import { + WalletListHeader, + WalletsAddMoreCarousel, + WalletsCardLoader, + WalletsDisclaimerBanner, + WalletsResponsiveLoader, +} from '../../components'; import ResetMT5PasswordHandler from '../../features/cfd/ResetMT5PasswordHandler'; import './WalletsListingRoute.scss'; @@ -10,8 +16,11 @@ const LazyDesktopWalletsList = lazy(() => import('../../components/DesktopWallet const WalletsListingRoute: React.FC = () => { const { isDesktop } = useDevice(); - const { data: wallets } = useWalletAccountsList(); - const hasAnyActiveRealWallets = wallets?.some(wallet => !wallet.is_virtual && !wallet.is_disabled); + const { data: isEuRegion, isLoading: isEuRegionLoading } = useIsEuRegion(); + const { data: activeWallet } = useActiveWalletAccount(); + const { data: allWallets, isLoading: isAllWalletsLoading } = useAllWalletAccounts(); + const hasAddedWallet = allWallets?.some(wallet => wallet.is_added); + const shouldHideAddMoreCarousel = isAllWalletsLoading || isEuRegionLoading || (isEuRegion && hasAddedWallet); return (
@@ -25,8 +34,9 @@ const WalletsListingRoute: React.FC = () => { )} - {hasAnyActiveRealWallets && } + {shouldHideAddMoreCarousel ? null : } + {isEuRegion && !activeWallet?.is_virtual && }
); }; diff --git a/packages/wallets/src/routes/WalletsListingRoute/__tests__/WalletsListingRoute.spec.tsx b/packages/wallets/src/routes/WalletsListingRoute/__tests__/WalletsListingRoute.spec.tsx index 4bb1959dda11..5063c1cfc8ed 100644 --- a/packages/wallets/src/routes/WalletsListingRoute/__tests__/WalletsListingRoute.spec.tsx +++ b/packages/wallets/src/routes/WalletsListingRoute/__tests__/WalletsListingRoute.spec.tsx @@ -1,5 +1,5 @@ import React, { PropsWithChildren } from 'react'; -import { APIProvider, AuthProvider, useWalletAccountsList } from '@deriv/api-v2'; +import { APIProvider, AuthProvider, useActiveWalletAccount, useIsEuRegion, useWalletAccountsList } from '@deriv/api-v2'; import { useDevice } from '@deriv-com/ui'; import { render, screen } from '@testing-library/react'; import { ModalProvider } from '../../../components/ModalProvider'; @@ -7,6 +7,8 @@ import WalletsListingRoute from '../WalletsListingRoute'; jest.mock('@deriv/api-v2', () => ({ ...jest.requireActual('@deriv/api-v2'), + useActiveWalletAccount: jest.fn(() => ({ data: { is_virtual: false } })), + useIsEuRegion: jest.fn(() => ({ data: true })), useWalletAccountsList: jest.fn(), })); @@ -19,6 +21,7 @@ jest.mock('../../../components', () => ({ ...jest.requireActual('../../../components'), WalletListHeader: () =>
WalletListHeader
, WalletsAddMoreCarousel: () =>
WalletsAddMoreCarousel
, + WalletsDisclaimerBanner: () =>
WalletsDisclaimerBanner
, WalletTourGuide: () =>
WalletTourGuide
, })); @@ -72,19 +75,26 @@ describe('WalletsListingRoute', () => { expect(await screen.findByText('WalletsCarousel')).toBeInTheDocument(); }); - it('hides the wallet add more carousel if a user has no enabled real accounts', () => { + it('hides the wallet add more carousel if a user has added a wallet', () => { (useWalletAccountsList as jest.Mock).mockReturnValue({ - data: [ - { - currency: 'USD', - currency_config: { fractional_digits: 2 }, - is_disabled: true, - is_virtual: false, - loginid: 'CR1', - }, - ], + data: [{ is_added: true }], }); render(, { wrapper }); expect(screen.queryByText('WalletsAddMoreCarousel')).not.toBeInTheDocument(); }); + + it('displays the wallet disclaimer banner if the user is in the EU region and has a non-virtual wallet', () => { + (useDevice as jest.Mock).mockReturnValue({ isDesktop: true, isMobile: false }); + (useIsEuRegion as jest.Mock).mockReturnValue({ data: true }); + render(, { wrapper }); + expect(screen.getByText('WalletsDisclaimerBanner')).toBeInTheDocument(); + }); + + it('does not display the wallet disclaimer banner if the user is in the EU region and the active wallet is a virtual wallet', () => { + (useDevice as jest.Mock).mockReturnValue({ isDesktop: true, isMobile: false }); + (useActiveWalletAccount as jest.Mock).mockReturnValue({ data: { is_virtual: true } }); + (useIsEuRegion as jest.Mock).mockReturnValue({ data: true }); + render(, { wrapper }); + expect(screen.queryByText('WalletsDisclaimerBanner')).not.toBeInTheDocument(); + }); });