Reorganize the store management link section and provide extensibility (https://github.com/woocommerce/woocommerce-admin/pull/5476)
Rearrange the store management links under categories and expose extensibility via the `woocommerce_admin_homescreen_quicklinks` filter.
This commit is contained in:
parent
17c149f66e
commit
06f9248572
|
@ -22,14 +22,15 @@ import {
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import QuickLinks from '../quick-links';
|
||||
import StatsOverview from './stats-overview';
|
||||
import './style.scss';
|
||||
import '../dashboard/style.scss';
|
||||
import TaskListPlaceholder from '../task-list/placeholder';
|
||||
import InboxPanel from '../inbox-panel';
|
||||
import { WelcomeModal } from './welcome-modal';
|
||||
|
||||
import './style.scss';
|
||||
import '../dashboard/style.scss';
|
||||
import { StoreManagementLinks } from '../store-management-links';
|
||||
|
||||
const TaskList = lazy( () =>
|
||||
import( /* webpackChunkName: "task-list" */ '../task-list' )
|
||||
);
|
||||
|
@ -92,7 +93,7 @@ export const Layout = ( {
|
|||
>
|
||||
{ isTaskListEnabled && renderTaskList() }
|
||||
<StatsOverview />
|
||||
{ ! isTaskListEnabled && <QuickLinks /> }
|
||||
{ ! isTaskListEnabled && <StoreManagementLinks /> }
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
|
|
|
@ -20,9 +20,6 @@ jest.mock( 'task-list', () => jest.fn().mockReturnValue( '[TaskList]' ) );
|
|||
// We aren't testing the <InboxPanel /> component here.
|
||||
jest.mock( 'inbox-panel', () => jest.fn().mockReturnValue( '[InboxPanel]' ) );
|
||||
|
||||
// We aren't testing the <QuickLinks /> component here.
|
||||
jest.mock( 'quick-links', () => jest.fn().mockReturnValue( '[QuickLinks]' ) );
|
||||
|
||||
jest.mock( '@woocommerce/data', () => ( {
|
||||
...jest.requireActual( '@woocommerce/data' ),
|
||||
useUserPreferences: jest.fn().mockReturnValue( {} ),
|
||||
|
|
|
@ -1,197 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
__experimentalText as Text,
|
||||
} from '@wordpress/components';
|
||||
import {
|
||||
Icon,
|
||||
megaphone,
|
||||
box,
|
||||
brush,
|
||||
home,
|
||||
shipping,
|
||||
percent,
|
||||
payment,
|
||||
pencil,
|
||||
lifesaver,
|
||||
external,
|
||||
} from '@wordpress/icons';
|
||||
import { partial } from 'lodash';
|
||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||
import { List } from '@woocommerce/components';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
function getItems( props ) {
|
||||
return [
|
||||
{
|
||||
title: __( 'Market my store', 'woocommerce-admin' ),
|
||||
type: 'wc-admin',
|
||||
path: 'marketing',
|
||||
icon: megaphone,
|
||||
listItemTag: 'marketing',
|
||||
},
|
||||
{
|
||||
title: __( 'Add products', 'woocommerce-admin' ),
|
||||
type: 'wp-admin',
|
||||
path: 'post-new.php?post_type=product',
|
||||
icon: box,
|
||||
listItemTag: 'add-products',
|
||||
},
|
||||
{
|
||||
title: __( 'Personalize my store', 'woocommerce-admin' ),
|
||||
type: 'wp-admin',
|
||||
path: 'customize.php',
|
||||
icon: brush,
|
||||
listItemTag: 'personalize-store',
|
||||
},
|
||||
{
|
||||
title: __( 'Shipping settings', 'woocommerce-admin' ),
|
||||
type: 'wc-settings',
|
||||
tab: 'shipping',
|
||||
icon: shipping,
|
||||
listItemTag: 'shipping-settings',
|
||||
},
|
||||
{
|
||||
title: __( 'Tax settings', 'woocommerce-admin' ),
|
||||
type: 'wc-settings',
|
||||
tab: 'tax',
|
||||
icon: percent,
|
||||
listItemTag: 'tax-settings',
|
||||
},
|
||||
{
|
||||
title: __( 'Payment settings', 'woocommerce-admin' ),
|
||||
type: 'wc-settings',
|
||||
tab: 'checkout',
|
||||
icon: payment,
|
||||
listItemTag: 'payment-settings',
|
||||
},
|
||||
{
|
||||
title: __( 'Edit store details', 'woocommerce-admin' ),
|
||||
type: 'wc-settings',
|
||||
tab: 'general',
|
||||
icon: pencil,
|
||||
listItemTag: 'edit-store-details',
|
||||
},
|
||||
{
|
||||
title: __( 'Get support', 'woocommerce-admin' ),
|
||||
type: 'external',
|
||||
href: 'https://woocommerce.com/my-account/create-a-ticket/',
|
||||
icon: lifesaver,
|
||||
after: <Icon icon={ external } />,
|
||||
listItemTag: 'support',
|
||||
},
|
||||
{
|
||||
title: __( 'View my store', 'woocommerce-admin' ),
|
||||
type: 'external',
|
||||
href: props.getSetting( 'siteUrl' ),
|
||||
icon: home,
|
||||
after: <Icon icon={ external } />,
|
||||
listItemTag: 'view-store',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function handleOnItemClick( props, event ) {
|
||||
const a = event.currentTarget;
|
||||
const listItemTag = a.dataset.listItemTag;
|
||||
|
||||
if ( ! listItemTag ) {
|
||||
return;
|
||||
}
|
||||
|
||||
props.recordEvent( 'home_quick_links_click', {
|
||||
task_name: listItemTag,
|
||||
} );
|
||||
|
||||
if ( typeof props.onItemClick !== 'function' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! props.onItemClick( listItemTag ) ) {
|
||||
event.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getLinkTypeAndHref( item ) {
|
||||
let linkType;
|
||||
let href;
|
||||
|
||||
switch ( item.type ) {
|
||||
case 'wc-admin':
|
||||
linkType = 'wc-admin';
|
||||
href = `admin.php?page=wc-admin&path=%2F${ item.path }`;
|
||||
break;
|
||||
case 'wp-admin':
|
||||
linkType = 'wp-admin';
|
||||
href = item.path;
|
||||
break;
|
||||
case 'wc-settings':
|
||||
linkType = 'wp-admin';
|
||||
href = `admin.php?page=wc-settings&tab=${ item.tab }`;
|
||||
break;
|
||||
default:
|
||||
linkType = 'external';
|
||||
href = item.href;
|
||||
break;
|
||||
}
|
||||
|
||||
return {
|
||||
linkType,
|
||||
href,
|
||||
};
|
||||
}
|
||||
|
||||
function getListItems( props ) {
|
||||
return getItems( props ).map( ( item ) => {
|
||||
return {
|
||||
title: (
|
||||
<Text as="div" variant="button">
|
||||
{ item.title }
|
||||
</Text>
|
||||
),
|
||||
before: <Icon icon={ item.icon } />,
|
||||
after: item.after,
|
||||
...getLinkTypeAndHref( item ),
|
||||
listItemTag: item.listItemTag,
|
||||
onClick: partial( handleOnItemClick, props ),
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
const QuickLinks = ( props ) => {
|
||||
const listItems = getListItems( props );
|
||||
|
||||
return (
|
||||
<Card size="large" className="woocommerce-quick-links">
|
||||
<CardHeader size="medium">
|
||||
<Text variant="title.small">
|
||||
{ __( 'Store management', 'woocommerce-admin' ) }
|
||||
</Text>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<List
|
||||
items={ listItems }
|
||||
className="woocommerce-quick-links__list"
|
||||
/>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
QuickLinks.defaultProps = {
|
||||
getSetting,
|
||||
recordEvent,
|
||||
};
|
||||
|
||||
export default QuickLinks;
|
|
@ -1,31 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { withConsole } from '@storybook/addon-console';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import QuickLinks from '..';
|
||||
|
||||
function logItemClick( listItemTag ) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log( `QuickLinks item with tag '${ listItemTag }' clicked` );
|
||||
return false;
|
||||
}
|
||||
|
||||
function getSetting() {
|
||||
return 'https://example.com';
|
||||
}
|
||||
|
||||
export default {
|
||||
title: 'WooCommerce Admin/homescreen/QuickLinks',
|
||||
component: QuickLinks,
|
||||
decorators: [ ( storyFn, context ) => withConsole()( storyFn )( context ) ],
|
||||
};
|
||||
|
||||
export const Default = () => {
|
||||
return (
|
||||
<QuickLinks getSetting={ getSetting } onItemClick={ logItemClick } />
|
||||
);
|
||||
};
|
|
@ -1,9 +0,0 @@
|
|||
.woocommerce-page .woocommerce-quick-links {
|
||||
$background-color: $white;
|
||||
|
||||
background-color: $background-color;
|
||||
|
||||
.components-card__body.is-size-large {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { toHaveAttribute } from '@testing-library/jest-dom/matchers';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import QuickLinks from '../index';
|
||||
|
||||
expect.extend( { toHaveAttribute } );
|
||||
|
||||
describe( 'QuickLinks', () => {
|
||||
it( 'should build href correctly for a `wc-admin` item', () => {
|
||||
render( <QuickLinks getSetting={ () => {} } /> );
|
||||
|
||||
const marketingItem = screen.getByRole( 'menuitem', {
|
||||
name: 'Market my store',
|
||||
} );
|
||||
|
||||
expect( marketingItem ).toHaveAttribute(
|
||||
'href',
|
||||
'admin.php?page=wc-admin&path=%2Fmarketing'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should build href correctly for a `wp-admin` item', () => {
|
||||
render( <QuickLinks getSetting={ () => {} } /> );
|
||||
|
||||
const addProductsItem = screen.getByRole( 'menuitem', {
|
||||
name: 'Add products',
|
||||
} );
|
||||
|
||||
expect( addProductsItem ).toHaveAttribute(
|
||||
'href',
|
||||
'post-new.php?post_type=product'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should build href correctly for a `wc-settings` item', () => {
|
||||
render( <QuickLinks getSetting={ () => {} } /> );
|
||||
|
||||
const shippingSettingsItem = screen.getByRole( 'menuitem', {
|
||||
name: 'Shipping settings',
|
||||
} );
|
||||
|
||||
expect( shippingSettingsItem ).toHaveAttribute(
|
||||
'href',
|
||||
'admin.php?page=wc-settings&tab=shipping'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should call `recordEvent` when a `wc-admin` item is clicked', () => {
|
||||
const recordEvent = jest.fn();
|
||||
|
||||
render(
|
||||
<QuickLinks
|
||||
getSetting={ () => {} }
|
||||
recordEvent={ recordEvent }
|
||||
// Prevent jsdom "Error: Not implemented: navigation" in test output
|
||||
onItemClick={ () => false }
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(
|
||||
screen.getByRole( 'menuitem', { name: 'Market my store' } )
|
||||
);
|
||||
|
||||
const homeQuickLinksClickEventName = 'home_quick_links_click';
|
||||
const propsWithMarketingTaskName = { task_name: 'marketing' };
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
homeQuickLinksClickEventName,
|
||||
propsWithMarketingTaskName
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should call `recordEvent` when a `wp-admin` item is clicked', () => {
|
||||
const recordEvent = jest.fn();
|
||||
|
||||
render(
|
||||
<QuickLinks
|
||||
getSetting={ () => {} }
|
||||
recordEvent={ recordEvent }
|
||||
// Prevent jsdom "Error: Not implemented: navigation" in test output
|
||||
onItemClick={ () => false }
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(
|
||||
screen.getByRole( 'menuitem', { name: 'Add products' } )
|
||||
);
|
||||
|
||||
const homeQuickLinksClickEventName = 'home_quick_links_click';
|
||||
const propsWithAddProductsTaskName = { task_name: 'add-products' };
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
homeQuickLinksClickEventName,
|
||||
propsWithAddProductsTaskName
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should call `recordEvent` when a `wc-settings` item is clicked', () => {
|
||||
const recordEvent = jest.fn();
|
||||
|
||||
render(
|
||||
<QuickLinks
|
||||
getSetting={ () => {} }
|
||||
recordEvent={ recordEvent }
|
||||
// Prevent jsdom "Error: Not implemented: navigation" in test output
|
||||
onItemClick={ () => false }
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(
|
||||
screen.getByRole( 'menuitem', { name: 'Shipping settings' } )
|
||||
);
|
||||
|
||||
const homeQuickLinksClickEventName = 'home_quick_links_click';
|
||||
const propsWithShippingSettingsTaskName = {
|
||||
task_name: 'shipping-settings',
|
||||
};
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
homeQuickLinksClickEventName,
|
||||
propsWithShippingSettingsTaskName
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should call `recordEvent` when an `external` item is clicked', () => {
|
||||
const recordEvent = jest.fn();
|
||||
|
||||
render(
|
||||
<QuickLinks
|
||||
getSetting={ () => {} }
|
||||
recordEvent={ recordEvent }
|
||||
// Prevent jsdom "Error: Not implemented: navigation" in test output
|
||||
onItemClick={ () => false }
|
||||
/>
|
||||
);
|
||||
|
||||
userEvent.click(
|
||||
screen.getByRole( 'menuitem', { name: 'Get support' } )
|
||||
);
|
||||
|
||||
const homeQuickLinksClickEventName = 'home_quick_links_click';
|
||||
const propsWithSupportTaskName = { task_name: 'support' };
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith(
|
||||
homeQuickLinksClickEventName,
|
||||
propsWithSupportTaskName
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'should call `getSetting` to determine the frontend url', () => {
|
||||
const getSetting = jest.fn( () => 'https://example.com' );
|
||||
|
||||
render(
|
||||
<QuickLinks getSetting={ getSetting } recordEvent={ () => {} } />
|
||||
);
|
||||
|
||||
expect( getSetting ).toHaveBeenCalledWith( 'siteUrl' );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,227 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { applyFilters } from '@wordpress/hooks';
|
||||
import {
|
||||
Card,
|
||||
CardBody,
|
||||
CardHeader,
|
||||
__experimentalText as Text,
|
||||
} from '@wordpress/components';
|
||||
import {
|
||||
megaphone,
|
||||
box,
|
||||
brush,
|
||||
home,
|
||||
shipping,
|
||||
percent,
|
||||
payment,
|
||||
pencil,
|
||||
} from '@wordpress/icons';
|
||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
import { QuickLinkCategory } from './quick-link-category';
|
||||
import { QuickLink } from './quick-link';
|
||||
|
||||
export function getItemsByCategory( siteUrl ) {
|
||||
return [
|
||||
{
|
||||
title: __( 'Marketing & Merchandising', 'woocommerce-admin' ),
|
||||
items: [
|
||||
{
|
||||
title: __( 'Marketing', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wc-admin',
|
||||
path: 'marketing',
|
||||
} ),
|
||||
icon: megaphone,
|
||||
listItemTag: 'marketing',
|
||||
},
|
||||
{
|
||||
title: __( 'Add products', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wp-admin',
|
||||
path: 'post-new.php?post_type=product',
|
||||
} ),
|
||||
icon: box,
|
||||
listItemTag: 'add-products',
|
||||
},
|
||||
{
|
||||
title: __( 'Personalize my store', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wp-admin',
|
||||
path: 'customize.php',
|
||||
} ),
|
||||
icon: brush,
|
||||
listItemTag: 'personalize-store',
|
||||
},
|
||||
{
|
||||
title: __( 'View my store', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'external',
|
||||
href: siteUrl,
|
||||
} ),
|
||||
icon: home,
|
||||
listItemTag: 'view-store',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: __( 'Settings', 'woocommerce-admin' ),
|
||||
items: [
|
||||
{
|
||||
title: __( 'Store details', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wc-settings',
|
||||
tab: 'general',
|
||||
} ),
|
||||
icon: pencil,
|
||||
listItemTag: 'edit-store-details',
|
||||
},
|
||||
{
|
||||
title: __( 'Payments', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wc-settings',
|
||||
tab: 'checkout',
|
||||
} ),
|
||||
icon: payment,
|
||||
listItemTag: 'payment-settings',
|
||||
},
|
||||
{
|
||||
title: __( 'Tax', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wc-settings',
|
||||
tab: 'tax',
|
||||
} ),
|
||||
icon: percent,
|
||||
listItemTag: 'tax-settings',
|
||||
},
|
||||
{
|
||||
title: __( 'Shipping', 'woocommerce-admin' ),
|
||||
link: getLinkTypeAndHref( {
|
||||
type: 'wc-settings',
|
||||
tab: 'shipping',
|
||||
} ),
|
||||
icon: shipping,
|
||||
listItemTag: 'shipping-settings',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function getLinkTypeAndHref( { path, tab = null, type, href = null } ) {
|
||||
return (
|
||||
{
|
||||
'wc-admin': {
|
||||
href: `admin.php?page=wc-admin&path=%2F${ path }`,
|
||||
linkType: 'wc-admin',
|
||||
},
|
||||
'wp-admin': {
|
||||
href: path,
|
||||
linkType: 'wp-admin',
|
||||
},
|
||||
'wc-settings': {
|
||||
href: `admin.php?page=wc-settings&tab=${ tab }`,
|
||||
linkType: 'wp-admin',
|
||||
},
|
||||
}[ type ] || {
|
||||
href,
|
||||
linkType: 'external',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export const generateExtensionLinks = ( links ) => {
|
||||
return links.reduce( ( acc, { icon, href, title } ) => {
|
||||
const url = new URL( href, window.location.href );
|
||||
|
||||
// We do not support extension links that take users away from the host.
|
||||
if ( url.origin === window.location.origin ) {
|
||||
acc.push( {
|
||||
icon,
|
||||
link: {
|
||||
href,
|
||||
linkType: 'wp-admin',
|
||||
},
|
||||
title,
|
||||
listItemTag: 'quick-links-extension-link',
|
||||
} );
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, [] );
|
||||
};
|
||||
|
||||
export const StoreManagementLinks = () => {
|
||||
const siteUrl = getSetting( 'siteUrl' );
|
||||
|
||||
const extensionQuickLinks = generateExtensionLinks(
|
||||
applyFilters( 'woocommerce_admin_homescreen_quicklinks', [] )
|
||||
);
|
||||
|
||||
const itemCategories = getItemsByCategory( siteUrl );
|
||||
|
||||
const extensionCategory = {
|
||||
title: __( 'Extensions', 'woocommerce-admin' ),
|
||||
items: extensionQuickLinks,
|
||||
};
|
||||
|
||||
const categories = extensionQuickLinks.length
|
||||
? [ ...itemCategories, extensionCategory ]
|
||||
: itemCategories;
|
||||
|
||||
return (
|
||||
<Card size="medium">
|
||||
<CardHeader size="medium">
|
||||
<Text variant="title.small">
|
||||
{ __( 'Store management', 'woocommerce-admin' ) }
|
||||
</Text>
|
||||
</CardHeader>
|
||||
<CardBody
|
||||
size="custom"
|
||||
className="woocommerce-store-management-links__card-body"
|
||||
>
|
||||
{ categories.map( ( category ) => {
|
||||
return (
|
||||
<QuickLinkCategory
|
||||
key={ category.title }
|
||||
title={ category.title }
|
||||
>
|
||||
{ category.items.map(
|
||||
( {
|
||||
icon,
|
||||
listItemTag,
|
||||
title,
|
||||
link: { href, linkType },
|
||||
} ) => (
|
||||
<QuickLink
|
||||
icon={ icon }
|
||||
key={ `${ title }_${ listItemTag }_${ href }` }
|
||||
title={ title }
|
||||
linkType={ linkType }
|
||||
href={ href }
|
||||
onClick={ () => {
|
||||
recordEvent(
|
||||
'home_quick_links_click',
|
||||
{
|
||||
task_name: listItemTag,
|
||||
}
|
||||
);
|
||||
} }
|
||||
/>
|
||||
)
|
||||
) }
|
||||
</QuickLinkCategory>
|
||||
);
|
||||
} ) }
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React from '@wordpress/element';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
export const QuickLinkCategory = ( { title, children } ) => {
|
||||
return (
|
||||
<div className="woocommerce-quick-links__category">
|
||||
<h3 className="woocommerce-quick-links__category-header">
|
||||
{ title }
|
||||
</h3>
|
||||
{ children }
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
.woocommerce-quick-links__category {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
margin-bottom: 8px;
|
||||
|
||||
.woocommerce-quick-links__category-header {
|
||||
margin: 0 24px 8px 24px;
|
||||
text-transform: uppercase;
|
||||
color: $gray-700;
|
||||
line-height: 16px;
|
||||
font-size: 11px;
|
||||
flex: 1 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { QuickLinkCategory } from '..';
|
||||
|
||||
describe( 'QuickLinkCategory', () => {
|
||||
it( 'displays the passed title and children', () => {
|
||||
const { queryByText } = render(
|
||||
<QuickLinkCategory title="hello world">
|
||||
<div>Test</div>
|
||||
</QuickLinkCategory>
|
||||
);
|
||||
|
||||
expect( queryByText( 'hello world' ) ).not.toBeEmptyDOMElement();
|
||||
expect( queryByText( 'Test' ) ).not.toBeEmptyDOMElement();
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React from '@wordpress/element';
|
||||
import { external, Icon } from '@wordpress/icons';
|
||||
import { __experimentalText as Text } from '@wordpress/components';
|
||||
import { Link } from '@woocommerce/components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import './style.scss';
|
||||
|
||||
export const QuickLink = ( { icon, title, href, linkType, onClick } ) => {
|
||||
const isExternal = linkType === 'external';
|
||||
|
||||
return (
|
||||
<div className="woocommerce-quick-links__item">
|
||||
<Link
|
||||
onClick={ onClick }
|
||||
href={ href }
|
||||
linkType={ linkType }
|
||||
className="woocommerce-quick-links__item-link"
|
||||
>
|
||||
<Icon
|
||||
className="woocommerce-quick-links__item-link__icon"
|
||||
icon={ icon }
|
||||
/>
|
||||
<Text
|
||||
className="woocommerce-quick-links__item-link__text"
|
||||
as="div"
|
||||
variant="button"
|
||||
>
|
||||
{ title }
|
||||
</Text>
|
||||
{ isExternal && <Icon icon={ external } /> }
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -0,0 +1,34 @@
|
|||
.woocommerce-quick-links__item {
|
||||
display: flex;
|
||||
flex: 1 50%;
|
||||
|
||||
&:hover {
|
||||
background-color: $gray-100;
|
||||
}
|
||||
|
||||
.woocommerce-quick-links__item-link {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
padding: 16px 27px 16px 24px;
|
||||
|
||||
.woocommerce-quick-links__item-link__icon {
|
||||
fill: var(--wp-admin-theme-color);
|
||||
}
|
||||
|
||||
.woocommerce-quick-links__item-link__text {
|
||||
margin-left: 16px;
|
||||
flex: 1;
|
||||
line-height: 16px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Modified styles for 2 column presentation.
|
||||
.woocommerce-homescreen.two-columns {
|
||||
.woocommerce-quick-links__item {
|
||||
flex: 1 100%;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import React from '@wordpress/element';
|
||||
import { render } from '@testing-library/react';
|
||||
import { brush } from '@wordpress/icons';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { QuickLink } from '../index';
|
||||
|
||||
describe( 'QuickLink', () => {
|
||||
it( 'renders an title and href based on props passed', () => {
|
||||
const { queryByText, queryByRole } = render(
|
||||
<QuickLink
|
||||
linkType="external"
|
||||
title="hello world"
|
||||
icon={ brush }
|
||||
href="https://example.com"
|
||||
/>
|
||||
);
|
||||
|
||||
expect( queryByText( 'hello world' ) ).not.toBeEmptyDOMElement();
|
||||
expect( queryByRole( 'link' ) ).toHaveAttribute(
|
||||
'href',
|
||||
'https://example.com'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'attaches a click handler to the link if it is passed', () => {
|
||||
const clickHandler = jest.fn();
|
||||
|
||||
const { queryByRole } = render(
|
||||
<QuickLink
|
||||
linkType="external"
|
||||
title="hello world"
|
||||
icon={ brush }
|
||||
href="https://example.com"
|
||||
onClick={ clickHandler }
|
||||
/>
|
||||
);
|
||||
|
||||
const link = queryByRole( 'link' );
|
||||
userEvent.click( link );
|
||||
expect( clickHandler ).toHaveBeenCalled();
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,5 @@
|
|||
// Setting a custom size that is not recognised by the <CardBody> allows us to override the card's default padding sizes.
|
||||
// We need to do this to allow item hover backgrounds to stretch the whole card body.
|
||||
.woocommerce-store-management-links__card-body.is-size-custom {
|
||||
padding: 24px 0 8px 0;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
jest.mock( '@woocommerce/tracks', () => ( {
|
||||
...jest.requireActual( '@woocommerce/tracks' ),
|
||||
recordEvent: jest.fn(),
|
||||
} ) );
|
||||
|
||||
jest.mock( '@woocommerce/wc-admin-settings', () => ( {
|
||||
...jest.requireActual( '@woocommerce/wc-admin-settings' ),
|
||||
getSetting: jest.fn( () => 'https://fake-site-url.com' ),
|
||||
} ) );
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { render } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
StoreManagementLinks,
|
||||
getLinkTypeAndHref,
|
||||
getItemsByCategory,
|
||||
generateExtensionLinks,
|
||||
} from '..';
|
||||
|
||||
describe( 'getLinkTypeAndHref', () => {
|
||||
it( 'generates the correct link for wc-admin links', () => {
|
||||
const result = getLinkTypeAndHref( {
|
||||
type: 'wc-admin',
|
||||
path: 'foo/bar',
|
||||
} );
|
||||
|
||||
expect( result.linkType ).toEqual( 'wc-admin' );
|
||||
expect( result.href ).toEqual(
|
||||
'admin.php?page=wc-admin&path=%2Ffoo/bar'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'generates the correct link for wp-admin links', () => {
|
||||
const result = getLinkTypeAndHref( {
|
||||
type: 'wp-admin',
|
||||
path: '/foo/bar',
|
||||
} );
|
||||
|
||||
expect( result.linkType ).toEqual( 'wp-admin' );
|
||||
expect( result.href ).toEqual( '/foo/bar' );
|
||||
} );
|
||||
|
||||
it( 'generates the correct link for wc-settings links', () => {
|
||||
const result = getLinkTypeAndHref( {
|
||||
type: 'wc-settings',
|
||||
tab: 'foo',
|
||||
} );
|
||||
|
||||
expect( result.linkType ).toEqual( 'wp-admin' );
|
||||
expect( result.href ).toEqual( 'admin.php?page=wc-settings&tab=foo' );
|
||||
} );
|
||||
|
||||
it( 'generates the an external link if there is no provided type', () => {
|
||||
const result = getLinkTypeAndHref( {
|
||||
href: 'http://example.com',
|
||||
} );
|
||||
|
||||
expect( result.linkType ).toEqual( 'external' );
|
||||
expect( result.href ).toEqual( 'http://example.com' );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'StoreManagementLinks', () => {
|
||||
it( 'records a track when a link is clicked', () => {
|
||||
const { queryByText } = render( <StoreManagementLinks /> );
|
||||
const linkDetails = getItemsByCategory( 'fakeUrl' )[ 0 ].items[ 0 ];
|
||||
|
||||
userEvent.click( queryByText( linkDetails.title ) );
|
||||
|
||||
expect( recordEvent ).toHaveBeenCalledWith( 'home_quick_links_click', {
|
||||
task_name: linkDetails.listItemTag,
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'generateExtensionLinks', () => {
|
||||
it( 'filters out external links', () => {
|
||||
expect(
|
||||
generateExtensionLinks( [
|
||||
{
|
||||
href: 'https://example.com',
|
||||
title: 'external link',
|
||||
icon: <div>hi</div>,
|
||||
},
|
||||
] )
|
||||
).toEqual( [] );
|
||||
} );
|
||||
|
||||
it( 'generates a valid link for relative links', () => {
|
||||
const validFullUrl = {
|
||||
href: 'http://localhost/foo/bar',
|
||||
title: 'external link',
|
||||
icon: <div>hi</div>,
|
||||
};
|
||||
|
||||
const validRelativeUrl = {
|
||||
href: '/foo/bar',
|
||||
title: 'external link',
|
||||
icon: <div>hi</div>,
|
||||
};
|
||||
|
||||
expect( generateExtensionLinks( [ validFullUrl ] ) ).toEqual( [
|
||||
{
|
||||
icon: validFullUrl.icon,
|
||||
link: {
|
||||
href: validFullUrl.href,
|
||||
linkType: 'wp-admin',
|
||||
},
|
||||
title: validFullUrl.title,
|
||||
listItemTag: 'quick-links-extension-link',
|
||||
},
|
||||
] );
|
||||
|
||||
expect( generateExtensionLinks( [ validRelativeUrl ] ) ).toEqual( [
|
||||
{
|
||||
icon: validRelativeUrl.icon,
|
||||
link: {
|
||||
href: validRelativeUrl.href,
|
||||
linkType: 'wp-admin',
|
||||
},
|
||||
title: validRelativeUrl.title,
|
||||
listItemTag: 'quick-links-extension-link',
|
||||
},
|
||||
] );
|
||||
} );
|
||||
} );
|
|
@ -22,3 +22,7 @@ allows Woo themed components based on the config found in postcss.config.js
|
|||
@import 'gutenberg-components/tab-panel/style.scss';
|
||||
@import 'gutenberg-components/guide/style.scss';
|
||||
@import 'gutenberg-components/animate/style.scss';
|
||||
|
||||
:root {
|
||||
@include admin-scheme( #007cba );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue