Skip to content

Commit

Permalink
Add value to Protect card - Cleanup, refactor, & final enhancements. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
elliottprogrammer authored Jul 24, 2024
1 parent 36b2d52 commit 4b63023
Show file tree
Hide file tree
Showing 10 changed files with 431 additions and 164 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const AutoFirewallStatus = () => {
const {
protect: { wafConfig: wafData },
} = getMyJetpackWindowInitialState();
const { jetpack_waf_automatic_rules: isAutoFirewallEnabled } = wafData;
const { jetpack_waf_automatic_rules: isAutoFirewallEnabled } = wafData || {};

if ( isPluginActive && isSiteConnected ) {
if ( isAutoFirewallEnabled ) {
return <WafStatus status="success" />;
return <WafStatus status="active" />;
}

return <WafStatus status="inactive" />;
Expand All @@ -34,18 +34,18 @@ export const AutoFirewallStatus = () => {
* WafStatus component
*
* @param {PropsWithChildren} props - The component props
* @param {'success' | 'inactive' | 'off'} props.status - The number of threats
* @param {'active' | 'inactive' | 'off'} props.status - The status of the WAF
*
* @returns {ReactElement} rendered component
*/
function WafStatus( { status }: { status: 'success' | 'inactive' | 'off' } ) {
function WafStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) {
const slug = 'protect';
const { detail } = useProduct( slug );
const { hasPaidPlanForProduct: hasProtectPaidPlan } = detail;
const { hasPaidPlanForProduct = false } = detail || {};
const tooltipContent = useProtectTooltipCopy();
const { autoFirewallTooltip } = tooltipContent;

if ( status === 'success' ) {
if ( status === 'active' ) {
return (
<>
<div>
Expand All @@ -70,21 +70,19 @@ function WafStatus( { status }: { status: 'success' | 'inactive' | 'off' } ) {
/>
</div>
<div className="value-section__status-text">{ __( 'Inactive', 'jetpack-my-jetpack' ) }</div>
{ ! hasProtectPaidPlan && (
<InfoTooltip
tracksEventName={ 'protect_card_tooltip_open' }
tracksEventProps={ {
location: 'auto-firewall',
status: 'inactive',
hasPaidPlan: false,
} }
>
<>
<h3 className="value-section__tooltip-heading">{ autoFirewallTooltip.title }</h3>
<p className="value-section__tooltip-content">{ autoFirewallTooltip.text }</p>
</>
</InfoTooltip>
) }
<InfoTooltip
tracksEventName={ 'protect_card_tooltip_open' }
tracksEventProps={ {
location: 'auto-firewall',
status: status,
has_paid_plan: hasPaidPlanForProduct,
} }
>
<>
<h3 className="value-section__tooltip-heading">{ autoFirewallTooltip.title }</h3>
<p className="value-section__tooltip-content">{ autoFirewallTooltip.text }</p>
</>
</InfoTooltip>
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const ProtectCard: FC< { admin: boolean } > = ( { admin } ) => {
const { recordEvent } = useAnalytics();
const slug = 'protect';
const { detail } = useProduct( slug );
const { isPluginActive, hasPaidPlanForProduct: hasProtectPaidPlan } = detail;
const { isPluginActive, hasPaidPlanForProduct: hasProtectPaidPlan } = detail || {};

/**
* Called when secondary "View" button is clicked.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { __ } from '@wordpress/i18n';
import useProduct from '../../../data/products/use-product';
import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state';
import useMyJetpackConnection from '../../../hooks/use-my-jetpack-connection';
import { isJetpackPluginActive } from '../../../utils/is-jetpack-plugin-active';
import ShieldOff from './assets/shield-off.svg';
import ShieldPartial from './assets/shield-partial.svg';
import { InfoTooltip } from './info-tooltip';
import { useProtectTooltipCopy } from './use-protect-tooltip-copy';
import type { ReactElement, PropsWithChildren } from 'react';

export const LoginsBlockedStatus = () => {
const slug = 'protect';
const { detail } = useProduct( slug );
const { isPluginActive: isProtectPluginActive = false } = detail || {};
const { isSiteConnected } = useMyJetpackConnection();
const {
protect: { wafConfig: wafData },
} = getMyJetpackWindowInitialState();
const { blocked_logins: blockedLoginsCount, brute_force_protection: hasBruteForceProtection } =
wafData || {};

// The Brute Force Protection module is available when either the Jetpack plugin Or the Protect plugin is active.
const isPluginActive = isProtectPluginActive || isJetpackPluginActive();

if ( isPluginActive && isSiteConnected ) {
if ( hasBruteForceProtection ) {
return <BlockedStatus status="active" />;
}

return <BlockedStatus status="inactive" />;
}
if ( isSiteConnected && blockedLoginsCount > 0 ) {
// logins have been blocked previoulsy, but either the Jetpack or Protect plugin is not active
return <BlockedStatus status="inactive" />;
}
return <BlockedStatus status="off" />;
};

/**
* BlockedStatus component
*
* @param {PropsWithChildren} props - The component props
* @param {'active' | 'inactive' | 'off'} props.status - The status of Brute Force Protection
*
* @returns {ReactElement} rendered component
*/
function BlockedStatus( { status }: { status: 'active' | 'inactive' | 'off' } ) {
const {
protect: { wafConfig: wafData },
} = getMyJetpackWindowInitialState();
const { blocked_logins: blockedLoginsCount } = wafData || {};

const tooltipContent = useProtectTooltipCopy();
const { blockedLoginsTooltip } = tooltipContent;

if ( status === 'active' ) {
return blockedLoginsCount > 0 ? (
<div className="logins_blocked__count">{ blockedLoginsCount }</div>
) : (
<>
<div>
<img
className="value-section__status-icon"
src={ ShieldPartial }
alt={ __(
'Shield icon - Brute Force Protection Status: Active',
'jetpack-my-jetpack'
) }
/>
</div>
<InfoTooltip
tracksEventName={ 'protect_card_tooltip_open' }
tracksEventProps={ {
location: 'blocked-logins',
status: status,
message: 'no data yet',
} }
>
<>
<h3 className="value-section__tooltip-heading">{ blockedLoginsTooltip.title }</h3>
<p className="value-section__tooltip-content">{ blockedLoginsTooltip.text }</p>
</>
</InfoTooltip>
</>
);
}
if ( status === 'inactive' ) {
return (
<>
{ blockedLoginsCount > 0 ? (
<>
<div>
<img
className="value-section__status-icon"
src={ ShieldOff }
alt={ __(
'Shield icon - Brute Force Protection Status: Inactive',
'jetpack-my-jetpack'
) }
/>
</div>
<div className="logins_blocked__count">{ blockedLoginsCount }</div>
</>
) : (
<div>
<img
className="value-section__status-icon"
src={ ShieldOff }
alt={ __(
'Shield icon - Brute Force Protection Status: Inactive',
'jetpack-my-jetpack'
) }
/>
</div>
) }
<InfoTooltip
tracksEventName={ 'protect_card_tooltip_open' }
tracksEventProps={ {
location: 'blocked-logins',
status: status,
} }
>
<>
<h3 className="value-section__tooltip-heading">{ blockedLoginsTooltip.title }</h3>
<p className="value-section__tooltip-content">{ blockedLoginsTooltip.text }</p>
</>
</InfoTooltip>
</>
);
}
return (
<>
<div>
<img
className="value-section__status-icon"
src={ ShieldOff }
alt={ __( 'Shield icon - Brute Force Protection Status: Off', 'jetpack-my-jetpack' ) }
/>
</div>
<div className="value-section__status-text">{ __( 'Off', 'jetpack-my-jetpack' ) }</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,91 +1,26 @@
import { __, _n, sprintf } from '@wordpress/i18n';
import { useMemo } from 'react';
import useProduct from '../../../data/products/use-product';
import { getMyJetpackWindowInitialState } from '../../../data/utils/get-my-jetpack-window-state';
import { timeSince } from '../../../utils/time-since';
import { AutoFirewallStatus } from './auto-firewall-status';
import { InfoTooltip } from './info-tooltip';
import { LoginsBlockedStatus } from './logins-blocked-status';
import { ScanAndThreatStatus } from './scan-threats-status';
import { useLastScanText } from './use-last-scan-text';
import { useProtectTooltipCopy } from './use-protect-tooltip-copy';
import type { TooltipContent } from './use-protect-tooltip-copy';
import type { FC } from 'react';

import './style.scss';

const ProtectValueSection = () => {
const slug = 'protect';
const { detail } = useProduct( slug );
const { isPluginActive = false } = detail || {};
const {
plugins,
themes,
protect: { scanData },
} = getMyJetpackWindowInitialState();
const {
plugins: fromScanPlugins,
themes: fromScanThemes,
num_threats: numThreats = 0,
last_checked: lastScanTime = null,
} = scanData;

const pluginsCount = fromScanPlugins.length || Object.keys( plugins ).length;
const themesCount = fromScanThemes.length || Object.keys( themes ).length;

const timeSinceLastScan = lastScanTime ? timeSince( Date.parse( lastScanTime ) ) : false;
const lastScanText = useMemo( () => {
if ( isPluginActive ) {
if ( timeSinceLastScan ) {
return sprintf(
/* translators: %s is how long ago since the last scan took place, i.e.- "17 hours ago" */
__( 'Last scan: %s', 'jetpack-my-jetpack' ),
timeSinceLastScan
);
}
return null;
}
return (
sprintf(
/* translators: %d is the number of plugins installed on the site. */
_n( '%d plugin', '%d plugins', pluginsCount, 'jetpack-my-jetpack' ),
pluginsCount
) +
' ' +
/* translators: The ampersand symbol here (&) is meaning "and". */
__( '&', 'jetpack-my-jetpack' ) +
'\xa0' + // `\xa0` is a non-breaking space.
sprintf(
/* translators: %d is the number of themes installed on the site. */
_n( '%d theme', '%d themes', themesCount, 'jetpack-my-jetpack' ).replace( ' ', '\xa0' ), // `\xa0` is a non-breaking space.
themesCount
)
);
}, [ isPluginActive, timeSinceLastScan, pluginsCount, themesCount ] );

const tooltipContent = useProtectTooltipCopy( { pluginsCount, themesCount, numThreats } );

return (
<ValueSection
isProtectActive={ isPluginActive }
lastScanText={ lastScanText }
tooltipContent={ tooltipContent }
/>
);
};

export default ProtectValueSection;

const ValueSection: FC< {
isProtectActive: boolean;
lastScanText?: string;
tooltipContent: TooltipContent;
} > = ( { isProtectActive, lastScanText, tooltipContent } ) => {
const lastScanText = useLastScanText();
const tooltipContent = useProtectTooltipCopy();
const { pluginsThemesTooltip } = tooltipContent;

return (
<>
<div className="value-section__last-scan">
{ lastScanText && <div>{ lastScanText }</div> }
{ ! isProtectActive && (
{ ! isPluginActive && (
<InfoTooltip
tracksEventName={ 'protect_card_tooltip_open' }
tracksEventProps={ {
Expand Down Expand Up @@ -121,11 +56,4 @@ const ValueSection: FC< {
);
};

const LoginsBlockedStatus = () => {
const {
protect: { wafConfig: wafData },
} = getMyJetpackWindowInitialState();
const { blocked_logins: blockedLoginsCount = 0 } = wafData || {};

return <div className="logins_blocked__count">{ blockedLoginsCount }</div>;
};
export default ProtectValueSection;
Loading

0 comments on commit 4b63023

Please sign in to comment.