diff --git a/js/src/hooks/useGoogleMCPhoneNumber.js b/js/src/hooks/useGoogleMCPhoneNumber.js index 1be1a8ce26..cfad17973f 100644 --- a/js/src/hooks/useGoogleMCPhoneNumber.js +++ b/js/src/hooks/useGoogleMCPhoneNumber.js @@ -8,6 +8,7 @@ import { parsePhoneNumberFromString as parsePhoneNumber } from 'libphonenumber-j * Internal dependencies */ import { STORE_KEY } from '.~/data/constants'; +import useGoogleMCAccount from './useGoogleMCAccount'; const emptyData = { country: '', @@ -40,29 +41,48 @@ const emptyData = { * @return {PhoneNumber} The payload of parsed phone number associated with the Google Merchant Center account and its loaded state. */ export default function useGoogleMCPhoneNumber() { - return useSelect( ( select ) => { - const { getGoogleMCPhoneNumber } = select( STORE_KEY ); - const { data: contact, loaded } = getGoogleMCPhoneNumber(); - let data = emptyData; + const { googleMCAccount } = useGoogleMCAccount(); - if ( contact ) { - // Prevent to call parsePhoneNumber with null. - const parsed = parsePhoneNumber( contact.phone_number || '' ); - if ( parsed ) { - data = { - ...parsed, - isValid: parsed.isValid(), - isVerified: - contact.phone_verification_status === 'verified', - display: parsed.formatInternational(), + return useSelect( + ( select ) => { + let data = emptyData; + + // If there is no MC account then there is no phone number data to fetch. + if ( ! googleMCAccount?.id ) { + return { + loaded: false, + data, }; - delete data.metadata; } - } - return { - loaded, - data, - }; - }, [] ); + const { getGoogleMCContactInformation, hasFinishedResolution } = + select( STORE_KEY ); + + const contact = getGoogleMCContactInformation(); + const loaded = hasFinishedResolution( + 'getGoogleMCContactInformation' + ); + + if ( contact && loaded ) { + // Prevent to call parsePhoneNumber with null. + const parsed = parsePhoneNumber( contact.phone_number || '' ); + if ( parsed ) { + data = { + ...parsed, + isValid: parsed.isValid(), + isVerified: + contact.phone_verification_status === 'verified', + display: parsed.formatInternational(), + }; + delete data.metadata; + } + } + + return { + loaded, + data, + }; + }, + [ googleMCAccount?.id ] + ); } diff --git a/js/src/hooks/useStoreAddress.js b/js/src/hooks/useStoreAddress.js index 8a332770ba..4d99469661 100644 --- a/js/src/hooks/useStoreAddress.js +++ b/js/src/hooks/useStoreAddress.js @@ -1,8 +1,14 @@ +/** + * External dependencies + */ +import { useSelect } from '@wordpress/data'; + /** * Internal dependencies */ -import useAppSelectDispatch from './useAppSelectDispatch'; +import { STORE_KEY } from '.~/data/constants'; import useCountryKeyNameMap from './useCountryKeyNameMap'; +import useGoogleMCAccount from './useGoogleMCAccount'; /** * @typedef {import('.~/hooks/types.js').StoreAddress} StoreAddress @@ -36,53 +42,73 @@ const emptyData = { * @return {StoreAddressResult} Store address result. */ export default function useStoreAddress( source = 'wc' ) { - const { - data: contact, - hasFinishedResolution: loaded, - invalidateResolution: refetch, - } = useAppSelectDispatch( 'getGoogleMCContactInformation' ); - + const { googleMCAccount } = useGoogleMCAccount(); const countryNameDict = useCountryKeyNameMap(); - let data = emptyData; + return useSelect( + ( select ) => { + let data = emptyData; + + // If there is no MC account then there is no store address data to fetch. + if ( ! googleMCAccount?.id ) { + return { + refetch: () => {}, + loaded: false, + data, + }; + } + + const { + getGoogleMCContactInformation, + hasFinishedResolution, + refetch, + } = select( STORE_KEY ); + + const contact = getGoogleMCContactInformation(); + const loaded = hasFinishedResolution( + 'getGoogleMCContactInformation' + ); - if ( loaded && contact ) { - const { - is_mc_address_different: isMCAddressDifferent, - wc_address_errors: missingRequiredFields, - } = contact; + if ( contact && loaded ) { + const { + is_mc_address_different: isMCAddressDifferent, + wc_address_errors: missingRequiredFields, + } = contact; - const storeAddress = - source === 'wc' ? contact.wc_address : contact.mc_address; + const storeAddress = + source === 'wc' ? contact.wc_address : contact.mc_address; - // Handle fallback for `null` fields to make sure the returned data types are consistent. - const streetAddress = storeAddress?.street_address || ''; - const city = storeAddress?.locality || ''; - const state = storeAddress?.region || ''; - const postcode = storeAddress?.postal_code || ''; + // Handle fallback for `null` fields to make sure the returned data types are consistent. + const streetAddress = storeAddress?.street_address || ''; + const city = storeAddress?.locality || ''; + const state = storeAddress?.region || ''; + const postcode = storeAddress?.postal_code || ''; - const [ address, address2 = '' ] = streetAddress.split( '\n' ); - const country = countryNameDict[ storeAddress?.country ] || ''; - const countryCode = storeAddress?.country || ''; - const isAddressFilled = ! missingRequiredFields.length; + const [ address, address2 = '' ] = streetAddress.split( '\n' ); + const country = countryNameDict[ storeAddress?.country ] || ''; + const countryCode = storeAddress?.country || ''; + const isAddressFilled = ! missingRequiredFields.length; - data = { - countryCode, - address, - address2, - city, - state, - country, - postcode, - isAddressFilled, - isMCAddressDifferent, - missingRequiredFields, - }; - } + data = { + countryCode, + address, + address2, + city, + state, + country, + postcode, + isAddressFilled, + isMCAddressDifferent, + missingRequiredFields, + }; + } - return { - refetch, - loaded, - data, - }; + return { + refetch, + loaded, + data, + }; + }, + [ countryNameDict, googleMCAccount?.id, source ] + ); } diff --git a/js/src/setup-mc/setup-stepper/saved-setup-stepper.js b/js/src/setup-mc/setup-stepper/saved-setup-stepper.js index 000b0a9336..5721020eab 100644 --- a/js/src/setup-mc/setup-stepper/saved-setup-stepper.js +++ b/js/src/setup-mc/setup-stepper/saved-setup-stepper.js @@ -14,6 +14,8 @@ import useTargetAudienceWithSuggestions from './useTargetAudienceWithSuggestions import useTargetAudienceFinalCountryCodes from '.~/hooks/useTargetAudienceFinalCountryCodes'; import useSettings from '.~/components/free-listings/configure-product-listings/useSettings'; import useShippingRates from '.~/hooks/useShippingRates'; +import useGoogleMCPhoneNumber from '.~/hooks/useGoogleMCPhoneNumber'; +import useStoreAddress from '.~/hooks/useStoreAddress'; import useShippingTimes from '.~/hooks/useShippingTimes'; import useSaveShippingRates from '.~/hooks/useSaveShippingRates'; import useSaveShippingTimes from '.~/hooks/useSaveShippingTimes'; @@ -39,6 +41,20 @@ import { const SavedSetupStepper = ( { savedStep } ) => { const [ step, setStep ] = useState( savedStep ); + const { data: address, loaded: addressLoaded } = useStoreAddress(); + const { data: phone, loaded: phoneLoaded } = useGoogleMCPhoneNumber(); + + const hasValidPhoneNumber = + phoneLoaded && phone?.isValid && phone?.isVerified; + + const hasValidAddress = + addressLoaded && + address?.isAddressFilled && + ! address?.isMCAddressDifferent; + + const hasConfirmedStoreRequirements = + hasValidPhoneNumber && hasValidAddress; + const { settings } = useSettings(); const { data: suggestedAudience } = useTargetAudienceWithSuggestions(); const { targetAudience, getFinalCountries } = @@ -102,7 +118,11 @@ const SavedSetupStepper = ( { savedStep } ) => { }; const handleSetupListingsContinue = () => { - continueStep( stepNameKeyMap.store_requirements ); + if ( hasConfirmedStoreRequirements ) { + continueStep( stepNameKeyMap.paid_ads ); + } else { + continueStep( stepNameKeyMap.store_requirements ); + } }; const handleStoreRequirementsContinue = () => { diff --git a/tests/e2e/specs/setup-mc/step-3-hide-store-requirements.test.js b/tests/e2e/specs/setup-mc/step-3-hide-store-requirements.test.js new file mode 100644 index 0000000000..c9f29447e6 --- /dev/null +++ b/tests/e2e/specs/setup-mc/step-3-hide-store-requirements.test.js @@ -0,0 +1,82 @@ +/** + * Internal dependencies + */ +import SetUpAccountsPage from '../../utils/pages/setup-mc/step-1-set-up-accounts'; + +/** + * External dependencies + */ +const { test, expect } = require( '@playwright/test' ); + +test.use( { storageState: process.env.ADMINSTATE } ); + +test.describe.configure( { mode: 'serial' } ); + +/** + * @type {import('../../utils/pages/setup-mc/step-1-set-up-accounts.js').default} setUpAccountsPage + */ +let setUpAccountsPage = null; + +/** + * @type {import('@playwright/test').Page} page + */ +let page = null; + +test.describe( 'Hide Store Requirements Step', () => { + test.beforeAll( async ( { browser } ) => { + page = await browser.newPage(); + setUpAccountsPage = new SetUpAccountsPage( page ); + await Promise.all( [ + // Mock google as connected. + setUpAccountsPage.mockGoogleNotConnected(), + + // Mock MC contact information + setUpAccountsPage.mockContactInformation(), + ] ); + } ); + + test.afterAll( async () => { + await setUpAccountsPage.closePage(); + } ); + + test( 'should have store requirements step if incomplete', async () => { + await setUpAccountsPage.goto(); + + // Mock MC step at step 1: + setUpAccountsPage.mockMCSetup( 'incomplete', 'accounts' ); + + // 1. Assert there are 3 steps + const steps = await page.locator( '.woocommerce-stepper__step' ); + await expect( steps ).toHaveCount( 4 ); + + // 2. Assert the label of the 3rd step is 'Confirm store requirements' + const thirdStepLabel = await steps + .nth( 2 ) + .locator( '.woocommerce-stepper__step-label' ); + await expect( thirdStepLabel ).toHaveText( + 'Confirm store requirements' + ); + } ); + + test( 'should not have store requirements step if complete', async () => { + await setUpAccountsPage.goto(); + + // TODO: Mock email is verified & address is filled + setUpAccountsPage.mockMCSetup( 'complete', 'accounts' ); + + // 1. Assert there are 3 steps + const steps = await page.locator( '.woocommerce-stepper__step' ); + await expect( steps ).toHaveCount( 3 ); + + // 2. Assert the label of the 3rd step is not 'Confirm store requirements' + const thirdStepLabel = await steps + .nth( 2 ) + .locator( '.woocommerce-stepper__step-label' ); + await expect( thirdStepLabel ).not.toHaveText( + 'Confirm store requirements' + ); + + // 3. Assert the label of the 3rd step equals 'Create a campaign' + await expect( thirdStepLabel ).toHaveText( 'Create a campaign' ); + } ); +} );