From 5098fe82561104993a2b5f6e0a80d57a6a452842 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Tue, 5 Nov 2024 22:04:09 -0600 Subject: [PATCH] Reinstate EditStoreAddress flow in settings --- .../contact-information-preview-card.js | 87 +++++++++++++ .../contact-information-preview-card.scss | 21 ++++ .../components/contact-information/index.js | 21 +++- .../contact-information/store-address-card.js | 71 +++++++++++ js/src/settings/edit-store-address.js | 115 ++++++++++++++++++ js/src/settings/index.js | 3 + js/src/utils/urls.js | 8 ++ 7 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 js/src/components/contact-information/contact-information-preview-card.js create mode 100644 js/src/components/contact-information/contact-information-preview-card.scss create mode 100644 js/src/settings/edit-store-address.js diff --git a/js/src/components/contact-information/contact-information-preview-card.js b/js/src/components/contact-information/contact-information-preview-card.js new file mode 100644 index 0000000000..b60db4b5cf --- /dev/null +++ b/js/src/components/contact-information/contact-information-preview-card.js @@ -0,0 +1,87 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { Icon, warning as warningIcon } from '@wordpress/icons'; +import { getPath, getQuery } from '@woocommerce/navigation'; + +/** + * Internal dependencies + */ +import AccountCard from '.~/components/account-card'; +import AppButton from '.~/components/app-button'; +import './contact-information-preview-card.scss'; + +/** + * Renders a contact information card component. + * It adds loading & warning state to the regular `AccountCard`, and an edit button link. + * + * @param {Object} props React props + * @param {import('.~/components/account-card').APPEARANCE} props.appearance + * @param {string} props.editHref URL where Edit button should point to. + * @param {string} props.editEventName Tracing event name used when the "Edit" button is clicked. + * @param {boolean} props.loading Set to `true` if the card should be rendered in the loading state. + * @param {JSX.Element} props.content Main content of the card to be rendered once the data is loaded. + * @param {string} [props.warning] Warning title, to be used instead of the default one. + * @return {JSX.Element} Filled AccountCard component. + */ +export default function ContactInformationPreviewCard( { + editHref, + editEventName, + loading, + content, + appearance, + warning, +} ) { + const { subpath } = getQuery(); + const editButton = ( + + ); + let description; + let title; + + if ( loading ) { + description = ( + + ); + } else if ( warning ) { + title = ( + <> + + { warning } + + ); + description = ( + + { content } + + ); + } else { + description = content; + } + + return ( + + ); +} diff --git a/js/src/components/contact-information/contact-information-preview-card.scss b/js/src/components/contact-information/contact-information-preview-card.scss new file mode 100644 index 0000000000..8f938a738c --- /dev/null +++ b/js/src/components/contact-information/contact-information-preview-card.scss @@ -0,0 +1,21 @@ +.gla-contact-info-preview-card { + // Vertically align icon inside the title. + .wcdl-subsection-title { + display: flex; + align-items: center; + } + &__notice-icon { + fill: $alert-red; + margin: calc(var(--main-gap) / -8) 0; + } + &__notice-details { + color: $gray-700; + } + + &__placeholder { + display: inline-block; + width: 18em; + + @include placeholder; + } +} diff --git a/js/src/components/contact-information/index.js b/js/src/components/contact-information/index.js index f89ff5cee3..4ca9d4abdc 100644 --- a/js/src/components/contact-information/index.js +++ b/js/src/components/contact-information/index.js @@ -6,9 +6,15 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ +import { getEditStoreAddressUrl } from '.~/utils/urls'; import Section from '.~/wcdl/section'; -import StoreAddressCard from './store-address-card'; import VerticalGapLayout from '.~/components/vertical-gap-layout'; +import AppDocumentationLink from '.~/components/app-documentation-link'; +import { StoreAddressCardPreview } from './store-address-card'; + +const learnMoreLinkId = 'contact-information-read-more'; +const learnMoreUrl = + 'https://woocommerce.com/document/google-for-woocommerce/get-started/requirements/#contact-information'; const description = ( <> @@ -37,7 +43,18 @@ export function ContactInformationPreview() { return (
- + + { __( 'Learn more', 'google-listings-and-ads' ) } + + } + />
); diff --git a/js/src/components/contact-information/store-address-card.js b/js/src/components/contact-information/store-address-card.js index 65582deb2a..d17553655d 100644 --- a/js/src/components/contact-information/store-address-card.js +++ b/js/src/components/contact-information/store-address-card.js @@ -14,6 +14,7 @@ import useStoreAddress from '.~/hooks/useStoreAddress'; import useStoreAddressSynced from '.~/hooks/useStoreAddressSynced'; import AccountCard, { APPEARANCE } from '.~/components/account-card'; import AppButton from '.~/components/app-button'; +import ContactInformationPreviewCard from './contact-information-preview-card'; import ValidationErrors from '.~/components/validation-errors'; import TrackableLink from '.~/components/trackable-link'; import mapStoreAddressErrors from './mapStoreAddressErrors'; @@ -166,3 +167,73 @@ const StoreAddressCard = () => { }; export default StoreAddressCard; + +/** + * Trigger when store address edit button is clicked. + * Before `1.5.0` this name was used for tracking clicking "Edit in settings" to edit the WC address. As of `>1.5.0`, that event is now tracked as `edit_wc_store_address`. + * + * @event gla_edit_mc_store_address + * @property {string} path The path used in the page from which the link was clicked, e.g. `"/google/settings"`. + * @property {string|undefined} [subpath] The subpath used in the page, e.g. `"/edit-store-address"` or `undefined` when there is no subpath. + */ + +/** + * Renders a component with the store address. + * In preview mode, meaning there will be no refresh button, just the edit link. + * + * @fires gla_edit_mc_store_address Whenever "Edit" is clicked. + * + * @param {Object} props React props + * @param {string} props.editHref URL where Edit button should point to. + * @param {JSX.Element} props.learnMore Link to be shown at the end of missing data message. + * @return {JSX.Element} Filled AccountCard component. + */ +export function StoreAddressCardPreview( { editHref, learnMore } ) { + const { loaded, data } = useStoreAddress( 'mc' ); + let content, warning; + + if ( loaded ) { + const { + isAddressFilled, + isMCAddressDifferent, + address, + address2, + city, + state, + country, + postcode, + } = data; + const stateAndCountry = state ? `${ state } - ${ country }` : country; + + if ( isAddressFilled && ! isMCAddressDifferent ) { + content = [ address, address2, city, stateAndCountry, postcode ] + .filter( Boolean ) + .join( ', ' ); + } else { + warning = __( + 'Please add your store address', + 'google-listings-and-ads' + ); + content = ( + <> + { __( + 'Google requires the store address for all stores using Google Merchant Center. ', + 'google-listings-and-ads' + ) } + { learnMore } + + ); + } + } + + return ( + + ); +} diff --git a/js/src/settings/edit-store-address.js b/js/src/settings/edit-store-address.js new file mode 100644 index 0000000000..42b8cbac9c --- /dev/null +++ b/js/src/settings/edit-store-address.js @@ -0,0 +1,115 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { getHistory } from '@woocommerce/navigation'; +import { useState } from '@wordpress/element'; +import { Flex } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import { getSettingsUrl } from '.~/utils/urls'; +import { useAppDispatch } from '.~/data'; +import useLayout from '.~/hooks/useLayout'; +import useStoreAddress from '.~/hooks/useStoreAddress'; +import TopBar from '.~/components/stepper/top-bar'; +import HelpIconButton from '.~/components/help-icon-button'; +import Section from '.~/wcdl/section'; +import AppButton from '.~/components/app-button'; + +import AppDocumentationLink from '.~/components/app-documentation-link'; +import StoreAddressCard from '.~/components/contact-information/store-address-card'; + +const learnMoreLinkId = 'contact-information-read-more'; +const learnMoreUrl = + 'https://woocommerce.com/document/google-for-woocommerce/get-started/requirements/#contact-information'; + +/** + * Triggered when the save button in contact information page is clicked. + * + * @event gla_contact_information_save_button_click + */ + +/** + * Renders the store address settings page. + * + * @see StoreAddressCard + * @fires gla_contact_information_save_button_click + * @fires gla_documentation_link_click with `{ context: "settings-store-address", link_id: "contact-information-read-more", href: "https://woocommerce.com/document/google-for-woocommerce/get-started/requirements/#contact-information" }` + */ +const EditStoreAddress = () => { + useLayout( 'full-content' ); + + const { updateGoogleMCContactInformation } = useAppDispatch(); + const { data: address } = useStoreAddress(); + const [ isSaving, setSaving ] = useState( false ); + + const handleSaveClick = () => { + setSaving( true ); + updateGoogleMCContactInformation() + .then( () => getHistory().push( getSettingsUrl() ) ) + .catch( () => setSaving( false ) ); + }; + + const isReadyToSave = + address.isAddressFilled && address.isMCAddressDifferent; + + return ( + <> + + } + backHref={ getSettingsUrl() } + /> +
+
+

+ { __( + 'Your store address is required by Google for verification purposes. It will be shared with the Google Merchant Center and will not be displayed to customers.', + 'google-listings-and-ads' + ) } +

+

+ + { __( + 'Learn more', + 'google-listings-and-ads' + ) } + +

+
+ } + > + + +
+ + + { __( 'Save details', 'google-listings-and-ads' ) } + + +
+ + + ); +}; + +export default EditStoreAddress; diff --git a/js/src/settings/index.js b/js/src/settings/index.js index a81032f74c..f23e775cb2 100644 --- a/js/src/settings/index.js +++ b/js/src/settings/index.js @@ -16,6 +16,7 @@ import { ContactInformationPreview } from '.~/components/contact-information'; import LinkedAccounts from './linked-accounts'; import ReconnectWPComAccount from './reconnect-wpcom-account'; import ReconnectGoogleAccount from './reconnect-google-account'; +import EditStoreAddress from './edit-store-address'; import EnableNewProductSyncNotice from '.~/components/enable-new-product-sync-notice'; import MainTabNav from '.~/components/main-tab-nav'; import RebrandingTour from '.~/components/tours/rebranding-tour'; @@ -53,6 +54,8 @@ const Settings = () => { ); case subpaths.reconnectGoogleAccount: return ; + case subpaths.editStoreAddress: + return ; default: } diff --git a/js/src/utils/urls.js b/js/src/utils/urls.js index 894b74db5f..66a0550df2 100644 --- a/js/src/utils/urls.js +++ b/js/src/utils/urls.js @@ -22,6 +22,7 @@ export const subpaths = { editFreeListings: '/free-listings/edit', editCampaign: '/campaigns/edit', createCampaign: '/campaigns/create', + editStoreAddress: '/edit-store-address', reconnectWPComAccount: '/reconnect-wpcom-account', reconnectGoogleAccount: '/reconnect-google-account', }; @@ -84,6 +85,13 @@ export const geReportsUrl = () => { return getNewPath( null, reportsPath, null ); }; +export const getEditStoreAddressUrl = () => { + return getNewPath( + { subpath: subpaths.editStoreAddress }, + settingsPath, + null + ); +}; /** * Returns the URL of the account re-connecting page. *