Skip to content

Commit

Permalink
Merge pull request #2480 from woocommerce/feature/google-api-project
Browse files Browse the repository at this point in the history
Google API Project
  • Loading branch information
puntope authored Jul 26, 2024
2 parents d6500c1 + 68a0d2d commit 23dafb9
Show file tree
Hide file tree
Showing 86 changed files with 7,367 additions and 247 deletions.
33 changes: 33 additions & 0 deletions js/src/components/app-notice/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* External dependencies
*/
import classnames from 'classnames';
import { Notice } from '@wordpress/components';

/**
* Internal dependencies
*/
import './index.scss';

/**
* Renders a Notice component with extra props.
*
* It supports all the props from @wordpress/components - Notice Component
*
* ## Usage
*
* ```jsx
* <AppNotice >
* My Notice
* </AppButton>
* ```
*
* @param {*} props Props to be forwarded to {@link Notice}.
*/
const AppNotice = ( props ) => {
const { className, ...rest } = props;
const classes = [ 'app-notice', className ];
return <Notice className={ classnames( ...classes ) } { ...rest } />;
};

export default AppNotice;
6 changes: 6 additions & 0 deletions js/src/components/app-notice/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.app-notice {
border: 0;
font-size: $helptext-font-size;
margin: 0 var(--large-gap) var(--main-gap);
padding: $grid-unit-20;
}
58 changes: 58 additions & 0 deletions js/src/components/enable-new-product-sync-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import AppButton from '.~/components/app-button';
import { glaData } from '.~/constants';
import { API_NAMESPACE } from '.~/data/constants';
import useApiFetchCallback from '.~/hooks/useApiFetchCallback';
import useDispatchCoreNotices from '.~/hooks/useDispatchCoreNotices';

/**
* Button to initiate auth process for WP Rest API
*
* @param {Object} params The component params
* @return {JSX.Element} The button.
*/
const EnableNewProductSyncButton = ( params ) => {
const { createNotice } = useDispatchCoreNotices();
const [ loading, setLoading ] = useState( false );
const nextPageName = glaData.mcSetupComplete ? 'settings' : 'setup-mc';
const query = { next_page_name: nextPageName };
const path = addQueryArgs( `${ API_NAMESPACE }/rest-api/authorize`, query );
const [ fetchRestAPIAuthorize ] = useApiFetchCallback( { path } );
const handleEnableClick = async () => {
try {
setLoading( true );
const d = await fetchRestAPIAuthorize();
setLoading( false );
window.location.href = d.auth_url;
} catch ( error ) {
setLoading( false );
createNotice(
'error',
__(
'Unable to enable new product sync. Please try again later.',
'google-listings-and-ads'
)
);
}
};

return (
<AppButton
isSecondary
loading={ loading }
onClick={ handleEnableClick }
{ ...params }
/>
);
};

export default EnableNewProductSyncButton;
56 changes: 56 additions & 0 deletions js/src/components/enable-new-product-sync-notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';
import { createInterpolateElement } from '@wordpress/element';

/**
* Internal dependencies
*/
import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount';
import EnableNewProductSyncButton from '.~/components/enable-new-product-sync-button';

/**
* Shows info {@link Notice}
* about enabling new product sync when the feature flag is turned on and hasn't switched to new product sync.
*
* @return {JSX.Element} {@link Notice} element with the info message and the button to enable new product sync.
*/
const EnableNewProductSyncNotice = () => {
const {
hasFinishedResolution: hasGoogleMCAccountFinishedResolution,
googleMCAccount,
} = useGoogleMCAccount();

// Do not render if already switch to new product sync.
if (
! hasGoogleMCAccountFinishedResolution ||
! googleMCAccount.notification_service_enabled ||
googleMCAccount.wpcom_rest_api_status
) {
return null;
}

return (
<Notice status="info" isDismissible={ false }>
{ createInterpolateElement(
__(
'<p>We will soon transition to a new and improved method for synchronizing product data with Google.</p><enableButton>Get early access</enableButton>',
'google-listings-and-ads'
),
{
enableButton: (
<EnableNewProductSyncButton
eventName="gla_enable_product_sync_click"
eventProps={ { context: 'banner' } }
/>
),
p: <p />,
}
) }
</Notice>
);
};

