Skip to content

Commit

Permalink
Merge pull request #778 from woocommerce/add/v5-connection-wizard
Browse files Browse the repository at this point in the history
Pinterest v5 user onboarding.
  • Loading branch information
message-dimke authored Jun 16, 2023
2 parents cd4834c + e428007 commit 5e60e5a
Show file tree
Hide file tree
Showing 44 changed files with 3,366 additions and 829 deletions.
14 changes: 6 additions & 8 deletions assets/source/catalog-sync/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,14 @@ import { useSettingsSelect } from '../setup-guide/app/helpers/effects';
const CatalogSyncApp = () => {
const adsCampaignIsActive = useSettingsSelect()?.ads_campaign_is_active;

const couponRedeemErrorID = useSettingsSelect()?.account_data
?.coupon_redeem_info?.error_id;
const couponRedeemErrorID =
useSettingsSelect()?.account_data?.coupon_redeem_info?.error_id;

useCreateNotice( wcSettings.pinterest_for_woocommerce.error );
const [ isOnboardingModalOpen, setIsOnboardingModalOpen ] = useState(
false
);
const [ isAdCreditsNoticeOpen, setIsAdCreditsNoticeOpen ] = useState(
false
);
const [ isOnboardingModalOpen, setIsOnboardingModalOpen ] =
useState( false );
const [ isAdCreditsNoticeOpen, setIsAdCreditsNoticeOpen ] =
useState( false );

const userInteractions = useSelect( ( select ) =>
select( USER_INTERACTION_STORE_NAME ).getUserInteractions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const OnboardingErrorModal = ( { onCloseModal } ) => {
const NOT_AVAILABLE_IN_COUNTRY_OR_CURRENCY_ERROR = 2327;
const WRONG_BILLING_PROFILE_ERROR = 2006;

const couponRedeemInfo = useSettingsSelect()?.account_data
?.coupon_redeem_info;
const couponRedeemInfo =
useSettingsSelect()?.account_data?.coupon_redeem_info;

let errorMessageText = '';
switch ( couponRedeemInfo?.error_id ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import OnboardingErrorModal from './OnboardingErrorModal';
*/
const OnboardingModals = ( { onCloseModal } ) => {
const adsCampaignIsActive = useSettingsSelect()?.ads_campaign_is_active;
const couponRedeemInfo = useSettingsSelect()?.account_data
?.coupon_redeem_info;
const couponRedeemInfo =
useSettingsSelect()?.account_data?.coupon_redeem_info;

// Generic modal when there is no campaign.
if ( ! adsCampaignIsActive ) {
Expand Down
5 changes: 3 additions & 2 deletions assets/source/catalog-sync/sections/SyncState.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ const SyncState = () => {
select( REPORTS_STORE_NAME ).getFeedState()
);

const hasAvailableCredits = useSettingsSelect()?.account_data
?.available_discounts?.marketing_offer?.remaining_discount;
const hasAvailableCredits =
useSettingsSelect()?.account_data?.available_discounts?.marketing_offer
?.remaining_discount;

const availableCredits = sprintf(
/* translators: %s credits value with currency formatted using wc_price */
Expand Down
5 changes: 2 additions & 3 deletions assets/source/components/prelaunch-notice/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,8 @@ const PrelaunchNotice = () => {
<p>
<a
{ ...documentationLinkProps( {
href:
wcSettings.pinterest_for_woocommerce.pinterestLinks
.preLaunchNotice,
href: wcSettings.pinterest_for_woocommerce
.pinterestLinks.preLaunchNotice,
eventName: 'pfw_get_started_notice_link_click',
linkId: 'prelaunch-notice',
context: 'pinterest-landing',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ const AccountConnection = ( {
const createNotice = useCreateNotice();
const modalName = 'account-disconnection';

const [ isConfirmationModalOpen, setIsConfirmationModalOpen ] = useState(
false
);
const [ isConfirmationModalOpen, setIsConfirmationModalOpen ] =
useState( false );

const openConfirmationModal = () => {
recordEvent( 'pfw_account_disconnect_button_click', { context } );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ const SyncSettings = () => {
const syncAppSettings = useSyncSettingsDispatch();
const createNotice = useCreateNotice();
const { removeNotice } = useDispatch( 'core/notices' );
const [ triggeredSyncSettings, setTriggeredSyncSettings ] = useState(
false
);
const [ triggeredSyncSettings, setTriggeredSyncSettings ] =
useState( false );

const syncSettings = async () => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,8 @@ function UnsupportedCountryNotice( { countryCode } ) {
supportedCountriesLink: (
<ExternalLink
{ ...documentationLinkProps( {
href:
wcSettings.pinterest_for_woocommerce
.pinterestLinks.adsAvailability,
href: wcSettings.pinterest_for_woocommerce
.pinterestLinks.adsAvailability,
eventName: 'pfw_get_started_notice_link_click',
linkId: 'ads-availability',
context: 'pinterest-landing',
Expand Down
5 changes: 2 additions & 3 deletions assets/source/setup-guide/app/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,8 @@ export const DISAPPROVAL_COPY_STATES = Object.freeze( {
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
{ ...documentationLinkProps( {
href:
wcSettings.pinterest_for_woocommerce.pinterestLinks
.merchantGuidelines,
href: wcSettings.pinterest_for_woocommerce
.pinterestLinks.merchantGuidelines,
linkId: 'merchant-guidelines',
context: 'merchant-disapproval-reasons',
rel: 'noreferrer',
Expand Down
147 changes: 95 additions & 52 deletions assets/source/setup-guide/app/steps/ClaimWebsite.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
createInterpolateElement,
} from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';
import { Spinner } from '@woocommerce/components';
import {
Button,
Card,
Expand All @@ -28,12 +27,9 @@ import StepHeader from '../components/StepHeader';
import StepOverview from '../components/StepOverview';
import UrlInputControl from '../components/UrlInputControl';
import StatusLabel from '../components/StatusLabel';
import {
useSettingsSelect,
useSettingsDispatch,
useCreateNotice,
} from '../helpers/effects';
import { useSettingsSelect, useCreateNotice } from '../helpers/effects';
import documentationLinkProps from '../helpers/documentation-link-props';
import { getNewPath } from '@woocommerce/navigation'; // eslint-disable-line

const StaticError = ( { reqError } ) => {
if ( reqError?.data?.pinterest_code === undefined ) {
Expand Down Expand Up @@ -92,38 +88,43 @@ const StaticError = ( { reqError } ) => {
* @fires wcadmin_pfw_documentation_link_click with `{ link_id: 'claim-website', context: props.view }`
* @param {Object} props React props.
* @param {'wizard'|'settings'} props.view Indicate which view this component is rendered on.
* @param {Function} [props.goToNextStep]
* When the website claim is complete, called when clicking the "Continue" button.
* The "Continue" button is only displayed when `props.view` is 'wizard'.
* @return {JSX.Element} Rendered component.
*/
const ClaimWebsite = ( { goToNextStep, view } ) => {
const ClaimWebsite = ( { view } ) => {
const [ status, setStatus ] = useState( STATUS.IDLE );
const [ reqError, setReqError ] = useState();
const isDomainVerified = useSettingsSelect( 'isDomainVerified' );
const setAppSettings = useSettingsDispatch( view === 'wizard' );
const createNotice = useCreateNotice();
const pfwSettings = wcSettings.pinterest_for_woocommerce;

useEffect( () => {
// If domain is not verified and verification status is not pending, error nor success - start verification.
if (
! Object.values( {
...LABEL_STATUS,
ERROR: STATUS.ERROR,
} ).includes( status ) &&
! isDomainVerified
) {
handleClaimWebsite();
}
if ( status !== STATUS.PENDING && isDomainVerified ) {
setStatus( STATUS.SUCCESS );
}
}, [ status, isDomainVerified ] );
}, [ status, isDomainVerified ] ); // eslint-disable-line

const handleClaimWebsite = async () => {
setStatus( STATUS.PENDING );
setReqError();

try {
const results = await apiFetch( {
await apiFetch( {
path: pfwSettings.apiRoute + '/domain_verification',
method: 'POST',
} );
await setAppSettings( { account_data: results.account_data } );

recordEvent( 'pfw_domain_verify_success' );

setStatus( STATUS.SUCCESS );
} catch ( error ) {
setStatus( STATUS.ERROR );
Expand Down Expand Up @@ -160,7 +161,12 @@ const ClaimWebsite = ( { goToNextStep, view } ) => {

const text = buttonLabels[ status ];

if ( Object.values( LABEL_STATUS ).includes( status ) ) {
if (
Object.values( {
...LABEL_STATUS,
IDLE: STATUS.IDLE,
} ).includes( status )
) {
return <StatusLabel status={ status } text={ text } />;
}

Expand All @@ -169,6 +175,57 @@ const ClaimWebsite = ( { goToNextStep, view } ) => {
);
};

const CompleteSetupButton = () => {
const buttonLabels = {
error: __( 'Try Again', 'pinterest-for-woocommerce' ),
success: __( 'Complete Setup', 'pinterest-for-woocommerce' ),
};

return (
<Button
isPrimary
disabled={
status !== STATUS.SUCCESS && status !== STATUS.ERROR
}
onClick={
status === STATUS.SUCCESS
? handleCompleteSetup
: handleClaimWebsite
}
>
{ buttonLabels[ status ] ??
__( 'Verifying…', 'pinterest-for-woocommerce' ) }
</Button>
);
};

const handleCompleteSetup = async () => {
try {
createNotice(
'success',
__( 'Connected successfully.', 'pinterest-for-woocommerce' )
);

recordEvent( 'pfw_setup', {
target: 'complete',
trigger: 'setup-complete',
} );

// Force reload WC admin page to initiate the relevant dependencies of the Dashboard page.
const path = getNewPath( {}, '/pinterest/settings', {} );

window.location = new URL( wcSettings.adminUrl + path );
} catch ( error ) {
createNotice(
'error',
__(
'There was a problem connecting the advertiser.',
'pinterest-for-woocommerce'
)
);
}
};

return (
<div className="woocommerce-setup-guide__claim-website">
{ view === 'wizard' && (
Expand Down Expand Up @@ -208,49 +265,35 @@ const ClaimWebsite = ( { goToNextStep, view } ) => {
</div>
<div className="woocommerce-setup-guide__step-column">
<Card>
{ undefined !== isDomainVerified ? (
<CardBody size="large">
<Text variant="subtitle">
{ __(
'Verify your domain to claim your website',
'pinterest-for-woocommerce'
) }
</Text>
<Text variant="body">
{ __(
'This will allow access to analytics for the Pins you publish from your site, the analytics on Pins that other people create from your site, and let people know where they can find more of your content.',
'pinterest-for-woocommerce'
) }
</Text>
<CardBody size="large">
<Text variant="subtitle">
{ __(
'Verify your domain to claim your website',
'pinterest-for-woocommerce'
) }
</Text>
<Text variant="body">
{ __(
'This will allow access to analytics for the Pins you publish from your site, the analytics on Pins that other people create from your site, and let people know where they can find more of your content.',
'pinterest-for-woocommerce'
) }
</Text>

<Flex gap={ 6 }>
<UrlInputControl
disabled
value={ pfwSettings.homeUrlToVerify }
/>
<VerifyButton />
</Flex>
<Flex gap={ 6 }>
<UrlInputControl
disabled
value={ pfwSettings.homeUrlToVerify }
/>
<VerifyButton />
</Flex>

<StaticError reqError={ reqError } />
</CardBody>
) : (
<CardBody size="large">
<Spinner />
</CardBody>
) }
<StaticError reqError={ reqError } />
</CardBody>
</Card>

{ view === 'wizard' && (
<div className="woocommerce-setup-guide__footer-button">
<Button
isPrimary
disabled={ status !== STATUS.SUCCESS }
onClick={ goToNextStep }
text={ __(
'Continue',
'pinterest-for-woocommerce'
) }
/>
<CompleteSetupButton />
</div>
) }
</div>
Expand Down
13 changes: 3 additions & 10 deletions assets/source/setup-guide/app/steps/ClaimWebsite.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jest.mock( '@wordpress/api-fetch', () => {
*/
import { recordEvent } from '@woocommerce/tracks';
import apiFetch from '@wordpress/api-fetch';
import { fireEvent, render, waitFor } from '@testing-library/react';
import { render, waitFor } from '@testing-library/react';

/**
* Internal dependencies
Expand All @@ -37,11 +37,8 @@ describe( 'Claim Website Record Events', () => {
throw 'Ups';
} );

const { getByText } = render(
<ClaimWebsite goToNextStep={ () => {} } view="wizard" />
);
render( <ClaimWebsite goToNextStep={ () => {} } view="wizard" /> );

fireEvent.click( getByText( 'Start verification' ) );
expect( recordEvent ).toHaveBeenCalledWith(
'pfw_domain_verify_failure',
expect.any( Object )
Expand All @@ -53,11 +50,7 @@ describe( 'Claim Website Record Events', () => {
return { account_data: { id: 'foo' } };
} );

const { getByText } = render(
<ClaimWebsite goToNextStep={ () => {} } view="wizard" />
);

fireEvent.click( getByText( 'Start verification' ) );
render( <ClaimWebsite goToNextStep={ () => {} } view="wizard" /> );

// Wait for async click handler and apiFetch resolution.
await waitFor( () =>
Expand Down
Loading

0 comments on commit 5e60e5a

Please sign in to comment.