From 517e35c7ac484d6ce8156c9db4dfb4889e7f2f80 Mon Sep 17 00:00:00 2001 From: andregardi <33497086+andregardi@users.noreply.github.com> Date: Wed, 11 Sep 2024 21:06:06 +0200 Subject: [PATCH] Enabling Staging Site Syncing for WooCommerce (#94280) * Spin up 'Staging Site Syncing for WooCommerce ' branch * Add allow_woo_sync param on usePullFromStagingMutation API call. * Style sync warning and display only for woo sites * Display add staging site warning only when the site has WooCommerce installed; Style the warning message; * Fix typo * Send allow_woo_sync on request. * Apply styling to the "WooCommerce overwrite" text * Add placeholder `CheckboxControl` component * Send allow_woo_sync as binary value * Introduce `disallowWooCommerceSync` logic * Disable Synchronize button until confirmation checkbox is checked. --------- Co-authored-by: Yan Sern Co-authored-by: Paulo Cruz Co-authored-by: Maciej Grabowski Co-authored-by: Ivan Ottinger <25105483+ivan-ottinger@users.noreply.github.com> --- .../new-staging-site-card-content.tsx | 35 +++++++-- .../card-content/staging-sync-card.tsx | 73 +++++++++++++++++-- .../hosting/staging-site-card/index.js | 1 + .../staging-site-card/sync-options-panel.tsx | 39 ++++++---- .../staging-site-card/use-staging-sync.ts | 5 +- 5 files changed, 124 insertions(+), 29 deletions(-) diff --git a/client/my-sites/hosting/staging-site-card/card-content/new-staging-site-card-content.tsx b/client/my-sites/hosting/staging-site-card/card-content/new-staging-site-card-content.tsx index 67e4c557e08389..018bc62a9d29e7 100644 --- a/client/my-sites/hosting/staging-site-card/card-content/new-staging-site-card-content.tsx +++ b/client/my-sites/hosting/staging-site-card/card-content/new-staging-site-card-content.tsx @@ -1,12 +1,33 @@ import config from '@automattic/calypso-config'; import { Button } from '@automattic/components'; import { useHasEnTranslation } from '@automattic/i18n-utils'; +import styled from '@emotion/styled'; import { useTranslate } from 'i18n-calypso'; import { HostingCardDescription } from 'calypso/components/hosting-card'; import InlineSupportLink from 'calypso/components/inline-support-link'; +import { useSelector } from 'calypso/state'; +import isSiteStore from 'calypso/state/selectors/is-site-store'; import { ExceedQuotaErrorContent } from './exceed-quota-error-content'; +const WarningContainer = styled.div( { + marginTop: '16px', + padding: '16px', + marginBottom: '24px', + border: '1px solid #f0c930', + borderRadius: '4px', +} ); + +const WarningTitle = styled.p( { + fontWeight: 500, + marginBottom: '8px', +} ); + +const WarningDescription = styled.p( { + marginBottom: '8px', +} ); + type CardContentProps = { + siteId: number; onAddClick: () => void; isButtonDisabled: boolean; showQuotaError: boolean; @@ -14,6 +35,7 @@ type CardContentProps = { }; export const NewStagingSiteCardContent = ( { + siteId, onAddClick, isButtonDisabled, showQuotaError, @@ -23,6 +45,7 @@ export const NewStagingSiteCardContent = ( { const translate = useTranslate(); const hasEnTranslation = useHasEnTranslation(); const stagingSiteSyncWoo = config.isEnabled( 'staging-site-sync-woo' ); + const isSiteWooStore = !! useSelector( ( state ) => isSiteStore( state, siteId ) ); return ( <> @@ -51,10 +74,10 @@ export const NewStagingSiteCardContent = ( { } ) } - { stagingSiteSyncWoo && ( -
-

{ translate( 'WooCommerce Site' ) }

-

+ { stagingSiteSyncWoo && isSiteWooStore && ( + + { translate( 'WooCommerce Site' ) } + { translate( 'Syncing staging database to production overwrites posts, pages, products and orders. {{a}}Learn more{{/a}}.', { @@ -65,8 +88,8 @@ export const NewStagingSiteCardContent = ( { }, } ) } -

-
+ + ) } { isDevelopmentSite && ( // Not wrapped in translation to avoid request unconfirmed copy diff --git a/client/my-sites/hosting/staging-site-card/card-content/staging-sync-card.tsx b/client/my-sites/hosting/staging-site-card/card-content/staging-sync-card.tsx index 5f3af6db89f1f6..c168bd6aa3ad4a 100644 --- a/client/my-sites/hosting/staging-site-card/card-content/staging-sync-card.tsx +++ b/client/my-sites/hosting/staging-site-card/card-content/staging-sync-card.tsx @@ -116,6 +116,28 @@ const OptionsTreeTitle = styled.p( { marginBottom: '16px', } ); +const SyncWarningContainer = styled.div( { + display: 'flex', + flexDirection: 'column', + border: '1px solid #D63638', + borderRadius: '4px', + maxWidth: '807px', + padding: '16px', + marginBottom: '16px', +} ); + +const SyncWarningTitle = styled.p( { + fontWeight: 600, + marginTop: '0px', + marginBottom: '8px', + color: '#D63638', +} ); + +const SyncWarningContent = styled.p( { + marginTop: '0px', + marginBottom: '0px', +} ); + interface SyncCardProps { type: 'production' | 'staging'; onPull: ( ( items?: string[] ) => void ) | ( () => void ); @@ -139,16 +161,24 @@ const StagingToProductionSync = ( { onConfirm, showSyncPanel, isSqlsOptionDisabled, + isSiteWooStore, + databaseSyncConfirmed, + setdatabaseSyncConfirmed, + isSqlSyncOptionChecked, }: { disabled: boolean; siteSlug: string; isSyncInProgress: boolean; onSelectItems: ( items: CheckboxOptionItem[] ) => void; + databaseSyncConfirmed: boolean; + setdatabaseSyncConfirmed: ( value: boolean ) => void; selectedItems: CheckboxOptionItem[]; isSyncButtonDisabled: boolean; onConfirm: () => void; showSyncPanel: boolean; isSqlsOptionDisabled: boolean; + isSiteWooStore?: boolean; + isSqlSyncOptionChecked?: boolean; } ) => { const [ typedSiteName, setTypedSiteName ] = useState( '' ); const translate = useTranslate(); @@ -221,6 +251,10 @@ const StagingToProductionSync = ( { disabled={ disabled } onChange={ onSelectItems } isSqlsOptionDisabled={ isSqlsOptionDisabled } + databaseSyncConfirmed={ databaseSyncConfirmed } + setdatabaseSyncConfirmed={ setdatabaseSyncConfirmed } + isSiteWooStore={ !! isSiteWooStore } + isSqlSyncOptionChecked={ !! isSqlSyncOptionChecked } > ) } @@ -242,15 +276,15 @@ const StagingToProductionSync = ( { return
  • { item.label }
  • ; } ) } - { stagingSiteSyncWoo && ( -
    -

    { translate( 'Warning' ) }

    -

    + { stagingSiteSyncWoo && isSiteWooStore && isSqlSyncOptionChecked && ( + + { translate( 'Warning:' ) } + { translate( 'We do not recommend syncing or pushing data from a staging site to live production news sites or sites that use eCommerce plugins, such as WooCommerce, without proper planning and testing. Keep in mind that data on the destination site could have newer transactions, such as customers and orders, and would be lost when overwritten by the staging site’s data.' ) } -

    -
    + + ) } { translate( "Enter your site's name {{span}}%(siteSlug)s{{/span}} to confirm.", { @@ -444,9 +478,11 @@ export const SiteSyncCard = ( { [] as CheckboxOptionItem[] ); const [ selectedOption, setSelectedOption ] = useState< string | null >( null ); + const [ databaseSyncConfirmed, setdatabaseSyncConfirmed ] = useState< boolean >( false ); const siteSlug = useSelector( type === 'staging' ? ( state ) => getSiteSlug( state, productionSiteId ) : getSelectedSiteSlug ); + const isSiteWooStore = !! useSelector( ( state ) => isSiteStore( state, productionSiteId ) ); const { progress, @@ -488,10 +524,25 @@ export const SiteSyncCard = ( { } }, [ resetSyncStatus, dispatch, type, onPull, transformSelectedItems, selectedItems ] ); + const isSqlSyncOptionChecked = selectedItems.some( ( item ) => item.name === 'sqls' ); + + useEffect( () => { + if ( ! isSqlSyncOptionChecked && databaseSyncConfirmed ) { + setdatabaseSyncConfirmed( false ); + } + }, [ isSqlSyncOptionChecked, databaseSyncConfirmed, setdatabaseSyncConfirmed ] ); + + const disallowWooCommerceSync = + config.isEnabled( 'staging-site-sync-woo' ) && + isSiteWooStore && + isSqlSyncOptionChecked && + ! databaseSyncConfirmed; + const isSyncButtonDisabled = disabled || ( selectedItems.length === 0 && selectedOption === actionForType ) || - selectedOption === null; + selectedOption === null || + disallowWooCommerceSync; let siteToSync: 'production' | 'staging' | null = null; if ( targetSite ) { @@ -512,6 +563,8 @@ export const SiteSyncCard = ( { } }, [ dispatch, selectedOption, status, syncError ] ); + const stagingSiteSyncWoo = config.isEnabled( 'staging-site-sync-woo' ); + return ( ) } { selectedOption !== actionForType && ( diff --git a/client/my-sites/hosting/staging-site-card/index.js b/client/my-sites/hosting/staging-site-card/index.js index 379e7d9a1fda84..a5ab15f8ab34a5 100644 --- a/client/my-sites/hosting/staging-site-card/index.js +++ b/client/my-sites/hosting/staging-site-card/index.js @@ -503,6 +503,7 @@ export const StagingSiteCard = ( { } else if ( showAddStagingSiteCard ) { stagingSiteCardContent = ( void; isSqlsOptionDisabled: boolean; + isSiteWooStore: boolean; + databaseSyncConfirmed: boolean; + isSqlSyncOptionChecked: boolean; + setdatabaseSyncConfirmed: ( value: boolean ) => void; } ) { const initialItemsMap = useMemo( () => @@ -189,21 +201,20 @@ export default function SyncOptionsPanel( { ); } ) } - { stagingSiteSyncWoo && ( + { stagingSiteSyncWoo && isSiteWooStore && (
    -

    + { translate( - 'This site has WooCommerce installed. All orders in the production database will be overwritten. {{a}}Learn more{{/a}}.', - { - components: { - a: ( - - ), - }, - } + 'This site has WooCommerce installed. All orders in the production database will be overwritten.' ) } -

    -

    { translate( 'Confirm I want to proceed with database synchronization ' ) }

    + +
    ) } diff --git a/client/my-sites/hosting/staging-site-card/use-staging-sync.ts b/client/my-sites/hosting/staging-site-card/use-staging-sync.ts index db3d4099612e5f..ed26ef5f870000 100644 --- a/client/my-sites/hosting/staging-site-card/use-staging-sync.ts +++ b/client/my-sites/hosting/staging-site-card/use-staging-sync.ts @@ -1,3 +1,4 @@ +import config from '@automattic/calypso-config'; import { useMutation, UseMutationOptions, useIsMutating } from '@tanstack/react-query'; import { useCallback } from 'react'; import wp from 'calypso/lib/wp'; @@ -52,6 +53,8 @@ export const usePullFromStagingMutation = ( MutationVariables > ) => { + const isStagingSiteSyncWooEnabled = config.isEnabled( 'staging-site-sync-woo' ); + const mutation = useMutation( { mutationFn: async ( options ) => wp.req.post( @@ -59,7 +62,7 @@ export const usePullFromStagingMutation = ( path: `/sites/${ productionSiteId }/staging-site/pull-from-staging/${ stagingSiteId }`, apiNamespace: 'wpcom/v2', }, - { options } + { options, allow_woo_sync: isStagingSiteSyncWooEnabled ? 1 : 0 } ), ...options, mutationKey: [ PULL_FROM_STAGING, stagingSiteId ],