diff --git a/plugins/woocommerce-admin/client/analytics/index.js b/plugins/woocommerce-admin/client/analytics/index.js new file mode 100644 index 00000000000..9f46de400f8 --- /dev/null +++ b/plugins/woocommerce-admin/client/analytics/index.js @@ -0,0 +1,21 @@ +/** @format */ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component, Fragment } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Header from 'components/header'; + +export default class extends Component { + render() { + return ( + +
+ + ); + } +} diff --git a/plugins/woocommerce-admin/client/analytics/report/index.js b/plugins/woocommerce-admin/client/analytics/report/index.js new file mode 100644 index 00000000000..4e4b1bd9b38 --- /dev/null +++ b/plugins/woocommerce-admin/client/analytics/report/index.js @@ -0,0 +1,28 @@ +/** @format */ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Component, Fragment } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import Header from 'components/header'; +import { getAdminLink } from 'lib/nav-utils'; + +export default class extends Component { + render() { + return ( + +
{ __( 'Analytics', 'woo-dash' ) }, + __( 'Report Title', 'woo-dash' ), + ] } + /> +
Report: { this.props.params.report }
+ + ); + } +} diff --git a/plugins/woocommerce-admin/client/components/header/index.js b/plugins/woocommerce-admin/client/components/header/index.js index 8703590993f..b20ee2416bd 100644 --- a/plugins/woocommerce-admin/client/components/header/index.js +++ b/plugins/woocommerce-admin/client/components/header/index.js @@ -9,7 +9,7 @@ import PropTypes from 'prop-types'; * Internal dependencies */ import './style.scss'; -import { getAdminLink } from '../../lib/nav-utils'; +import { getAdminLink } from 'lib/nav-utils'; // TODO Implement timeline icon @@ -20,7 +20,7 @@ const Header = ( { sections, showTimeline } ) => { return (

- WooCommerce + WooCommerce { crumbs }

