diff --git a/changelog/fix-6497-advanced-fraud-settings-empty b/changelog/fix-6497-advanced-fraud-settings-empty new file mode 100644 index 00000000000..98e38c0b807 --- /dev/null +++ b/changelog/fix-6497-advanced-fraud-settings-empty @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Add notice when no rules are enabled in advanced fraud settings diff --git a/client/settings/fraud-protection/advanced-settings/index.tsx b/client/settings/fraud-protection/advanced-settings/index.tsx index 3c910898159..f18b70a624d 100644 --- a/client/settings/fraud-protection/advanced-settings/index.tsx +++ b/client/settings/fraud-protection/advanced-settings/index.tsx @@ -70,20 +70,28 @@ const observerEventMapping: Record< string, string > = { }; const Breadcrumb = () => ( -

- - { 'WooPayments' } - -  >  - { __( 'Advanced fraud protection', 'woocommerce-payments' ) } -

+ <> +

+ + { 'WooPayments' } + +  >  + { __( 'Advanced fraud protection', 'woocommerce-payments' ) } +

+

+ { __( + 'At least one risk filter needs to be enabled for advanced protection.', + 'woocommerce-payments' + ) } +

+ ); const SaveFraudProtectionSettingsButton: React.FC = ( { children } ) => { @@ -154,42 +162,66 @@ const FraudProtectionAdvancedSettingsPage: React.FC = () => { .every( Boolean ); }; + const checkAnyRuleFilterEnabled = ( + settings: ProtectionSettingsUI + ): boolean => { + return Object.values( settings ).some( ( setting ) => setting.enabled ); + }; + const handleSaveSettings = () => { - if ( validateSettings( protectionSettingsUI ) ) { - if ( ProtectionLevel.ADVANCED !== currentProtectionLevel ) { - updateProtectionLevel( ProtectionLevel.ADVANCED ); - dispatch( 'core/notices' ).createSuccessNotice( + if ( ! validateSettings( protectionSettingsUI ) ) { + window.scrollTo( { + top: 0, + } ); + return; + } + + if ( ! checkAnyRuleFilterEnabled( protectionSettingsUI ) ) { + if ( ProtectionLevel.BASIC === currentProtectionLevel ) { + dispatch( 'core/notices' ).createErrorNotice( __( - 'Current protection level is set to "advanced".', + 'At least one risk filter needs to be enabled for advanced protection.', 'woocommerce-payments' ) ); + return; } - const settings = writeRuleset( protectionSettingsUI ); + updateProtectionLevel( ProtectionLevel.BASIC ); + dispatch( 'core/notices' ).createErrorNotice( + __( + 'Current protection level is set to "basic". At least one risk filter needs to be enabled for advanced protection.', + 'woocommerce-payments' + ) + ); + } else if ( ProtectionLevel.ADVANCED !== currentProtectionLevel ) { + updateProtectionLevel( ProtectionLevel.ADVANCED ); + dispatch( 'core/notices' ).createSuccessNotice( + __( + 'Current protection level is set to "advanced".', + 'woocommerce-payments' + ) + ); + } - // Persist the AVS verification setting until the account cache is updated locally. - if ( - wcpaySettings?.accountStatus?.fraudProtection - ?.declineOnAVSFailure - ) { - wcpaySettings.accountStatus.fraudProtection.declineOnAVSFailure = settings.some( - ( setting ) => setting.key === 'avs_verification' - ); - } + const settings = writeRuleset( protectionSettingsUI ); - updateAdvancedFraudProtectionSettings( settings ); + // Persist the AVS verification setting until the account cache is updated locally. + if ( + wcpaySettings?.accountStatus?.fraudProtection?.declineOnAVSFailure + ) { + wcpaySettings.accountStatus.fraudProtection.declineOnAVSFailure = settings.some( + ( setting ) => setting.key === 'avs_verification' + ); + } - saveSettings(); + updateAdvancedFraudProtectionSettings( settings ); - recordEvent( 'wcpay_fraud_protection_advanced_settings_saved', { - settings: JSON.stringify( settings ), - } ); - } else { - window.scrollTo( { - top: 0, - } ); - } + saveSettings(); + + recordEvent( 'wcpay_fraud_protection_advanced_settings_saved', { + settings: JSON.stringify( settings ), + } ); }; // Hack to make "Payments > Settings" the active selected menu item. diff --git a/client/settings/fraud-protection/advanced-settings/test/__snapshots__/index.test.tsx.snap b/client/settings/fraud-protection/advanced-settings/test/__snapshots__/index.test.tsx.snap index abd09b5d4c7..dffbf33c6b1 100644 --- a/client/settings/fraud-protection/advanced-settings/test/__snapshots__/index.test.tsx.snap +++ b/client/settings/fraud-protection/advanced-settings/test/__snapshots__/index.test.tsx.snap @@ -66,6 +66,11 @@ Object {  >  Advanced fraud protection +

+ At least one risk filter needs to be enabled for advanced protection. +

@@ -1066,6 +1071,11 @@ Object {  >  Advanced fraud protection +

+ At least one risk filter needs to be enabled for advanced protection. +

@@ -2149,6 +2159,11 @@ Object {  >  Advanced fraud protection +

+ At least one risk filter needs to be enabled for advanced protection. +

@@ -3006,6 +3021,11 @@ Object {  >  Advanced fraud protection +

+ At least one risk filter needs to be enabled for advanced protection. +

@@ -3926,6 +3946,11 @@ Object {  >  Advanced fraud protection +

+ At least one risk filter needs to be enabled for advanced protection. +

+

+ At least one risk filter needs to be enabled for advanced protection. +

+

+ At least one risk filter needs to be enabled for advanced protection. +

+

+ At least one risk filter needs to be enabled for advanced protection. +

( { dispatch: jest.fn( () => ( { setIsMatching: jest.fn(), createSuccessNotice: jest.fn(), + createErrorNotice: jest.fn(), onLoad: jest.fn(), } ) ), registerStore: jest.fn(), @@ -438,4 +439,45 @@ describe( 'Advanced fraud protection settings', () => { expect( protectionLevelState.updateState.mock.calls.length ).toBe( 0 ); expect( protectionLevelState.updateState.mock.calls ).toEqual( [] ); } ); + test( 'does not update protection level to advanced when no risk rules are enabled', async () => { + const protectionLevelState = { + state: 'standard', + updateState: jest.fn( ( level ) => { + protectionLevelState.state = level; + } ), + }; + mockUseCurrentProtectionLevel.mockReturnValue( [ + protectionLevelState.state, + protectionLevelState.updateState, + ] ); + mockUseSettings.mockReturnValue( { + settings: { + advanced_fraud_protection_settings: defaultSettings, + }, + isSaving: false, + saveSettings: jest.fn(), + isLoading: false, + } ); + mockUseAdvancedFraudProtectionSettings.mockReturnValue( [ + defaultSettings, + jest.fn(), + ] ); + container = render( +
+
+
+
+ +
+ ); + const [ saveButton ] = await container.findAllByText( 'Save Changes' ); + saveButton.click(); + await waitFor( () => { + expect( mockUseSettings().saveSettings.mock.calls.length ).toBe( + 1 + ); + } ); + + expect( protectionLevelState.state ).toBe( 'basic' ); + } ); } ); diff --git a/client/settings/fraud-protection/style.scss b/client/settings/fraud-protection/style.scss index 70d75d9f0b5..1981d4b3559 100644 --- a/client/settings/fraud-protection/style.scss +++ b/client/settings/fraud-protection/style.scss @@ -43,7 +43,7 @@ } &-header-breadcrumb { margin-top: 0; - margin-bottom: 24px; + margin-bottom: 8px; @media screen and ( min-width: 961px ) { margin-top: -16px; } @@ -261,6 +261,10 @@ ); cursor: pointer; } + &-advanced-settings-notice { + margin-top: 0; + margin-bottom: 16px; + } } .components-modal__header {