From 13e664f7af4f877420366a94db1420712108cd24 Mon Sep 17 00:00:00 2001 From: Luiz Kowalski Date: Fri, 26 Jul 2024 15:40:01 -0300 Subject: [PATCH] AI Logo Generator: fix the "Use on site" button (#38552) * Change label of button to refer to the block * Do not call the hook's applyLogo and rely only on the callback provided * Support an external onApplyLogo handler on the generator modal * Change the post-use screen to not reload the editor * Link to the proper Jetpack redirect link on the learn more button * Fix message to avoid misleading user about the result of the action * Provide the saved media ID on the apply logo handler and make it required * Use the media ID to update the site logo and icon * changelog * Changelog * Remove time interval request check to prevent errors when multiple blocks are present on the editor --- .../update-jetpack-ai-fix-use-on-site-button | 4 ++ .../components/generator-modal.tsx | 25 +++------ .../components/logo-presenter.tsx | 45 +++++---------- .../components/visit-site-banner.tsx | 12 ++-- .../lib/wpcom-limited-request.ts | 11 ---- .../ai-client/src/logo-generator/types.ts | 3 +- .../update-jetpack-ai-fix-use-on-site-button | 4 ++ .../extended-blocks/core-site-logo/index.tsx | 56 ++++++++++++++++++- 8 files changed, 94 insertions(+), 66 deletions(-) create mode 100644 projects/js-packages/ai-client/changelog/update-jetpack-ai-fix-use-on-site-button create mode 100644 projects/plugins/jetpack/changelog/update-jetpack-ai-fix-use-on-site-button diff --git a/projects/js-packages/ai-client/changelog/update-jetpack-ai-fix-use-on-site-button b/projects/js-packages/ai-client/changelog/update-jetpack-ai-fix-use-on-site-button new file mode 100644 index 0000000000000..01bbe1049ff31 --- /dev/null +++ b/projects/js-packages/ai-client/changelog/update-jetpack-ai-fix-use-on-site-button @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +AI Logo Generator: provide the saved media ID on the save logo callback. diff --git a/projects/js-packages/ai-client/src/logo-generator/components/generator-modal.tsx b/projects/js-packages/ai-client/src/logo-generator/components/generator-modal.tsx index d7729ab2a6735..1195c44236cc8 100644 --- a/projects/js-packages/ai-client/src/logo-generator/components/generator-modal.tsx +++ b/projects/js-packages/ai-client/src/logo-generator/components/generator-modal.tsx @@ -43,6 +43,7 @@ const debug = debugFactory( 'jetpack-ai-calypso:generator-modal' ); export const GeneratorModal: React.FC< GeneratorModalProps > = ( { isOpen, onClose, + onApplyLogo, siteDetails, context, } ) => { @@ -62,7 +63,6 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( { useLogoGenerator(); const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors(); const siteId = siteDetails?.ID; - const siteURL = siteDetails?.URL; const [ logoAccepted, setLogoAccepted ] = useState( false ); // First fetch the feature data so we have the most up-to-date info from the backend. @@ -165,17 +165,9 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( { recordTracksEvent( EVENT_MODAL_CLOSE, { context, placement: EVENT_PLACEMENT_QUICK_LINKS } ); }; - const handleApplyLogo = () => { + const handleApplyLogo = ( mediaId: number ) => { setLogoAccepted( true ); - }; - - const handleCloseAndReload = () => { - closeModal(); - - setTimeout( () => { - // Reload the page to update the logo. - window.location.reload(); - }, 1000 ); + onApplyLogo?.( mediaId ); }; const handleFeedbackClick = () => { @@ -235,13 +227,10 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( { /> { logoAccepted ? (
- +
- -
@@ -271,7 +260,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( { { isOpen && ( = ( { siteId } ) => { ); }; -const UseOnSiteButton: React.FC< { onApplyLogo: () => void } > = ( { onApplyLogo } ) => { +const UseOnSiteButton: React.FC< { onApplyLogo: ( mediaId: number ) => void } > = ( { + onApplyLogo, +} ) => { const { tracks } = useAnalytics(); const { recordEvent: recordTracksEvent } = tracks; - const { - applyLogo, - isSavingLogoToLibrary, - isApplyingLogo, - selectedLogo, - logos, - selectedLogoIndex, - context, - } = useLogoGenerator(); + const { isSavingLogoToLibrary, selectedLogo, logos, selectedLogoIndex, context } = + useLogoGenerator(); const handleClick = async () => { - if ( ! isApplyingLogo && ! isSavingLogoToLibrary ) { + if ( ! isSavingLogoToLibrary ) { recordTracksEvent( EVENT_USE, { context, logos_count: logos.length, selected_logo: selectedLogoIndex != null ? selectedLogoIndex + 1 : 0, } ); - try { - await applyLogo(); - onApplyLogo(); - } catch ( error ) { - debug( 'Error applying logo', error ); - } + onApplyLogo?.( selectedLogo?.mediaId ); } }; - return isApplyingLogo && ! isSavingLogoToLibrary ? ( - - ) : ( + return ( ); }; @@ -144,11 +129,11 @@ const LogoLoading: React.FC = () => { ); }; -const LogoReady: React.FC< { siteId: string; logo: Logo; onApplyLogo: () => void } > = ( { - siteId, - logo, - onApplyLogo, -} ) => { +const LogoReady: React.FC< { + siteId: string; + logo: Logo; + onApplyLogo: ( mediaId: number ) => void; +} > = ( { siteId, logo, onApplyLogo } ) => { return ( <> = ( { logo } ) => { />
} /> - { __( 'Your logo has been successfully updated!', 'jetpack-ai-client' ) } + { __( 'Your new logo was set to the block!', 'jetpack-ai-client' ) }
); diff --git a/projects/js-packages/ai-client/src/logo-generator/components/visit-site-banner.tsx b/projects/js-packages/ai-client/src/logo-generator/components/visit-site-banner.tsx index c9cb45868b027..552918bec8a39 100644 --- a/projects/js-packages/ai-client/src/logo-generator/components/visit-site-banner.tsx +++ b/projects/js-packages/ai-client/src/logo-generator/components/visit-site-banner.tsx @@ -17,9 +17,8 @@ import type React from 'react'; export const VisitSiteBanner: React.FC< { className?: string; - siteURL?: string; onVisitBlankTarget: () => void; -} > = ( { className = null, siteURL = '#', onVisitBlankTarget } ) => { +} > = ( { className = null, onVisitBlankTarget } ) => { return (
@@ -39,8 +38,13 @@ export const VisitSiteBanner: React.FC< { ) }
-
diff --git a/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts b/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts index d38cdbd383367..fbfc67c167e36 100644 --- a/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts +++ b/projects/js-packages/ai-client/src/logo-generator/lib/wpcom-limited-request.ts @@ -9,7 +9,6 @@ import apiFetch from '../../api-fetch/index.js'; const MAX_CONCURRENT_REQUESTS = 5; let concurrentCounter = 0; -let lastCallTimestamp: number | null = null; /** * Concurrency-limited request to wpcom-proxy-request. @@ -25,16 +24,6 @@ export default async function wpcomLimitedRequest< T >( params: object ): Promis throw new Error( 'Too many requests' ); } - const now = Date.now(); - - // Check if the last call was made less than 100 milliseconds ago - if ( lastCallTimestamp && now - lastCallTimestamp < 100 ) { - concurrentCounter -= 1; - throw new Error( 'Too many requests' ); - } - - lastCallTimestamp = now; // Update the timestamp - return apiFetch< T >( params ).finally( () => { concurrentCounter -= 1; } ); diff --git a/projects/js-packages/ai-client/src/logo-generator/types.ts b/projects/js-packages/ai-client/src/logo-generator/types.ts index 43ad5947878f7..9161f479c2a98 100644 --- a/projects/js-packages/ai-client/src/logo-generator/types.ts +++ b/projects/js-packages/ai-client/src/logo-generator/types.ts @@ -15,13 +15,14 @@ export interface GeneratorModalProps { siteDetails?: SiteDetails; isOpen: boolean; onClose: () => void; + onApplyLogo: ( mediaId: number ) => void; context: string; } export interface LogoPresenterProps { logo?: Logo; loading?: boolean; - onApplyLogo: () => void; + onApplyLogo: ( mediaId: number ) => void; logoAccepted?: boolean; siteId: string | number; } diff --git a/projects/plugins/jetpack/changelog/update-jetpack-ai-fix-use-on-site-button b/projects/plugins/jetpack/changelog/update-jetpack-ai-fix-use-on-site-button new file mode 100644 index 0000000000000..a1858d728270c --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-jetpack-ai-fix-use-on-site-button @@ -0,0 +1,4 @@ +Significance: minor +Type: other + +AI Logo Generator: support saving the logo and the icon when an image is ready. diff --git a/projects/plugins/jetpack/extensions/extended-blocks/core-site-logo/index.tsx b/projects/plugins/jetpack/extensions/extended-blocks/core-site-logo/index.tsx index 9c05d1537ad6d..192fbb065454a 100644 --- a/projects/plugins/jetpack/extensions/extended-blocks/core-site-logo/index.tsx +++ b/projects/plugins/jetpack/extensions/extended-blocks/core-site-logo/index.tsx @@ -4,7 +4,7 @@ import { GeneratorModal } from '@automattic/jetpack-ai-client'; import { BlockControls } from '@wordpress/block-editor'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { useSelect } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; import { useCallback, useEffect, useState } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; /* @@ -28,6 +28,46 @@ type CoreSelect = { }; }; +/** + * Hook to set the site logo on the local state, affecting the logo block. + * + * @returns {object} An object with the setLogo function. + */ +const useSetLogo = () => { + const editEntityRecord = useDispatch( 'core' ).editEntityRecord; + const saveLogo = useCallback( + ( mediaId: number ) => { + editEntityRecord( 'root', 'site', undefined, { + site_logo: mediaId, + } ); + }, + [ editEntityRecord ] + ); + + const saveIcon = useCallback( + ( mediaId: number ) => { + editEntityRecord( 'root', 'site', undefined, { + site_icon: mediaId, + } ); + }, + [ editEntityRecord ] + ); + + const setLogo = useCallback( + ( mediaId: number, updateIcon: boolean ) => { + saveLogo( mediaId ); + if ( updateIcon ) { + saveIcon( mediaId ); + } + }, + [ saveLogo, saveIcon ] + ); + + return { + setLogo, + }; +}; + const useSiteDetails = () => { const siteSettings = useSelect( select => { return ( select( 'core' ) as CoreSelect ).getEntityRecord( 'root', 'site' ); @@ -48,6 +88,8 @@ const useSiteDetails = () => { const siteLogoEditWithAiComponents = createHigherOrderComponent( BlockEdit => { return props => { const [ isLogoGeneratorModalVisible, setIsLogoGeneratorModalVisible ] = useState( false ); + const { setLogo } = useSetLogo(); + const shouldSyncIcon = props?.attributes?.shouldSyncIcon || false; const showModal = useCallback( () => { setIsLogoGeneratorModalVisible( true ); @@ -57,9 +99,18 @@ const siteLogoEditWithAiComponents = createHigherOrderComponent( BlockEdit => { setIsLogoGeneratorModalVisible( false ); }, [] ); + const applyLogoHandler = useCallback( + ( mediaId: number ) => { + if ( mediaId ) { + setLogo( mediaId, shouldSyncIcon ); + } + }, + [ setLogo, shouldSyncIcon ] + ); + useEffect( () => { return () => { - // close modal if open + // close modal if open when the component unmounts closeModal(); }; }, [ closeModal ] ); @@ -75,6 +126,7 @@ const siteLogoEditWithAiComponents = createHigherOrderComponent( BlockEdit => {