Skip to content

Commit

Permalink
Fix double scrollbars on product editor page (woocommerce#38281)
Browse files Browse the repository at this point in the history
* Refactor Layout component to functional component

* Add class to pages based on page path

* Add styling for interface skeleton on product pages

* Add changelog entries

* Move product page styles out of product editor package and into client

* Fix linting issues

* Check for location before checking path in page tracking

* Dont add body classes when no page path exists

* Record page view without router location for embed pages
  • Loading branch information
joshuatf committed May 18, 2023
1 parent b8aa7eb commit 81e9239
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 233 deletions.
4 changes: 4 additions & 0 deletions packages/js/product-editor/changelog/fix-38149
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: fix

Fix double scrollbars on product editor page
17 changes: 0 additions & 17 deletions packages/js/product-editor/src/components/editor/style.scss
Original file line number Diff line number Diff line change
@@ -1,18 +1 @@
@import '@wordpress/interface/src/style.scss';

.interface-interface-skeleton {
@include breakpoint( '<782px' ) {
top: $adminbar-height-mobile;
}
top: $adminbar-height;
background-color: $white;
}

.interface-interface-skeleton__sidebar {
width: 280px;
}

.interface-interface-skeleton__header {
// Higher than the sidebar which has a z-index of 90.
z-index: 100;
}
56 changes: 56 additions & 0 deletions plugins/woocommerce-admin/client/layout/hooks/use-page-classes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* External dependencies
*/
import { useEffect } from '@wordpress/element';
import { RouteMatch } from 'react-router-dom';

type Page = {
container: JSX.Element;
path: string;
breadcrumbs:
| string[]
| ( ( { match }: { match: RouteMatch } ) => string[] );
wpOpenMenu: string;
navArgs: {
id: string;
};
capability: string;
};

export function usePageClasses( page: Page ) {
function convertCamelCaseToKebabCase( str: string ) {
return str.replace(
/[A-Z]/g,
( letter ) => `-${ letter.toLowerCase() }`
);
}

function getPathClassName( path: string ) {
const suffix =
path === '/'
? '_home'
: path
.replace( /:[a-zA-Z?]+/g, function ( match ) {
return convertCamelCaseToKebabCase( match ).replace(
':',
''
);
} )
.replace( /\//g, '_' );

return `woocommerce-admin-page_${ suffix }`;
}

useEffect( () => {
if ( ! page.path ) {
return;
}

const classes = getPathClassName( page.path );

document.body.classList.add( classes );
return () => {
document.body.classList.remove( classes );
};
}, [ page.path ] );
}
167 changes: 78 additions & 89 deletions plugins/woocommerce-admin/client/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { SlotFillProvider } from '@wordpress/components';
import { compose } from '@wordpress/compose';
import { withSelect } from '@wordpress/data';
import { Component, lazy, Suspense } from '@wordpress/element';
import { Component, lazy, Suspense, useEffect } from '@wordpress/element';
import {
unstable_HistoryRouter as HistoryRouter,
Route,
Expand All @@ -15,7 +15,7 @@ import {
} from 'react-router-dom';
import { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
import { get, isFunction, identity, memoize } from 'lodash';
import { isFunction, identity } from 'lodash';
import {
CustomerEffortScoreModalContainer,
triggerExitPageCesSurvey,
Expand Down Expand Up @@ -45,6 +45,7 @@ import { Footer } from './footer';
import Notices from './notices';
import TransientNotices from './transient-notices';
import { getAdminSetting } from '~/utils/admin-settings';
import { usePageClasses } from './hooks/use-page-classes';
import '~/activity-panel';
import '~/mobile-banner';
import './navigation';
Expand Down Expand Up @@ -118,39 +119,18 @@ const LayoutSwitchWrapper = ( props ) => {
);
};

class _Layout extends Component {
memoizedLayoutContext = memoize(
( page ) => page?.navArgs?.id?.toLowerCase() || 'page'
);
componentDidMount() {
this.recordPageViewTrack();
triggerExitPageCesSurvey();
}

componentDidUpdate( prevProps ) {
const previousPath = get( prevProps, 'location.pathname' );
const currentPath = get( this.props, 'location.pathname' );

if ( ! previousPath || ! currentPath ) {
return;
}

if ( previousPath !== currentPath ) {
this.recordPageViewTrack();
setTimeout( () => {
triggerExitPageCesSurvey();
}, 0 );
}
}

recordPageViewTrack() {
const {
activePlugins,
installedPlugins,
isEmbedded,
isJetpackConnected,
} = this.props;
function _Layout( {
activePlugins,
installedPlugins,
isEmbedded,
isJetpackConnected,
location,
match,
page,
} ) {
usePageClasses( page );

function recordPageViewTrack() {
const navigationFlag = {
has_navigation: !! window.wcNavigation,
};
Expand All @@ -164,7 +144,7 @@ class _Layout extends Component {
return;
}

const pathname = get( this.props, 'location.pathname' );
const { pathname } = location;
if ( ! pathname ) {
return;
}
Expand All @@ -185,69 +165,78 @@ class _Layout extends Component {
} );
}

isWCPaySettingsPage() {
const { page, section, tab } = getQuery();
useEffect( () => {
triggerExitPageCesSurvey();
}, [] );

useEffect( () => {
recordPageViewTrack();
setTimeout( () => {
triggerExitPageCesSurvey();
}, 0 );
}, [ location?.pathname ] );

function isWCPaySettingsPage() {
const { page: queryPage, section, tab } = getQuery();
return (
page === 'wc-settings' &&
queryPage === 'wc-settings' &&
tab === 'checkout' &&
section === 'woocommerce_payments'
);
}

render() {
const { isEmbedded, ...restProps } = this.props;
const { location, page } = this.props;
const { breadcrumbs } = page;
const query = Object.fromEntries(
new URLSearchParams( location && location.search )
);
const { breadcrumbs } = page;

return (
<LayoutContextProvider
value={ getLayoutContextValue( [
this.memoizedLayoutContext( page ),
] ) }
>
<SlotFillProvider>
<div className="woocommerce-layout">
<Header
sections={
isFunction( breadcrumbs )
? breadcrumbs( this.props )
: breadcrumbs
}
isEmbedded={ isEmbedded }
query={ query }
/>
<TransientNotices />
{ ! isEmbedded && (
<PrimaryLayout>
<div className="woocommerce-layout__main">
<Controller
{ ...restProps }
query={ query }
/>
</div>
</PrimaryLayout>
) }
const query = Object.fromEntries(
new URLSearchParams( location && location.search )
);

{ isEmbedded && this.isWCPaySettingsPage() && (
<Suspense fallback={ null }>
<WCPayUsageModal />
</Suspense>
) }
<Footer />
<CustomerEffortScoreModalContainer />
</div>
<PluginArea scope="woocommerce-admin" />
{ window.wcAdminFeatures.navigation && (
<PluginArea scope="woocommerce-navigation" />
return (
<LayoutContextProvider
value={ getLayoutContextValue( [
page?.navArgs?.id?.toLowerCase() || 'page',
] ) }
>
<SlotFillProvider>
<div className="woocommerce-layout">
<Header
sections={
isFunction( breadcrumbs )
? breadcrumbs( { match } )
: breadcrumbs
}
isEmbedded={ isEmbedded }
query={ query }
/>
<TransientNotices />
{ ! isEmbedded && (
<PrimaryLayout>
<div className="woocommerce-layout__main">
<Controller
page={ page }
match={ match }
query={ query }
/>
</div>
</PrimaryLayout>
) }
<PluginArea scope="woocommerce-tasks" />
</SlotFillProvider>
</LayoutContextProvider>
);
}

{ isEmbedded && isWCPaySettingsPage() && (
<Suspense fallback={ null }>
<WCPayUsageModal />
</Suspense>
) }
<Footer />
<CustomerEffortScoreModalContainer />
</div>
<PluginArea scope="woocommerce-admin" />
{ window.wcAdminFeatures.navigation && (
<PluginArea scope="woocommerce-navigation" />
) }
<PluginArea scope="woocommerce-tasks" />
</SlotFillProvider>
</LayoutContextProvider>
);
}

_Layout.propTypes = {
Expand Down
Loading

0 comments on commit 81e9239

Please sign in to comment.