CYS: Fix opt-in flow fonts (#50086)
* CYS: Fix opt-in flow fonts * Add changefile(s) from automation for the following project(s): woocommerce * add E2E test * fix e2e test --------- Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
parent
d4e686a063
commit
d080f44c17
|
@ -14,7 +14,7 @@ import { SidebarNavigationScreenFooter } from './sidebar-navigation-screen-foote
|
|||
import { SidebarNavigationScreenHeader } from './sidebar-navigation-screen-header/sidebar-navigation-screen-header';
|
||||
import { SidebarNavigationScreenHomepage } from './sidebar-navigation-screen-homepage/sidebar-navigation-screen-homepage';
|
||||
import { SidebarNavigationScreenMain } from './sidebar-navigation-screen-main';
|
||||
import { SidebarNavigationScreenTypography } from './sidebar-navigation-screen-typography';
|
||||
import { SidebarNavigationScreenTypography } from './sidebar-navigation-screen-typography/sidebar-navigation-screen-typography';
|
||||
// import { SidebarNavigationScreenPages } from './sidebar-navigation-screen-pages';
|
||||
|
||||
import { getNewPath, navigateTo, useQuery } from '@woocommerce/navigation';
|
||||
|
|
|
@ -12,26 +12,27 @@ import {
|
|||
import { useSelect } from '@wordpress/data';
|
||||
import { Link } from '@woocommerce/components';
|
||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||
import { Button, Modal, CheckboxControl } from '@wordpress/components';
|
||||
import { Button, Modal, CheckboxControl, Spinner } from '@wordpress/components';
|
||||
import interpolateComponents from '@automattic/interpolate-components';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { SidebarNavigationScreen } from './sidebar-navigation-screen';
|
||||
import { SidebarNavigationScreen } from '../sidebar-navigation-screen';
|
||||
import { ADMIN_URL } from '~/utils/admin-settings';
|
||||
import { FontPairing } from './global-styles';
|
||||
import { CustomizeStoreContext } from '..';
|
||||
import { FontPairing } from '../global-styles';
|
||||
import { CustomizeStoreContext } from '../..';
|
||||
import { FlowType } from '~/customize-store/types';
|
||||
import { isIframe, sendMessageToParent } from '~/customize-store/utils';
|
||||
import { trackEvent } from '~/customize-store/tracking';
|
||||
import { installFontFamilies } from '../../utils/fonts';
|
||||
import { enableTracking } from '~/customize-store/design-without-ai/services';
|
||||
|
||||
export const SidebarNavigationScreenTypography = ( {
|
||||
onNavigateBackClick,
|
||||
}: {
|
||||
onNavigateBackClick: () => void;
|
||||
} ) => {
|
||||
const { context, sendEvent } = useContext( CustomizeStoreContext );
|
||||
const { context } = useContext( CustomizeStoreContext );
|
||||
const aiOnline = context.flowType === FlowType.AIOnline;
|
||||
const isFontLibraryAvailable = context.isFontLibraryAvailable;
|
||||
|
||||
|
@ -90,6 +91,8 @@ export const SidebarNavigationScreenTypography = ( {
|
|||
const openModal = () => setIsModalOpen( true );
|
||||
const closeModal = () => setIsModalOpen( false );
|
||||
|
||||
const [ isFetchingFonts, setIsFetchingFonts ] = useState( false );
|
||||
|
||||
const [ OptInDataSharing, setIsOptInDataSharing ] =
|
||||
useState< boolean >( true );
|
||||
|
||||
|
@ -207,22 +210,23 @@ export const SidebarNavigationScreenTypography = ( {
|
|||
{ __( 'Cancel', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button
|
||||
onClick={ () => {
|
||||
onClick={ async () => {
|
||||
optIn();
|
||||
if ( isIframe( window ) ) {
|
||||
sendMessageToParent( {
|
||||
type: 'INSTALL_FONTS',
|
||||
} );
|
||||
} else {
|
||||
sendEvent(
|
||||
'INSTALL_FONTS'
|
||||
);
|
||||
}
|
||||
setIsFetchingFonts( true );
|
||||
await enableTracking();
|
||||
await installFontFamilies();
|
||||
|
||||
closeModal();
|
||||
setIsFetchingFonts( false );
|
||||
} }
|
||||
variant="primary"
|
||||
disabled={ ! OptInDataSharing }
|
||||
>
|
||||
{ __( 'Opt in', 'woocommerce' ) }
|
||||
{ isFetchingFonts ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
__( 'Opt in', 'woocommerce' )
|
||||
) }
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
|
@ -0,0 +1,282 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { resolveSelect } from '@wordpress/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
FontFace,
|
||||
FontFamiliesToInstall,
|
||||
FontFamily,
|
||||
} from '~/customize-store/types/font';
|
||||
import { FONT_FAMILIES_TO_INSTALL } from '../sidebar/global-styles/font-pairing-variations/constants';
|
||||
|
||||
export type FontCollectionsResponse = Array< {
|
||||
slug: string;
|
||||
description: string;
|
||||
name: string;
|
||||
} >;
|
||||
|
||||
export type FontCollectionResponse = {
|
||||
slug: string;
|
||||
name: string;
|
||||
font_families: Array< {
|
||||
font_family_settings: FontFamily;
|
||||
categories: Array< string >;
|
||||
} >;
|
||||
};
|
||||
|
||||
const getInstalledFontFamilyByNameFontFamily = (
|
||||
installedFontFamilies: Array< {
|
||||
id: number;
|
||||
font_family_settings: FontFamily;
|
||||
font_face: Array< FontFace >;
|
||||
} >,
|
||||
nameFontFamily: string
|
||||
) => {
|
||||
return installedFontFamilies.find(
|
||||
( { font_family_settings } ) =>
|
||||
font_family_settings.slug === nameFontFamily
|
||||
);
|
||||
};
|
||||
|
||||
const getFontFamiliesToInstall = (
|
||||
fontCollection: FontCollectionResponse,
|
||||
slugFontFamily: string,
|
||||
fontFamilyToInstall: FontFamiliesToInstall[ 'slug' ]
|
||||
) => {
|
||||
const fontFromCollection = fontCollection.font_families.find(
|
||||
( { font_family_settings } ) =>
|
||||
font_family_settings.slug === slugFontFamily
|
||||
);
|
||||
|
||||
if ( ! fontFromCollection ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const fontFace = fontFromCollection?.font_family_settings.fontFace.filter(
|
||||
( { fontWeight } ) =>
|
||||
fontFamilyToInstall.fontWeights.includes( fontWeight )
|
||||
);
|
||||
|
||||
const fontFamilyWithFontFace = {
|
||||
...fontFromCollection?.font_family_settings,
|
||||
fontFace,
|
||||
};
|
||||
|
||||
return fontFamilyWithFontFace;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves font families and font faces to install based on a provided font collection and a list of installed font families.
|
||||
* The fontFamilyWithFontFaceToInstall include fontFamilies with font faces that are not installed yet.
|
||||
* The fontFaceToInstall include font faces that are not installed yet, but already have the font family installed.
|
||||
*
|
||||
* @param fontCollection - The complete font collection containing all available font data.
|
||||
* @param installedFontFamilies - An array of installed font families with associated font faces and settings.
|
||||
* @return An object containing font families with font faces to install and individual font faces to install.
|
||||
*/
|
||||
export const getFontFamiliesAndFontFaceToInstall = (
|
||||
fontCollection: FontCollectionResponse,
|
||||
installedFontFamilies: Array< {
|
||||
id: number;
|
||||
font_face: Array< FontFace >;
|
||||
font_family_settings: FontFamily;
|
||||
} >
|
||||
) => {
|
||||
return Object.entries( FONT_FAMILIES_TO_INSTALL ).reduce(
|
||||
( acc, [ slug, fontData ] ) => {
|
||||
const fontFamilyWithFontFaceToInstall = getFontFamiliesToInstall(
|
||||
fontCollection,
|
||||
slug,
|
||||
fontData
|
||||
);
|
||||
|
||||
if ( ! fontFamilyWithFontFaceToInstall ) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const fontFamily = getInstalledFontFamilyByNameFontFamily(
|
||||
installedFontFamilies,
|
||||
fontFamilyWithFontFaceToInstall.slug
|
||||
);
|
||||
|
||||
if ( ! fontFamily ) {
|
||||
return {
|
||||
...acc,
|
||||
fontFamiliesWithFontFacesToInstall: [
|
||||
...acc.fontFamiliesWithFontFacesToInstall,
|
||||
fontFamilyWithFontFaceToInstall,
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const fontFace = fontFamily.font_face.filter( ( { fontWeight } ) =>
|
||||
fontData.fontWeights.includes( fontWeight )
|
||||
);
|
||||
|
||||
return {
|
||||
...acc,
|
||||
fontFacesToInstall: [
|
||||
...acc.fontFacesToInstall,
|
||||
...fontFace.map( ( face ) => ( {
|
||||
...face,
|
||||
fontFamilyId: fontFamily.id,
|
||||
} ) ),
|
||||
],
|
||||
};
|
||||
},
|
||||
{
|
||||
fontFamiliesWithFontFacesToInstall: [],
|
||||
fontFacesToInstall: [],
|
||||
} as {
|
||||
fontFamiliesWithFontFacesToInstall: Array< FontFamily >;
|
||||
fontFacesToInstall: Array<
|
||||
FontFace & {
|
||||
fontFamilyId: number;
|
||||
}
|
||||
>;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const installFontFamily = ( data: FontFamily ) => {
|
||||
const config = {
|
||||
path: '/wp/v2/font-families',
|
||||
method: 'POST',
|
||||
data: {
|
||||
font_family_settings: JSON.stringify( {
|
||||
name: data.name,
|
||||
slug: data.slug,
|
||||
fontFamily: data.fontFamily,
|
||||
preview: data.preview,
|
||||
} ),
|
||||
},
|
||||
};
|
||||
|
||||
return apiFetch< {
|
||||
id: number;
|
||||
font_family_settings: string;
|
||||
} >( config );
|
||||
};
|
||||
|
||||
async function downloadFontFaceAssets( src: string ) {
|
||||
try {
|
||||
const fontBlob = await ( await fetch( new Request( src ) ) ).blob();
|
||||
const fileName = src.split( '/' ).pop() as string;
|
||||
return new File( [ fontBlob ], fileName, {
|
||||
type: fontBlob.type,
|
||||
} );
|
||||
} catch ( error ) {
|
||||
throw new Error( `Error downloading font face asset from ${ src }` );
|
||||
}
|
||||
}
|
||||
|
||||
function makeFontFacesFormData(
|
||||
fontFaceFile: File,
|
||||
formData: FormData,
|
||||
index: number
|
||||
) {
|
||||
const fileId = `file-${ index }`;
|
||||
formData.append( fileId, fontFaceFile, fontFaceFile.name );
|
||||
return fileId;
|
||||
}
|
||||
|
||||
export const installFontFace = async (
|
||||
data: FontFace & {
|
||||
fontFamilyId: number;
|
||||
},
|
||||
index: number
|
||||
) => {
|
||||
const { fontFamilyId, ...font } = data;
|
||||
const fontFaceAssets = await downloadFontFaceAssets(
|
||||
Array.isArray( font.src ) ? font.src[ 0 ] : font.src
|
||||
);
|
||||
const formData = new FormData();
|
||||
|
||||
const fontFile = await makeFontFacesFormData(
|
||||
fontFaceAssets,
|
||||
formData,
|
||||
index
|
||||
);
|
||||
|
||||
formData.append(
|
||||
'font_face_settings',
|
||||
JSON.stringify( { ...font, src: fontFile } )
|
||||
);
|
||||
const config = {
|
||||
path: `/wp/v2/font-families/${ data.fontFamilyId }/font-faces/`,
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
};
|
||||
|
||||
return apiFetch( config );
|
||||
};
|
||||
|
||||
export const installFontFamilies = async () => {
|
||||
const installedFontFamily = ( await resolveSelect(
|
||||
'core'
|
||||
).getEntityRecords( 'postType', 'wp_font_family', {
|
||||
per_page: -1,
|
||||
} ) ) as Array< {
|
||||
id: number;
|
||||
font_faces: Array< number >;
|
||||
font_family_settings: FontFamily;
|
||||
} >;
|
||||
|
||||
const installedFontFamiliesWithFontFaces = await Promise.all(
|
||||
installedFontFamily.map( async ( fontFamily ) => {
|
||||
const fontFaces = await apiFetch< Array< FontFace > >( {
|
||||
path: `/wp/v2/font-families/${ fontFamily.id }/font-faces`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
return {
|
||||
...fontFamily,
|
||||
font_face: fontFaces,
|
||||
};
|
||||
} )
|
||||
);
|
||||
|
||||
const fontCollection = await apiFetch< FontCollectionResponse >( {
|
||||
path: `/wp/v2/font-collections/google-fonts`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
const { fontFacesToInstall, fontFamiliesWithFontFacesToInstall } =
|
||||
getFontFamiliesAndFontFaceToInstall(
|
||||
fontCollection,
|
||||
installedFontFamiliesWithFontFaces
|
||||
);
|
||||
|
||||
const fontFamiliesWithFontFaceToInstallPromises =
|
||||
fontFamiliesWithFontFacesToInstall.map( async ( fontFamily ) => {
|
||||
const fontFamilyResponse = await installFontFamily( fontFamily );
|
||||
return Promise.all(
|
||||
fontFamily.fontFace.map( async ( fontFace, index ) => {
|
||||
return installFontFace(
|
||||
{
|
||||
...fontFace,
|
||||
fontFamilyId: fontFamilyResponse.id,
|
||||
},
|
||||
index
|
||||
);
|
||||
} )
|
||||
);
|
||||
} );
|
||||
|
||||
const fontFacesToInstallPromises =
|
||||
fontFacesToInstall.map( installFontFace );
|
||||
|
||||
return ( await Promise.all( [
|
||||
...fontFamiliesWithFontFaceToInstallPromises,
|
||||
...fontFacesToInstallPromises,
|
||||
] ) ) as Array<
|
||||
Array< {
|
||||
font_face_settings: FontFace;
|
||||
} >
|
||||
>;
|
||||
};
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Sender } from 'xstate';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { resolveSelect, dispatch } from '@wordpress/data';
|
||||
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { dispatch, resolveSelect } from '@wordpress/data';
|
||||
import { Sender } from 'xstate';
|
||||
// @ts-expect-error -- No types for this exist yet.
|
||||
// eslint-disable-next-line @woocommerce/dependency-group
|
||||
import { mergeBaseAndUserConfigs } from '@wordpress/edit-site/build-module/components/global-styles/global-styles-provider';
|
||||
|
@ -15,24 +15,18 @@ import { store as coreStore } from '@wordpress/core-data';
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { updateTemplate } from '../data/actions';
|
||||
import { HOMEPAGE_TEMPLATES } from '../data/homepageTemplates';
|
||||
import { installAndActivateTheme as setTheme } from '../data/service';
|
||||
import { THEME_SLUG } from '../data/constants';
|
||||
import { FontFace, FontFamily } from '../types/font';
|
||||
import {
|
||||
FontCollectionResponse,
|
||||
installFontFace,
|
||||
installFontFamily,
|
||||
getFontFamiliesAndFontFaceToInstall,
|
||||
} from './fonts';
|
||||
import { COLOR_PALETTES } from '../assembler-hub/sidebar/global-styles/color-palette-variations/constants';
|
||||
import {
|
||||
FONT_PAIRINGS_WHEN_AI_IS_OFFLINE,
|
||||
FONT_PAIRINGS_WHEN_USER_DID_NOT_ALLOW_TRACKING,
|
||||
} from '../assembler-hub/sidebar/global-styles/font-pairing-variations/constants';
|
||||
import { DesignWithoutAIStateMachineContext, Theme } from './types';
|
||||
import { updateTemplate } from '../data/actions';
|
||||
import { THEME_SLUG } from '../data/constants';
|
||||
import { HOMEPAGE_TEMPLATES } from '../data/homepageTemplates';
|
||||
import { installAndActivateTheme as setTheme } from '../data/service';
|
||||
import { trackEvent } from '../tracking';
|
||||
import { DesignWithoutAIStateMachineContext, Theme } from './types';
|
||||
import { installFontFamilies as installDefaultFontFamilies } from '../assembler-hub/utils/fonts';
|
||||
|
||||
const assembleSite = async () => {
|
||||
await updateTemplate( {
|
||||
|
@ -179,66 +173,7 @@ const installFontFamilies = async () => {
|
|||
}
|
||||
|
||||
try {
|
||||
const installedFontFamily = ( await resolveSelect(
|
||||
'core'
|
||||
).getEntityRecords( 'postType', 'wp_font_family', {
|
||||
per_page: -1,
|
||||
} ) ) as Array< {
|
||||
id: number;
|
||||
font_faces: Array< number >;
|
||||
font_family_settings: FontFamily;
|
||||
} >;
|
||||
|
||||
const installedFontFamiliesWithFontFaces = await Promise.all(
|
||||
installedFontFamily.map( async ( fontFamily ) => {
|
||||
const fontFaces = await apiFetch< Array< FontFace > >( {
|
||||
path: `/wp/v2/font-families/${ fontFamily.id }/font-faces`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
return {
|
||||
...fontFamily,
|
||||
font_face: fontFaces,
|
||||
};
|
||||
} )
|
||||
);
|
||||
|
||||
const fontCollection = await apiFetch< FontCollectionResponse >( {
|
||||
path: `/wp/v2/font-collections/google-fonts`,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
const { fontFacesToInstall, fontFamiliesWithFontFacesToInstall } =
|
||||
getFontFamiliesAndFontFaceToInstall(
|
||||
fontCollection,
|
||||
installedFontFamiliesWithFontFaces
|
||||
);
|
||||
|
||||
const fontFamiliesWithFontFaceToInstallPromises =
|
||||
fontFamiliesWithFontFacesToInstall.map( async ( fontFamily ) => {
|
||||
const fontFamilyResponse = await installFontFamily(
|
||||
fontFamily
|
||||
);
|
||||
return Promise.all(
|
||||
fontFamily.fontFace.map( async ( fontFace, index ) => {
|
||||
installFontFace(
|
||||
{
|
||||
...fontFace,
|
||||
fontFamilyId: fontFamilyResponse.id,
|
||||
},
|
||||
index
|
||||
);
|
||||
} )
|
||||
);
|
||||
} );
|
||||
|
||||
const fontFacesToInstallPromises =
|
||||
fontFacesToInstall.map( installFontFace );
|
||||
|
||||
await Promise.all( [
|
||||
...fontFamiliesWithFontFaceToInstallPromises,
|
||||
...fontFacesToInstallPromises,
|
||||
] );
|
||||
await installDefaultFontFamilies();
|
||||
} catch ( error ) {
|
||||
throw error;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
CYS: Improve opt-in flow fonts.
|
|
@ -57,6 +57,13 @@ test.describe( 'Assembler -> Font Picker', { tag: '@gutenberg' }, () => {
|
|||
'woocommerce_customize_store_onboarding_tour_hidden',
|
||||
'yes'
|
||||
);
|
||||
|
||||
await setOption(
|
||||
request,
|
||||
baseURL,
|
||||
'woocommerce_allow_tracking',
|
||||
'no'
|
||||
);
|
||||
} catch ( error ) {
|
||||
console.log( 'Store completed option not updated' );
|
||||
}
|
||||
|
@ -78,6 +85,13 @@ test.describe( 'Assembler -> Font Picker', { tag: '@gutenberg' }, () => {
|
|||
'no'
|
||||
);
|
||||
|
||||
await setOption(
|
||||
request,
|
||||
baseURL,
|
||||
'woocommerce_allow_tracking',
|
||||
'no'
|
||||
);
|
||||
|
||||
// Reset theme back to default.
|
||||
await activateTheme( DEFAULT_THEME );
|
||||
} catch ( error ) {
|
||||
|
@ -209,4 +223,26 @@ test.describe( 'Assembler -> Font Picker', { tag: '@gutenberg' }, () => {
|
|||
expect( isPrimaryFontUsed ).toBe( true );
|
||||
expect( isSecondaryFontUsed ).toBe( true );
|
||||
} );
|
||||
|
||||
test( 'Clicking opt-in new fonts should be available', async ( {
|
||||
pageObject,
|
||||
} ) => {
|
||||
const assembler = await pageObject.getAssembler();
|
||||
|
||||
await assembler.getByText( 'Usage tracking' ).click();
|
||||
await expect(
|
||||
assembler.getByText( 'Access more fonts' )
|
||||
).toBeVisible();
|
||||
|
||||
await assembler.getByRole( 'button', { name: 'Opt in' } ).click();
|
||||
|
||||
await assembler
|
||||
.getByText( 'Access more fonts' )
|
||||
.waitFor( { state: 'hidden' } );
|
||||
|
||||
const fontPickers = assembler.locator(
|
||||
'.woocommerce-customize-store_global-styles-variations_item'
|
||||
);
|
||||
await expect( fontPickers ).toHaveCount( 10 );
|
||||
} );
|
||||
} );
|
||||
|
|
Loading…
Reference in New Issue