@automattic/jetpack-ai-client 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.16.0] - 2024-07-29
9
+ ### Added
10
+ - AI Logo Generator: support placement property on the generator modal, for tracking purposes. [#38574]
11
+
12
+ ### Fixed
13
+ - AI Logo Generator: make the initial prompt update when the site name and description are fully laoded from store. [#38491]
14
+ - AI Logo Generator: provide the saved media ID on the save logo callback. [#38552]
15
+
8
16
  ## [0.15.0] - 2024-07-22
9
17
  ### Added
10
18
  - Jetpack AI: Add logo generator codebase to the ai-client package. [#38391]
@@ -358,6 +366,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
358
366
  - Updated package dependencies. [#31659]
359
367
  - Updated package dependencies. [#31785]
360
368
 
369
+ [0.16.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.15.0...v0.16.0
361
370
  [0.15.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.6...v0.15.0
362
371
  [0.14.6]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.5...v0.14.6
363
372
  [0.14.5]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.4...v0.14.5
@@ -13,7 +13,7 @@ import { useState, useEffect, useCallback, useRef } from 'react';
13
13
  /**
14
14
  * Internal dependencies
15
15
  */
16
- import { DEFAULT_LOGO_COST, EVENT_MODAL_OPEN, EVENT_FEEDBACK, EVENT_MODAL_CLOSE, EVENT_PLACEMENT_QUICK_LINKS, EVENT_GENERATE, } from '../constants.js';
16
+ import { DEFAULT_LOGO_COST, EVENT_MODAL_OPEN, EVENT_FEEDBACK, EVENT_MODAL_CLOSE, EVENT_GENERATE, } from '../constants.js';
17
17
  import useLogoGenerator from '../hooks/use-logo-generator.js';
18
18
  import useRequestErrors from '../hooks/use-request-errors.js';
19
19
  import { isLogoHistoryEmpty, clearDeletedMedia } from '../lib/logo-storage.js';
@@ -27,7 +27,7 @@ import { UpgradeScreen } from './upgrade-screen.js';
27
27
  import { VisitSiteBanner } from './visit-site-banner.js';
28
28
  import './generator-modal.scss';
29
29
  const debug = debugFactory('jetpack-ai-calypso:generator-modal');
30
- export const GeneratorModal = ({ isOpen, onClose, siteDetails, context, }) => {
30
+ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, siteDetails, context, placement, }) => {
31
31
  const { tracks } = useAnalytics();
32
32
  const { recordEvent: recordTracksEvent } = tracks;
33
33
  const { setSiteDetails, fetchAiAssistantFeature, loadLogoHistory } = useDispatch(STORE_NAME);
@@ -41,7 +41,6 @@ export const GeneratorModal = ({ isOpen, onClose, siteDetails, context, }) => {
41
41
  const { selectedLogo, getAiAssistantFeature, generateFirstPrompt, generateLogo, setContext } = useLogoGenerator();
42
42
  const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
43
43
  const siteId = siteDetails?.ID;
44
- const siteURL = siteDetails?.URL;
45
44
  const [logoAccepted, setLogoAccepted] = useState(false);
46
45
  // First fetch the feature data so we have the most up-to-date info from the backend.
47
46
  const feature = getAiAssistantFeature();
@@ -115,9 +114,9 @@ export const GeneratorModal = ({ isOpen, onClose, siteDetails, context, }) => {
115
114
  ]);
116
115
  const handleModalOpen = useCallback(async () => {
117
116
  setContext(context);
118
- recordTracksEvent(EVENT_MODAL_OPEN, { context, placement: EVENT_PLACEMENT_QUICK_LINKS });
117
+ recordTracksEvent(EVENT_MODAL_OPEN, { context, placement });
119
118
  initializeModal();
120
- }, [setContext, context, initializeModal]);
119
+ }, [setContext, context, placement, initializeModal]);
121
120
  const closeModal = () => {
122
121
  // Reset the state when the modal is closed, so we trigger the modal initialization again when it's opened.
123
122
  needsToHandleModalOpen.current = true;
@@ -127,17 +126,11 @@ export const GeneratorModal = ({ isOpen, onClose, siteDetails, context, }) => {
127
126
  setNeedsMoreRequests(false);
128
127
  clearErrors();
129
128
  setLogoAccepted(false);
130
- recordTracksEvent(EVENT_MODAL_CLOSE, { context, placement: EVENT_PLACEMENT_QUICK_LINKS });
129
+ recordTracksEvent(EVENT_MODAL_CLOSE, { context, placement });
131
130
  };
132
- const handleApplyLogo = () => {
131
+ const handleApplyLogo = (mediaId) => {
133
132
  setLogoAccepted(true);
134
- };
135
- const handleCloseAndReload = () => {
136
- closeModal();
137
- setTimeout(() => {
138
- // Reload the page to update the logo.
139
- window.location.reload();
140
- }, 1000);
133
+ onApplyLogo?.(mediaId);
141
134
  };
142
135
  const handleFeedbackClick = () => {
143
136
  recordTracksEvent(EVENT_FEEDBACK, { context });
@@ -176,9 +169,9 @@ export const GeneratorModal = ({ isOpen, onClose, siteDetails, context, }) => {
176
169
  body = (_jsx(UpgradeScreen, { onCancel: closeModal, upgradeURL: upgradeURL, reason: needsFeature ? 'feature' : 'requests' }));
177
170
  }
178
171
  else {
179
- body = (_jsxs(_Fragment, { children: [!logoAccepted && _jsx(Prompt, { initialPrompt: initialPrompt }), _jsx(LogoPresenter, { logo: selectedLogo, onApplyLogo: handleApplyLogo, logoAccepted: logoAccepted, siteId: String(siteId) }), logoAccepted ? (_jsxs("div", { className: "jetpack-ai-logo-generator__accept", children: [_jsx(VisitSiteBanner, { siteURL: siteURL, onVisitBlankTarget: handleCloseAndReload }), _jsxs("div", { className: "jetpack-ai-logo-generator__accept-actions", children: [_jsx(Button, { variant: "link", onClick: handleCloseAndReload, children: __('Close and refresh', 'jetpack-ai-client') }), _jsx(Button, { href: siteURL, variant: "primary", children: __('Visit site', 'jetpack-ai-client') })] })] })) : (_jsxs(_Fragment, { children: [_jsx(HistoryCarousel, {}), _jsx("div", { className: "jetpack-ai-logo-generator__footer", children: _jsxs(Button, { variant: "link", className: "jetpack-ai-logo-generator__feedback-button", href: "https://jetpack.com/redirect/?source=jetpack-ai-feedback", target: "_blank", onClick: handleFeedbackClick, children: [_jsx("span", { children: __('Provide feedback', 'jetpack-ai-client') }), _jsx(Icon, { icon: external, className: "icon" })] }) })] }))] }));
172
+ body = (_jsxs(_Fragment, { children: [!logoAccepted && _jsx(Prompt, { initialPrompt: initialPrompt }), _jsx(LogoPresenter, { logo: selectedLogo, onApplyLogo: handleApplyLogo, logoAccepted: logoAccepted, siteId: String(siteId) }), logoAccepted ? (_jsxs("div", { className: "jetpack-ai-logo-generator__accept", children: [_jsx(VisitSiteBanner, { onVisitBlankTarget: closeModal }), _jsx("div", { className: "jetpack-ai-logo-generator__accept-actions", children: _jsx(Button, { variant: "primary", onClick: closeModal, children: __('Close', 'jetpack-ai-client') }) })] })) : (_jsxs(_Fragment, { children: [_jsx(HistoryCarousel, {}), _jsx("div", { className: "jetpack-ai-logo-generator__footer", children: _jsxs(Button, { variant: "link", className: "jetpack-ai-logo-generator__feedback-button", href: "https://jetpack.com/redirect/?source=jetpack-ai-feedback", target: "_blank", onClick: handleFeedbackClick, children: [_jsx("span", { children: __('Provide feedback', 'jetpack-ai-client') }), _jsx(Icon, { icon: external, className: "icon" })] }) })] }))] }));
180
173
  }
181
- return (_jsx(_Fragment, { children: isOpen && (_jsx(Modal, { className: "jetpack-ai-logo-generator-modal", onRequestClose: logoAccepted ? handleCloseAndReload : closeModal, shouldCloseOnClickOutside: false, shouldCloseOnEsc: false, title: __('Jetpack AI Logo Generator', 'jetpack-ai-client'), children: _jsx("div", { className: clsx('jetpack-ai-logo-generator-modal__body', {
174
+ return (_jsx(_Fragment, { children: isOpen && (_jsx(Modal, { className: "jetpack-ai-logo-generator-modal", onRequestClose: closeModal, shouldCloseOnClickOutside: false, shouldCloseOnEsc: false, title: __('Jetpack AI Logo Generator', 'jetpack-ai-client'), children: _jsx("div", { className: clsx('jetpack-ai-logo-generator-modal__body', {
182
175
  'notice-modal': needsFeature || needsMoreRequests || featureFetchError || firstLogoPromptFetchError,
183
176
  }), children: body }) })) }));
184
177
  };
@@ -55,36 +55,30 @@ const SaveInLibraryButton = ({ siteId }) => {
55
55
  const savedLabel = __('Saved', 'jetpack-ai-client');
56
56
  return !saving && !saved ? (_jsxs(Button, { className: "jetpack-ai-logo-generator-modal-presenter__action", onClick: handleClick, children: [_jsx(Icon, { icon: _jsx(MediaIcon, {}) }), _jsx("span", { className: "action-text", children: __('Save in Library', 'jetpack-ai-client') })] })) : (_jsxs("button", { className: "jetpack-ai-logo-generator-modal-presenter__action", children: [_jsx(Icon, { icon: saving ? _jsx(MediaIcon, {}) : _jsx(CheckIcon, {}) }), _jsx("span", { className: "action-text", children: saving ? savingLabel : savedLabel })] }));
57
57
  };
58
- const UseOnSiteButton = ({ onApplyLogo }) => {
58
+ const UseOnSiteButton = ({ onApplyLogo, }) => {
59
59
  const { tracks } = useAnalytics();
60
60
  const { recordEvent: recordTracksEvent } = tracks;
61
- const { applyLogo, isSavingLogoToLibrary, isApplyingLogo, selectedLogo, logos, selectedLogoIndex, context, } = useLogoGenerator();
61
+ const { isSavingLogoToLibrary, selectedLogo, logos, selectedLogoIndex, context } = useLogoGenerator();
62
62
  const handleClick = async () => {
63
- if (!isApplyingLogo && !isSavingLogoToLibrary) {
63
+ if (!isSavingLogoToLibrary) {
64
64
  recordTracksEvent(EVENT_USE, {
65
65
  context,
66
66
  logos_count: logos.length,
67
67
  selected_logo: selectedLogoIndex != null ? selectedLogoIndex + 1 : 0,
68
68
  });
69
- try {
70
- await applyLogo();
71
- onApplyLogo();
72
- }
73
- catch (error) {
74
- debug('Error applying logo', error);
75
- }
69
+ onApplyLogo?.(selectedLogo?.mediaId);
76
70
  }
77
71
  };
78
- return isApplyingLogo && !isSavingLogoToLibrary ? (_jsxs("button", { className: "jetpack-ai-logo-generator-modal-presenter__action", children: [_jsx(Icon, { icon: _jsx(LogoIcon, {}) }), _jsx("span", { className: "action-text", children: __('Applying logo…', 'jetpack-ai-client') })] })) : (_jsxs(Button, { className: "jetpack-ai-logo-generator-modal-presenter__action", onClick: handleClick, disabled: isSavingLogoToLibrary || !selectedLogo?.mediaId, children: [_jsx(Icon, { icon: _jsx(LogoIcon, {}) }), _jsx("span", { className: "action-text", children: __('Use on Site', 'jetpack-ai-client') })] }));
72
+ return (_jsxs(Button, { className: "jetpack-ai-logo-generator-modal-presenter__action", onClick: handleClick, disabled: isSavingLogoToLibrary || !selectedLogo?.mediaId, children: [_jsx(Icon, { icon: _jsx(LogoIcon, {}) }), _jsx("span", { className: "action-text", children: __('Use on block', 'jetpack-ai-client') })] }));
79
73
  };
80
74
  const LogoLoading = () => {
81
75
  return (_jsxs(_Fragment, { children: [_jsx(ImageLoader, { className: "jetpack-ai-logo-generator-modal-presenter__logo" }), _jsx("span", { className: "jetpack-ai-logo-generator-modal-presenter__loading-text", children: __('Generating new logo…', 'jetpack-ai-client') })] }));
82
76
  };
83
- const LogoReady = ({ siteId, logo, onApplyLogo, }) => {
77
+ const LogoReady = ({ siteId, logo, onApplyLogo }) => {
84
78
  return (_jsxs(_Fragment, { children: [_jsx("img", { src: logo.url, alt: logo.description, className: "jetpack-ai-logo-generator-modal-presenter__logo" }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-presenter__action-wrapper", children: [_jsx("span", { className: "jetpack-ai-logo-generator-modal-presenter__description", children: logo.description }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-presenter__actions", children: [_jsx(SaveInLibraryButton, { siteId: siteId }), _jsx(UseOnSiteButton, { onApplyLogo: onApplyLogo })] })] })] }));
85
79
  };
86
80
  const LogoUpdated = ({ logo }) => {
87
- return (_jsxs(_Fragment, { children: [_jsx("img", { src: logo.url, alt: logo.description, className: "jetpack-ai-logo-generator-modal-presenter__logo" }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-presenter__success-wrapper", children: [_jsx(Icon, { icon: _jsx(CheckIcon, {}) }), _jsx("span", { children: __('Your logo has been successfully updated!', 'jetpack-ai-client') })] })] }));
81
+ return (_jsxs(_Fragment, { children: [_jsx("img", { src: logo.url, alt: logo.description, className: "jetpack-ai-logo-generator-modal-presenter__logo" }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-presenter__success-wrapper", children: [_jsx(Icon, { icon: _jsx(CheckIcon, {}) }), _jsx("span", { children: __('Your new logo was set to the block!', 'jetpack-ai-client') })] })] }));
88
82
  };
89
83
  export const LogoPresenter = ({ logo = null, loading = false, onApplyLogo, logoAccepted = false, siteId, }) => {
90
84
  const { isRequestingImage } = useLogoGenerator();
@@ -5,6 +5,5 @@ import './visit-site-banner.scss';
5
5
  import type React from 'react';
6
6
  export declare const VisitSiteBanner: React.FC<{
7
7
  className?: string;
8
- siteURL?: string;
9
8
  onVisitBlankTarget: () => void;
10
9
  }>;
@@ -11,6 +11,6 @@ import clsx from 'clsx';
11
11
  */
12
12
  import jetpackLogo from '../assets/images/jetpack-logo.svg';
13
13
  import './visit-site-banner.scss';
14
- export const VisitSiteBanner = ({ className = null, siteURL = '#', onVisitBlankTarget }) => {
15
- return (_jsxs("div", { className: clsx('jetpack-ai-logo-generator-modal-visit-site-banner', className), children: [_jsx("div", { className: "jetpack-ai-logo-generator-modal-visit-site-banner__jetpack-logo", children: _jsx("img", { src: jetpackLogo, alt: "Jetpack" }) }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-visit-site-banner__content", children: [_jsx("strong", { children: __('Do you want to know all the amazing things you can do with Jetpack AI?', 'jetpack-ai-client') }), _jsx("span", { children: __('Generate and tweak content, create forms, get feedback and much more.', 'jetpack-ai-client') }), _jsx("div", { children: _jsxs(Button, { variant: "link", href: siteURL, target: "_blank", onClick: onVisitBlankTarget, children: [__('Visit website', 'jetpack-ai-client'), _jsx(Icon, { icon: external, size: 20 })] }) })] })] }));
14
+ export const VisitSiteBanner = ({ className = null, onVisitBlankTarget }) => {
15
+ return (_jsxs("div", { className: clsx('jetpack-ai-logo-generator-modal-visit-site-banner', className), children: [_jsx("div", { className: "jetpack-ai-logo-generator-modal-visit-site-banner__jetpack-logo", children: _jsx("img", { src: jetpackLogo, alt: "Jetpack" }) }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal-visit-site-banner__content", children: [_jsx("strong", { children: __('Do you want to know all the amazing things you can do with Jetpack AI?', 'jetpack-ai-client') }), _jsx("span", { children: __('Generate and tweak content, create forms, get feedback and much more.', 'jetpack-ai-client') }), _jsx("div", { children: _jsxs(Button, { variant: "link", href: "https://jetpack.com/redirect/?source=logo_generator_learn_more_about_jetpack_ai", target: "_blank", onClick: onVisitBlankTarget, children: [__('Learn more about Jetpack AI', 'jetpack-ai-client'), _jsx(Icon, { icon: external, size: 20 })] }) })] })] }));
16
16
  };
@@ -78,7 +78,7 @@ Site description: ${description}`;
78
78
  setFirstLogoPromptFetchError(error);
79
79
  throw error;
80
80
  }
81
- }, [setFirstLogoPromptFetchError, increaseAiAssistantRequestsCount]);
81
+ }, [setFirstLogoPromptFetchError, increaseAiAssistantRequestsCount, name, description]);
82
82
  const enhancePrompt = async function ({ prompt }) {
83
83
  setEnhancePromptFetchError(null);
84
84
  increaseAiAssistantRequestsCount();
@@ -7,7 +7,6 @@ import apiFetch from '../../api-fetch/index.js';
7
7
  */
8
8
  const MAX_CONCURRENT_REQUESTS = 5;
9
9
  let concurrentCounter = 0;
10
- let lastCallTimestamp = null;
11
10
  /**
12
11
  * Concurrency-limited request to wpcom-proxy-request.
13
12
  * @param { object } params - The request params, as expected by apiFetch.
@@ -20,13 +19,6 @@ export default async function wpcomLimitedRequest(params) {
20
19
  concurrentCounter -= 1;
21
20
  throw new Error('Too many requests');
22
21
  }
23
- const now = Date.now();
24
- // Check if the last call was made less than 100 milliseconds ago
25
- if (lastCallTimestamp && now - lastCallTimestamp < 100) {
26
- concurrentCounter -= 1;
27
- throw new Error('Too many requests');
28
- }
29
- lastCallTimestamp = now; // Update the timestamp
30
22
  return apiFetch(params).finally(() => {
31
23
  concurrentCounter -= 1;
32
24
  });
@@ -13,12 +13,14 @@ export interface GeneratorModalProps {
13
13
  siteDetails?: SiteDetails;
14
14
  isOpen: boolean;
15
15
  onClose: () => void;
16
+ onApplyLogo: (mediaId: number) => void;
16
17
  context: string;
18
+ placement: string;
17
19
  }
18
20
  export interface LogoPresenterProps {
19
21
  logo?: Logo;
20
22
  loading?: boolean;
21
- onApplyLogo: () => void;
23
+ onApplyLogo: (mediaId: number) => void;
22
24
  logoAccepted?: boolean;
23
25
  siteId: string | number;
24
26
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "private": false,
3
3
  "name": "@automattic/jetpack-ai-client",
4
- "version": "0.15.0",
4
+ "version": "0.16.0",
5
5
  "description": "A JS client for consuming Jetpack AI services",
6
6
  "homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/ai-client/#readme",
7
7
  "bugs": {
@@ -44,7 +44,7 @@
44
44
  "dependencies": {
45
45
  "@automattic/jetpack-base-styles": "^0.6.28",
46
46
  "@automattic/jetpack-connection": "^0.34.1",
47
- "@automattic/jetpack-shared-extension-utils": "^0.14.19",
47
+ "@automattic/jetpack-shared-extension-utils": "^0.15.0",
48
48
  "@microsoft/fetch-event-source": "2.0.1",
49
49
  "@types/react": "18.3.1",
50
50
  "@types/wordpress__block-editor": "11.5.14",
@@ -17,7 +17,6 @@ import {
17
17
  EVENT_MODAL_OPEN,
18
18
  EVENT_FEEDBACK,
19
19
  EVENT_MODAL_CLOSE,
20
- EVENT_PLACEMENT_QUICK_LINKS,
21
20
  EVENT_GENERATE,
22
21
  } from '../constants.js';
23
22
  import useLogoGenerator from '../hooks/use-logo-generator.js';
@@ -43,8 +42,10 @@ const debug = debugFactory( 'jetpack-ai-calypso:generator-modal' );
43
42
  export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
44
43
  isOpen,
45
44
  onClose,
45
+ onApplyLogo,
46
46
  siteDetails,
47
47
  context,
48
+ placement,
48
49
  } ) => {
49
50
  const { tracks } = useAnalytics();
50
51
  const { recordEvent: recordTracksEvent } = tracks;
@@ -62,7 +63,6 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
62
63
  useLogoGenerator();
63
64
  const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
64
65
  const siteId = siteDetails?.ID;
65
- const siteURL = siteDetails?.URL;
66
66
  const [ logoAccepted, setLogoAccepted ] = useState( false );
67
67
 
68
68
  // First fetch the feature data so we have the most up-to-date info from the backend.
@@ -148,10 +148,10 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
148
148
 
149
149
  const handleModalOpen = useCallback( async () => {
150
150
  setContext( context );
151
- recordTracksEvent( EVENT_MODAL_OPEN, { context, placement: EVENT_PLACEMENT_QUICK_LINKS } );
151
+ recordTracksEvent( EVENT_MODAL_OPEN, { context, placement } );
152
152
 
153
153
  initializeModal();
154
- }, [ setContext, context, initializeModal ] );
154
+ }, [ setContext, context, placement, initializeModal ] );
155
155
 
156
156
  const closeModal = () => {
157
157
  // Reset the state when the modal is closed, so we trigger the modal initialization again when it's opened.
@@ -162,20 +162,12 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
162
162
  setNeedsMoreRequests( false );
163
163
  clearErrors();
164
164
  setLogoAccepted( false );
165
- recordTracksEvent( EVENT_MODAL_CLOSE, { context, placement: EVENT_PLACEMENT_QUICK_LINKS } );
165
+ recordTracksEvent( EVENT_MODAL_CLOSE, { context, placement } );
166
166
  };
167
167
 
168
- const handleApplyLogo = () => {
168
+ const handleApplyLogo = ( mediaId: number ) => {
169
169
  setLogoAccepted( true );
170
- };
171
-
172
- const handleCloseAndReload = () => {
173
- closeModal();
174
-
175
- setTimeout( () => {
176
- // Reload the page to update the logo.
177
- window.location.reload();
178
- }, 1000 );
170
+ onApplyLogo?.( mediaId );
179
171
  };
180
172
 
181
173
  const handleFeedbackClick = () => {
@@ -235,13 +227,10 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
235
227
  />
236
228
  { logoAccepted ? (
237
229
  <div className="jetpack-ai-logo-generator__accept">
238
- <VisitSiteBanner siteURL={ siteURL } onVisitBlankTarget={ handleCloseAndReload } />
230
+ <VisitSiteBanner onVisitBlankTarget={ closeModal } />
239
231
  <div className="jetpack-ai-logo-generator__accept-actions">
240
- <Button variant="link" onClick={ handleCloseAndReload }>
241
- { __( 'Close and refresh', 'jetpack-ai-client' ) }
242
- </Button>
243
- <Button href={ siteURL } variant="primary">
244
- { __( 'Visit site', 'jetpack-ai-client' ) }
232
+ <Button variant="primary" onClick={ closeModal }>
233
+ { __( 'Close', 'jetpack-ai-client' ) }
245
234
  </Button>
246
235
  </div>
247
236
  </div>
@@ -271,7 +260,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
271
260
  { isOpen && (
272
261
  <Modal
273
262
  className="jetpack-ai-logo-generator-modal"
274
- onRequestClose={ logoAccepted ? handleCloseAndReload : closeModal }
263
+ onRequestClose={ closeModal }
275
264
  shouldCloseOnClickOutside={ false }
276
265
  shouldCloseOnEsc={ false }
277
266
  title={ __( 'Jetpack AI Logo Generator', 'jetpack-ai-client' ) }
@@ -86,49 +86,34 @@ const SaveInLibraryButton: React.FC< { siteId: string } > = ( { siteId } ) => {
86
86
  );
87
87
  };
88
88
 
89
- const UseOnSiteButton: React.FC< { onApplyLogo: () => void } > = ( { onApplyLogo } ) => {
89
+ const UseOnSiteButton: React.FC< { onApplyLogo: ( mediaId: number ) => void } > = ( {
90
+ onApplyLogo,
91
+ } ) => {
90
92
  const { tracks } = useAnalytics();
91
93
  const { recordEvent: recordTracksEvent } = tracks;
92
- const {
93
- applyLogo,
94
- isSavingLogoToLibrary,
95
- isApplyingLogo,
96
- selectedLogo,
97
- logos,
98
- selectedLogoIndex,
99
- context,
100
- } = useLogoGenerator();
94
+ const { isSavingLogoToLibrary, selectedLogo, logos, selectedLogoIndex, context } =
95
+ useLogoGenerator();
101
96
 
102
97
  const handleClick = async () => {
103
- if ( ! isApplyingLogo && ! isSavingLogoToLibrary ) {
98
+ if ( ! isSavingLogoToLibrary ) {
104
99
  recordTracksEvent( EVENT_USE, {
105
100
  context,
106
101
  logos_count: logos.length,
107
102
  selected_logo: selectedLogoIndex != null ? selectedLogoIndex + 1 : 0,
108
103
  } );
109
104
 
110
- try {
111
- await applyLogo();
112
- onApplyLogo();
113
- } catch ( error ) {
114
- debug( 'Error applying logo', error );
115
- }
105
+ onApplyLogo?.( selectedLogo?.mediaId );
116
106
  }
117
107
  };
118
108
 
119
- return isApplyingLogo && ! isSavingLogoToLibrary ? (
120
- <button className="jetpack-ai-logo-generator-modal-presenter__action">
121
- <Icon icon={ <LogoIcon /> } />
122
- <span className="action-text">{ __( 'Applying logo…', 'jetpack-ai-client' ) }</span>
123
- </button>
124
- ) : (
109
+ return (
125
110
  <Button
126
111
  className="jetpack-ai-logo-generator-modal-presenter__action"
127
112
  onClick={ handleClick }
128
113
  disabled={ isSavingLogoToLibrary || ! selectedLogo?.mediaId }
129
114
  >
130
115
  <Icon icon={ <LogoIcon /> } />
131
- <span className="action-text">{ __( 'Use on Site', 'jetpack-ai-client' ) }</span>
116
+ <span className="action-text">{ __( 'Use on block', 'jetpack-ai-client' ) }</span>
132
117
  </Button>
133
118
  );
134
119
  };
@@ -144,11 +129,11 @@ const LogoLoading: React.FC = () => {
144
129
  );
145
130
  };
146
131
 
147
- const LogoReady: React.FC< { siteId: string; logo: Logo; onApplyLogo: () => void } > = ( {
148
- siteId,
149
- logo,
150
- onApplyLogo,
151
- } ) => {
132
+ const LogoReady: React.FC< {
133
+ siteId: string;
134
+ logo: Logo;
135
+ onApplyLogo: ( mediaId: number ) => void;
136
+ } > = ( { siteId, logo, onApplyLogo } ) => {
152
137
  return (
153
138
  <>
154
139
  <img
@@ -179,7 +164,7 @@ const LogoUpdated: React.FC< { logo: Logo } > = ( { logo } ) => {
179
164
  />
180
165
  <div className="jetpack-ai-logo-generator-modal-presenter__success-wrapper">
181
166
  <Icon icon={ <CheckIcon /> } />
182
- <span>{ __( 'Your logo has been successfully updated!', 'jetpack-ai-client' ) }</span>
167
+ <span>{ __( 'Your new logo was set to the block!', 'jetpack-ai-client' ) }</span>
183
168
  </div>
184
169
  </>
185
170
  );
@@ -17,9 +17,8 @@ import type React from 'react';
17
17
 
18
18
  export const VisitSiteBanner: React.FC< {
19
19
  className?: string;
20
- siteURL?: string;
21
20
  onVisitBlankTarget: () => void;
22
- } > = ( { className = null, siteURL = '#', onVisitBlankTarget } ) => {
21
+ } > = ( { className = null, onVisitBlankTarget } ) => {
23
22
  return (
24
23
  <div className={ clsx( 'jetpack-ai-logo-generator-modal-visit-site-banner', className ) }>
25
24
  <div className="jetpack-ai-logo-generator-modal-visit-site-banner__jetpack-logo">
@@ -39,8 +38,13 @@ export const VisitSiteBanner: React.FC< {
39
38
  ) }
40
39
  </span>
41
40
  <div>
42
- <Button variant="link" href={ siteURL } target="_blank" onClick={ onVisitBlankTarget }>
43
- { __( 'Visit website', 'jetpack-ai-client' ) }
41
+ <Button
42
+ variant="link"
43
+ href="https://jetpack.com/redirect/?source=logo_generator_learn_more_about_jetpack_ai"
44
+ target="_blank"
45
+ onClick={ onVisitBlankTarget }
46
+ >
47
+ { __( 'Learn more about Jetpack AI', 'jetpack-ai-client' ) }
44
48
  <Icon icon={ external } size={ 20 } />
45
49
  </Button>
46
50
  </div>
@@ -128,7 +128,7 @@ Site description: ${ description }`;
128
128
  throw error;
129
129
  }
130
130
  },
131
- [ setFirstLogoPromptFetchError, increaseAiAssistantRequestsCount ]
131
+ [ setFirstLogoPromptFetchError, increaseAiAssistantRequestsCount, name, description ]
132
132
  );
133
133
 
134
134
  const enhancePrompt = async function ( { prompt }: { prompt: string } ): Promise< string > {
@@ -9,7 +9,6 @@ import apiFetch from '../../api-fetch/index.js';
9
9
  const MAX_CONCURRENT_REQUESTS = 5;
10
10
 
11
11
  let concurrentCounter = 0;
12
- let lastCallTimestamp: number | null = null;
13
12
 
14
13
  /**
15
14
  * Concurrency-limited request to wpcom-proxy-request.
@@ -25,16 +24,6 @@ export default async function wpcomLimitedRequest< T >( params: object ): Promis
25
24
  throw new Error( 'Too many requests' );
26
25
  }
27
26
 
28
- const now = Date.now();
29
-
30
- // Check if the last call was made less than 100 milliseconds ago
31
- if ( lastCallTimestamp && now - lastCallTimestamp < 100 ) {
32
- concurrentCounter -= 1;
33
- throw new Error( 'Too many requests' );
34
- }
35
-
36
- lastCallTimestamp = now; // Update the timestamp
37
-
38
27
  return apiFetch< T >( params ).finally( () => {
39
28
  concurrentCounter -= 1;
40
29
  } );
@@ -15,13 +15,15 @@ export interface GeneratorModalProps {
15
15
  siteDetails?: SiteDetails;
16
16
  isOpen: boolean;
17
17
  onClose: () => void;
18
+ onApplyLogo: ( mediaId: number ) => void;
18
19
  context: string;
20
+ placement: string;
19
21
  }
20
22
 
21
23
  export interface LogoPresenterProps {
22
24
  logo?: Logo;
23
25
  loading?: boolean;
24
- onApplyLogo: () => void;
26
+ onApplyLogo: ( mediaId: number ) => void;
25
27
  logoAccepted?: boolean;
26
28
  siteId: string | number;
27
29
  }