Add introduction banner card into multichannel marketing page (#37110)
This commit is contained in:
commit
bebad071a3
|
@ -8,3 +8,4 @@ export { PluginCardBody, SmartPluginCardBody } from './PluginCardBody';
|
||||||
export { CardHeaderTitle } from './CardHeaderTitle';
|
export { CardHeaderTitle } from './CardHeaderTitle';
|
||||||
export { CardHeaderDescription } from './CardHeaderDescription';
|
export { CardHeaderDescription } from './CardHeaderDescription';
|
||||||
export { CenteredSpinner } from './CenteredSpinner';
|
export { CenteredSpinner } from './CenteredSpinner';
|
||||||
|
export { CreateNewCampaignModal } from './CreateNewCampaignModal';
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
export { useIntroductionBanner } from './useIntroductionBanner';
|
||||||
export { useInstalledPlugins } from './useInstalledPlugins';
|
export { useInstalledPlugins } from './useInstalledPlugins';
|
||||||
export { useRegisteredChannels } from './useRegisteredChannels';
|
export { useRegisteredChannels } from './useRegisteredChannels';
|
||||||
export { useRecommendedChannels } from './useRecommendedChannels';
|
export { useRecommendedChannels } from './useRecommendedChannels';
|
||||||
export { useCampaignTypes } from './useCampaignTypes';
|
export { useCampaignTypes } from './useCampaignTypes';
|
||||||
|
export { useCampaigns } from './useCampaigns';
|
||||||
|
|
|
@ -27,13 +27,10 @@ type UseCampaignsType = {
|
||||||
/**
|
/**
|
||||||
* Custom hook to get campaigns.
|
* Custom hook to get campaigns.
|
||||||
*
|
*
|
||||||
* @param page Page number. First page is `1`.
|
* @param page Page number. Default is `1`.
|
||||||
* @param perPage Page size, i.e. number of records in one page.
|
* @param perPage Page size, i.e. number of records in one page. Default is `5`.
|
||||||
*/
|
*/
|
||||||
export const useCampaigns = (
|
export const useCampaigns = ( page = 1, perPage = 5 ): UseCampaignsType => {
|
||||||
page: number,
|
|
||||||
perPage: number
|
|
||||||
): UseCampaignsType => {
|
|
||||||
const { data: channels } = useRegisteredChannels();
|
const { data: channels } = useRegisteredChannels();
|
||||||
|
|
||||||
return useSelect(
|
return useSelect(
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
|
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
|
type UseIntroductionBanner = {
|
||||||
|
loading: boolean;
|
||||||
|
isIntroductionBannerDismissed: boolean;
|
||||||
|
dismissIntroductionBanner: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const OPTION_NAME_BANNER_DISMISSED =
|
||||||
|
'woocommerce_marketing_overview_multichannel_banner_dismissed';
|
||||||
|
const OPTION_VALUE_YES = 'yes';
|
||||||
|
|
||||||
|
export const useIntroductionBanner = (): UseIntroductionBanner => {
|
||||||
|
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
|
||||||
|
|
||||||
|
const dismissIntroductionBanner = () => {
|
||||||
|
updateOptions( {
|
||||||
|
[ OPTION_NAME_BANNER_DISMISSED ]: OPTION_VALUE_YES,
|
||||||
|
} );
|
||||||
|
recordEvent( 'marketing_multichannel_banner_dismissed', {} );
|
||||||
|
};
|
||||||
|
|
||||||
|
const { loading, data } = useSelect( ( select ) => {
|
||||||
|
const { getOption, hasFinishedResolution } =
|
||||||
|
select( OPTIONS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading: ! hasFinishedResolution( 'getOption', [
|
||||||
|
OPTION_NAME_BANNER_DISMISSED,
|
||||||
|
] ),
|
||||||
|
data: getOption( OPTION_NAME_BANNER_DISMISSED ),
|
||||||
|
};
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
isIntroductionBannerDismissed: data === OPTION_VALUE_YES,
|
||||||
|
dismissIntroductionBanner,
|
||||||
|
};
|
||||||
|
};
|
|
@ -7,21 +7,23 @@ import userEvent from '@testing-library/user-event';
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { useCampaigns } from './useCampaigns';
|
import { useCampaignTypes, useCampaigns } from '~/marketing/hooks';
|
||||||
import { useCampaignTypes } from '~/marketing/hooks';
|
|
||||||
import { Campaigns } from './Campaigns';
|
import { Campaigns } from './Campaigns';
|
||||||
|
|
||||||
jest.mock( './useCampaigns', () => ( {
|
|
||||||
useCampaigns: jest.fn(),
|
|
||||||
} ) );
|
|
||||||
|
|
||||||
jest.mock( '~/marketing/hooks', () => ( {
|
jest.mock( '~/marketing/hooks', () => ( {
|
||||||
|
useCampaigns: jest.fn(),
|
||||||
useCampaignTypes: jest.fn(),
|
useCampaignTypes: jest.fn(),
|
||||||
} ) );
|
} ) );
|
||||||
|
|
||||||
jest.mock( './CreateNewCampaignModal', () => ( {
|
jest.mock( '~/marketing/components', () => {
|
||||||
|
const originalModule = jest.requireActual( '~/marketing/components' );
|
||||||
|
|
||||||
|
return {
|
||||||
|
__esModule: true,
|
||||||
|
...originalModule,
|
||||||
CreateNewCampaignModal: () => <div>Mocked CreateNewCampaignModal</div>,
|
CreateNewCampaignModal: () => <div>Mocked CreateNewCampaignModal</div>,
|
||||||
} ) );
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a test campaign data object.
|
* Create a test campaign data object.
|
||||||
|
|
|
@ -24,9 +24,11 @@ import {
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { CardHeaderTitle } from '~/marketing/components';
|
import {
|
||||||
import { useCampaigns } from './useCampaigns';
|
CardHeaderTitle,
|
||||||
import { CreateNewCampaignModal } from './CreateNewCampaignModal';
|
CreateNewCampaignModal,
|
||||||
|
} from '~/marketing/components';
|
||||||
|
import { useCampaigns } from '~/marketing/hooks';
|
||||||
import './Campaigns.scss';
|
import './Campaigns.scss';
|
||||||
|
|
||||||
const tableCaption = __( 'Campaigns', 'woocommerce' );
|
const tableCaption = __( 'Campaigns', 'woocommerce' );
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { Fragment, useState } from '@wordpress/element';
|
import {
|
||||||
|
Fragment,
|
||||||
|
useState,
|
||||||
|
forwardRef,
|
||||||
|
useImperativeHandle,
|
||||||
|
useRef,
|
||||||
|
} from '@wordpress/element';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
@ -32,11 +38,19 @@ type ChannelsProps = {
|
||||||
onInstalledAndActivated?: () => void;
|
onInstalledAndActivated?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Channels: React.FC< ChannelsProps > = ( {
|
export type ChannelsRef = {
|
||||||
registeredChannels,
|
/**
|
||||||
recommendedChannels,
|
* Scroll into the "Add channels" section in the card.
|
||||||
onInstalledAndActivated,
|
* The section will be expanded, and the "Add channels" button will be in focus.
|
||||||
} ) => {
|
*/
|
||||||
|
scrollIntoAddChannels: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Channels = forwardRef< ChannelsRef, ChannelsProps >(
|
||||||
|
(
|
||||||
|
{ registeredChannels, recommendedChannels, onInstalledAndActivated },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const hasRegisteredChannels = registeredChannels.length >= 1;
|
const hasRegisteredChannels = registeredChannels.length >= 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +58,21 @@ export const Channels: React.FC< ChannelsProps > = ( {
|
||||||
* Initial state is expanded if there are no registered channels in first page load.
|
* Initial state is expanded if there are no registered channels in first page load.
|
||||||
*/
|
*/
|
||||||
const [ expanded, setExpanded ] = useState( ! hasRegisteredChannels );
|
const [ expanded, setExpanded ] = useState( ! hasRegisteredChannels );
|
||||||
|
const addChannelsButtonRef = useRef< HTMLButtonElement >( null );
|
||||||
|
|
||||||
|
useImperativeHandle(
|
||||||
|
ref,
|
||||||
|
() => ( {
|
||||||
|
scrollIntoAddChannels: () => {
|
||||||
|
setExpanded( true );
|
||||||
|
addChannelsButtonRef.current?.focus();
|
||||||
|
addChannelsButtonRef.current?.scrollIntoView( {
|
||||||
|
block: 'center',
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
} ),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="woocommerce-marketing-channels-card">
|
<Card className="woocommerce-marketing-channels-card">
|
||||||
|
@ -62,16 +91,14 @@ export const Channels: React.FC< ChannelsProps > = ( {
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
|
|
||||||
{ /* Registered channels section. */ }
|
{ /* Registered channels section. */ }
|
||||||
{ registeredChannels.map( ( el, idx ) => {
|
{ registeredChannels.map( ( el, idx ) => (
|
||||||
return (
|
|
||||||
<Fragment key={ el.slug }>
|
<Fragment key={ el.slug }>
|
||||||
<RegisteredChannelCardBody registeredChannel={ el } />
|
<RegisteredChannelCardBody registeredChannel={ el } />
|
||||||
{ idx !== registeredChannels.length - 1 && (
|
{ idx !== registeredChannels.length - 1 && (
|
||||||
<CardDivider />
|
<CardDivider />
|
||||||
) }
|
) }
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
) ) }
|
||||||
} ) }
|
|
||||||
|
|
||||||
{ /* Recommended channels section. */ }
|
{ /* Recommended channels section. */ }
|
||||||
{ recommendedChannels.length >= 1 && (
|
{ recommendedChannels.length >= 1 && (
|
||||||
|
@ -81,13 +108,18 @@ export const Channels: React.FC< ChannelsProps > = ( {
|
||||||
<CardDivider />
|
<CardDivider />
|
||||||
<CardBody>
|
<CardBody>
|
||||||
<Button
|
<Button
|
||||||
|
ref={ addChannelsButtonRef }
|
||||||
variant="link"
|
variant="link"
|
||||||
onClick={ () => setExpanded( ! expanded ) }
|
onClick={ () =>
|
||||||
|
setExpanded( ! expanded )
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{ __( 'Add channels', 'woocommerce' ) }
|
{ __( 'Add channels', 'woocommerce' ) }
|
||||||
<Icon
|
<Icon
|
||||||
icon={
|
icon={
|
||||||
expanded ? chevronUp : chevronDown
|
expanded
|
||||||
|
? chevronUp
|
||||||
|
: chevronDown
|
||||||
}
|
}
|
||||||
size={ 24 }
|
size={ 24 }
|
||||||
/>
|
/>
|
||||||
|
@ -96,8 +128,7 @@ export const Channels: React.FC< ChannelsProps > = ( {
|
||||||
</>
|
</>
|
||||||
) }
|
) }
|
||||||
{ !! expanded &&
|
{ !! expanded &&
|
||||||
recommendedChannels.map( ( el, idx ) => {
|
recommendedChannels.map( ( el, idx ) => (
|
||||||
return (
|
|
||||||
<Fragment key={ el.plugin }>
|
<Fragment key={ el.plugin }>
|
||||||
<SmartPluginCardBody
|
<SmartPluginCardBody
|
||||||
plugin={ el }
|
plugin={ el }
|
||||||
|
@ -110,10 +141,10 @@ export const Channels: React.FC< ChannelsProps > = ( {
|
||||||
<CardDivider />
|
<CardDivider />
|
||||||
) }
|
) }
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
) ) }
|
||||||
} ) }
|
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
export { Channels } from './Channels';
|
export { Channels } from './Channels';
|
||||||
|
export type { ChannelsRef } from './Channels';
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
.woocommerce-marketing-introduction-banner {
|
||||||
|
& > div {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-content {
|
||||||
|
flex: 1 0;
|
||||||
|
margin: 32px 20px 32px 40px;
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-title {
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 28px;
|
||||||
|
margin-bottom: $gap-smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-features {
|
||||||
|
color: $gray-700;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: $studio-woocommerce-purple-50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-buttons {
|
||||||
|
margin-top: $gap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-illustration {
|
||||||
|
flex: 0 0 270px;
|
||||||
|
background: linear-gradient(90deg, rgba(247, 237, 247, 0) 5.31%, rgba(196, 152, 217, 0.12) 77.75%),
|
||||||
|
linear-gradient(90deg, rgba(247, 237, 247, 0) 22%, rgba(196, 152, 217, 0.12) 84.6%);
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-image-placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: center / contain no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-marketing-introduction-banner-close-button {
|
||||||
|
position: absolute;
|
||||||
|
top: $gap-small;
|
||||||
|
right: $gap;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,152 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { __ } from '@wordpress/i18n';
|
||||||
|
import { useState } from '@wordpress/element';
|
||||||
|
import { Card, Flex, FlexItem, FlexBlock, Button } from '@wordpress/components';
|
||||||
|
import { Icon, trendingUp, megaphone, closeSmall } from '@wordpress/icons';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { CreateNewCampaignModal } from '~/marketing/components';
|
||||||
|
import {
|
||||||
|
useRegisteredChannels,
|
||||||
|
useRecommendedChannels,
|
||||||
|
} from '~/marketing/hooks';
|
||||||
|
import './IntroductionBanner.scss';
|
||||||
|
import wooIconUrl from './woo.svg';
|
||||||
|
import illustrationUrl from './illustration.svg';
|
||||||
|
|
||||||
|
type IntroductionBannerProps = {
|
||||||
|
onDismissClick: () => void;
|
||||||
|
onAddChannelsClick: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IntroductionBanner = ( {
|
||||||
|
onDismissClick,
|
||||||
|
onAddChannelsClick,
|
||||||
|
}: IntroductionBannerProps ) => {
|
||||||
|
const [ isModalOpen, setModalOpen ] = useState( false );
|
||||||
|
const { data: dataRegistered } = useRegisteredChannels();
|
||||||
|
const { data: dataRecommended } = useRecommendedChannels();
|
||||||
|
|
||||||
|
const showCreateCampaignButton = !! dataRegistered?.length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean to display the "Add channels" button in the introduction banner.
|
||||||
|
*
|
||||||
|
* This depends on the number of registered channels,
|
||||||
|
* because if there are no registered channels,
|
||||||
|
* the Channels card will not have the "Add channels" toggle button,
|
||||||
|
* and it does not make sense to display the "Add channels" button in this introduction banner
|
||||||
|
* that will do nothing upon click.
|
||||||
|
*
|
||||||
|
* If there are registered channels and recommended channels,
|
||||||
|
* the Channels card will display the "Add channels" toggle button,
|
||||||
|
* and clicking on the "Add channels" button in this introduction banner
|
||||||
|
* will scroll to the button in Channels card.
|
||||||
|
*/
|
||||||
|
const showAddChannelsButton =
|
||||||
|
!! dataRegistered?.length && !! dataRecommended?.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="woocommerce-marketing-introduction-banner">
|
||||||
|
<div className="woocommerce-marketing-introduction-banner-content">
|
||||||
|
<div className="woocommerce-marketing-introduction-banner-title">
|
||||||
|
{ __(
|
||||||
|
'Reach new customers and increase sales without leaving WooCommerce',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
<Flex
|
||||||
|
className="woocommerce-marketing-introduction-banner-features"
|
||||||
|
direction="column"
|
||||||
|
gap={ 1 }
|
||||||
|
expanded={ false }
|
||||||
|
>
|
||||||
|
<FlexItem>
|
||||||
|
<Flex>
|
||||||
|
<Icon icon={ trendingUp } />
|
||||||
|
<FlexBlock>
|
||||||
|
{ __(
|
||||||
|
'Reach customers on other sales channels',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
</FlexBlock>
|
||||||
|
</Flex>
|
||||||
|
</FlexItem>
|
||||||
|
<FlexItem>
|
||||||
|
<Flex>
|
||||||
|
<Icon icon={ megaphone } />
|
||||||
|
<FlexBlock>
|
||||||
|
{ __(
|
||||||
|
'Advertise with marketing campaigns',
|
||||||
|
'woocommerce'
|
||||||
|
) }
|
||||||
|
</FlexBlock>
|
||||||
|
</Flex>
|
||||||
|
</FlexItem>
|
||||||
|
<FlexItem>
|
||||||
|
<Flex>
|
||||||
|
<img
|
||||||
|
src={ wooIconUrl }
|
||||||
|
alt={ __( 'WooCommerce logo', 'woocommerce' ) }
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
/>
|
||||||
|
<FlexBlock>
|
||||||
|
{ __( 'Built by WooCommerce', 'woocommerce' ) }
|
||||||
|
</FlexBlock>
|
||||||
|
</Flex>
|
||||||
|
</FlexItem>
|
||||||
|
</Flex>
|
||||||
|
{ ( showCreateCampaignButton || showAddChannelsButton ) && (
|
||||||
|
<Flex
|
||||||
|
className="woocommerce-marketing-introduction-banner-buttons"
|
||||||
|
justify="flex-start"
|
||||||
|
>
|
||||||
|
{ showCreateCampaignButton && (
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={ () => {
|
||||||
|
setModalOpen( true );
|
||||||
|
} }
|
||||||
|
>
|
||||||
|
{ __( 'Create a campaign', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
) }
|
||||||
|
{ showAddChannelsButton && (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
onClick={ onAddChannelsClick }
|
||||||
|
>
|
||||||
|
{ __( 'Add channels', 'woocommerce' ) }
|
||||||
|
</Button>
|
||||||
|
) }
|
||||||
|
</Flex>
|
||||||
|
) }
|
||||||
|
{ isModalOpen && (
|
||||||
|
<CreateNewCampaignModal
|
||||||
|
onRequestClose={ () => setModalOpen( false ) }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
</div>
|
||||||
|
<div className="woocommerce-marketing-introduction-banner-illustration">
|
||||||
|
<Button
|
||||||
|
isSmall
|
||||||
|
className="woocommerce-marketing-introduction-banner-close-button"
|
||||||
|
onClick={ onDismissClick }
|
||||||
|
>
|
||||||
|
<Icon icon={ closeSmall } />
|
||||||
|
</Button>
|
||||||
|
<div
|
||||||
|
className="woocommerce-marketing-introduction-banner-image-placeholder"
|
||||||
|
style={ {
|
||||||
|
backgroundImage: `url("${ illustrationUrl }")`,
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 25 KiB |
|
@ -0,0 +1 @@
|
||||||
|
export { IntroductionBanner } from './IntroductionBanner';
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg preserveAspectRatio="xMidYMid" version="1.1" viewBox="0 0 256 153" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||||
|
<title>WooCommerce Logo</title>
|
||||||
|
<metadata>
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||||
|
<dc:title/>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<path d="m23.759 0h208.38c13.187 0 23.863 10.675 23.863 23.863v79.542c0 13.187-10.675 23.863-23.863 23.863h-74.727l10.257 25.118-45.109-25.118h-98.695c-13.187 0-23.863-10.675-23.863-23.863v-79.542c-0.10466-13.083 10.571-23.863 23.758-23.863z" fill="#7f54b3"/>
|
||||||
|
<path d="m14.578 21.75c1.4569-1.9772 3.6423-3.0179 6.5561-3.226 5.3073-0.41626 8.3252 2.0813 9.0537 7.4927 3.226 21.75 6.7642 40.169 10.511 55.259l22.79-43.395c2.0813-3.9545 4.6829-6.0358 7.8049-6.2439 4.5789-0.3122 7.3886 2.6016 8.5333 8.7415 2.6016 13.841 5.9317 25.6 9.8862 35.59 2.7057-26.433 7.2846-45.476 13.737-57.236 1.561-2.9138 3.8504-4.3707 6.8683-4.5789 2.3935-0.20813 4.5789 0.52033 6.5561 2.0813 1.9772 1.561 3.0179 3.5382 3.226 5.9317 0.10406 1.8732-0.20813 3.4341-1.0407 4.9951-4.0585 7.4927-7.3886 20.085-10.094 37.567-2.6016 16.963-3.5382 30.179-2.9138 39.649 0.20813 2.6016-0.20813 4.8911-1.2488 6.8683-1.2488 2.2894-3.122 3.5382-5.5154 3.7463-2.7057 0.20813-5.5154-1.0406-8.2211-3.8504-9.678-9.8862-17.379-24.663-22.998-44.332-6.7642 13.32-11.759 23.311-14.985 29.971-6.1398 11.759-11.343 17.795-15.714 18.107-2.8098 0.20813-5.2033-2.1854-7.2846-7.1805-5.3073-13.633-11.031-39.961-17.171-78.985-0.41626-2.7057 0.20813-5.0992 1.665-6.9724zm223.64 16.338c-3.7463-6.5561-9.2618-10.511-16.65-12.072-1.9772-0.41626-3.8504-0.62439-5.6195-0.62439-9.9902 0-18.107 5.2033-24.455 15.61-5.4114 8.8455-8.1171 18.628-8.1171 29.346 0 8.013 1.665 14.881 4.9951 20.605 3.7463 6.5561 9.2618 10.511 16.65 12.072 1.9772 0.41626 3.8504 0.62439 5.6195 0.62439 10.094 0 18.211-5.2033 24.455-15.61 5.4114-8.9496 8.1171-18.732 8.1171-29.45 0.10406-8.1171-1.665-14.881-4.9951-20.501zm-13.112 28.826c-1.4569 6.8683-4.0585 11.967-7.9089 15.402-3.0179 2.7057-5.8276 3.8504-8.4293 3.3301-2.4976-0.52033-4.5789-2.7057-6.1398-6.7642-1.2488-3.226-1.8732-6.452-1.8732-9.4699 0-2.6016 0.20813-5.2033 0.72846-7.5967 0.93659-4.2667 2.7057-8.4293 5.5154-12.384 3.4341-5.0992 7.0764-7.1805 10.823-6.452 2.4976 0.52033 4.5789 2.7057 6.1398 6.7642 1.2488 3.226 1.8732 6.452 1.8732 9.4699 0 2.7057-0.20813 5.3073-0.72846 7.7008zm-52.033-28.826c-3.7463-6.5561-9.3659-10.511-16.65-12.072-1.9772-0.41626-3.8504-0.62439-5.6195-0.62439-9.9902 0-18.107 5.2033-24.455 15.61-5.4114 8.8455-8.1171 18.628-8.1171 29.346 0 8.013 1.665 14.881 4.9951 20.605 3.7463 6.5561 9.2618 10.511 16.65 12.072 1.9772 0.41626 3.8504 0.62439 5.6195 0.62439 10.094 0 18.211-5.2033 24.455-15.61 5.4114-8.9496 8.1171-18.732 8.1171-29.45 0-8.1171-1.665-14.881-4.9951-20.501zm-13.216 28.826c-1.4569 6.8683-4.0585 11.967-7.9089 15.402-3.0179 2.7057-5.8276 3.8504-8.4293 3.3301-2.4976-0.52033-4.5789-2.7057-6.1398-6.7642-1.2488-3.226-1.8732-6.452-1.8732-9.4699 0-2.6016 0.20813-5.2033 0.72846-7.5967 0.93658-4.2667 2.7057-8.4293 5.5154-12.384 3.4341-5.0992 7.0764-7.1805 10.823-6.452 2.4976 0.52033 4.5789 2.7057 6.1398 6.7642 1.2488 3.226 1.8732 6.452 1.8732 9.4699 0.10406 2.7057-0.20813 5.3073-0.72846 7.7008z" fill="#fff"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.4 KiB |
|
@ -1,6 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
|
import { useRef } from '@wordpress/element';
|
||||||
import { useUser } from '@woocommerce/data';
|
import { useUser } from '@woocommerce/data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,19 +11,28 @@ import '~/marketing/data';
|
||||||
import '~/marketing/data-multichannel';
|
import '~/marketing/data-multichannel';
|
||||||
import { CenteredSpinner } from '~/marketing/components';
|
import { CenteredSpinner } from '~/marketing/components';
|
||||||
import {
|
import {
|
||||||
|
useIntroductionBanner,
|
||||||
|
useCampaigns,
|
||||||
useRegisteredChannels,
|
useRegisteredChannels,
|
||||||
useRecommendedChannels,
|
useRecommendedChannels,
|
||||||
useCampaignTypes,
|
useCampaignTypes,
|
||||||
} from '~/marketing/hooks';
|
} from '~/marketing/hooks';
|
||||||
import { getAdminSetting } from '~/utils/admin-settings';
|
import { getAdminSetting } from '~/utils/admin-settings';
|
||||||
|
import { IntroductionBanner } from './IntroductionBanner';
|
||||||
import { Campaigns } from './Campaigns';
|
import { Campaigns } from './Campaigns';
|
||||||
import { Channels } from './Channels';
|
import { Channels, ChannelsRef } from './Channels';
|
||||||
import { InstalledExtensions } from './InstalledExtensions';
|
import { InstalledExtensions } from './InstalledExtensions';
|
||||||
import { DiscoverTools } from './DiscoverTools';
|
import { DiscoverTools } from './DiscoverTools';
|
||||||
import { LearnMarketing } from './LearnMarketing';
|
import { LearnMarketing } from './LearnMarketing';
|
||||||
import './MarketingOverviewMultichannel.scss';
|
import './MarketingOverviewMultichannel.scss';
|
||||||
|
|
||||||
export const MarketingOverviewMultichannel: React.FC = () => {
|
export const MarketingOverviewMultichannel: React.FC = () => {
|
||||||
|
const {
|
||||||
|
loading: loadingIntroductionBanner,
|
||||||
|
isIntroductionBannerDismissed,
|
||||||
|
dismissIntroductionBanner,
|
||||||
|
} = useIntroductionBanner();
|
||||||
|
const { loading: loadingCampaigns, meta: metaCampaigns } = useCampaigns();
|
||||||
const {
|
const {
|
||||||
loading: loadingCampaignTypes,
|
loading: loadingCampaignTypes,
|
||||||
data: dataCampaignTypes,
|
data: dataCampaignTypes,
|
||||||
|
@ -36,8 +46,11 @@ export const MarketingOverviewMultichannel: React.FC = () => {
|
||||||
const { loading: loadingRecommended, data: dataRecommended } =
|
const { loading: loadingRecommended, data: dataRecommended } =
|
||||||
useRecommendedChannels();
|
useRecommendedChannels();
|
||||||
const { currentUserCan } = useUser();
|
const { currentUserCan } = useUser();
|
||||||
|
const channelsRef = useRef< ChannelsRef >( null );
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
loadingIntroductionBanner ||
|
||||||
|
( loadingCampaigns && metaCampaigns?.total === undefined ) ||
|
||||||
( loadingCampaignTypes && ! dataCampaignTypes ) ||
|
( loadingCampaignTypes && ! dataCampaignTypes ) ||
|
||||||
( loadingRegistered && ! dataRegistered ) ||
|
( loadingRegistered && ! dataRegistered ) ||
|
||||||
( loadingRecommended && ! dataRecommended )
|
( loadingRecommended && ! dataRecommended )
|
||||||
|
@ -45,6 +58,11 @@ export const MarketingOverviewMultichannel: React.FC = () => {
|
||||||
return <CenteredSpinner />;
|
return <CenteredSpinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shouldShowCampaigns = !! (
|
||||||
|
dataRegistered?.length &&
|
||||||
|
( isIntroductionBannerDismissed || metaCampaigns?.total )
|
||||||
|
);
|
||||||
|
|
||||||
const shouldShowExtensions =
|
const shouldShowExtensions =
|
||||||
getAdminSetting( 'allowMarketplaceSuggestions', false ) &&
|
getAdminSetting( 'allowMarketplaceSuggestions', false ) &&
|
||||||
currentUserCan( 'install_plugins' );
|
currentUserCan( 'install_plugins' );
|
||||||
|
@ -56,10 +74,19 @@ export const MarketingOverviewMultichannel: React.FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="woocommerce-marketing-overview-multichannel">
|
<div className="woocommerce-marketing-overview-multichannel">
|
||||||
{ !! dataRegistered?.length && <Campaigns /> }
|
{ ! isIntroductionBannerDismissed && (
|
||||||
|
<IntroductionBanner
|
||||||
|
onDismissClick={ dismissIntroductionBanner }
|
||||||
|
onAddChannelsClick={ () => {
|
||||||
|
channelsRef.current?.scrollIntoAddChannels();
|
||||||
|
} }
|
||||||
|
/>
|
||||||
|
) }
|
||||||
|
{ shouldShowCampaigns && <Campaigns /> }
|
||||||
{ !! ( dataRegistered && dataRecommended ) &&
|
{ !! ( dataRegistered && dataRecommended ) &&
|
||||||
!! ( dataRegistered.length || dataRecommended.length ) && (
|
!! ( dataRegistered.length || dataRecommended.length ) && (
|
||||||
<Channels
|
<Channels
|
||||||
|
ref={ channelsRef }
|
||||||
registeredChannels={ dataRegistered }
|
registeredChannels={ dataRegistered }
|
||||||
recommendedChannels={ dataRecommended }
|
recommendedChannels={ dataRecommended }
|
||||||
onInstalledAndActivated={ refetch }
|
onInstalledAndActivated={ refetch }
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
Add introduction banner to multichannel marketing page.
|
Loading…
Reference in New Issue