@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 +9 -0
- package/build/logo-generator/components/generator-modal.js +9 -16
- package/build/logo-generator/components/logo-presenter.js +7 -13
- package/build/logo-generator/components/visit-site-banner.d.ts +0 -1
- package/build/logo-generator/components/visit-site-banner.js +2 -2
- package/build/logo-generator/hooks/use-logo-generator.js +1 -1
- package/build/logo-generator/lib/wpcom-limited-request.js +0 -8
- package/build/logo-generator/types.d.ts +3 -1
- package/package.json +2 -2
- package/src/logo-generator/components/generator-modal.tsx +11 -22
- package/src/logo-generator/components/logo-presenter.tsx +15 -30
- package/src/logo-generator/components/visit-site-banner.tsx +8 -4
- package/src/logo-generator/hooks/use-logo-generator.ts +1 -1
- package/src/logo-generator/lib/wpcom-limited-request.ts +0 -11
- package/src/logo-generator/types.ts +3 -1
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,
|
|
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
|
|
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
|
|
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, {
|
|
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:
|
|
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 {
|
|
61
|
+
const { isSavingLogoToLibrary, selectedLogo, logos, selectedLogoIndex, context } = useLogoGenerator();
|
|
62
62
|
const handleClick = async () => {
|
|
63
|
-
if (!
|
|
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
|
-
|
|
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
|
|
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
|
|
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();
|
|
@@ -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,
|
|
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:
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
230
|
+
<VisitSiteBanner onVisitBlankTarget={ closeModal } />
|
|
239
231
|
<div className="jetpack-ai-logo-generator__accept-actions">
|
|
240
|
-
<Button variant="
|
|
241
|
-
{ __( 'Close
|
|
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={
|
|
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 } > = ( {
|
|
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
|
-
|
|
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 ( !
|
|
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
|
-
|
|
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
|
|
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
|
|
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< {
|
|
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
|
|
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,
|
|
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
|
|
43
|
-
|
|
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
|
}
|