Migrate header items to slot fills (https://github.com/woocommerce/woocommerce-admin/pull/7805)
* Add SlotFill area to header * Add activity panel fill * Move activity panel to root client folder * Move activity panel registration to its own folder * Add navigation fill * Add page title slotfill * Slot fill the back button * Move mobile banner to slot fill * Fix navigation fill on embed pages * Add changelog entry * Allow order prop to header item fill * Split header into before and after * Fix header title gaps * Fix nav and mobile app banner placement * Fix display options import * Only use last item for page header title fill * Use function to pass fill props instead of bind * Rename header slots * Fix mobile banner dismissal check * Fix up inbox panel rename * Update task title in tests * Fix up task status retrieval
This commit is contained in:
parent
e31086327b
commit
7aeb0a19d2
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: Enhancement
|
||||
|
||||
Add SlotFill areas to header #7805
|
|
@ -12,19 +12,21 @@ import {
|
|||
ONBOARDING_STORE_NAME,
|
||||
OPTIONS_STORE_NAME,
|
||||
useUser,
|
||||
useUserPreferences,
|
||||
} from '@woocommerce/data';
|
||||
import { getHistory, getNewPath } from '@woocommerce/navigation';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { useSlot } from '@woocommerce/experimental';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
import { IconFlag } from './icon-flag';
|
||||
import { isNotesPanelVisible } from './unread-indicators';
|
||||
import { isWCAdmin } from '../../dashboard/utils';
|
||||
import { isWCAdmin } from '~/dashboard/utils';
|
||||
import { Tabs } from './tabs';
|
||||
import { SetupProgress } from './setup-progress';
|
||||
import { IconFlag } from './icon-flag';
|
||||
import { DisplayOptions } from './display-options';
|
||||
import { HighlightTooltip } from './highlight-tooltip';
|
||||
import { Panel } from './panel';
|
||||
|
@ -32,8 +34,8 @@ import {
|
|||
getLowStockCount as getLowStockProducts,
|
||||
getOrderStatuses,
|
||||
getUnreadOrders,
|
||||
} from '../../homescreen/activity-panel/orders/utils';
|
||||
import { getUnapprovedReviews } from '../../homescreen/activity-panel/reviews/utils';
|
||||
} from '../homescreen/activity-panel/orders/utils';
|
||||
import { getUnapprovedReviews } from '../homescreen/activity-panel/reviews/utils';
|
||||
import { ABBREVIATED_NOTIFICATION_SLOT_NAME } from './panels/inbox/abbreviated-notifications-panel';
|
||||
|
||||
const HelpPanel = lazy( () =>
|
||||
|
@ -46,13 +48,14 @@ const InboxPanel = lazy( () =>
|
|||
)
|
||||
);
|
||||
|
||||
export const ActivityPanel = ( { isEmbedded, query, userPreferencesData } ) => {
|
||||
export const ActivityPanel = ( { isEmbedded, query } ) => {
|
||||
const [ currentTab, setCurrentTab ] = useState( '' );
|
||||
const [ isPanelClosing, setIsPanelClosing ] = useState( false );
|
||||
const [ isPanelOpen, setIsPanelOpen ] = useState( false );
|
||||
const [ isPanelSwitching, setIsPanelSwitching ] = useState( false );
|
||||
const { fills } = useSlot( ABBREVIATED_NOTIFICATION_SLOT_NAME );
|
||||
const hasExtendedNotifications = Boolean( fills?.length );
|
||||
const { updateUserPreferences, ...userData } = useUserPreferences();
|
||||
|
||||
const getPreviewSiteBtnTrackData = ( select, getOption ) => {
|
||||
let trackData = {};
|
||||
|
@ -322,11 +325,8 @@ export const ActivityPanel = ( { isEmbedded, query, userPreferencesData } ) => {
|
|||
|
||||
const closedHelpPanelHighlight = () => {
|
||||
recordEvent( 'help_tooltip_click' );
|
||||
if (
|
||||
userPreferencesData &&
|
||||
userPreferencesData.updateUserPreferences
|
||||
) {
|
||||
userPreferencesData.updateUserPreferences( {
|
||||
if ( userData && updateUserPreferences ) {
|
||||
updateUserPreferences( {
|
||||
help_panel_highlight_shown: 'yes',
|
||||
} );
|
||||
}
|
||||
|
@ -335,11 +335,8 @@ export const ActivityPanel = ( { isEmbedded, query, userPreferencesData } ) => {
|
|||
const shouldShowHelpTooltip = () => {
|
||||
const { task } = query;
|
||||
const startedTasks =
|
||||
userPreferencesData &&
|
||||
userPreferencesData.task_list_tracked_started_tasks;
|
||||
const highlightShown =
|
||||
userPreferencesData &&
|
||||
userPreferencesData.help_panel_highlight_shown;
|
||||
userData && userData.task_list_tracked_started_tasks;
|
||||
const highlightShown = userData && userData.help_panel_highlight_shown;
|
||||
if (
|
||||
task &&
|
||||
highlightShown !== 'yes' &&
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { registerPlugin } from '@wordpress/plugins';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import ActivityPanel from './activity-panel';
|
||||
import { WooHeaderItem } from '~/header/utils';
|
||||
|
||||
const ActivityPanelHeaderItem = () => (
|
||||
<WooHeaderItem order={ 20 }>
|
||||
{ ( { isEmbedded, query } ) => {
|
||||
if ( ! window.wcAdminFeatures[ 'activity-panels' ] ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <ActivityPanel isEmbedded={ isEmbedded } query={ query } />;
|
||||
} }
|
||||
</WooHeaderItem>
|
||||
);
|
||||
|
||||
registerPlugin( 'activity-panel-header-item', {
|
||||
render: ActivityPanelHeaderItem,
|
||||
scope: 'woocommerce-admin',
|
||||
} );
|
|
@ -8,8 +8,8 @@ import { Spinner } from '@woocommerce/components';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import useFocusOnMount from '../../hooks/useFocusOnMount';
|
||||
import useFocusOutside from '../../hooks/useFocusOutside';
|
||||
import useFocusOnMount from '~/hooks/useFocusOnMount';
|
||||
import useFocusOutside from '~/hooks/useFocusOutside';
|
||||
|
||||
export const Panel = ( {
|
||||
content,
|
|
@ -21,7 +21,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import ActivityHeader from '../activity-header';
|
||||
import { getCountryCode } from '../../../dashboard/utils';
|
||||
import { getCountryCode } from '~/dashboard/utils';
|
||||
|
||||
export const SETUP_TASK_HELP_ITEMS_FILTER =
|
||||
'woocommerce_admin_setup_task_help_items';
|
|
@ -17,9 +17,9 @@ import {
|
|||
getLowStockCount,
|
||||
getOrderStatuses,
|
||||
getUnreadOrders,
|
||||
} from '../../../../homescreen/activity-panel/orders/utils';
|
||||
import { getUnapprovedReviews } from '../../../../homescreen/activity-panel/reviews/utils';
|
||||
import { isWCAdmin } from '../../../../dashboard/utils';
|
||||
} from '~/homescreen/activity-panel/orders/utils';
|
||||
import { getUnapprovedReviews } from '~/homescreen/activity-panel/reviews/utils';
|
||||
import { isWCAdmin } from '~/dashboard/utils';
|
||||
import { Bell } from './icons/bell';
|
||||
|
||||
const EXTENDED_TASK_LIST_ID = 'extended_task_list';
|
|
@ -2,7 +2,7 @@
|
|||
* Internal dependencies
|
||||
*/
|
||||
import './inbox.scss';
|
||||
import NotesPanel from '../../../../inbox-panel';
|
||||
import NotesPanel from '~/inbox-panel';
|
||||
import { AbbreviatedNotificationsPanel } from './abbreviated-notifications-panel';
|
||||
|
||||
export const InboxPanel = ( {
|
|
@ -9,18 +9,21 @@ import {
|
|||
createEvent,
|
||||
} from '@testing-library/react';
|
||||
import { useSelect } from '@wordpress/data';
|
||||
import { useUser } from '@woocommerce/data';
|
||||
import { useUser, useUserPreferences } from '@woocommerce/data';
|
||||
import { useState } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ActivityPanel } from '../';
|
||||
import { ActivityPanel } from '../activity-panel';
|
||||
import { Panel } from '../panel';
|
||||
|
||||
jest.mock( '@woocommerce/data', () => ( {
|
||||
...jest.requireActual( '@woocommerce/data' ),
|
||||
useUser: jest.fn().mockReturnValue( { currentUserCan: () => true } ),
|
||||
useUserPreferences: jest.fn().mockReturnValue( {
|
||||
updateUserPreferences: () => {},
|
||||
} ),
|
||||
} ) );
|
||||
|
||||
// We aren't testing the <DisplayOptions /> component here.
|
||||
|
@ -214,14 +217,12 @@ describe( 'Activity Panel', () => {
|
|||
|
||||
describe( 'help panel tooltip', () => {
|
||||
it( 'should render highlight tooltip when task count is at-least 2, task is not completed, and tooltip not shown yet', () => {
|
||||
useUserPreferences.mockReturnValue( {
|
||||
updateUserPreferences: () => {},
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
} );
|
||||
const { getByText } = render(
|
||||
<ActivityPanel
|
||||
userPreferencesData={ {
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
} }
|
||||
isEmbedded
|
||||
query={ { task: 'payment' } }
|
||||
/>
|
||||
<ActivityPanel isEmbedded query={ { task: 'payment' } } />
|
||||
);
|
||||
|
||||
expect( getByText( '[HighlightTooltip]' ) ).toBeInTheDocument();
|
||||
|
@ -234,26 +235,23 @@ describe( 'Activity Panel', () => {
|
|||
setupTaskListHidden: false,
|
||||
trackedCompletedTasks: [],
|
||||
} ) );
|
||||
useUserPreferences.mockReturnValue( {
|
||||
updateUserPreferences: () => {},
|
||||
task_list_tracked_started_tasks: { payment: 1 },
|
||||
} );
|
||||
render(
|
||||
<ActivityPanel
|
||||
userPreferencesData={ {
|
||||
task_list_tracked_started_tasks: { payment: 1 },
|
||||
} }
|
||||
isEmbedded
|
||||
query={ { task: 'payment' } }
|
||||
/>
|
||||
<ActivityPanel isEmbedded query={ { task: 'payment' } } />
|
||||
);
|
||||
|
||||
expect( screen.queryByText( '[HighlightTooltip]' ) ).toBeNull();
|
||||
|
||||
useUserPreferences.mockReturnValue( {
|
||||
updateUserPreferences: () => {},
|
||||
task_list_tracked_started_tasks: {},
|
||||
} );
|
||||
|
||||
render(
|
||||
<ActivityPanel
|
||||
userPreferencesData={ {
|
||||
task_list_tracked_started_tasks: {},
|
||||
} }
|
||||
isEmbedded
|
||||
query={ { task: 'payment' } }
|
||||
/>
|
||||
<ActivityPanel isEmbedded query={ { task: 'payment' } } />
|
||||
);
|
||||
|
||||
expect( screen.queryByText( '[HighlightTooltip]' ) ).toBeNull();
|
||||
|
@ -267,29 +265,26 @@ describe( 'Activity Panel', () => {
|
|||
isCompletedTask: true,
|
||||
} ) );
|
||||
|
||||
useUserPreferences.mockReturnValue( {
|
||||
updateUserPreferences: () => {},
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
} );
|
||||
|
||||
const { queryByText } = render(
|
||||
<ActivityPanel
|
||||
userPreferencesData={ {
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
} }
|
||||
isEmbedded
|
||||
query={ { task: 'payment' } }
|
||||
/>
|
||||
<ActivityPanel isEmbedded query={ { task: 'payment' } } />
|
||||
);
|
||||
|
||||
expect( queryByText( '[HighlightTooltip]' ) ).toBeNull();
|
||||
} );
|
||||
|
||||
it( 'should not render highlight tooltip when task is visited twice, not completed, but already shown', () => {
|
||||
useUserPreferences.mockReturnValue( {
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
help_panel_highlight_shown: 'yes',
|
||||
} );
|
||||
|
||||
const { queryByText } = render(
|
||||
<ActivityPanel
|
||||
userPreferencesData={ {
|
||||
task_list_tracked_started_tasks: { payment: 2 },
|
||||
help_panel_highlight_shown: 'yes',
|
||||
} }
|
||||
isEmbedded
|
||||
query={ { task: 'payment' } }
|
||||
/>
|
||||
<ActivityPanel isEmbedded query={ { task: 'payment' } } />
|
||||
);
|
||||
|
||||
expect( queryByText( '[HighlightTooltip]' ) ).toBeNull();
|
|
@ -11,7 +11,7 @@ import { getSetting } from '@woocommerce/wc-admin-settings';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { getUnreadNotesCount } from '../../inbox-panel/utils';
|
||||
import { getUnreadNotesCount } from '~/inbox-panel/utils';
|
||||
|
||||
const UNREAD_NOTES_QUERY = {
|
||||
page: 1,
|
|
@ -3,93 +3,40 @@
|
|||
*/
|
||||
import { __, sprintf } from '@wordpress/i18n';
|
||||
import { useEffect, useLayoutEffect, useRef } from '@wordpress/element';
|
||||
import { Tooltip } from '@wordpress/components';
|
||||
import classnames from 'classnames';
|
||||
import { decodeEntities } from '@wordpress/html-entities';
|
||||
import { useUserPreferences } from '@woocommerce/data';
|
||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||
import { Text } from '@woocommerce/experimental';
|
||||
import { Icon, chevronLeft } from '@wordpress/icons';
|
||||
import { getHistory, updateQueryString } from '@woocommerce/navigation';
|
||||
import { ENTER, SPACE } from '@wordpress/keycodes';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { Text, useSlot } from '@woocommerce/experimental';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
import ActivityPanel from './activity-panel';
|
||||
import { MobileAppBanner } from '../mobile-banner';
|
||||
import useIsScrolled from '../hooks/useIsScrolled';
|
||||
import Navigation from '../navigation';
|
||||
import {
|
||||
WooHeaderNavigationItem,
|
||||
WooHeaderItem,
|
||||
WooHeaderPageTitle,
|
||||
} from './utils';
|
||||
|
||||
const renderTaskListBackButton = () => {
|
||||
const currentUrl = new URL( window.location.href );
|
||||
const task = currentUrl.searchParams.get( 'task' );
|
||||
|
||||
if ( task ) {
|
||||
const homeText = __( 'WooCommerce Home', 'woocommerce-admin' );
|
||||
|
||||
const navigateHome = () => {
|
||||
recordEvent( 'topbar_back_button', {
|
||||
page_name: getPageTitle( window.title ),
|
||||
} );
|
||||
updateQueryString( {}, getHistory().location.pathname, {} );
|
||||
};
|
||||
|
||||
// if it's a task list page, render a back button to the homescreen
|
||||
return (
|
||||
<Tooltip text={ homeText }>
|
||||
<div
|
||||
tabIndex="0"
|
||||
role="button"
|
||||
data-testid="header-back-button"
|
||||
className="woocommerce-layout__header-back-button"
|
||||
onKeyDown={ ( { keyCode } ) => {
|
||||
if ( keyCode === ENTER || keyCode === SPACE ) {
|
||||
navigateHome();
|
||||
}
|
||||
} }
|
||||
>
|
||||
<Icon icon={ chevronLeft } onClick={ navigateHome } />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const getPageTitle = ( defaultTitle ) => {
|
||||
const currentUrl = new URL( window.location.href );
|
||||
const task = currentUrl.searchParams.get( 'task' );
|
||||
|
||||
// If it's the task list then render a title based on which task the user is on.
|
||||
return (
|
||||
{
|
||||
payments: __( 'Set up payments', 'woocommerce-admin' ),
|
||||
tax: __( 'Add tax rates', 'woocommerce-admin' ),
|
||||
appearance: __( 'Personalize your store', 'woocommerce-admin' ),
|
||||
marketing: __( 'Set up marketing tools', 'woocommerce-admin' ),
|
||||
products: __( 'Add products', 'woocommerce-admin' ),
|
||||
shipping: __( 'Set up shipping costs', 'woocommerce-admin' ),
|
||||
}[ task ] || defaultTitle
|
||||
);
|
||||
};
|
||||
export const PAGE_TITLE_FILTER = 'woocommerce_admin_header_page_title';
|
||||
|
||||
export const Header = ( { sections, isEmbedded = false, query } ) => {
|
||||
const headerElement = useRef( null );
|
||||
const siteTitle = getSetting( 'siteTitle', '' );
|
||||
const pageTitle = sections.slice( -1 )[ 0 ];
|
||||
const isScrolled = useIsScrolled();
|
||||
const { updateUserPreferences, ...userData } = useUserPreferences();
|
||||
const isModalDismissed = userData.android_app_banner_dismissed === 'yes';
|
||||
let debounceTimer = null;
|
||||
|
||||
const className = classnames( 'woocommerce-layout__header', {
|
||||
'is-scrolled': isScrolled,
|
||||
} );
|
||||
|
||||
const pageTitleSlot = useSlot( 'woocommerce_header_page_title' );
|
||||
const hasPageTitleFills = Boolean( pageTitleSlot?.fills?.length );
|
||||
const headerItemSlot = useSlot( 'woocommerce_header_item' );
|
||||
const headerItemSlotFills = headerItemSlot?.fills;
|
||||
|
||||
useLayoutEffect( () => {
|
||||
updateBodyMargin();
|
||||
window.addEventListener( 'resize', updateBodyMargin );
|
||||
|
@ -103,7 +50,7 @@ export const Header = ( { sections, isEmbedded = false, query } ) => {
|
|||
|
||||
wpBody.style.marginTop = null;
|
||||
};
|
||||
}, [ isModalDismissed ] );
|
||||
}, [ headerItemSlotFills ] );
|
||||
|
||||
const updateBodyMargin = () => {
|
||||
clearTimeout( debounceTimer );
|
||||
|
@ -145,44 +92,29 @@ export const Header = ( { sections, isEmbedded = false, query } ) => {
|
|||
}
|
||||
}, [ isEmbedded, sections, siteTitle ] );
|
||||
|
||||
const dismissHandler = () => {
|
||||
updateUserPreferences( {
|
||||
android_app_banner_dismissed: 'yes',
|
||||
} );
|
||||
};
|
||||
|
||||
const backButton = renderTaskListBackButton();
|
||||
const backButtonClass = backButton ? 'with-back-button' : '';
|
||||
|
||||
return (
|
||||
<div className={ className } ref={ headerElement }>
|
||||
{ ! isModalDismissed && (
|
||||
<MobileAppBanner
|
||||
onDismiss={ dismissHandler }
|
||||
onInstall={ dismissHandler }
|
||||
/>
|
||||
) }
|
||||
|
||||
<div className="woocommerce-layout__header-wrapper">
|
||||
{ window.wcAdminFeatures.navigation && <Navigation /> }
|
||||
{ renderTaskListBackButton() }
|
||||
<WooHeaderNavigationItem.Slot
|
||||
fillProps={ { isEmbedded, query } }
|
||||
/>
|
||||
|
||||
<Text
|
||||
className={ `woocommerce-layout__header-heading ${ backButtonClass }` }
|
||||
className={ `woocommerce-layout__header-heading` }
|
||||
as="h1"
|
||||
>
|
||||
{ getPageTitle( decodeEntities( pageTitle ) ) }
|
||||
{ decodeEntities(
|
||||
hasPageTitleFills ? (
|
||||
<WooHeaderPageTitle.Slot
|
||||
fillProps={ { isEmbedded, query } }
|
||||
/>
|
||||
) : (
|
||||
pageTitle
|
||||
)
|
||||
) }
|
||||
</Text>
|
||||
|
||||
{ window.wcAdminFeatures[ 'activity-panels' ] && (
|
||||
<ActivityPanel
|
||||
isEmbedded={ isEmbedded }
|
||||
query={ query }
|
||||
userPreferencesData={ {
|
||||
...userData,
|
||||
updateUserPreferences,
|
||||
} }
|
||||
/>
|
||||
) }
|
||||
<WooHeaderItem.Slot fillProps={ { isEmbedded, query } } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -17,16 +17,6 @@
|
|||
min-height: $header-height;
|
||||
}
|
||||
|
||||
.woocommerce-layout__header-back-button {
|
||||
cursor: pointer;
|
||||
margin-left: $gutter-large;
|
||||
display: flex;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset -1px -1px 0 #757575, inset 1px 1px 0 #757575;
|
||||
}
|
||||
}
|
||||
|
||||
@include breakpoint( '<782px' ) {
|
||||
flex-flow: row wrap;
|
||||
top: $adminbar-height-mobile;
|
||||
|
@ -53,10 +43,6 @@
|
|||
background: $studio-white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
|
||||
&.with-back-button {
|
||||
padding-left: $fallback-gutter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,13 +49,6 @@ const encodedBreadcrumb = [
|
|||
'Accounts & Privacy',
|
||||
];
|
||||
|
||||
const stubLocation = ( location ) => {
|
||||
jest.spyOn( window, 'location', 'get' ).mockReturnValue( {
|
||||
...window.location,
|
||||
...location,
|
||||
} );
|
||||
};
|
||||
|
||||
describe( 'Header', () => {
|
||||
beforeEach( () => {
|
||||
// Mock RAF to be synchronous for testing
|
||||
|
@ -75,20 +68,6 @@ describe( 'Header', () => {
|
|||
window.requestAnimationFrame.mockRestore();
|
||||
} );
|
||||
|
||||
it( 'should render a back button and a custom title on task list pages', () => {
|
||||
stubLocation( { href: 'http://localhost?task=payments' } );
|
||||
|
||||
const { queryByTestId, queryByText } = render(
|
||||
<Header sections={ encodedBreadcrumb } isEmbedded={ false } />
|
||||
);
|
||||
|
||||
expect(
|
||||
queryByTestId( 'header-back-button' )
|
||||
).not.toBeEmptyDOMElement();
|
||||
|
||||
expect( queryByText( 'Set up payments' ) ).not.toBeEmptyDOMElement();
|
||||
} );
|
||||
|
||||
it( 'should render decoded breadcrumb name', () => {
|
||||
const { queryByText } = render(
|
||||
<Header sections={ encodedBreadcrumb } isEmbedded={ true } />
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Slot, Fill } from '@wordpress/components';
|
||||
import { cloneElement } from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Ordered header item.
|
||||
*
|
||||
* @param {Node} children - Node children.
|
||||
* @param {number} order - Node order.
|
||||
* @param {Array} props - Fill props.
|
||||
* @return {Node} Node.
|
||||
*/
|
||||
const createOrderedChildren = ( children, order, props ) => {
|
||||
return typeof children === 'function'
|
||||
? cloneElement( children( props ), { order } )
|
||||
: cloneElement( children, { ...props, order } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a Fill for extensions to add items to the WooCommerce Admin header.
|
||||
*
|
||||
* @slotFill WooHeaderItem
|
||||
* @example
|
||||
* const MyHeaderItem = () => (
|
||||
* <WooHeaderItem>My header item</WooHeaderItem>
|
||||
* );
|
||||
*
|
||||
* registerPlugin( 'my-extension', {
|
||||
* render: MyHeaderItem,
|
||||
* scope: 'woocommerce-admin',
|
||||
* } );
|
||||
* @param {Object} param0
|
||||
* @param {Array} param0.children - Node children.
|
||||
* @param {Array} param0.order - Node order.
|
||||
*/
|
||||
export const WooHeaderItem = ( { children, order = 1 } ) => {
|
||||
return (
|
||||
<Fill name={ 'woocommerce_header_item' }>
|
||||
{ ( fillProps ) => {
|
||||
return createOrderedChildren( children, order, fillProps );
|
||||
} }
|
||||
</Fill>
|
||||
);
|
||||
};
|
||||
|
||||
WooHeaderItem.Slot = ( { fillProps } ) => (
|
||||
<Slot name={ 'woocommerce_header_item' } fillProps={ fillProps }>
|
||||
{ ( fills ) => {
|
||||
return fills.sort( ( a, b ) => {
|
||||
return a[ 0 ].props.order - b[ 0 ].props.order;
|
||||
} );
|
||||
} }
|
||||
</Slot>
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a Fill for extensions to add items to the WooCommerce Admin
|
||||
* navigation area left of the page title.
|
||||
*
|
||||
* @slotFill WooHeaderNavigationItem
|
||||
* @example
|
||||
* const MyNavigationItem = () => (
|
||||
* <WooHeaderNavigationItem>My nav item</WooHeaderNavigationItem>
|
||||
* );
|
||||
*
|
||||
* registerPlugin( 'my-extension', {
|
||||
* render: MyNavigationItem,
|
||||
* scope: 'woocommerce-admin',
|
||||
* } );
|
||||
* @param {Object} param0
|
||||
* @param {Array} param0.children - Node children.
|
||||
* @param {Array} param0.order - Node order.
|
||||
*/
|
||||
export const WooHeaderNavigationItem = ( { children, order = 1 } ) => {
|
||||
return (
|
||||
<Fill name={ 'woocommerce_header_navigation_item' }>
|
||||
{ ( fillProps ) => {
|
||||
return createOrderedChildren( children, order, fillProps );
|
||||
} }
|
||||
</Fill>
|
||||
);
|
||||
};
|
||||
|
||||
WooHeaderNavigationItem.Slot = ( { fillProps } ) => (
|
||||
<Slot name={ 'woocommerce_header_navigation_item' } fillProps={ fillProps }>
|
||||
{ ( fills ) => {
|
||||
return fills.sort( ( a, b ) => {
|
||||
return a[ 0 ].props.order - b[ 0 ].props.order;
|
||||
} );
|
||||
} }
|
||||
</Slot>
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a Fill for extensions to add custom page titles.
|
||||
*
|
||||
* @slotFill WooHeaderPageTitle
|
||||
* @example
|
||||
* const MyPageTitle = () => (
|
||||
* <WooHeaderPageTitle>My page title</WooHeaderPageTitle>
|
||||
* );
|
||||
*
|
||||
* registerPlugin( 'my-page-title', {
|
||||
* render: MyPageTitle,
|
||||
* scope: 'woocommerce-admin',
|
||||
* } );
|
||||
* @param {Object} param0
|
||||
* @param {Array} param0.children - Node children.
|
||||
*/
|
||||
export const WooHeaderPageTitle = ( { children } ) => {
|
||||
return <Fill name={ 'woocommerce_header_page_title' }>{ children }</Fill>;
|
||||
};
|
||||
|
||||
WooHeaderPageTitle.Slot = ( { fillProps } ) => (
|
||||
<Slot name={ 'woocommerce_header_page_title' } fillProps={ fillProps }>
|
||||
{ ( fills ) => {
|
||||
const last = fills.pop();
|
||||
return [ last ];
|
||||
} }
|
||||
</Slot>
|
||||
);
|
|
@ -25,7 +25,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
import {
|
||||
ActivityCard,
|
||||
ActivityCardPlaceholder,
|
||||
} from '../../../header/activity-panel/activity-card';
|
||||
} from '~/activity-panel/activity-card';
|
||||
import './style.scss';
|
||||
|
||||
function recordOrderEvent( eventName ) {
|
||||
|
|
|
@ -30,7 +30,7 @@ import './style.scss';
|
|||
import {
|
||||
ActivityCard,
|
||||
ActivityCardPlaceholder,
|
||||
} from '../../../header/activity-panel/activity-card';
|
||||
} from '~/activity-panel/activity-card';
|
||||
import CheckmarkCircleIcon from './checkmark-circle-icon';
|
||||
import { CurrencyContext } from '../../../lib/currency-context';
|
||||
import sanitizeHTML from '../../../lib/sanitize-html';
|
||||
|
|
|
@ -15,7 +15,7 @@ import moment from 'moment';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ActivityCard } from '../../../header/activity-panel/activity-card';
|
||||
import { ActivityCard } from '~/activity-panel/activity-card';
|
||||
|
||||
export class ProductStockCard extends Component {
|
||||
constructor( props ) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import { ITEMS_STORE_NAME } from '@woocommerce/data';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ActivityCardPlaceholder } from '../../../header/activity-panel/activity-card';
|
||||
import { ActivityCardPlaceholder } from '~/activity-panel/activity-card';
|
||||
import { ProductStockCard } from './card';
|
||||
import { getLowStockCountQuery } from '../orders/utils';
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ import { useExperiment } from '@woocommerce/explat';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import ActivityHeader from '../header/activity-panel/activity-header';
|
||||
import ActivityHeader from '~/activity-panel/activity-header';
|
||||
import { ActivityPanel } from './activity-panel';
|
||||
import { Column } from './column';
|
||||
import InboxPanel from '../inbox-panel';
|
||||
|
|
|
@ -23,7 +23,7 @@ import moment from 'moment';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ActivityCard } from '../header/activity-panel/activity-card';
|
||||
import { ActivityCard } from '~/activity-panel/activity-card';
|
||||
import { hasValidNotes, truncateRenderableHTML } from './utils';
|
||||
import { getScreenName } from '../utils';
|
||||
import DismissAllModal from './dissmiss-all-modal';
|
||||
|
|
|
@ -29,6 +29,8 @@ import { Controller, getPages } from './controller';
|
|||
import { Header } from '../header';
|
||||
import Notices from './notices';
|
||||
import TransientNotices from './transient-notices';
|
||||
import '~/activity-panel';
|
||||
import '~/mobile-banner';
|
||||
import './navigation';
|
||||
|
||||
const StoreAlerts = lazy( () =>
|
||||
|
|
|
@ -18,6 +18,8 @@ import { NAVIGATION_STORE_NAME } from '@woocommerce/data';
|
|||
import getReports from '../analytics/report/get-reports';
|
||||
import { getPages } from './controller';
|
||||
import { isWCAdmin } from '../dashboard/utils';
|
||||
import Navigation from '~/navigation';
|
||||
import { WooHeaderNavigationItem } from '~/header/utils';
|
||||
|
||||
const NavigationPlugin = () => {
|
||||
const { persistedQuery } = useSelect( ( select ) => {
|
||||
|
@ -26,13 +28,21 @@ const NavigationPlugin = () => {
|
|||
};
|
||||
} );
|
||||
|
||||
if ( ! window.wcAdminFeatures.navigation ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the current page is embedded, stay with the default urls
|
||||
* provided by Navigation because the router isn't present to
|
||||
* respond to <Link /> component's manipulation of the url.
|
||||
*/
|
||||
if ( ! isWCAdmin( window.location.href ) ) {
|
||||
return null;
|
||||
return (
|
||||
<WooHeaderNavigationItem order={ -100 }>
|
||||
<Navigation />
|
||||
</WooHeaderNavigationItem>
|
||||
);
|
||||
}
|
||||
|
||||
const reports = getReports().filter( ( item ) => item.navArgs );
|
||||
|
@ -51,6 +61,9 @@ const NavigationPlugin = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<WooHeaderNavigationItem order={ -100 }>
|
||||
<Navigation />
|
||||
</WooHeaderNavigationItem>
|
||||
{ pages.map( ( page ) => (
|
||||
<WooNavigationItem
|
||||
item={ page.navArgs.id }
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React, { useEffect, useState } from '@wordpress/element';
|
||||
import { Button } from '@wordpress/components';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import GridiconCrossIcon from 'gridicons/dist/cross-small';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { platform, ANDROID_PLATFORM } from '../lib/platform';
|
||||
import { AppIcon } from './app-icon';
|
||||
import { PLAY_STORE_LINK, TRACKING_EVENT_NAME } from './constants';
|
||||
import './banner.scss';
|
||||
|
||||
const SHOW_APP_BANNER_MODIFIER_CLASS = 'woocommerce-layout__show-app-banner';
|
||||
|
||||
export const Banner = ( { onInstall, onDismiss } ) => {
|
||||
const [ isActioned, setIsActioned ] = useState( false );
|
||||
const isVisible = platform() === ANDROID_PLATFORM && ! isActioned;
|
||||
|
||||
useEffect( () => {
|
||||
const layout = document.getElementsByClassName(
|
||||
'woocommerce-layout'
|
||||
)[ 0 ];
|
||||
|
||||
if ( isVisible && layout ) {
|
||||
// This is a hack to allow the mobile banner to work in the context of the header which is
|
||||
// position fixed. This can be refactored away when we move away from the activity panel
|
||||
// in future.
|
||||
layout.classList.add( SHOW_APP_BANNER_MODIFIER_CLASS );
|
||||
}
|
||||
|
||||
return () => {
|
||||
if ( layout ) {
|
||||
layout.classList.remove( SHOW_APP_BANNER_MODIFIER_CLASS );
|
||||
}
|
||||
};
|
||||
}, [ isVisible ] );
|
||||
|
||||
if ( ! isVisible ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="woocommerce-mobile-app-banner">
|
||||
<Icon
|
||||
icon={ <GridiconCrossIcon data-testid="dismiss-btn" /> }
|
||||
onClick={ () => {
|
||||
onDismiss();
|
||||
setIsActioned( true );
|
||||
recordEvent( TRACKING_EVENT_NAME, {
|
||||
action: 'dismiss',
|
||||
} );
|
||||
} }
|
||||
/>
|
||||
<AppIcon />
|
||||
<div className="woocommerce-mobile-app-banner__description">
|
||||
<p className="woocommerce-mobile-app-banner__description__text">
|
||||
{ __(
|
||||
'Run your store from anywhere',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
</p>
|
||||
<p className="woocommerce-mobile-app-banner__description__text">
|
||||
{ __(
|
||||
'Download the WooCommerce app',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
href={ PLAY_STORE_LINK }
|
||||
isSecondary
|
||||
onClick={ () => {
|
||||
onInstall();
|
||||
setIsActioned( true );
|
||||
recordEvent( TRACKING_EVENT_NAME, {
|
||||
action: 'install',
|
||||
} );
|
||||
} }
|
||||
>
|
||||
{ __( 'Install', 'woocommerce-admin' ) }
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -4,15 +4,18 @@ $banner-height: 56px;
|
|||
// This class is a hack, added conditionally when displaying the app banner, it
|
||||
// can be refactored away when the activity panel goes away.
|
||||
.woocommerce-layout__show-app-banner {
|
||||
padding-top: $banner-height;
|
||||
|
||||
@include breakpoint( '>782px' ) {
|
||||
padding-top: 0;
|
||||
@include breakpoint( '<782px' ) {
|
||||
.woocommerce-layout__header-wrapper {
|
||||
padding-top: $banner-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.woocommerce-mobile-app-banner {
|
||||
background-color: $woocommerce-brand-purple;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: $banner-height;
|
|
@ -1,93 +1,37 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React, { useEffect, useState } from '@wordpress/element';
|
||||
import { Button } from '@wordpress/components';
|
||||
import { Icon } from '@wordpress/icons';
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import GridiconCrossIcon from 'gridicons/dist/cross-small';
|
||||
import { registerPlugin } from '@wordpress/plugins';
|
||||
import { useUserPreferences } from '@woocommerce/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { platform, ANDROID_PLATFORM } from '../lib/platform';
|
||||
import { AppIcon } from './app-icon';
|
||||
import './style.scss';
|
||||
import { PLAY_STORE_LINK, TRACKING_EVENT_NAME } from './constants';
|
||||
import { Banner } from './banner';
|
||||
import { WooHeaderItem } from '~/header/utils';
|
||||
|
||||
const SHOW_APP_BANNER_MODIFIER_CLASS = 'woocommerce-layout__show-app-banner';
|
||||
export const MobileAppBanner = () => {
|
||||
const { updateUserPreferences, ...userData } = useUserPreferences();
|
||||
const isDismissed = userData.android_app_banner_dismissed === 'yes';
|
||||
|
||||
export const MobileAppBanner = ( { onInstall, onDismiss } ) => {
|
||||
useEffect( () => {
|
||||
const layout = document.getElementsByClassName(
|
||||
'woocommerce-layout'
|
||||
)[ 0 ];
|
||||
const onClick = () => {
|
||||
updateUserPreferences( {
|
||||
android_app_banner_dismissed: 'yes',
|
||||
} );
|
||||
};
|
||||
|
||||
if ( platform() === ANDROID_PLATFORM ) {
|
||||
if ( layout ) {
|
||||
// This is a hack to allow the mobile banner to work in the context of the header which is
|
||||
// position fixed. This can be refactored away when we move away from the activity panel
|
||||
// in future.
|
||||
layout.classList.add( SHOW_APP_BANNER_MODIFIER_CLASS );
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
if ( layout ) {
|
||||
layout.classList.remove( SHOW_APP_BANNER_MODIFIER_CLASS );
|
||||
}
|
||||
};
|
||||
}, [] );
|
||||
|
||||
const [ isDismissed, setDismissed ] = useState( false );
|
||||
|
||||
// On iOS the "Smart App Banner" meta tag is used so only display this on Android.
|
||||
if ( platform() === ANDROID_PLATFORM && ! isDismissed ) {
|
||||
return (
|
||||
<div className="woocommerce-mobile-app-banner">
|
||||
<Icon
|
||||
icon={ <GridiconCrossIcon data-testid="dismiss-btn" /> }
|
||||
onClick={ () => {
|
||||
onDismiss();
|
||||
setDismissed( true );
|
||||
recordEvent( TRACKING_EVENT_NAME, {
|
||||
action: 'dismiss',
|
||||
} );
|
||||
} }
|
||||
/>
|
||||
<AppIcon />
|
||||
<div className="woocommerce-mobile-app-banner__description">
|
||||
<p className="woocommerce-mobile-app-banner__description__text">
|
||||
{ __(
|
||||
'Run your store from anywhere',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
</p>
|
||||
<p className="woocommerce-mobile-app-banner__description__text">
|
||||
{ __(
|
||||
'Download the WooCommerce app',
|
||||
'woocommerce-admin'
|
||||
) }
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
href={ PLAY_STORE_LINK }
|
||||
isSecondary
|
||||
onClick={ () => {
|
||||
onInstall();
|
||||
setDismissed( true );
|
||||
recordEvent( TRACKING_EVENT_NAME, {
|
||||
action: 'install',
|
||||
} );
|
||||
} }
|
||||
>
|
||||
{ __( 'Install', 'woocommerce-admin' ) }
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
if ( isDismissed ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
return (
|
||||
<WooHeaderItem>
|
||||
<Banner onDismiss={ onClick } onInstall={ onClick } />
|
||||
</WooHeaderItem>
|
||||
);
|
||||
};
|
||||
|
||||
registerPlugin( 'mobile-banner-header-item', {
|
||||
render: MobileAppBanner,
|
||||
scope: 'woocommerce-admin',
|
||||
} );
|
||||
|
|
|
@ -22,18 +22,18 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { MobileAppBanner } from '../index';
|
||||
import { Banner } from '../banner';
|
||||
import { platform } from '../../lib/platform';
|
||||
import { TRACKING_EVENT_NAME } from '../constants';
|
||||
|
||||
describe( 'MobileAppBanner', () => {
|
||||
describe( 'Banner', () => {
|
||||
beforeEach( () => {
|
||||
platform.mockReturnValue( 'android' );
|
||||
} );
|
||||
|
||||
it( 'closes if the user dismisses it', () => {
|
||||
const { container, getByTestId } = render(
|
||||
<MobileAppBanner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
<Banner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
fireEvent.click( getByTestId( 'dismiss-btn' ) );
|
||||
|
@ -42,7 +42,7 @@ describe( 'MobileAppBanner', () => {
|
|||
|
||||
it( 'closes if the user clicks install', () => {
|
||||
const { queryByRole, container } = render(
|
||||
<MobileAppBanner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
<Banner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
fireEvent.click( queryByRole( 'link' ) );
|
||||
|
@ -51,7 +51,7 @@ describe( 'MobileAppBanner', () => {
|
|||
|
||||
it( 'records a tracking event for install', () => {
|
||||
const { queryByRole } = render(
|
||||
<MobileAppBanner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
<Banner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
fireEvent.click( queryByRole( 'link' ) );
|
||||
|
@ -62,7 +62,7 @@ describe( 'MobileAppBanner', () => {
|
|||
|
||||
it( 'records a dismiss event for dismiss', () => {
|
||||
const { container, getByTestId } = render(
|
||||
<MobileAppBanner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
<Banner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
fireEvent.click( getByTestId( 'dismiss-btn' ) );
|
||||
|
@ -76,10 +76,7 @@ describe( 'MobileAppBanner', () => {
|
|||
it( 'calls the onDismiss handler when dismiss is clicked', () => {
|
||||
const dismissHandler = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<MobileAppBanner
|
||||
onInstall={ () => {} }
|
||||
onDismiss={ dismissHandler }
|
||||
/>
|
||||
<Banner onInstall={ () => {} } onDismiss={ dismissHandler } />
|
||||
);
|
||||
|
||||
fireEvent.click( getByTestId( 'dismiss-btn' ) );
|
||||
|
@ -89,10 +86,7 @@ describe( 'MobileAppBanner', () => {
|
|||
it( 'calls the onInstall handler when install is clicked', () => {
|
||||
const installHandler = jest.fn();
|
||||
const { queryByRole } = render(
|
||||
<MobileAppBanner
|
||||
onInstall={ installHandler }
|
||||
onDismiss={ () => {} }
|
||||
/>
|
||||
<Banner onInstall={ installHandler } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
fireEvent.click( queryByRole( 'link' ) );
|
||||
|
@ -103,7 +97,7 @@ describe( 'MobileAppBanner', () => {
|
|||
platform.mockReturnValue( 'ios' );
|
||||
|
||||
const { container } = render(
|
||||
<MobileAppBanner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
<Banner onInstall={ () => {} } onDismiss={ () => {} } />
|
||||
);
|
||||
|
||||
expect( container ).toBeEmptyDOMElement();
|
||||
|
|
|
@ -8,7 +8,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { HighlightTooltip } from '../../../header/activity-panel/highlight-tooltip';
|
||||
import { HighlightTooltip } from '~/activity-panel/highlight-tooltip';
|
||||
|
||||
const tooltipHiddenOption = 'woocommerce_navigation_favorites_tooltip_hidden';
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
.woocommerce-layout__header-back-button {
|
||||
cursor: pointer;
|
||||
margin-left: $fallback-gutter-large;
|
||||
margin-left: $gutter-large;
|
||||
margin-right: -$gap;
|
||||
display: flex;
|
||||
z-index: 2;
|
||||
|
||||
&:focus {
|
||||
box-shadow: inset -1px -1px 0 #757575, inset 1px 1px 0 #757575;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { Tooltip } from '@wordpress/components';
|
||||
import { Icon, chevronLeft } from '@wordpress/icons';
|
||||
import { getHistory, updateQueryString } from '@woocommerce/navigation';
|
||||
import { ENTER, SPACE } from '@wordpress/keycodes';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './back-button.scss';
|
||||
|
||||
export type BackButtonProps = {
|
||||
title: string;
|
||||
};
|
||||
|
||||
export const BackButton: React.FC< BackButtonProps > = ( { title } ) => {
|
||||
const homeText = __( 'WooCommerce Home', 'woocommerce-admin' );
|
||||
|
||||
const navigateHome = () => {
|
||||
recordEvent( 'topbar_back_button', {
|
||||
page_name: title,
|
||||
} );
|
||||
updateQueryString( {}, getHistory().location.pathname, {} );
|
||||
};
|
||||
|
||||
// if it's a task list page, render a back button to the homescreen
|
||||
return (
|
||||
<Tooltip text={ homeText }>
|
||||
<div
|
||||
tabIndex={ 0 }
|
||||
role="button"
|
||||
data-testid="header-back-button"
|
||||
className="woocommerce-layout__header-back-button"
|
||||
onKeyDown={ ( { keyCode } ) => {
|
||||
if ( keyCode === ENTER || keyCode === SPACE ) {
|
||||
navigateHome();
|
||||
}
|
||||
} }
|
||||
>
|
||||
<Icon icon={ chevronLeft } onClick={ navigateHome } />
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
|
@ -1,12 +1,19 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { addFilter } from '@wordpress/hooks';
|
||||
import { WooOnboardingTask } from '@woocommerce/onboarding';
|
||||
import { getHistory, getNewPath } from '@woocommerce/navigation';
|
||||
import { ONBOARDING_STORE_NAME, TaskType } from '@woocommerce/data';
|
||||
import { useCallback } from '@wordpress/element';
|
||||
import { useDispatch } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { WooHeaderNavigationItem, WooHeaderPageTitle } from '~/header/utils';
|
||||
import { BackButton } from './back-button';
|
||||
|
||||
export type TaskProps = {
|
||||
query: { task: string };
|
||||
task?: TaskType;
|
||||
|
@ -26,9 +33,15 @@ export const Task: React.FC< TaskProps > = ( { query, task } ) => {
|
|||
}, [ id ] );
|
||||
|
||||
return (
|
||||
<WooOnboardingTask.Slot
|
||||
id={ id }
|
||||
fillProps={ { onComplete, query, task } }
|
||||
/>
|
||||
<>
|
||||
<WooHeaderNavigationItem>
|
||||
<BackButton title={ task.title } />
|
||||
</WooHeaderNavigationItem>
|
||||
<WooHeaderPageTitle>{ task.title }</WooHeaderPageTitle>
|
||||
<WooOnboardingTask.Slot
|
||||
id={ id }
|
||||
fillProps={ { onComplete, query, task } }
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { DisplayOption } from '../header/activity-panel/display-options';
|
||||
import { DisplayOption } from '~/activity-panel/display-options';
|
||||
import { Task } from './task';
|
||||
import { TaskList } from './task-list';
|
||||
import { TasksPlaceholder } from './placeholder';
|
||||
|
|
|
@ -48,7 +48,7 @@ describe( 'Task', () => {
|
|||
it( 'should pass the task name as id to the OnboardingTask.Slot', () => {
|
||||
const { queryByText } = render(
|
||||
<div>
|
||||
<Task query={ { task: 'test' } } />
|
||||
<Task query={ { task: 'test' } } task={ { title: 'Test' } } />
|
||||
</div>
|
||||
);
|
||||
expect( queryByText( 'test' ) ).toBeInTheDocument();
|
||||
|
@ -63,7 +63,7 @@ describe( 'Task', () => {
|
|||
} );
|
||||
const { getByRole } = render(
|
||||
<div>
|
||||
<Task query={ { task: 'test' } } />
|
||||
<Task query={ { task: 'test' } } task={ { title: 'Test' } } />
|
||||
</div>
|
||||
);
|
||||
act( () => {
|
||||
|
|
|
@ -28,7 +28,7 @@ jest.mock( '../placeholder', () => ( {
|
|||
TasksPlaceholder: () => <div>task-placeholder</div>,
|
||||
} ) );
|
||||
|
||||
jest.mock( '../../header/activity-panel/display-options', () => ( {
|
||||
jest.mock( '~/activity-panel/display-options', () => ( {
|
||||
DisplayOption: ( { children } ) => <div>{ children } </div>,
|
||||
} ) );
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { recordEvent } from '@woocommerce/tracks';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { DisplayOption } from '../header/activity-panel/display-options';
|
||||
import { DisplayOption } from '~/activity-panel/display-options';
|
||||
import { Task } from '../tasks/task';
|
||||
import { TaskList } from '../tasks/task-list';
|
||||
import { TasksPlaceholder } from '../tasks/placeholder';
|
||||
|
|
|
@ -8,7 +8,7 @@ export class ProductsSetup extends BasePage {
|
|||
url = 'wp-admin/admin.php?page=wc-admin&task=products';
|
||||
|
||||
async isDisplayed() {
|
||||
await waitForElementByText( 'h1', 'Add products' );
|
||||
await waitForElementByText( 'h1', 'Add my products' );
|
||||
}
|
||||
|
||||
async isStartWithATemplateDisplayed( templatesCount: number ) {
|
||||
|
|
Loading…
Reference in New Issue