diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/index.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/index.tsx index 375095a4ece..b2c43506ea5 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/index.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/index.tsx @@ -45,12 +45,12 @@ import { addFilter } from '@wordpress/hooks'; import { CustomizeStoreComponent } from '../types'; import { Layout } from './layout'; import './style.scss'; -import { PreloadFonts } from './preload-fonts'; import { GoBackWarningModal } from './go-back-warning-modal'; import { onBackButtonClicked } from '../utils'; import { getNewPath } from '@woocommerce/navigation'; import useBodyClass from '../hooks/use-body-class'; - +import { OptInSubscribe } from './opt-in/opt-in'; +import { OptInContextProvider } from './opt-in/context'; import './tracking'; const { RouterProvider } = unlock( routerPrivateApis ); @@ -181,12 +181,14 @@ export const AssemblerHub: CustomizeStoreComponent = ( props ) => { ) } - - - - - - + + + + + + + + diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/context.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/context.tsx new file mode 100644 index 00000000000..a2efc98c311 --- /dev/null +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/context.tsx @@ -0,0 +1,53 @@ +/** + * External dependencies + */ +import { OPTIONS_STORE_NAME } from '@woocommerce/data'; +import { useSelect } from '@wordpress/data'; +import React, { createContext, useState } from '@wordpress/element'; +import type { ReactNode } from 'react'; + +export const enum OPTIN_FLOW_STATUS { + 'IDLE' = 'IDLE', + 'LOADING' = 'LOADING', + 'DONE' = 'DONE', +} + +export const OptInContext = createContext< { + optInFlowStatus: OPTIN_FLOW_STATUS; + setOptInFlowStatus: ( status: OPTIN_FLOW_STATUS ) => void; +} >( { + optInFlowStatus: OPTIN_FLOW_STATUS.IDLE, + setOptInFlowStatus: () => {}, +} ); + +export const OptInContextProvider = ( { + children, +}: { + children: ReactNode; +} ) => { + const isAllowTrackingEnabled = useSelect( + ( select ) => + select( OPTIONS_STORE_NAME ).getOption( + 'woocommerce_allow_tracking' + ) === 'yes', + [] + ); + + const [ optInFlowStatus, setOptInFlowStatus ] = + useState< OPTIN_FLOW_STATUS >( + isAllowTrackingEnabled + ? OPTIN_FLOW_STATUS.DONE + : OPTIN_FLOW_STATUS.IDLE + ); + + return ( + + { children } + + ); +}; diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx new file mode 100644 index 00000000000..23758b5e218 --- /dev/null +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/opt-in/opt-in.tsx @@ -0,0 +1,161 @@ +/** + * External dependencies + */ +import { OPTIONS_STORE_NAME } from '@woocommerce/data'; +import apiFetch from '@wordpress/api-fetch'; +import { resolveSelect, select, subscribe, useDispatch } from '@wordpress/data'; +import { useContext, useEffect } from '@wordpress/element'; +// @ts-expect-error No types for this exist yet. +// eslint-disable-next-line @woocommerce/dependency-group +import { store as coreStore } from '@wordpress/core-data'; +// @ts-expect-error No types for this exist yet. +// eslint-disable-next-line @woocommerce/dependency-group +import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +// @ts-expect-error No types for this exist yet. +// eslint-disable-next-line @woocommerce/dependency-group +import { unlock } from '@wordpress/edit-site/build-module/lock-unlock'; + +/** + * Internal dependencies + */ +import { FontFamily, FontFace } from '../../types/font'; +import { usePatterns } from '../hooks/use-patterns'; +import { installFontFamilies } from '../utils/fonts'; +import { FONT_FAMILIES_TO_INSTALL } from '../sidebar/global-styles/font-pairing-variations/constants'; +import { OptInContext, OPTIN_FLOW_STATUS } from './context'; + +const { useGlobalSetting } = unlock( blockEditorPrivateApis ); + +export const OptInSubscribe = () => { + const { setOptInFlowStatus } = useContext( OptInContext ); + + const [ enabledFontFamilies, setFontFamilies ]: [ + { + custom: Array< FontFamily >; + theme: Array< FontFamily >; + }, + ( font: { + custom: Array< FontFamily >; + theme: Array< FontFamily >; + } ) => void + ] = useGlobalSetting( 'typography.fontFamilies' ); + + const { + // @ts-expect-error No types for this exist yet. + __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits, + } = useDispatch( coreStore ); + + const installPatterns = async () => { + await apiFetch< { + success: boolean; + } >( { + path: `/wc/private/patterns`, + method: 'POST', + } ); + }; + + const installFonts = async () => { + await installFontFamilies(); + + const globalStylesId = + // @ts-expect-error No types for this exist yet. + select( coreStore ).__experimentalGetCurrentGlobalStylesId(); + + const installedFontFamilies = ( await resolveSelect( + coreStore + // @ts-expect-error No types for this exist yet. + ).getEntityRecords( 'postType', 'wp_font_family', { + _embed: true, + per_page: -1, + } ) ) as Array< { + id: number; + font_family_settings: FontFamily; + _embedded: { + font_faces: Array< { + font_face_settings: FontFace; + } >; + }; + } >; + + const parsedInstalledFontFamilies = ( installedFontFamilies || [] ).map( + ( fontFamilyPost ) => { + return { + id: fontFamilyPost.id, + ...fontFamilyPost.font_family_settings, + fontFace: + fontFamilyPost?._embedded?.font_faces.map( + ( face ) => face.font_face_settings + ) || [], + }; + } + ); + + const { custom } = enabledFontFamilies; + + const enabledFontSlugs = [ + ...( custom ? custom.map( ( font ) => font.slug ) : [] ), + ]; + + const fontFamiliesToEnable = parsedInstalledFontFamilies.reduce( + ( acc, font ) => { + if ( + enabledFontSlugs.includes( font.slug ) || + FONT_FAMILIES_TO_INSTALL[ font.slug ] === undefined + ) { + return acc; + } + + return [ + ...acc, + { + ...font, + }, + ]; + }, + [] as Array< FontFamily > + ); + + setFontFamilies( { + ...enabledFontFamilies, + custom: [ + ...( enabledFontFamilies.custom ?? [] ), + ...( fontFamiliesToEnable ?? [] ), + ], + } ); + + saveSpecifiedEntityEdits( 'root', 'globalStyles', globalStylesId, [ + 'settings.typography.fontFamilies', + ] ); + }; + + const { invalidateCache } = usePatterns(); + + useEffect( () => { + const unsubscribe = subscribe( async () => { + const isOptedIn = + select( OPTIONS_STORE_NAME ).getOption( + 'woocommerce_allow_tracking' + ) === 'yes'; + + if ( isOptedIn ) { + setOptInFlowStatus( OPTIN_FLOW_STATUS.LOADING ); + await installPatterns(); + invalidateCache(); + await installFonts(); + + setOptInFlowStatus( OPTIN_FLOW_STATUS.DONE ); + + unsubscribe(); + } + // @ts-expect-error The type is not updated. + }, OPTIONS_STORE_NAME ); + + return () => { + unsubscribe(); + }; + // We don't want to run this effect on every render, only once because it is a subscription. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [] ); + + return null; +}; diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/preload-fonts.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/preload-fonts.tsx index 25624729f1b..9ee86a64894 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/preload-fonts.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/preload-fonts.tsx @@ -2,9 +2,6 @@ /** * External dependencies */ -// @ts-expect-error No types for this exist yet. -import { store as coreStore } from '@wordpress/core-data'; -import { useSelect, useDispatch } from '@wordpress/data'; import { privateApis as blockEditorPrivateApis, // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -16,26 +13,18 @@ import { unlock } from '@wordpress/edit-site/build-module/lock-unlock'; /** * Internal dependencies */ -import { - FONT_PAIRINGS, - FONT_FAMILIES_TO_INSTALL, -} from './sidebar/global-styles/font-pairing-variations/constants'; +import { FONT_PAIRINGS } from './sidebar/global-styles/font-pairing-variations/constants'; import { FontFamiliesLoader } from './sidebar/global-styles/font-pairing-variations/font-families-loader'; -import { useContext, useEffect, useMemo } from '@wordpress/element'; -import { FontFace, FontFamily } from '../types/font'; +import { useContext, useMemo } from '@wordpress/element'; +import { FontFamily } from '../types/font'; import { FontFamiliesLoaderDotCom } from './sidebar/global-styles/font-pairing-variations/font-families-loader-dot-com'; import { CustomizeStoreContext } from '.'; import { isAIFlow, isNoAIFlow } from '../guards'; const { useGlobalSetting } = unlock( blockEditorPrivateApis ); -let areFontsPreloaded = false; - export const PreloadFonts = () => { - // @ts-expect-error No types for this exist yet. - const { __experimentalSaveSpecifiedEntityEdits: saveSpecifiedEntityEdits } = - useDispatch( coreStore ); - const [ enabledFontFamilies, setFontFamilies ]: [ + const [ enabledFontFamilies ]: [ { custom: Array< FontFamily >; theme: Array< FontFamily >; @@ -55,99 +44,6 @@ export const PreloadFonts = () => { const { context } = useContext( CustomizeStoreContext ); - const { globalStylesId, installedFontFamilies } = useSelect( ( select ) => { - // @ts-expect-error No types for this exist yet. - const { __experimentalGetCurrentGlobalStylesId, getEntityRecords } = - select( coreStore ); - return { - globalStylesId: __experimentalGetCurrentGlobalStylesId(), - installedFontFamilies: getEntityRecords( - 'postType', - 'wp_font_family', - { _embed: true, per_page: -1 } - ) as Array< { - id: number; - font_family_settings: FontFamily; - _embedded: { - font_faces: Array< { - font_face_settings: FontFace; - } >; - }; - } >, - }; - } ); - - const parsedInstalledFontFamilies = useMemo( () => { - return ( - ( installedFontFamilies || [] ).map( ( fontFamilyPost ) => { - return { - id: fontFamilyPost.id, - ...fontFamilyPost.font_family_settings, - fontFace: - fontFamilyPost?._embedded?.font_faces.map( - ( face ) => face.font_face_settings - ) || [], - }; - } ) || [] - ); - }, [ installedFontFamilies ] ); - - useEffect( () => { - if ( - areFontsPreloaded || - installedFontFamilies === null || - enabledFontFamilies === null - ) { - return; - } - - const { custom } = enabledFontFamilies; - - const enabledFontSlugs = [ - ...( custom ? custom.map( ( font ) => font.slug ) : [] ), - ]; - - const fontFamiliesToEnable = parsedInstalledFontFamilies.reduce( - ( acc, font ) => { - if ( - enabledFontSlugs.includes( font.slug ) || - FONT_FAMILIES_TO_INSTALL[ font.slug ] === undefined - ) { - return acc; - } - - return [ - ...acc, - { - ...font, - }, - ]; - }, - [] as Array< FontFamily > - ); - - setFontFamilies( { - ...enabledFontFamilies, - custom: [ - ...( enabledFontFamilies.custom ?? [] ), - ...( fontFamiliesToEnable ?? [] ), - ], - } ); - - saveSpecifiedEntityEdits( 'root', 'globalStyles', globalStylesId, [ - 'settings.typography.fontFamilies', - ] ); - - areFontsPreloaded = true; - }, [ - enabledFontFamilies, - globalStylesId, - installedFontFamilies, - parsedInstalledFontFamilies, - saveSpecifiedEntityEdits, - setFontFamilies, - ] ); - const allFontChoices = FONT_PAIRINGS.map( ( fontPair ) => fontPair?.settings?.typography?.fontFamilies?.theme ); diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/global-styles/font-pairing-variations/index.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/global-styles/font-pairing-variations/index.tsx index 26c0a85c4a5..eb15bd471b4 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/global-styles/font-pairing-variations/index.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/global-styles/font-pairing-variations/index.tsx @@ -30,6 +30,10 @@ import { CustomizeStoreContext } from '~/customize-store/assembler-hub'; import { FlowType } from '~/customize-store/types'; import { FontFamily } from './font-families-loader-dot-com'; import { isAIFlow } from '~/customize-store/guards'; +import { + OptInContext, + OPTIN_FLOW_STATUS, +} from '~/customize-store/assembler-hub/opt-in/context'; export const FontPairing = () => { const { aiSuggestions, isLoading } = useSelect( ( select ) => { @@ -72,6 +76,8 @@ export const FontPairing = () => { ) === 'yes' ); + const { optInFlowStatus } = useContext( OptInContext ); + const fontPairings = useMemo( () => { if ( isAIFlow( context.flowType ) ) { return aiOnline && aiSuggestions?.lookAndFeel @@ -106,7 +112,15 @@ export const FontPairing = () => { } ); - if ( ! trackingAllowed || ! isFontLibraryAvailable ) { + // We only show the default fonts when: + // - user did not allow tracking + // - site doesn't have the Font Library available + // - opt-in flow is still processing + if ( + ! trackingAllowed || + ! isFontLibraryAvailable || + optInFlowStatus !== OPTIN_FLOW_STATUS.DONE + ) { return defaultFonts; } @@ -134,14 +148,15 @@ export const FontPairing = () => { }, [ aiOnline, aiSuggestions?.lookAndFeel, - baseFontFamilies, + baseFontFamilies.theme, context.flowType, custom, isFontLibraryAvailable, + optInFlowStatus, trackingAllowed, ] ); - if ( isLoading ) { + if ( isLoading || optInFlowStatus === OPTIN_FLOW_STATUS.LOADING ) { return (
diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx index 1d0bdd44c23..e3b0c875c3f 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-homepage-ptk/sidebar-navigation-screen-homepage-ptk.tsx @@ -163,7 +163,7 @@ export const SidebarNavigationScreenHomepagePTK = ( { const [ optInDataSharing, setIsOptInDataSharing ] = useState< boolean >( true ); - const [ isFetchingPatterns, setIsFetchingPatterns ] = useState( false ); + const [ isSettingTracking, setIsSettingTracking ] = useState( false ); const optIn = () => { trackEvent( @@ -324,25 +324,18 @@ export const SidebarNavigationScreenHomepagePTK = ( { onClick={ async () => { optIn(); await enableTracking(); - setIsFetchingPatterns( + setIsSettingTracking( true ); - await apiFetch< { - success: boolean; - } >( { - path: `/wc/private/patterns`, - method: 'POST', - } ); - invalidateCache(); closeModal(); - setIsFetchingPatterns( + setIsSettingTracking( false ); } } variant="primary" disabled={ ! optInDataSharing } > - { isFetchingPatterns ? ( + { isSettingTracking ? ( ) : ( __( diff --git a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-typography/sidebar-navigation-screen-typography.tsx b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-typography/sidebar-navigation-screen-typography.tsx index 88b26ec2820..115dd3561c6 100644 --- a/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-typography/sidebar-navigation-screen-typography.tsx +++ b/plugins/woocommerce-admin/client/customize-store/assembler-hub/sidebar/sidebar-navigation-screen-typography/sidebar-navigation-screen-typography.tsx @@ -24,7 +24,6 @@ import { FontPairing } from '../global-styles'; import { CustomizeStoreContext } from '../..'; import { FlowType } from '~/customize-store/types'; import { trackEvent } from '~/customize-store/tracking'; -import { installFontFamilies } from '../../utils/fonts'; import { enableTracking } from '~/customize-store/design-without-ai/services'; export const SidebarNavigationScreenTypography = ( { @@ -91,7 +90,7 @@ export const SidebarNavigationScreenTypography = ( { const openModal = () => setIsModalOpen( true ); const closeModal = () => setIsModalOpen( false ); - const [ isFetchingFonts, setIsFetchingFonts ] = useState( false ); + const [ isSettingTracking, setIsSettingTracking ] = useState( false ); const [ OptInDataSharing, setIsOptInDataSharing ] = useState< boolean >( true ); @@ -175,17 +174,15 @@ export const SidebarNavigationScreenTypography = ( {