diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84ae625f40c0a..fd2a17d0423b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4108,8 +4108,8 @@ importers: specifier: 18.3.1 version: 18.3.1(react@18.3.1) react-router-dom: - specifier: 6.2.2 - version: 6.2.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 6.24.0 + version: 6.24.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: '@automattic/jetpack-webpack-config': specifier: workspace:* @@ -6526,6 +6526,10 @@ packages: resolution: {integrity: sha512-WOHih+ClN7N8oHk9N4JUiMxQJmRVaOxcg8w7F/oHUXzJt920ekASLI/7cYX8XkntDWRhLZtsk6LbGrkgOAvi5A==} engines: {node: '>=14.0.0'} + '@remix-run/router@1.17.0': + resolution: {integrity: sha512-2D6XaHEVvkCn682XBnipbJjgZUU7xjLtA4dGJRBVUKpEaDYOZMENZoZjAOSb7qirxt5RupjzZxz4fK2FO+EFPw==} + engines: {node: '>=14.0.0'} + '@remix-run/router@1.2.1': resolution: {integrity: sha512-XiY0IsyHR+DXYS5vBxpoBe/8veTeoRpMHP+vDosLZxL5bnpetzI0igkxkLZS235ldLzyfkxF+2divEwWHP3vMQ==} engines: {node: '>=14'} @@ -12734,14 +12738,15 @@ packages: react: '>=16.8' react-dom: '>=16.8' - react-router-dom@6.2.2: - resolution: {integrity: sha512-AtYEsAST7bDD4dLSQHDnk/qxWLJdad5t1HFa1qJyUrCeGgEuCSw0VB/27ARbF9Fi/W5598ujvJOm3ujUCVzuYQ==} + react-router-dom@6.21.0: + resolution: {integrity: sha512-1dUdVj3cwc1npzJaf23gulB562ESNvxf7E4x8upNJycqyUm5BRRZ6dd3LrlzhtLaMrwOCO8R0zoiYxdaJx4LlQ==} + engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' - react-router-dom@6.21.0: - resolution: {integrity: sha512-1dUdVj3cwc1npzJaf23gulB562ESNvxf7E4x8upNJycqyUm5BRRZ6dd3LrlzhtLaMrwOCO8R0zoiYxdaJx4LlQ==} + react-router-dom@6.24.0: + resolution: {integrity: sha512-960sKuau6/yEwS8e+NVEidYQb1hNjAYM327gjEyXlc6r3Skf2vtwuJ2l7lssdegD2YjoKG5l8MsVyeTDlVeY8g==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -12771,13 +12776,14 @@ packages: peerDependencies: react: '>=16.8' - react-router@6.2.2: - resolution: {integrity: sha512-/MbxyLzd7Q7amp4gDOGaYvXwhEojkJD5BtExkuKmj39VEE0m3l/zipf6h2WIB2jyAO0lI6NGETh4RDcktRm4AQ==} + react-router@6.21.0: + resolution: {integrity: sha512-hGZ0HXbwz3zw52pLZV3j3+ec+m/PQ9cTpBvqjFQmy2XVUWGn5MD+31oXHb6dVTxYzmAeaiUBYjkoNz66n3RGCg==} + engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' - react-router@6.21.0: - resolution: {integrity: sha512-hGZ0HXbwz3zw52pLZV3j3+ec+m/PQ9cTpBvqjFQmy2XVUWGn5MD+31oXHb6dVTxYzmAeaiUBYjkoNz66n3RGCg==} + react-router@6.24.0: + resolution: {integrity: sha512-sQrgJ5bXk7vbcC4BxQxeNa5UmboFm35we1AFK0VvQaz9g0LzxEIuLOhHIoZ8rnu9BO21ishGeL9no1WB76W/eg==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -16760,6 +16766,8 @@ snapshots: '@remix-run/router@1.14.0': {} + '@remix-run/router@1.17.0': {} + '@remix-run/router@1.2.1': {} '@remix-run/router@1.5.0': {} @@ -25820,19 +25828,19 @@ snapshots: react-dom: 18.3.1(react@18.3.1) react-router: 6.14.1(react@18.3.1) - react-router-dom@6.2.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.21.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - history: 5.3.0 + '@remix-run/router': 1.14.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.2.2(react@18.3.1) + react-router: 6.21.0(react@18.3.1) - react-router-dom@6.21.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.24.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@remix-run/router': 1.14.0 + '@remix-run/router': 1.17.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.21.0(react@18.3.1) + react-router: 6.24.0(react@18.3.1) react-router-dom@6.6.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -25864,14 +25872,14 @@ snapshots: '@remix-run/router': 1.7.1 react: 18.3.1 - react-router@6.2.2(react@18.3.1): + react-router@6.21.0(react@18.3.1): dependencies: - history: 5.3.0 + '@remix-run/router': 1.14.0 react: 18.3.1 - react-router@6.21.0(react@18.3.1): + react-router@6.24.0(react@18.3.1): dependencies: - '@remix-run/router': 1.14.0 + '@remix-run/router': 1.17.0 react: 18.3.1 react-router@6.6.2(react@18.3.1): diff --git a/projects/plugins/protect/package.json b/projects/plugins/protect/package.json index c0b14dafaa139..fda695736daa1 100644 --- a/projects/plugins/protect/package.json +++ b/projects/plugins/protect/package.json @@ -44,7 +44,7 @@ "prop-types": "15.8.1", "react": "18.3.1", "react-dom": "18.3.1", - "react-router-dom": "6.2.2" + "react-router-dom": "6.24.0" }, "devDependencies": { "@automattic/jetpack-webpack-config": "workspace:*", diff --git a/projects/plugins/protect/src/class-jetpack-protect.php b/projects/plugins/protect/src/class-jetpack-protect.php index 854978215ee46..26730756a952c 100644 --- a/projects/plugins/protect/src/class-jetpack-protect.php +++ b/projects/plugins/protect/src/class-jetpack-protect.php @@ -212,7 +212,6 @@ public function initial_state() { 'apiNonce' => wp_create_nonce( 'wp_rest' ), 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ), 'status' => Status::get_status( $refresh_status_from_wpcom ), - 'viewingScanHistory' => false, 'scanHistory' => Scan_History::get_scan_history( $refresh_status_from_wpcom ), 'installedPlugins' => Plugins_Installer::get_plugins(), 'installedThemes' => Sync_Functions::get_themes(), diff --git a/projects/plugins/protect/src/class-rest-controller.php b/projects/plugins/protect/src/class-rest-controller.php index 0e11a3d08bd24..6e082b5a8bd68 100644 --- a/projects/plugins/protect/src/class-rest-controller.php +++ b/projects/plugins/protect/src/class-rest-controller.php @@ -198,30 +198,6 @@ public static function register_rest_endpoints() { }, ) ); - - register_rest_route( - 'jetpack-protect/v1', - 'scan-history', - array( - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => __CLASS__ . '::api_get_scan_history', - 'permission_callback' => function () { - return current_user_can( 'manage_options' ); - }, - ) - ); - - register_rest_route( - 'jetpack-protect/v1', - 'clear-scan-history-cache', - array( - 'methods' => \WP_REST_Server::EDITABLE, - 'callback' => __CLASS__ . '::api_clear_scan_history_cache', - 'permission_callback' => function () { - return current_user_can( 'manage_options' ); - }, - ) - ); } /** @@ -433,31 +409,4 @@ public static function api_complete_onboarding_steps( $request ) { return new WP_REST_Response( 'Onboarding step(s) completed.' ); } - - /** - * Return Scan History for the API endpoint - * - * @param WP_REST_Request $request The request object. - * - * @return WP_REST_Response - */ - public static function api_get_scan_history( $request ) { - $scan_history = Scan_History::get_scan_history( false, $request['filter'] ); - return rest_ensure_response( $scan_history, 200 ); - } - - /** - * Clear the Scan_History cache for the API endpoint - * - * @return WP_REST_Response - */ - public static function api_clear_scan_history_cache() { - $cache_cleared = Scan_History::delete_option(); - - if ( ! $cache_cleared ) { - return new WP_REST_Response( 'An error occured while attempting to clear the Jetpack Scan history cache.', 500 ); - } - - return new WP_REST_Response( 'Jetpack Scan history cache cleared.' ); - } } diff --git a/projects/plugins/protect/src/class-scan-history.php b/projects/plugins/protect/src/class-scan-history.php index b671c83c30bf0..cdbedeed07c25 100644 --- a/projects/plugins/protect/src/class-scan-history.php +++ b/projects/plugins/protect/src/class-scan-history.php @@ -114,10 +114,9 @@ public static function delete_option() { * Gets the current history of the Jetpack Protect checks * * @param bool $refresh_from_wpcom Refresh the local plan and history cache from wpcom. - * @param array $filter The filter to apply to the data. * @return History_Model|bool */ - public static function get_scan_history( $refresh_from_wpcom = false, $filter = null ) { + public static function get_scan_history( $refresh_from_wpcom = false ) { $has_required_plan = Plan::has_required_plan(); if ( ! $has_required_plan ) { return false; @@ -142,7 +141,7 @@ public static function get_scan_history( $refresh_from_wpcom = false, $filter = ) ); } else { - $history = self::normalize_api_data( $history, $filter ); + $history = self::normalize_api_data( $history ); } self::$history = $history; @@ -204,156 +203,30 @@ public static function fetch_from_api() { * Formats the payload from the Scan API into an instance of History_Model. * * @param object $scan_data The data returned by the scan API. - * @param array $filter The filter to apply to the data. * @return History_Model */ - private static function normalize_api_data( $scan_data, $filter ) { - $history = new History_Model(); - $history->num_threats = 0; - $history->num_core_threats = 0; - $history->num_plugins_threats = 0; - $history->num_themes_threats = 0; - - if ( $filter ) { - $history->filter = $filter; - } - - $history->last_checked = $scan_data->last_checked; + private static function normalize_api_data( $scan_data ) { + $history = new History_Model(); if ( empty( $scan_data->threats ) || ! is_array( $scan_data->threats ) ) { return $history; } foreach ( $scan_data->threats as $threat ) { - if ( ! in_array( $threat->status, $history->filter, true ) ) { - continue; - } - - if ( isset( $threat->extension->type ) ) { - if ( 'plugin' === $threat->extension->type ) { - self::handle_extension_threats( $threat, $history, 'plugin' ); - continue; - } - - if ( 'theme' === $threat->extension->type ) { - self::handle_extension_threats( $threat, $history, 'theme' ); - continue; - } - } + $threat_model = new Threat_Model( $threat ); + $history->threats[] = $threat_model; - if ( 'Vulnerable.WP.Core' === $threat->signature ) { - self::handle_core_threats( $threat, $history ); - continue; + ++$history->num_threats; + switch ( $threat_model->status ) { + case 'fixed': + ++$history->num_fixed_threats; + break; + case 'ignored': + ++$history->num_ignored_threats; + break; } - - self::handle_additional_threats( $threat, $history ); } return $history; } - - /** - * Handles threats for extensions such as plugins or themes. - * - * @param object $threat The threat object. - * @param object $history The history object. - * @param string $type The type of extension ('plugin' or 'theme'). - * @return void - */ - private static function handle_extension_threats( $threat, $history, $type ) { - $extension_list = $type === 'plugin' ? 'plugins' : 'themes'; - $extensions = &$history->{ $extension_list}; - $found_index = null; - - // Check if the extension does not exist in the array - foreach ( $extensions as $index => $extension ) { - if ( $extension->slug === $threat->extension->slug ) { - $found_index = $index; - break; - } - } - - // Add the extension if it does not yet exist in the history - if ( $found_index === null ) { - $new_extension = new Extension_Model( - array( - 'name' => $threat->extension->name ?? null, - 'slug' => $threat->extension->slug ?? null, - 'version' => $threat->extension->version ?? null, - 'type' => $type, - 'checked' => true, - 'threats' => array(), - ) - ); - $extensions[] = $new_extension; - $found_index = array_key_last( $extensions ); - } - - // Add the threat to the found extension - $extensions[ $found_index ]->threats[] = new Threat_Model( $threat ); - - // Increment the threat counts - ++$history->num_threats; - if ( $type === 'plugin' ) { - ++$history->num_plugins_threats; - } elseif ( $type === 'theme' ) { - ++$history->num_themes_threats; - } - } - - /** - * Handles core threats - * - * @param object $threat The threat object. - * @param object $history The history object. - * @return void - */ - private static function handle_core_threats( $threat, $history ) { - // Check if the core version does not exist in the array - $found_index = null; - foreach ( $history->core as $index => $core ) { - if ( $core->version === $threat->version ) { - $found_index = $index; - break; - } - } - - // Add the extension if it does not yet exist in the history - if ( null === $found_index ) { - $new_core = new Extension_Model( - array( - 'name' => 'WordPress', - 'version' => $threat->version, - 'type' => 'core', - 'checked' => true, - 'threats' => array(), - ) - ); - $history->core[] = $new_core; - $found_index = array_key_last( $history->core ); - } - - // Add the threat to the found core - $history->core[ $found_index ]->threats[] = new Threat_Model( $threat ); - - ++$history->num_threats; - ++$history->num_core_threats; - } - - /** - * Handles additional threats that are not core, plugin or theme - * - * @param object $threat The threat object. - * @param object $history The history object. - * @return void - */ - private static function handle_additional_threats( $threat, $history ) { - if ( ! empty( $threat->filename ) ) { - $history->files[] = new Threat_Model( $threat ); - ++$history->num_threats; - } elseif ( ! empty( $threat->table ) ) { - $history->database[] = new Threat_Model( $threat ); - ++$history->num_threats; - } - } } diff --git a/projects/plugins/protect/src/js/api.js b/projects/plugins/protect/src/js/api.js index 3b75d4246b604..4b5afaedc2877 100644 --- a/projects/plugins/protect/src/js/api.js +++ b/projects/plugins/protect/src/js/api.js @@ -45,13 +45,6 @@ const API = { method: 'POST', data: { step_ids: stepIds }, } ), - - fetchScanHistory: $filter => - apiFetch( { - path: 'jetpack-protect/v1/scan-history', - method: 'POST', - data: { filter: $filter }, - } ), }; export default API; diff --git a/projects/plugins/protect/src/js/components/admin-page/index.jsx b/projects/plugins/protect/src/js/components/admin-page/index.jsx index f11e152256988..22bbe244c91d8 100644 --- a/projects/plugins/protect/src/js/components/admin-page/index.jsx +++ b/projects/plugins/protect/src/js/components/admin-page/index.jsx @@ -57,7 +57,7 @@ const AdminPage = ( { children } ) => { { notice.message && } - + { children }; +} diff --git a/projects/plugins/protect/src/js/components/button-group/stories/index.stories.jsx b/projects/plugins/protect/src/js/components/button-group/stories/index.stories.jsx new file mode 100644 index 0000000000000..50e2d377d7922 --- /dev/null +++ b/projects/plugins/protect/src/js/components/button-group/stories/index.stories.jsx @@ -0,0 +1,12 @@ +/* eslint-disable react/react-in-jsx-scope */ +import React from 'react'; +import ButtonGroup from '../index.jsx'; + +export default { + title: 'Plugins/Protect/Button Group', + component: ButtonGroup, + argTypes: {}, +}; + +const FooterTemplate = args => ; +export const Default = FooterTemplate.bind( {} ); diff --git a/projects/plugins/protect/src/js/components/button-group/styles.module.scss b/projects/plugins/protect/src/js/components/button-group/styles.module.scss new file mode 100644 index 0000000000000..cda9ca003cb3a --- /dev/null +++ b/projects/plugins/protect/src/js/components/button-group/styles.module.scss @@ -0,0 +1,13 @@ +.button-group { + display: flex; + + > *:first-child { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + > *:last-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } +} diff --git a/projects/plugins/protect/src/js/components/navigation/badge.jsx b/projects/plugins/protect/src/js/components/navigation/badge.jsx index f24ba5549059d..b0b132115d3fd 100644 --- a/projects/plugins/protect/src/js/components/navigation/badge.jsx +++ b/projects/plugins/protect/src/js/components/navigation/badge.jsx @@ -1,56 +1,10 @@ import { Text } from '@automattic/jetpack-components'; import { Popover } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { Icon, check, info } from '@wordpress/icons'; import PropTypes from 'prop-types'; import React, { useState, useCallback } from 'react'; import styles from './styles.module.scss'; -/** - * Gets the Badge element - * - * @param {number} count - The number of threats found for this item. - * @param {boolean} checked - Whether this item was checked for threats yet. - * @returns {object} The badge element - */ -const getBadgeElement = ( count, checked ) => { - if ( ! checked ) { - return { - popoverText: __( - 'This item was added to your site after the most recent scan. We will check for threats during the next scheduled one.', - 'jetpack-protect' - ), - badgeElement: ( - - ), - }; - } - - if ( count === 0 ) { - return { - popoverText: __( 'No known threats found to affect this version', 'jetpack-protect' ), - badgeElement: ( - - ), - }; - } - - return { - popoverText: null, - badgeElement: ( - - { count } - - ), - }; -}; - -const ItemBadge = ( { count, checked } ) => { - const { popoverText, badgeElement } = getBadgeElement( count, checked ); +const ItemBadge = ( { badgeElement, popoverText } ) => { const [ showPopover, setShowPopover ] = useState( false ); const handleEnter = useCallback( () => { @@ -83,10 +37,10 @@ const ItemBadge = ( { count, checked } ) => { }; ItemBadge.propTypes = { - /* The number of threats found for this item */ - count: PropTypes.number, - /* Whether this item was checked for threats yet */ - checked: PropTypes.bool, + /** Badge element to display */ + badgeElement: PropTypes.node, + /** Popover text to display */ + popoverText: PropTypes.string, }; export default ItemBadge; diff --git a/projects/plugins/protect/src/js/components/navigation/item.jsx b/projects/plugins/protect/src/js/components/navigation/item.jsx index d902625c3997d..b29410f5503bc 100644 --- a/projects/plugins/protect/src/js/components/navigation/item.jsx +++ b/projects/plugins/protect/src/js/components/navigation/item.jsx @@ -9,12 +9,12 @@ const NavigationItem = ( { id, label, icon, - badge, + badgeElement, + badgePopoverText, disabled, onClick, onKeyDown, onFocus, - checked, } ) => { const context = useContext( NavigationContext ); @@ -77,7 +77,7 @@ const NavigationItem = ( { ref={ handleRef } > { label } - + ); }; diff --git a/projects/plugins/protect/src/js/components/navigation/styles.module.scss b/projects/plugins/protect/src/js/components/navigation/styles.module.scss index c533ae1429600..973ff96946534 100644 --- a/projects/plugins/protect/src/js/components/navigation/styles.module.scss +++ b/projects/plugins/protect/src/js/components/navigation/styles.module.scss @@ -37,12 +37,6 @@ & .navigation-item-icon { fill: var( --jp-white ); } - - & .navigation-item-badge { - border: 1px solid var( --jp-red ); - background-color: var( --jp-red ); - color: var( --jp-white ); - } } // CHILDRENS @@ -66,27 +60,6 @@ &-icon { margin-right: calc( var( --spacing-base ) * 2); // 16px } - - // .navigation-item-badge - &-badge { - border: 1px solid var( --jp-red-60 ); - color: var( --jp-red-60 ); - border-radius: 50%; - padding: calc( var( --spacing-base ) / 2 ) var( --spacing-base ); // 4px | 8px - min-width: 30px; - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - } - - &-check-badge { - fill: var( --jp-green-50 ); - } - - &-info-badge { - fill: var( --jp-gray-20 ); - } } .navigation-group { diff --git a/projects/plugins/protect/src/js/components/paid-accordion/index.jsx b/projects/plugins/protect/src/js/components/paid-accordion/index.jsx index 1839ef6c26a8b..0b0b087b3c913 100644 --- a/projects/plugins/protect/src/js/components/paid-accordion/index.jsx +++ b/projects/plugins/protect/src/js/components/paid-accordion/index.jsx @@ -2,16 +2,35 @@ import { Spinner, Text, useBreakpointMatch } from '@automattic/jetpack-component import { useSelect } from '@wordpress/data'; import { dateI18n } from '@wordpress/date'; import { sprintf, __ } from '@wordpress/i18n'; -import { Icon, check, chevronDown, chevronUp } from '@wordpress/icons'; +import { Icon, check, chevronDown, chevronUp, warning } from '@wordpress/icons'; import clsx from 'clsx'; import React, { useState, useCallback, useContext } from 'react'; -import useScanHistory from '../../hooks/use-scan-history'; import { STORE_ID } from '../../state/store'; import ThreatSeverityBadge from '../severity'; import styles from './styles.module.scss'; const PaidAccordionContext = React.createContext(); +const FixDetails = ( { date, isFixed } ) => ( + + { isFixed + ? sprintf( + /* translators: %s: Fixed on date */ + __( 'Threat fixed %s', 'jetpack-protect' ), + dateI18n( 'M j, Y', date ) + ) + : __( 'Threat ignored', 'jetpack-protect' ) } + +); + +const StatusBadge = ( { status } ) => ( +
+ { 'fixed' === status + ? __( 'Fixed', 'jetpack-protect' ) + : __( 'Ignored', 'jetpack-protect', /* dummy arg to avoid bad minification */ 0 ) } +
+); + export const PaidAccordionItem = ( { id, title, @@ -23,12 +42,12 @@ export const PaidAccordionItem = ( { firstDetected, fixedOn, onOpen, + status, } ) => { const accordionData = useContext( PaidAccordionContext ); const open = accordionData?.open === id; const setOpen = accordionData?.setOpen; const threatsAreFixing = useSelect( select => select( STORE_ID ).getThreatsAreFixing() ); - const { viewingScanHistory } = useScanHistory(); const bodyClassNames = clsx( styles[ 'accordion-body' ], { [ styles[ 'accordion-body-open' ] ]: open, @@ -46,55 +65,12 @@ export const PaidAccordionItem = ( { const [ isSmall ] = useBreakpointMatch( [ 'sm', 'lg' ], [ null, '<' ] ); - const FixDetails = ( { date, isFixed } ) => ( - - { isFixed - ? sprintf( - /* translators: %s: Fixed on date */ - __( 'Threat fixed %s', 'jetpack-protect' ), - dateI18n( 'M j, Y', date ) - ) - : __( 'Threat ignored', 'jetpack-protect' ) } - - ); - - const ScanHistoryDetails = ( { viewingHistory, detectedAt, fixedAt } ) => { - if ( ! viewingHistory ) { - return null; - } - - return ( - <> - { detectedAt && ( - - { sprintf( - /* translators: %s: First detected date */ - __( 'Threat found %s', 'jetpack-protect' ), - dateI18n( 'M j, Y', detectedAt ) - ) } - - - - ) } - - - ); - }; - - const StatusBadge = ( { status } ) => ( -
- { 'fixed' === status - ? __( 'Fixed', 'jetpack-protect' ) - : __( 'Ignored', 'jetpack-protect', /* dummy arg to avoid bad minification */ 0 ) } -
- ); - return (
- ) : ( - - ) } - - ); -}; - -const HeaderContainer = ( { displayButtonCol } ) => { - const { viewingScanHistory, handleCurrentClick, handleHistoryClick, allScanHistoryIsLoading } = - useScanHistory(); - - return ( - - - { displayButtonCol && ( - - ) } ); }; -const ErrorSection = ( { viewingScanHistory, errorMessage, errorCode } ) => { - const activityContext = viewingScanHistory - ? 'retrieving your scan history' - : 'scanning your site'; - const baseErrorMessage = sprintf( - /* translators: %s is the activity context, like "scanning your site" or "retrieving your scan history" */ - __( 'We are having problems %s.', 'jetpack-protect' ), - activityContext - ); - - let displayErrorMessage = errorMessage ? `${ errorMessage } (${ errorCode }).` : baseErrorMessage; - displayErrorMessage += ' ' + __( 'Try again in a few minutes.', 'jetpack-protect' ); - +const ErrorSection = ( { errorMessage, errorCode } ) => { return ( <> - + -

{ baseErrorMessage }

- { displayErrorMessage } +

{ __( 'We are having problems scanning your site', 'jetpack-protect' ) }

+ { !! errorMessage && { `${ errorMessage } (${ errorCode }).` } }
} secondary={ @@ -121,7 +63,7 @@ const ErrorSection = ( { viewingScanHistory, errorMessage, errorCode } ) => { const ScanningSection = ( { currentProgress } ) => { return ( <> - + @@ -167,7 +109,7 @@ const ScanningSection = ( { currentProgress } ) => { const DefaultSection = () => { return ( <> - + @@ -181,7 +123,6 @@ const DefaultSection = () => { }; const ScanPage = () => { - const { viewingScanHistory } = useScanHistory(); const { lastChecked, error, errorCode, errorMessage, hasRequiredPlan } = useProtectData(); const { refreshStatus } = useDispatch( STORE_ID ); const { statusIsFetching, scanIsUnavailable, status } = useSelect( select => ( { @@ -220,33 +161,18 @@ const ScanPage = () => { const renderSection = useMemo( () => { // Error - if ( error || ( ! viewingScanHistory && scanIsUnavailable ) ) { - return ( - - ); + if ( error ) { + return ; } // Scanning const scanningStatuses = new Set( [ 'scheduled', 'scanning', 'optimistically_scanning' ] ); - if ( ! viewingScanHistory && ( scanningStatuses.has( status.status ) || ! lastChecked ) ) { + if ( scanningStatuses.has( status.status ) || ! lastChecked ) { return ; } return ; - }, [ - error, - errorMessage, - errorCode, - viewingScanHistory, - scanIsUnavailable, - status.status, - status.currentProgress, - lastChecked, - ] ); + }, [ error, errorMessage, errorCode, status.status, status.currentProgress, lastChecked ] ); return ( diff --git a/projects/plugins/protect/src/js/components/scan-section-nav/index.jsx b/projects/plugins/protect/src/js/components/scan-section-nav/index.jsx new file mode 100644 index 0000000000000..38dc9ee662dba --- /dev/null +++ b/projects/plugins/protect/src/js/components/scan-section-nav/index.jsx @@ -0,0 +1,37 @@ +import { Button } from '@automattic/jetpack-components'; +import { __ } from '@wordpress/i18n'; +import React, { useCallback } from 'react'; +import { useLocation, useNavigate } from 'react-router-dom'; +import ButtonGroup from '../button-group'; + +/** + * Navigation for scan sections. + * + * @returns {React.Element} The React Component. + */ +export default function ScanSectionNav() { + const navigate = useNavigate(); + const location = useLocation(); + + const navigateToScanPage = useCallback( () => navigate( '/scan' ), [ navigate ] ); + const navigateToHistoryPage = useCallback( () => navigate( '/scan/history' ), [ navigate ] ); + + return ( + + + + + ); +} diff --git a/projects/plugins/protect/src/js/components/summary/index.jsx b/projects/plugins/protect/src/js/components/summary/index.jsx index fd416021cc138..bdb50f237b34d 100644 --- a/projects/plugins/protect/src/js/components/summary/index.jsx +++ b/projects/plugins/protect/src/js/components/summary/index.jsx @@ -12,25 +12,13 @@ import { dateI18n } from '@wordpress/date'; import { __, sprintf } from '@wordpress/i18n'; import React, { useState } from 'react'; import useProtectData from '../../hooks/use-protect-data'; -import useScanHistory from '../../hooks/use-scan-history'; import { STORE_ID } from '../../state/store'; import OnboardingPopover from '../onboarding-popover'; +import ScanSectionNav from '../scan-section-nav'; import styles from './styles.module.scss'; const Summary = () => { const [ isSm ] = useBreakpointMatch( 'sm' ); - const { - filter, - viewingScanHistory, - allScanHistoryIsLoading, - ignoredScanHistoryIsLoading, - fixedScanHistoryIsLoading, - toggleAllScanHistory, - toggleIgnoredScanHistory, - toggleFixedScanHistory, - handleHistoryClick, - handleCurrentClick, - } = useScanHistory(); const { numThreats, lastChecked, hasRequiredPlan } = useProtectData(); const scanIsEnqueuing = useSelect( select => select( STORE_ID ).getScanIsEnqueuing() ); const { scan } = useDispatch( STORE_ID ); @@ -48,72 +36,6 @@ const Summary = () => { }; }; - const renderScanOptions = () => ( - <> - -