diff --git a/plugins/woocommerce-admin/client/index.js b/plugins/woocommerce-admin/client/index.js index df4b6ddda86..3f2ed05c931 100644 --- a/plugins/woocommerce-admin/client/index.js +++ b/plugins/woocommerce-admin/client/index.js @@ -2,25 +2,86 @@ /** * External dependencies */ -import { APIProvider } from '@wordpress/components'; -import { createElement, render } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; -import { pick } from 'lodash'; +import { APIProvider } from '@wordpress/components'; +import { Component, createElement, render } from '@wordpress/element'; +import { HashRouter as Router, Route, Switch } from 'react-router-dom'; +import { parse } from 'qs'; +import { pick, find } from 'lodash'; /** * Internal dependencies */ +import Analytics from './analytics'; +import AnalyticsReport from './analytics/report'; import Dashboard from './dashboard'; -render( - createElement( - APIProvider, +const getPages = () => { + const pages = [ { - ...wpApiSettings, - ...pick( wp.api, [ 'postTypeRestBaseMapping', 'taxonomyRestBaseMapping' ] ), + container: Dashboard, + path: '/', + wpMenu: 'toplevel_page_woodash', }, - createElement( Dashboard ) - ), + { + container: Analytics, + path: '/analytics', + wpMenu: 'toplevel_page_woodash--analytics', + }, + { + container: AnalyticsReport, + path: '/analytics/:report', + wpMenu: 'toplevel_page_woodash--analytics', + }, + ]; + + return pages; +}; + +class Controller extends Component { + render() { + // Pass URL parameters (example :report -> params.report) and query string parameters + const { path, params } = this.props.match; + const search = this.props.location.search.substring( 1 ); + const query = parse( search ); + const page = find( getPages(), { path } ); + window.wpNavMenuClassChange( page.wpMenu ); + return createElement( page.container, { params, query } ); + } +} + +// When the route changes, we need to update wp-admin's menu with the correct section & current link +window.wpNavMenuClassChange = function( menuClass ) { + jQuery( '.current' ).each( function( i, obj ) { + jQuery( obj ).removeClass( 'current' ); + } ); + jQuery( '.wp-has-current-submenu' ) + .removeClass( 'wp-has-current-submenu' ) + .removeClass( 'wp-menu-open' ) + .removeClass( 'selected' ) + .addClass( 'wp-not-current-submenu menu-top' ); + jQuery( 'li > a[href$="admin.php?page=woodash' + window.location.hash + '"]' ) + .parent() + .addClass( 'current' ); + jQuery( '#' + menuClass ) + .removeClass( 'wp-not-current-submenu' ) + .addClass( 'wp-has-current-submenu wp-menu-open current' ); +}; + +render( + + + + { getPages().map( page => { + return ; + } ) } + + + + , document.getElementById( 'root' ) ); diff --git a/plugins/woocommerce-admin/client/lib/nav-utils.js b/plugins/woocommerce-admin/client/lib/nav-utils.js index b477eb734c3..cfa05d7bea8 100644 --- a/plugins/woocommerce-admin/client/lib/nav-utils.js +++ b/plugins/woocommerce-admin/client/lib/nav-utils.js @@ -6,6 +6,6 @@ * @param {String} path Relative path. * @return {String} Full admin URL. */ -export const getAdminLink = ( path ) => { - return wcSettings.adminUrl + path; +export const getAdminLink = path => { + return wcSettings.adminUrl + 'admin.php?page=woodash#' + path; }; diff --git a/plugins/woocommerce-admin/lib/admin.php b/plugins/woocommerce-admin/lib/admin.php index 7e9dc2e606e..5faf50ae2d3 100644 --- a/plugins/woocommerce-admin/lib/admin.php +++ b/plugins/woocommerce-admin/lib/admin.php @@ -12,9 +12,9 @@ function woo_dash_is_admin_page() { } /** - * Register a new menu page for the Dashboard + * Register menu pages for the Dashboard and Analytics sections */ -function woo_dash_register_page(){ +function woo_dash_register_pages(){ // toplevel_page_woodash add_menu_page( __( 'Woo Dash', 'woo-dash' ), @@ -25,8 +25,29 @@ function woo_dash_register_page(){ 'dashicons-cart', 6 ); + + // toplevel_page_wooanalytics + add_menu_page( + __( 'WooCommerce Analytics', 'woo-dash' ), + __( 'WooAnalytics', 'woo-dash' ), + 'manage_options', + 'woodash#/analytics', + 'woo_dash_page', + 'dashicons-chart-bar', + 6 + ); + + // TODO: Remove. Test report link + add_submenu_page( + 'woodash#/analytics', + __( 'Report Title', 'woo-dash' ), + __( 'Report Title', 'woo-dash' ), + 'manage_options', + 'woodash#/analytics/test', + 'woo_dash_page' + ); } -add_action( 'admin_menu', 'woo_dash_register_page' ); +add_action( 'admin_menu', 'woo_dash_register_pages' ); /** * Load the assets on the Dashboard page diff --git a/plugins/woocommerce-admin/lib/client-assets.php b/plugins/woocommerce-admin/lib/client-assets.php index e13638e72ee..9564a3fce9c 100644 --- a/plugins/woocommerce-admin/lib/client-assets.php +++ b/plugins/woocommerce-admin/lib/client-assets.php @@ -33,7 +33,8 @@ function woo_dash_register_script() { ); wp_add_inline_script( WOO_DASH_APP, - 'var wcSettings = '. json_encode( $settings ) . ';', + 'var wcSettings = '. json_encode( $settings ) . ';' . + "jQuery( '#toplevel_page_woodash a' ).attr( 'href', 'admin.php?page=woodash#/' );", 'before' ); } diff --git a/plugins/woocommerce-admin/package-lock.json b/plugins/woocommerce-admin/package-lock.json index bcc7a3cbd66..acdfb018c03 100644 --- a/plugins/woocommerce-admin/package-lock.json +++ b/plugins/woocommerce-admin/package-lock.json @@ -5451,6 +5451,12 @@ "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", "dev": true }, + "hoist-non-react-statics": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz", + "integrity": "sha512-6Bl6XsDT1ntE0lHbIhr4Kp2PGcleGZ66qu5Jqk8lc0Xc/IeG6gVLmwUGs/K0Us+L8VWoKgj0uWdPMataOsm31w==", + "dev": true + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -8274,6 +8280,23 @@ "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", "dev": true }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "dev": true, + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + } + } + }, "path-type": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -9418,6 +9441,50 @@ "safe-buffer": "5.1.1" } }, + "react-router-dom": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.2.2.tgz", + "integrity": "sha512-cHMFC1ZoLDfEaMFoKTjN7fry/oczMgRt5BKfMAkTu5zEuJvUiPp1J8d0eXSVTnBh6pxlbdqDhozunOOLtmKfPA==", + "dev": true, + "requires": { + "history": "4.7.2", + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "prop-types": "15.6.1", + "react-router": "4.2.0", + "warning": "3.0.0" + }, + "dependencies": { + "history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "dev": true, + "requires": { + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "resolve-pathname": "2.2.0", + "value-equal": "0.4.0", + "warning": "3.0.0" + } + }, + "react-router": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz", + "integrity": "sha512-DY6pjwRhdARE4TDw7XjxjZsbx9lKmIcyZoZ+SDO7SBJ1KUeWNxT22Kara2AC7u6/c2SYEHlEDLnzBCcNhLE8Vg==", + "dev": true, + "requires": { + "history": "4.7.2", + "hoist-non-react-statics": "2.5.0", + "invariant": "2.2.4", + "loose-envify": "1.3.1", + "path-to-regexp": "1.7.0", + "prop-types": "15.6.1", + "warning": "3.0.0" + } + } + } + }, "read-chunk": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", @@ -9813,6 +9880,12 @@ "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", "dev": true }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -11398,6 +11471,12 @@ "spdx-expression-parse": "3.0.0" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==", + "dev": true + }, "vendors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", @@ -11500,6 +11579,15 @@ "indexof": "0.0.1" } }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/plugins/woocommerce-admin/package.json b/plugins/woocommerce-admin/package.json index d71c7f08ee9..209b64baaf6 100755 --- a/plugins/woocommerce-admin/package.json +++ b/plugins/woocommerce-admin/package.json @@ -44,6 +44,7 @@ "node-sass": "^4.9.0", "prettier": "github:automattic/calypso-prettier#c56b4251", "prop-types": "^15.6.1", + "react-router-dom": "^4.2.2", "readline-sync": "^1.4.9", "sass-loader": "^7.0.1", "style-loader": "^0.21.0",