export default EnableNewProductSyncNotice;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* External dependencies
*/
import { sprintf, __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { getSetting } from '@woocommerce/settings'; // eslint-disable-line import/no-unresolved
// The above is an unpublished package, delivered with WC, we use Dependency Extraction Webpack Plugin to import it.
// See https://github.com/woocommerce/woocommerce-admin/issues/7781
Expand All @@ -13,10 +14,17 @@ import AccountCard, { APPEARANCE } from '.~/components/account-card';
import AppButton from '.~/components/app-button';
import ConnectedIconLabel from '.~/components/connected-icon-label';
import Section from '.~/wcdl/section';
import { GOOGLE_WPCOM_APP_CONNECTED_STATUS } from '.~/constants';
import { API_NAMESPACE } from '.~/data/constants';
import useDispatchCoreNotices from '.~/hooks/useDispatchCoreNotices';
import useApiFetchCallback from '.~/hooks/useApiFetchCallback';
import { useAppDispatch } from '.~/data';
import EnableNewProductSyncButton from '.~/components/enable-new-product-sync-button';
import AppNotice from '.~/components/app-notice';
import DisconnectModal, {
API_DATA_FETCH_FEATURE,
} from '.~/settings/disconnect-modal';
import { getSettingsUrl } from '.~/utils/urls';

/**
* Clicking on the "connect to a different Google Merchant Center account" button.
Expand All @@ -32,10 +40,12 @@ import { useAppDispatch } from '.~/data';
* @param {Object} props React props.
* @param {{ id: number }} props.googleMCAccount A data payload object containing the user's Google Merchant Center account ID.
* @param {boolean} [props.hideAccountSwitch=false] Indicate whether hide the account switch block at the card footer.
* @param {boolean} [props.hideNotificationService=true] Indicate whether hide the enable Notification service block at the card footer.
*/
const ConnectedGoogleMCAccountCard = ( {
googleMCAccount,
hideAccountSwitch = false,
hideNotificationService = false,
} ) => {
const { createNotice, removeNotice } = useDispatchCoreNotices();
const { invalidateResolution } = useAppDispatch();
Expand All @@ -46,6 +56,22 @@ const ConnectedGoogleMCAccountCard = ( {
method: 'DELETE',
} );

const [
fetchDisableNotifications,
{ loading: loadingDisableNotifications },
] = useApiFetchCallback( {
path: `${ API_NAMESPACE }/rest-api/authorize`,
method: 'DELETE',
} );

/**
* Temporary code for disabling the API PULL Beta Feature from the GMC Card
*/
const [ openedModal, setOpenedModal ] = useState( null );
const dismissModal = () => setOpenedModal( null );
const openDisableDataFetchModal = () =>
setOpenedModal( API_DATA_FETCH_FEATURE );

const domain = new URL( getSetting( 'homeUrl' ) ).host;

/**
Expand Down Expand Up @@ -85,6 +111,47 @@ const ConnectedGoogleMCAccountCard = ( {
removeNotice( notice.id );
};

const disableNotifications = async () => {
const { notice } = await createNotice(
'info',
__(
'Disabling the new Product Sync feature, please wait…',
'google-listings-and-ads'
)
);

try {
await fetchDisableNotifications();
invalidateResolution( 'getGoogleMCAccount', [] );
} catch ( error ) {
createNotice(
'error',
__(
'Unable to disable new product sync. Please try again later.',
'google-listings-and-ads'
)
);
}

removeNotice( notice.id );
};

// Show the button if the status is "approved" and the Notification Service is not hidden.
const showDisconnectNotificationsButton =
! hideNotificationService &&
googleMCAccount.wpcom_rest_api_status ===
GOOGLE_WPCOM_APP_CONNECTED_STATUS.APPROVED;

// Show the error if the status is set but is not "approved" and the Notification Service is not hidden.
const showErrorNotificationsNotice =
! hideNotificationService &&
googleMCAccount.wpcom_rest_api_status &&
googleMCAccount.notification_service_enabled &&
googleMCAccount.wpcom_rest_api_status !==
GOOGLE_WPCOM_APP_CONNECTED_STATUS.APPROVED;

const showFooter = ! hideAccountSwitch || showDisconnectNotificationsButton;

return (
<AccountCard
appearance={ APPEARANCE.GOOGLE_MERCHANT_CENTER }
Expand All @@ -94,20 +161,74 @@ const ConnectedGoogleMCAccountCard = ( {
domain,
googleMCAccount.id
) }
indicator={ <ConnectedIconLabel /> }
indicator={
showErrorNotificationsNotice ? (
<EnableNewProductSyncButton
text={ __( 'Grant access', 'google-listings-and-ads' ) }
eventName="gla_enable_product_sync_click"
eventProps={ { context: 'mc_card' } }
/>
) : (
<ConnectedIconLabel />
)
}
>
{ ! hideAccountSwitch && (
{ showDisconnectNotificationsButton && (
<AppNotice status="success" isDismissible={ false }>
{ __(
'Google has been granted access to fetch your product data.',
'google-listings-and-ads'
) }
</AppNotice>
) }

{ showErrorNotificationsNotice && (
<AppNotice status="warning" isDismissible={ false }>
{ __(
'There was an issue granting access to Google for fetching your products.',
'google-listings-and-ads'
) }
</AppNotice>
) }

{ openedModal && (
<DisconnectModal
onRequestClose={ dismissModal }
onDisconnected={ () => {
window.location.href = getSettingsUrl();
} }
disconnectTarget={ openedModal }
disconnectAction={ disableNotifications }
/>
) }

{ showFooter && (
<Section.Card.Footer>
<AppButton
isLink
disabled={ loadingGoogleMCDisconnect }
text={ __(
'Or, connect to a different Google Merchant Center account',
'google-listings-and-ads'
) }
eventName="gla_mc_account_connect_different_account_button_click"
onClick={ handleSwitch }
/>
{ ! hideAccountSwitch && (
<AppButton
isLink
disabled={ loadingGoogleMCDisconnect }
text={ __(
'Or, connect to a different Google Merchant Center account',
'google-listings-and-ads'
) }
eventName="gla_mc_account_connect_different_account_button_click"
onClick={ handleSwitch }
/>
) }
{ showDisconnectNotificationsButton && (
<AppButton
isDestructive
isLink
disabled={ loadingDisableNotifications }
text={ __(
'Disable product data fetch',
'google-listings-and-ads'
) }
eventName="gla_disable_product_sync_click"
onClick={ openDisableDataFetchModal }
/>
) }
</Section.Card.Footer>
) }
</AccountCard>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ const GoogleMCAccountCard = () => {
return <NonConnected />;
}

return <ConnectedGoogleMCAccountCard googleMCAccount={ googleMCAccount } />;
return (
<ConnectedGoogleMCAccountCard
hideNotificationService
googleMCAccount={ googleMCAccount }
/>
);
};

export default GoogleMCAccountCard;
7 changes: 7 additions & 0 deletions js/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,10 @@ export const ASSET_FORM_KEY = {
...ASSET_KEY,
...ASSET_GROUP_KEY,
};

export const GOOGLE_WPCOM_APP_CONNECTED_STATUS = {
APPROVED: 'approved',
DISAPPROVED: 'disapproved',
ERROR: 'error',
DISABLED: 'disabled',
};
Loading

0 comments on commit 23dafb9

Please sign in to comment.