Skip to content

Commit

Permalink
Initial new dashboard page
Browse files Browse the repository at this point in the history
  • Loading branch information
thijsoo committed Sep 5, 2024
1 parent 8d7ab9c commit d6727ea
Show file tree
Hide file tree
Showing 9 changed files with 622 additions and 0 deletions.
5 changes: 5 additions & 0 deletions admin/class-admin-asset-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,11 @@ protected function styles_to_be_registered() {
'src' => 'academy-' . $flat_version,
'deps' => [ self::PREFIX . 'tailwind' ],
],
[
'name' => 'new-dashboard',
'src' => 'new-dashboard-' . $flat_version,
'deps' => [ self::PREFIX . 'tailwind' ],
],
[
'name' => 'support',
'src' => 'support-' . $flat_version,
Expand Down
1 change: 1 addition & 0 deletions config/webpack/paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const getEntries = ( sourceDirectory = "./packages/js/src" ) => ( {
settings: `${ sourceDirectory }/settings.js`,
"new-settings": `${ sourceDirectory }/settings/initialize.js`,
academy: `${ sourceDirectory }/academy/initialize.js`,
"new-dashboard": `${ sourceDirectory }/dashboard/initialize.js`,
support: `${ sourceDirectory }/support/initialize.js`,
"how-to-block": `${ sourceDirectory }/structured-data-blocks/how-to/block.js`,
"faq-block": `${ sourceDirectory }/structured-data-blocks/faq/block.js`,
Expand Down
31 changes: 31 additions & 0 deletions packages/js/src/dashboard/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* eslint-disable complexity */

import { __ } from "@wordpress/i18n";
import { Paper, Title } from "@yoast/ui-library";

/**
* @returns {JSX.Element} The app component.
*/
const App = () => {
return (
<div className="yst-p-4 min-[783px]:yst-p-8 yst-mb-8 xl:yst-mb-0">
<Paper as="main">
<header className="yst-p-8 yst-border-b yst-border-slate-200">
<div className="yst-max-w-screen-sm">
<Title>{ __( "Alert center", "wordpress-seo" ) }</Title>
<p className="yst-text-tiny yst-mt-3">
{ __( "Monitor and manage potential SEO problems affecting your site and stay informed with important notifications and updates.", "wordpress-seo" ) }
</p>
</div>
</header>
<div className="yst-h-full yst-p-8">
<div className="yst-max-w-6xl yst-grid yst-gap-6 yst-grid-cols-1 sm:yst-grid-cols-2 min-[783px]:yst-grid-cols-1 lg:yst-grid-cols-2 xl:yst-grid-cols-4">
Content
</div>
</div>
</Paper>
</div>
);
};

export default App;
5 changes: 5 additions & 0 deletions packages/js/src/dashboard/constants/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Keep constants centralized to avoid circular dependency problems.
*/
export const STORE_NAME = "@yoast/dashboard";

32 changes: 32 additions & 0 deletions packages/js/src/dashboard/initialize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { SlotFillProvider } from "@wordpress/components";
import { select } from "@wordpress/data";
import domReady from "@wordpress/dom-ready";
import { render } from "@wordpress/element";
import { Root } from "@yoast/ui-library";
import { get } from "lodash";
import { LINK_PARAMS_NAME } from "../shared-admin/store";
import App from "./app";
import { STORE_NAME } from "./constants";
import registerStore from "./store";

domReady( () => {
const root = document.getElementById( "yoast-seo-dashboard" );
if ( ! root ) {
return;
}
registerStore( {
initialState: {
[ LINK_PARAMS_NAME ]: get( window, "wpseoScriptData.linkParams", {} ),
},
} );
const isRtl = select( STORE_NAME ).selectPreference( "isRtl", false );

render(
<Root context={ { isRtl } }>
<SlotFillProvider>
<App />
</SlotFillProvider>
</Root>,
root
);
} );
49 changes: 49 additions & 0 deletions packages/js/src/dashboard/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// eslint-disable-next-line import/named
import { combineReducers, createReduxStore, register } from "@wordpress/data";
import { merge } from "lodash";
import { getInitialLinkParamsState, LINK_PARAMS_NAME, linkParamsActions, linkParamsReducer, linkParamsSelectors } from "../../shared-admin/store";
import { STORE_NAME } from "../constants";
import preferences, { createInitialPreferencesState, preferencesActions, preferencesSelectors } from "./preferences";

/** @typedef {import("@wordpress/data/src/types").WPDataStore} WPDataStore */

/**
* @param {Object} initialState Initial state.
* @returns {WPDataStore} The WP data store.
*/
const createStore = ( { initialState } ) => {
return createReduxStore( STORE_NAME, {
actions: {
...linkParamsActions,
...preferencesActions,
},
selectors: {
...linkParamsSelectors,
...preferencesSelectors,
},
initialState: merge(
{},
{
[ LINK_PARAMS_NAME ]: getInitialLinkParamsState(),
preferences: createInitialPreferencesState(),
},
initialState
),
reducer: combineReducers( {
[ LINK_PARAMS_NAME ]: linkParamsReducer,
preferences,
} ),

} );
};

/**
* Registers the store to WP data's default registry.
* @param {Object} [initialState] Initial state.
* @returns {void}
*/
const registerStore = ( { initialState = {} } = {} ) => {
register( createStore( { initialState } ) );
};

export default registerStore;
34 changes: 34 additions & 0 deletions packages/js/src/dashboard/store/preferences.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { createSelector, createSlice } from "@reduxjs/toolkit";
import { get } from "lodash";

/**
* @returns {Object} The initial state.
*/
export const createInitialPreferencesState = () => ( {
...get( window, "wpseoScriptData.preferences", {} ),
} );

const slice = createSlice( {
name: "preferences",
initialState: createInitialPreferencesState(),
reducers: {},
} );

export const preferencesSelectors = {
selectPreference: ( state, preference, defaultValue = {} ) => get( state, `preferences.${ preference }`, defaultValue ),
selectPreferences: state => get( state, "preferences", {} ),
};
preferencesSelectors.selectUpsellSettingsAsProps = createSelector(
[
state => preferencesSelectors.selectPreference( state, "upsellSettings", {} ),
( state, ctbName = "premiumCtbId" ) => ctbName,
],
( upsellSettings, ctbName ) => ( {
"data-action": upsellSettings?.actionId,
"data-ctb-id": upsellSettings?.[ ctbName ],
} )
);

export const preferencesActions = slice.actions;

export default slice.reducer;
169 changes: 169 additions & 0 deletions src/dashboard/user-interface/general-page-integration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<?php

namespace Yoast\WP\SEO\Dashboard\User_Interface;

use WPSEO_Admin_Asset_Manager;
use Yoast\WP\SEO\Conditionals\Admin_Conditional;
use Yoast\WP\SEO\Helpers\Current_Page_Helper;
use Yoast\WP\SEO\Helpers\Product_Helper;
use Yoast\WP\SEO\Helpers\Short_Link_Helper;
use Yoast\WP\SEO\Integrations\Integration_Interface;

/**
* Class General_Page_Integration.
*/
class General_Page_Integration implements Integration_Interface {

/**
* The page name.
*
* @TODO RENAME THIS TO SOMETHING SENSIBLE AFTER FEATURE FLAG PERIOD
*/
public const PAGE = 'wpseo_page_dashboard_new';

/**
* Holds the WPSEO_Admin_Asset_Manager.
*
* @var WPSEO_Admin_Asset_Manager
*/
private $asset_manager;

/**
* Holds the Current_Page_Helper.
*
* @var Current_Page_Helper
*/
private $current_page_helper;

/**
* Holds the Product_Helper.
*
* @var Product_Helper
*/
private $product_helper;

/**
* Holds the Short_Link_Helper.
*
* @var Short_Link_Helper
*/
private $shortlink_helper;

/**
* Constructs Academy_Integration.
*
* @param WPSEO_Admin_Asset_Manager $asset_manager The WPSEO_Admin_Asset_Manager.
* @param Current_Page_Helper $current_page_helper The Current_Page_Helper.
* @param Product_Helper $product_helper The Product_Helper.
* @param Short_Link_Helper $shortlink_helper The Short_Link_Helper.
*/
public function __construct(
WPSEO_Admin_Asset_Manager $asset_manager,
Current_Page_Helper $current_page_helper,
Product_Helper $product_helper,
Short_Link_Helper $shortlink_helper
) {
$this->asset_manager = $asset_manager;
$this->current_page_helper = $current_page_helper;
$this->product_helper = $product_helper;
$this->shortlink_helper = $shortlink_helper;
}

/**
* Returns the conditionals based on which this loadable should be active.
*
* @return array<string>
*/
public static function get_conditionals() {
return [ Admin_Conditional::class ];
}

/**
* Initializes the integration.
*
* This is the place to register hooks and filters.
*
* @return void
*/
public function register_hooks() {
if ( \apply_filters( 'wpseo_new_dashboard', false ) ) {
// Add page.
\add_filter( 'wpseo_submenu_pages', [ $this, 'add_page' ] );

// Are we on the dashboard page?
if ( $this->current_page_helper->get_current_yoast_seo_page() === self::PAGE ) {
\add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
}
}

/**
* Adds the page.
*
* @param array<string,array<string>> $pages The pages.
*
* @return array<string,array<string>> The pages.
*/
public function add_page( $pages ) {
\array_splice(
$pages,
3,
0,
[
[
'wpseo_dashboard',
'',
\__( 'Dashboard New', 'wordpress-seo' ),
'wpseo_manage_options',
self::PAGE,
[ $this, 'display_page' ],
],
]
);

return $pages;
}

/**
* Displays the page.
*
* @return void
*/
public function display_page() {
echo '<div id="yoast-seo-dashboard"></div>';
}

/**
* Enqueues the assets.
*
* @return void
*/
public function enqueue_assets() {
// Remove the emoji script as it is incompatible with both React and any contenteditable fields.
\remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
\wp_enqueue_media();
$this->asset_manager->enqueue_script( 'new-dashboard' );
$this->asset_manager->enqueue_style( 'new-dashboard' );
$this->asset_manager->localize_script( 'dashboard', 'wpseoScriptData', $this->get_script_data() );
}

/**
* Creates the script data.
*
* @return array<string,array<string|bool,array<string>>> The script data.
*/
public function get_script_data() {
return [
'preferences' => [
'isPremium' => $this->product_helper->is_premium(),
'isRtl' => \is_rtl(),
'pluginUrl' => \plugins_url( '', \WPSEO_FILE ),
'upsellSettings' => [
'actionId' => 'load-nfd-ctb',
'premiumCtbId' => 'f6a84663-465f-4cb5-8ba5-f7a6d72224b2',
],
],
'linkParams' => $this->shortlink_helper->get_query_params(),
];
}
}
Loading

0 comments on commit d6727ea

Please sign in to comment.