Skip to content

Commit eddef3c

Browse files
authored
Merge pull request #1638 from woocommerce/add/1610-product-feed-status-section-ui
Free Listings + Paid Ads: Add the product feed status section UI
2 parents 6bcd41c + 4566683 commit eddef3c

File tree

7 files changed

+212
-13
lines changed

7 files changed

+212
-13
lines changed

js/src/data/actions.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,24 @@ export function handleFetchError( error, message ) {
9595
* @property {boolean} [contact_info_visible] Whether the phone number, email, and/or address are visible on the website.
9696
*/
9797

98+
/**
99+
* @typedef {Object} ProductStatisticsDetails
100+
* @property {number} active Number of active products.
101+
* @property {number} expiring Number of expiring products.
102+
* @property {number} pending Number of pending products.
103+
* @property {number} disapproved Number of disapproved products.
104+
* @property {number} not_synced Number of not synced products.
105+
*/
106+
107+
/**
108+
* Product status statistics on Google Merchant Center
109+
*
110+
* @typedef {Object} ProductStatistics
111+
* @property {number} scheduled_sync Number of scheduled jobs which will sync products to Google.
112+
* @property {number} timestamp Timestamp reflecting when the product status statistics were last generated.
113+
* @property {ProductStatisticsDetails} statistics Statistics information of product status on Google Merchant Center.
114+
*/
115+
98116
/**
99117
*
100118
* @return {Array<ShippingRate>} Array of individual shipping rates.
@@ -871,6 +889,13 @@ export function* receiveMCSetup( mcSetup ) {
871889
};
872890
}
873891

892+
/**
893+
* Creates a wp-data action with data payload to be dispatched the received
894+
* MC product statistics to wp-data store.
895+
*
896+
* @param {ProductStatistics} mcProductStatistics The received MC product statistics data.
897+
* @yield {Object} The wp-data action with data payload.
898+
*/
874899
export function* receiveMCProductStatistics( mcProductStatistics ) {
875900
return {
876901
type: TYPES.RECEIVE_MC_PRODUCT_STATISTICS,

js/src/data/selectors.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,17 @@ export const getMCSetup = ( state ) => {
129129
return state.mc_setup;
130130
};
131131

132+
/**
133+
* @typedef {import('.~/data/actions').ProductStatistics } ProductStatistics
134+
*/
135+
136+
/**
137+
* Get the MC product statistics data.
138+
*
139+
* @param {Object} state The current store state will be injected by `wp.data`.
140+
*
141+
* @return {ProductStatistics|null} The MC product statistics data. Returns `null` if data have not yet loaded.
142+
*/
132143
export const getMCProductStatistics = ( state ) => {
133144
return state.mc_product_statistics;
134145
};

js/src/product-feed/product-statistics/status-box/sync-status.js

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ import Status from '.~/product-feed/product-statistics/status-box/status';
1212
import { glaData } from '.~/constants';
1313
import SyncIcon from '.~/components/sync-icon';
1414
import SuccessIcon from '.~/components/success-icon';
15+
import getNumberOfSyncProducts from '.~/utils/getNumberOfSyncProducts';
16+
17+
/**
18+
* @typedef {import('.~/data/actions').ProductStatistics } ProductStatistics
19+
*/
1520

1621
/**
1722
* Returns the text as well as the icon an description for the Sync Status
1823
* based on the `scheduled_sync` value as the synced number of products.
1924
*
20-
* @param {Object} data Data with the sync information
21-
* @param {number} data.scheduled_sync Amount of scheduled jobs which will sync products to Google.
22-
* @param {Object} data.statistics Merchant Center product status statistics information.
23-
* @param {number} data.timestamp Timestamp reflecting when the product status statistics were last generated.
25+
* @param {ProductStatistics} data Product status statistics on Google Merchant Center
2426
* @return {Object} The icon, status and description of the sync process.
2527
*/
2628
function getSyncResult( {
@@ -36,15 +38,7 @@ function getSyncResult( {
3638
};
3739
}
3840

39-
const totalSynced = Object.entries( statistics ).reduce(
40-
( sum, [ key, num ] ) => {
41-
if ( key === 'not_synced' ) {
42-
return sum;
43-
}
44-
return sum + num;
45-
},
46-
0
47-
);
41+
const totalSynced = getNumberOfSyncProducts( statistics );
4842

4943
return {
5044
Icon: SuccessIcon,
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { sprintf, __, _n } from '@wordpress/i18n';
5+
import { Flex, FlexItem, FlexBlock } from '@wordpress/components';
6+
7+
/**
8+
* Internal dependencies
9+
*/
10+
import Section from '.~/wcdl/section';
11+
import AppDocumentationLink from '.~/components/app-documentation-link';
12+
import SyncIcon from '.~/components/sync-icon';
13+
import AppTooltip from '.~/components/app-tooltip';
14+
import getNumberOfSyncProducts from '.~/utils/getNumberOfSyncProducts';
15+
import './product-feed-status-section.scss';
16+
17+
function ProductQuantity( { quantity } ) {
18+
if ( ! Number.isInteger( quantity ) ) {
19+
return null;
20+
}
21+
22+
const text = sprintf(
23+
// translators: %d: number of products will be synced to Google Merchant Center.
24+
_n( '%d product', '%d products', quantity, 'google-listings-and-ads' ),
25+
quantity
26+
);
27+
28+
return (
29+
<>
30+
<span className="gla-product-feed-status-section__product-quantity-separator" />
31+
<AppTooltip
32+
className
33+
position="top center"
34+
text={ __(
35+
'You can manage and edit your product feed after this setup',
36+
'google-listings-and-ads'
37+
) }
38+
>
39+
{ text }
40+
</AppTooltip>
41+
</>
42+
);
43+
}
44+
45+
// TODO: `href`` is not yet ready. Will be added later.
46+
/**
47+
* @fires gla_documentation_link_click with `{ context: 'setup-paid-ads', link_id: 'product-feed-status-learn-more', href: 'https://example.com' }`
48+
*/
49+
50+
/**
51+
* Renders a section layout to elaborate on how the product listings will be processed
52+
* and show the number of products will be synced to Google Merchant Center.
53+
*/
54+
export default function ProductFeedStatusSection() {
55+
/*
56+
const { data, hasFinishedResolution } = useAppSelectDispatch(
57+
'getMCProductStatistics'
58+
);
59+
*/
60+
// TODO: Replace the dummy data with the above code later to use the adjusted API.
61+
const data = {
62+
statistics: {
63+
active: 1,
64+
expiring: 2,
65+
pending: 3,
66+
disapproved: 4,
67+
not_synced: 5,
68+
},
69+
};
70+
const hasFinishedResolution = true;
71+
const productQuantity = hasFinishedResolution
72+
? getNumberOfSyncProducts( data.statistics )
73+
: null;
74+
75+
return (
76+
<Section
77+
className="gla-product-feed-status-section"
78+
title={ __( 'Product feed status', 'google-listings-and-ads' ) }
79+
description={
80+
<AppDocumentationLink
81+
context="setup-paid-ads"
82+
linkId="product-feed-status-learn-more"
83+
href="https://example.com" // TODO: Not yet ready. Will be added later.
84+
>
85+
{ __( 'Learn more', 'google-listings-and-ads' ) }
86+
</AppDocumentationLink>
87+
}
88+
>
89+
<Section.Card>
90+
<Section.Card.Body>
91+
<Flex align="flex-start" gap={ 3 }>
92+
<FlexItem>
93+
<SyncIcon />
94+
</FlexItem>
95+
<FlexBlock>
96+
<Section.Card.Title>
97+
{ __(
98+
'Your product listings are being uploaded',
99+
'google-listings-and-ads'
100+
) }
101+
<ProductQuantity quantity={ productQuantity } />
102+
</Section.Card.Title>
103+
{ __(
104+
'Google will review your product listings within 3-5 days. Once approved, your products will automatically be live and searchable on Google. You’ll be notified if there are any product feed issues.',
105+
'google-listings-and-ads'
106+
) }
107+
</FlexBlock>
108+
</Flex>
109+
</Section.Card.Body>
110+
</Section.Card>
111+
</Section>
112+
);
113+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
.gla-product-feed-status-section {
2+
.gla-sync-icon {
3+
fill: $gla-color-green;
4+
transform: rotateZ(90deg);
5+
}
6+
7+
.wcdl-subsection-title {
8+
display: flex;
9+
align-items: center;
10+
}
11+
12+
&__product-quantity-separator,
13+
.app-tooltip__children-container {
14+
font-size: $gla-font-smallest;
15+
font-weight: normal;
16+
color: $gray-700;
17+
}
18+
19+
&__product-quantity-separator::before {
20+
content: "";
21+
display: inline-block;
22+
margin: 0 $grid-unit-10;
23+
}
24+
25+
.app-tooltip__children-container {
26+
padding-bottom: calc($grid-unit-05 / 2);
27+
line-height: 1;
28+
border-bottom: $border-width dashed $gray-600;
29+
}
30+
31+
.components-popover__content {
32+
width: 200px;
33+
white-space: normal;
34+
font-weight: normal;
35+
}
36+
}

js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import StepContentHeader from '.~/components/stepper/step-content-header';
1616
import StepContentFooter from '.~/components/stepper/step-content-footer';
1717
import FaqsSection from '.~/components/paid-ads/faqs-section';
1818
import AppButton from '.~/components/app-button';
19+
import ProductFeedStatusSection from './product-feed-status-section';
1920
import { getProductFeedUrl } from '.~/utils/urls';
2021
import { GUIDE_NAMES } from '.~/constants';
2122
import { API_NAMESPACE } from '.~/data/constants';
@@ -67,6 +68,7 @@ export default function SetupPaidAds() {
6768
'google-listings-and-ads'
6869
) }
6970
/>
71+
<ProductFeedStatusSection />
7072
<FaqsSection />
7173
<StepContentFooter>
7274
<Flex justify="right" gap={ 4 }>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @typedef {import('.~/data/actions').ProductStatisticsDetails } ProductStatisticsDetails
3+
*/
4+
5+
/**
6+
* Return the total number of syncing/synced products except for the `not_synced` category.
7+
*
8+
* @param {ProductStatisticsDetails} statistics The statistics data of scheduled synchronized products.
9+
* @return {number} Number of syncing/synced products.
10+
*/
11+
export default function getNumberOfSyncProducts( statistics ) {
12+
return Object.entries( statistics ).reduce( ( sum, [ key, num ] ) => {
13+
if ( key === 'not_synced' ) {
14+
return sum;
15+
}
16+
return sum + num;
17+
}, 0 );
18+
}

0 commit comments

Comments
 (0)