@automattic/jetpack-ai-client 0.16.0 → 0.16.2
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 +20 -0
- package/build/logo-generator/components/feature-fetch-failure-screen.js +1 -1
- package/build/logo-generator/components/generator-modal.js +17 -12
- package/build/logo-generator/components/logo-presenter.js +1 -1
- package/build/logo-generator/components/upgrade-screen.js +2 -2
- package/build/logo-generator/components/visit-site-banner.d.ts +1 -1
- package/build/logo-generator/components/visit-site-banner.js +1 -1
- package/build/logo-generator/hooks/use-checkout.js +16 -6
- package/build/logo-generator/lib/logo-storage.js +3 -1
- package/build/logo-generator/types.d.ts +1 -0
- package/package.json +22 -21
- package/src/logo-generator/assets/images/jetpack-logo.svg +1 -4
- package/src/logo-generator/components/feature-fetch-failure-screen.tsx +1 -1
- package/src/logo-generator/components/generator-modal.tsx +22 -14
- package/src/logo-generator/components/logo-presenter.tsx +2 -2
- package/src/logo-generator/components/upgrade-screen.tsx +2 -2
- package/src/logo-generator/components/visit-site-banner.tsx +2 -2
- package/src/logo-generator/hooks/use-checkout.ts +23 -8
- package/src/logo-generator/lib/logo-storage.ts +3 -1
- package/src/logo-generator/types.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,24 @@ 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.2] - 2024-08-19
|
|
9
|
+
### Changed
|
|
10
|
+
- Update dependencies. [#38861] [#38662] [#38665] [#38893]
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Lossless image optimization for images (should improve performance with no visible changes). [#38750]
|
|
14
|
+
|
|
15
|
+
## [0.16.1] - 2024-08-05
|
|
16
|
+
### Changed
|
|
17
|
+
- AI Logo Generator: fix UI issues. [#38590]
|
|
18
|
+
- Fixup versions [#38612]
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- AI Logo Generator: fix multiple feature requests error + retry handling. [#38630]
|
|
22
|
+
- AI Logo Generator: fix small UI issues. [#38676]
|
|
23
|
+
- AI Logo Generator: fix upgrade URLs so they work on any site type. [#38598]
|
|
24
|
+
- AI Logo Generator: update upgrade message. [#38690]
|
|
25
|
+
|
|
8
26
|
## [0.16.0] - 2024-07-29
|
|
9
27
|
### Added
|
|
10
28
|
- AI Logo Generator: support placement property on the generator modal, for tracking purposes. [#38574]
|
|
@@ -366,6 +384,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
366
384
|
- Updated package dependencies. [#31659]
|
|
367
385
|
- Updated package dependencies. [#31785]
|
|
368
386
|
|
|
387
|
+
[0.16.2]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.1...v0.16.2
|
|
388
|
+
[0.16.1]: https://github.com/Automattic/jetpack-ai-client/compare/v0.16.0...v0.16.1
|
|
369
389
|
[0.16.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.15.0...v0.16.0
|
|
370
390
|
[0.15.0]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.6...v0.15.0
|
|
371
391
|
[0.14.6]: https://github.com/Automattic/jetpack-ai-client/compare/v0.14.5...v0.14.6
|
|
@@ -5,6 +5,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
import { Button } from '@wordpress/components';
|
|
6
6
|
import { __ } from '@wordpress/i18n';
|
|
7
7
|
export const FeatureFetchFailureScreen = ({ onCancel, onRetry }) => {
|
|
8
|
-
const errorMessage = __('We are sorry. There was an error loading your Jetpack AI
|
|
8
|
+
const errorMessage = __('We are sorry. There was an error loading your Jetpack AI plan data. Please, try again.', 'jetpack-ai-client');
|
|
9
9
|
return (_jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-message-wrapper", children: [_jsx("div", { className: "jetpack-ai-logo-generator-modal__notice-message", children: _jsx("span", { className: "jetpack-ai-logo-generator-modal__loading-message", children: errorMessage }) }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-actions", children: [_jsx(Button, { variant: "tertiary", onClick: onCancel, children: __('Cancel', 'jetpack-ai-client') }), _jsx(Button, { variant: "primary", onClick: onRetry, children: __('Try again', 'jetpack-ai-client') })] })] }));
|
|
10
10
|
};
|
|
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
*/
|
|
5
5
|
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
|
|
6
6
|
import { Modal, Button } from '@wordpress/components';
|
|
7
|
-
import { useDispatch } from '@wordpress/data';
|
|
7
|
+
import { useDispatch, select } from '@wordpress/data';
|
|
8
8
|
import { __ } from '@wordpress/i18n';
|
|
9
9
|
import { external, Icon } from '@wordpress/icons';
|
|
10
10
|
import clsx from 'clsx';
|
|
@@ -14,6 +14,7 @@ import { useState, useEffect, useCallback, useRef } from 'react';
|
|
|
14
14
|
* Internal dependencies
|
|
15
15
|
*/
|
|
16
16
|
import { DEFAULT_LOGO_COST, EVENT_MODAL_OPEN, EVENT_FEEDBACK, EVENT_MODAL_CLOSE, EVENT_GENERATE, } from '../constants.js';
|
|
17
|
+
import { useCheckout } from '../hooks/use-checkout.js';
|
|
17
18
|
import useLogoGenerator from '../hooks/use-logo-generator.js';
|
|
18
19
|
import useRequestErrors from '../hooks/use-request-errors.js';
|
|
19
20
|
import { isLogoHistoryEmpty, clearDeletedMedia } from '../lib/logo-storage.js';
|
|
@@ -27,21 +28,22 @@ import { UpgradeScreen } from './upgrade-screen.js';
|
|
|
27
28
|
import { VisitSiteBanner } from './visit-site-banner.js';
|
|
28
29
|
import './generator-modal.scss';
|
|
29
30
|
const debug = debugFactory('jetpack-ai-calypso:generator-modal');
|
|
30
|
-
export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, siteDetails, context, placement, }) => {
|
|
31
|
+
export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDetails, context, placement, }) => {
|
|
31
32
|
const { tracks } = useAnalytics();
|
|
32
33
|
const { recordEvent: recordTracksEvent } = tracks;
|
|
33
34
|
const { setSiteDetails, fetchAiAssistantFeature, loadLogoHistory } = useDispatch(STORE_NAME);
|
|
35
|
+
const { getIsRequestingAiAssistantFeature } = select(STORE_NAME);
|
|
34
36
|
const [loadingState, setLoadingState] = useState(null);
|
|
35
37
|
const [initialPrompt, setInitialPrompt] = useState();
|
|
36
38
|
const needsToHandleModalOpen = useRef(true);
|
|
37
39
|
const requestedFeatureData = useRef(false);
|
|
38
40
|
const [needsFeature, setNeedsFeature] = useState(false);
|
|
39
41
|
const [needsMoreRequests, setNeedsMoreRequests] = useState(false);
|
|
40
|
-
const [upgradeURL, setUpgradeURL] = useState('');
|
|
41
42
|
const { selectedLogo, getAiAssistantFeature, generateFirstPrompt, generateLogo, setContext } = useLogoGenerator();
|
|
42
43
|
const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
|
|
43
44
|
const siteId = siteDetails?.ID;
|
|
44
45
|
const [logoAccepted, setLogoAccepted] = useState(false);
|
|
46
|
+
const { nextTierCheckoutURL: upgradeURL } = useCheckout();
|
|
45
47
|
// First fetch the feature data so we have the most up-to-date info from the backend.
|
|
46
48
|
const feature = getAiAssistantFeature();
|
|
47
49
|
const generateFirstLogo = useCallback(async () => {
|
|
@@ -79,13 +81,10 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, siteDetails, cont
|
|
|
79
81
|
!hasNoNextTier &&
|
|
80
82
|
!hasHistory &&
|
|
81
83
|
currentLimit - currentUsage < logoCost + promptCreationCost;
|
|
82
|
-
// If the site requires an upgrade,
|
|
84
|
+
// If the site requires an upgrade, show the upgrade screen immediately.
|
|
83
85
|
setNeedsFeature(!feature?.hasFeature ?? true);
|
|
84
86
|
setNeedsMoreRequests(siteNeedsMoreRequests);
|
|
85
87
|
if (!feature?.hasFeature || siteNeedsMoreRequests) {
|
|
86
|
-
const siteUpgradeURL = new URL(`${location.origin}/checkout/${siteDetails?.domain}/${feature?.nextTier?.slug}`);
|
|
87
|
-
siteUpgradeURL.searchParams.set('redirect_to', location.href);
|
|
88
|
-
setUpgradeURL(siteUpgradeURL.toString());
|
|
89
88
|
setLoadingState(null);
|
|
90
89
|
return;
|
|
91
90
|
}
|
|
@@ -142,10 +141,13 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, siteDetails, cont
|
|
|
142
141
|
}
|
|
143
142
|
// When the site details are set, we need to fetch the feature data.
|
|
144
143
|
if (!requestedFeatureData.current) {
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
const isRequestingFeature = getIsRequestingAiAssistantFeature();
|
|
145
|
+
if (!isRequestingFeature) {
|
|
146
|
+
requestedFeatureData.current = true;
|
|
147
|
+
fetchAiAssistantFeature();
|
|
148
|
+
}
|
|
147
149
|
}
|
|
148
|
-
}, [siteId, siteDetails, setSiteDetails]);
|
|
150
|
+
}, [siteId, siteDetails, setSiteDetails, getIsRequestingAiAssistantFeature]);
|
|
149
151
|
// Handles modal opening logic
|
|
150
152
|
useEffect(() => {
|
|
151
153
|
// While the modal is not open, the siteId is not set, or the feature data is not available, do nothing.
|
|
@@ -163,13 +165,16 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, siteDetails, cont
|
|
|
163
165
|
body = _jsx(FirstLoadScreen, { state: loadingState });
|
|
164
166
|
}
|
|
165
167
|
else if (featureFetchError || firstLogoPromptFetchError) {
|
|
166
|
-
body = _jsx(FeatureFetchFailureScreen, { onCancel: closeModal, onRetry:
|
|
168
|
+
body = (_jsx(FeatureFetchFailureScreen, { onCancel: closeModal, onRetry: () => {
|
|
169
|
+
closeModal();
|
|
170
|
+
onReload?.();
|
|
171
|
+
} }));
|
|
167
172
|
}
|
|
168
173
|
else if (needsFeature || needsMoreRequests) {
|
|
169
174
|
body = (_jsx(UpgradeScreen, { onCancel: closeModal, upgradeURL: upgradeURL, reason: needsFeature ? 'feature' : 'requests' }));
|
|
170
175
|
}
|
|
171
176
|
else {
|
|
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, {
|
|
177
|
+
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, {}), _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" })] }) })] }))] }));
|
|
173
178
|
}
|
|
174
179
|
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', {
|
|
175
180
|
'notice-modal': needsFeature || needsMoreRequests || featureFetchError || firstLogoPromptFetchError,
|
|
@@ -53,7 +53,7 @@ const SaveInLibraryButton = ({ siteId }) => {
|
|
|
53
53
|
};
|
|
54
54
|
const savingLabel = __('Saving…', 'jetpack-ai-client');
|
|
55
55
|
const savedLabel = __('Saved', 'jetpack-ai-client');
|
|
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(
|
|
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
58
|
const UseOnSiteButton = ({ onApplyLogo, }) => {
|
|
59
59
|
const { tracks } = useAnalytics();
|
|
@@ -13,12 +13,12 @@ import useLogoGenerator from '../hooks/use-logo-generator.js';
|
|
|
13
13
|
export const UpgradeScreen = ({ onCancel, upgradeURL, reason }) => {
|
|
14
14
|
const { tracks } = useAnalytics();
|
|
15
15
|
const { recordEvent: recordTracksEvent } = tracks;
|
|
16
|
-
const upgradeMessageFeature = __('
|
|
16
|
+
const upgradeMessageFeature = __('The logo generator requires a paid Jetpack AI plan. Upgrade your plan to access exclusive features, including logo generation. The upgrade will also increase the amount of requests you can use in all AI-powered features.', 'jetpack-ai-client');
|
|
17
17
|
const upgradeMessageRequests = __('Not enough requests left to generate a logo. Upgrade your Jetpack AI to increase the amount of requests you can use in all AI-powered features.', 'jetpack-ai-client');
|
|
18
18
|
const { context } = useLogoGenerator();
|
|
19
19
|
const handleUpgradeClick = () => {
|
|
20
20
|
recordTracksEvent(EVENT_UPGRADE, { context, placement: EVENT_PLACEMENT_FREE_USER_SCREEN });
|
|
21
21
|
onCancel();
|
|
22
22
|
};
|
|
23
|
-
return (_jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-message-wrapper", children: [_jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-message", children: [_jsx("span", { className: "jetpack-ai-logo-generator-modal__loading-message", children: reason === 'feature' ? upgradeMessageFeature : upgradeMessageRequests }), "\u00A0", _jsx(Button, { variant: "link", href: "https://jetpack.com/ai/", target: "_blank", children: __('Learn more', 'jetpack-ai-client') })] }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-actions", children: [_jsx(Button, { variant: "tertiary", onClick: onCancel, children: __('Cancel', 'jetpack-ai-client') }), _jsx(Button, { variant: "primary", href: upgradeURL, target: "_blank", onClick: handleUpgradeClick, children: __('Upgrade', 'jetpack-ai-client') })] })] }));
|
|
23
|
+
return (_jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-message-wrapper", children: [_jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-message", children: [_jsx("span", { className: "jetpack-ai-logo-generator-modal__loading-message", children: reason === 'feature' ? upgradeMessageFeature : upgradeMessageRequests }), "\u00A0", _jsx(Button, { variant: "link", href: "https://jetpack.com/ai/", target: "_blank", children: __('Learn more about Jetpack AI.', 'jetpack-ai-client') })] }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-actions", children: [_jsx(Button, { variant: "tertiary", onClick: onCancel, children: __('Cancel', 'jetpack-ai-client') }), _jsx(Button, { variant: "primary", href: upgradeURL, target: "_blank", onClick: handleUpgradeClick, children: __('Upgrade', 'jetpack-ai-client') })] })] }));
|
|
24
24
|
};
|
|
@@ -12,5 +12,5 @@ import clsx from 'clsx';
|
|
|
12
12
|
import jetpackLogo from '../assets/images/jetpack-logo.svg';
|
|
13
13
|
import './visit-site-banner.scss';
|
|
14
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 })] }) })] })] }));
|
|
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 ? onVisitBlankTarget : null, children: [__('Learn more about Jetpack AI', 'jetpack-ai-client'), _jsx(Icon, { icon: external, size: 20 })] }) })] })] }));
|
|
16
16
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
+
import { isAtomicSite, isSimpleSite, getSiteFragment, } from '@automattic/jetpack-shared-extension-utils';
|
|
4
5
|
import { useSelect } from '@wordpress/data';
|
|
5
6
|
import debugFactory from 'debug';
|
|
6
7
|
/**
|
|
@@ -9,18 +10,27 @@ import debugFactory from 'debug';
|
|
|
9
10
|
import { STORE_NAME } from '../store/index.js';
|
|
10
11
|
const debug = debugFactory('ai-client:logo-generator:use-checkout');
|
|
11
12
|
export const useCheckout = () => {
|
|
12
|
-
const { nextTier
|
|
13
|
+
const { nextTier } = useSelect(select => {
|
|
13
14
|
const selectors = select(STORE_NAME);
|
|
14
15
|
return {
|
|
15
16
|
nextTier: selectors.getAiAssistantFeature().nextTier,
|
|
16
|
-
siteDetails: selectors.getSiteDetails(),
|
|
17
17
|
};
|
|
18
18
|
}, []);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Use the Jetpack redirect URL to open the checkout page
|
|
21
|
+
*/
|
|
22
|
+
const wpcomCheckoutUrl = new URL(`https://jetpack.com/redirect/`);
|
|
23
|
+
wpcomCheckoutUrl.searchParams.set('source', 'jetpack-ai-yearly-tier-upgrade-nudge');
|
|
24
|
+
wpcomCheckoutUrl.searchParams.set('site', getSiteFragment());
|
|
25
|
+
wpcomCheckoutUrl.searchParams.set('path', `jetpack_ai_yearly:-q-${nextTier?.limit}`);
|
|
26
|
+
/**
|
|
27
|
+
* Open the product interstitial page
|
|
28
|
+
*/
|
|
29
|
+
const jetpackCheckoutUrl = `${window?.Jetpack_Editor_Initial_State?.adminUrl}admin.php?redirect_to_referrer=1&page=my-jetpack#/add-jetpack-ai`;
|
|
30
|
+
const nextTierCheckoutURL = isAtomicSite() || isSimpleSite() ? wpcomCheckoutUrl.toString() : jetpackCheckoutUrl;
|
|
31
|
+
debug('Next tier checkout URL: ', nextTierCheckoutURL);
|
|
22
32
|
return {
|
|
23
|
-
nextTierCheckoutURL
|
|
33
|
+
nextTierCheckoutURL,
|
|
24
34
|
hasNextTier: !!nextTier,
|
|
25
35
|
};
|
|
26
36
|
};
|
|
@@ -119,5 +119,7 @@ export async function clearDeletedMedia(siteId) {
|
|
|
119
119
|
.filter(({ exists }) => !exists)
|
|
120
120
|
.forEach(({ mediaId }) => removeLogo({ siteId, mediaId }));
|
|
121
121
|
}
|
|
122
|
-
catch (error) {
|
|
122
|
+
catch (error) {
|
|
123
|
+
// Assume that the media exists if there was a network error and do nothing to avoid data loss.
|
|
124
|
+
}
|
|
123
125
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"private": false,
|
|
3
3
|
"name": "@automattic/jetpack-ai-client",
|
|
4
|
-
"version": "0.16.
|
|
4
|
+
"version": "0.16.2",
|
|
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": {
|
|
@@ -23,14 +23,15 @@
|
|
|
23
23
|
},
|
|
24
24
|
"type": "module",
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@storybook/addon-actions": "8.
|
|
27
|
-
"@storybook/blocks": "8.
|
|
28
|
-
"@storybook/preview-api": "8.
|
|
29
|
-
"@storybook/react": "8.
|
|
30
|
-
"@types/markdown-it": "14.
|
|
31
|
-
"@types/turndown": "5.0.
|
|
26
|
+
"@storybook/addon-actions": "8.2.9",
|
|
27
|
+
"@storybook/blocks": "8.2.9",
|
|
28
|
+
"@storybook/preview-api": "8.2.9",
|
|
29
|
+
"@storybook/react": "8.2.9",
|
|
30
|
+
"@types/markdown-it": "14.1.2",
|
|
31
|
+
"@types/turndown": "5.0.5",
|
|
32
32
|
"jest": "^29.6.2",
|
|
33
33
|
"jest-environment-jsdom": "29.7.0",
|
|
34
|
+
"storybook": "8.2.9",
|
|
34
35
|
"typescript": "5.0.4"
|
|
35
36
|
},
|
|
36
37
|
"exports": {
|
|
@@ -42,21 +43,21 @@
|
|
|
42
43
|
"main": "./build/index.js",
|
|
43
44
|
"types": "./build/index.d.ts",
|
|
44
45
|
"dependencies": {
|
|
45
|
-
"@automattic/jetpack-base-styles": "^0.6.
|
|
46
|
-
"@automattic/jetpack-connection": "^0.
|
|
47
|
-
"@automattic/jetpack-shared-extension-utils": "^0.15.
|
|
46
|
+
"@automattic/jetpack-base-styles": "^0.6.29",
|
|
47
|
+
"@automattic/jetpack-connection": "^0.35.2",
|
|
48
|
+
"@automattic/jetpack-shared-extension-utils": "^0.15.3",
|
|
48
49
|
"@microsoft/fetch-event-source": "2.0.1",
|
|
49
|
-
"@types/react": "18.3.
|
|
50
|
-
"@types/wordpress__block-editor": "11.5.
|
|
51
|
-
"@wordpress/api-fetch": "7.
|
|
52
|
-
"@wordpress/blob": "4.
|
|
53
|
-
"@wordpress/block-editor": "
|
|
54
|
-
"@wordpress/components": "28.
|
|
55
|
-
"@wordpress/compose": "7.
|
|
56
|
-
"@wordpress/data": "10.
|
|
57
|
-
"@wordpress/element": "6.
|
|
58
|
-
"@wordpress/i18n": "5.
|
|
59
|
-
"@wordpress/icons": "10.
|
|
50
|
+
"@types/react": "18.3.3",
|
|
51
|
+
"@types/wordpress__block-editor": "11.5.15",
|
|
52
|
+
"@wordpress/api-fetch": "7.5.0",
|
|
53
|
+
"@wordpress/blob": "4.5.0",
|
|
54
|
+
"@wordpress/block-editor": "14.0.0",
|
|
55
|
+
"@wordpress/components": "28.5.0",
|
|
56
|
+
"@wordpress/compose": "7.5.0",
|
|
57
|
+
"@wordpress/data": "10.5.0",
|
|
58
|
+
"@wordpress/element": "6.5.0",
|
|
59
|
+
"@wordpress/i18n": "5.5.0",
|
|
60
|
+
"@wordpress/icons": "10.5.0",
|
|
60
61
|
"clsx": "2.1.1",
|
|
61
62
|
"debug": "4.3.4",
|
|
62
63
|
"markdown-it": "14.0.0",
|
|
@@ -1,4 +1 @@
|
|
|
1
|
-
<svg
|
|
2
|
-
<path d="M16 32.5C24.8366 32.5 32 25.3366 32 16.5C32 7.66344 24.8366 0.5 16 0.5C7.16344 0.5 0 7.66344 0 16.5C0 25.3366 7.16344 32.5 16 32.5Z" fill="#069E08"/>
|
|
3
|
-
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.3295 3.67557V19.1565H7.36005L15.3295 3.67557ZM16.9478 29.3244V13.813H24.9478L16.9478 29.3244Z" fill="white"/>
|
|
4
|
-
</svg>
|
|
1
|
+
<svg fill="none" height="33" viewBox="0 0 32 33" width="32" xmlns="http://www.w3.org/2000/svg"><path d="m16 32.5c8.8366 0 16-7.1634 16-16 0-8.83656-7.1634-16-16-16-8.83656 0-16 7.16344-16 16 0 8.8366 7.16344 16 16 16z" fill="#069e08"/><path clip-rule="evenodd" d="m15.3295 3.67557v15.48093h-7.96945zm1.6183 25.64883v-15.5114h8z" fill="#fff" fill-rule="evenodd"/></svg>
|
|
@@ -13,7 +13,7 @@ export const FeatureFetchFailureScreen: React.FC< {
|
|
|
13
13
|
onRetry: () => void;
|
|
14
14
|
} > = ( { onCancel, onRetry } ) => {
|
|
15
15
|
const errorMessage = __(
|
|
16
|
-
'We are sorry. There was an error loading your Jetpack AI
|
|
16
|
+
'We are sorry. There was an error loading your Jetpack AI plan data. Please, try again.',
|
|
17
17
|
'jetpack-ai-client'
|
|
18
18
|
);
|
|
19
19
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
|
|
5
5
|
import { Modal, Button } from '@wordpress/components';
|
|
6
|
-
import { useDispatch } from '@wordpress/data';
|
|
6
|
+
import { useDispatch, select } from '@wordpress/data';
|
|
7
7
|
import { __ } from '@wordpress/i18n';
|
|
8
8
|
import { external, Icon } from '@wordpress/icons';
|
|
9
9
|
import clsx from 'clsx';
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
EVENT_MODAL_CLOSE,
|
|
20
20
|
EVENT_GENERATE,
|
|
21
21
|
} from '../constants.js';
|
|
22
|
+
import { useCheckout } from '../hooks/use-checkout.js';
|
|
22
23
|
import useLogoGenerator from '../hooks/use-logo-generator.js';
|
|
23
24
|
import useRequestErrors from '../hooks/use-request-errors.js';
|
|
24
25
|
import { isLogoHistoryEmpty, clearDeletedMedia } from '../lib/logo-storage.js';
|
|
@@ -43,6 +44,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
43
44
|
isOpen,
|
|
44
45
|
onClose,
|
|
45
46
|
onApplyLogo,
|
|
47
|
+
onReload,
|
|
46
48
|
siteDetails,
|
|
47
49
|
context,
|
|
48
50
|
placement,
|
|
@@ -50,6 +52,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
50
52
|
const { tracks } = useAnalytics();
|
|
51
53
|
const { recordEvent: recordTracksEvent } = tracks;
|
|
52
54
|
const { setSiteDetails, fetchAiAssistantFeature, loadLogoHistory } = useDispatch( STORE_NAME );
|
|
55
|
+
const { getIsRequestingAiAssistantFeature } = select( STORE_NAME );
|
|
53
56
|
const [ loadingState, setLoadingState ] = useState<
|
|
54
57
|
'loadingFeature' | 'analyzing' | 'generating' | null
|
|
55
58
|
>( null );
|
|
@@ -58,12 +61,12 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
58
61
|
const requestedFeatureData = useRef< boolean >( false );
|
|
59
62
|
const [ needsFeature, setNeedsFeature ] = useState( false );
|
|
60
63
|
const [ needsMoreRequests, setNeedsMoreRequests ] = useState( false );
|
|
61
|
-
const [ upgradeURL, setUpgradeURL ] = useState( '' );
|
|
62
64
|
const { selectedLogo, getAiAssistantFeature, generateFirstPrompt, generateLogo, setContext } =
|
|
63
65
|
useLogoGenerator();
|
|
64
66
|
const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
|
|
65
67
|
const siteId = siteDetails?.ID;
|
|
66
68
|
const [ logoAccepted, setLogoAccepted ] = useState( false );
|
|
69
|
+
const { nextTierCheckoutURL: upgradeURL } = useCheckout();
|
|
67
70
|
|
|
68
71
|
// First fetch the feature data so we have the most up-to-date info from the backend.
|
|
69
72
|
const feature = getAiAssistantFeature();
|
|
@@ -107,16 +110,10 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
107
110
|
! hasHistory &&
|
|
108
111
|
currentLimit - currentUsage < logoCost + promptCreationCost;
|
|
109
112
|
|
|
110
|
-
// If the site requires an upgrade,
|
|
113
|
+
// If the site requires an upgrade, show the upgrade screen immediately.
|
|
111
114
|
setNeedsFeature( ! feature?.hasFeature ?? true );
|
|
112
115
|
setNeedsMoreRequests( siteNeedsMoreRequests );
|
|
113
|
-
|
|
114
116
|
if ( ! feature?.hasFeature || siteNeedsMoreRequests ) {
|
|
115
|
-
const siteUpgradeURL = new URL(
|
|
116
|
-
`${ location.origin }/checkout/${ siteDetails?.domain }/${ feature?.nextTier?.slug }`
|
|
117
|
-
);
|
|
118
|
-
siteUpgradeURL.searchParams.set( 'redirect_to', location.href );
|
|
119
|
-
setUpgradeURL( siteUpgradeURL.toString() );
|
|
120
117
|
setLoadingState( null );
|
|
121
118
|
return;
|
|
122
119
|
}
|
|
@@ -182,10 +179,13 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
182
179
|
|
|
183
180
|
// When the site details are set, we need to fetch the feature data.
|
|
184
181
|
if ( ! requestedFeatureData.current ) {
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
const isRequestingFeature = getIsRequestingAiAssistantFeature();
|
|
183
|
+
if ( ! isRequestingFeature ) {
|
|
184
|
+
requestedFeatureData.current = true;
|
|
185
|
+
fetchAiAssistantFeature();
|
|
186
|
+
}
|
|
187
187
|
}
|
|
188
|
-
}, [ siteId, siteDetails, setSiteDetails ] );
|
|
188
|
+
}, [ siteId, siteDetails, setSiteDetails, getIsRequestingAiAssistantFeature ] );
|
|
189
189
|
|
|
190
190
|
// Handles modal opening logic
|
|
191
191
|
useEffect( () => {
|
|
@@ -206,7 +206,15 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
206
206
|
if ( loadingState ) {
|
|
207
207
|
body = <FirstLoadScreen state={ loadingState } />;
|
|
208
208
|
} else if ( featureFetchError || firstLogoPromptFetchError ) {
|
|
209
|
-
body =
|
|
209
|
+
body = (
|
|
210
|
+
<FeatureFetchFailureScreen
|
|
211
|
+
onCancel={ closeModal }
|
|
212
|
+
onRetry={ () => {
|
|
213
|
+
closeModal();
|
|
214
|
+
onReload?.();
|
|
215
|
+
} }
|
|
216
|
+
/>
|
|
217
|
+
);
|
|
210
218
|
} else if ( needsFeature || needsMoreRequests ) {
|
|
211
219
|
body = (
|
|
212
220
|
<UpgradeScreen
|
|
@@ -227,7 +235,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
|
|
|
227
235
|
/>
|
|
228
236
|
{ logoAccepted ? (
|
|
229
237
|
<div className="jetpack-ai-logo-generator__accept">
|
|
230
|
-
<VisitSiteBanner
|
|
238
|
+
<VisitSiteBanner />
|
|
231
239
|
<div className="jetpack-ai-logo-generator__accept-actions">
|
|
232
240
|
<Button variant="primary" onClick={ closeModal }>
|
|
233
241
|
{ __( 'Close', 'jetpack-ai-client' ) }
|
|
@@ -79,10 +79,10 @@ const SaveInLibraryButton: React.FC< { siteId: string } > = ( { siteId } ) => {
|
|
|
79
79
|
<span className="action-text">{ __( 'Save in Library', 'jetpack-ai-client' ) }</span>
|
|
80
80
|
</Button>
|
|
81
81
|
) : (
|
|
82
|
-
<
|
|
82
|
+
<Button className="jetpack-ai-logo-generator-modal-presenter__action">
|
|
83
83
|
<Icon icon={ saving ? <MediaIcon /> : <CheckIcon /> } />
|
|
84
84
|
<span className="action-text">{ saving ? savingLabel : savedLabel }</span>
|
|
85
|
-
</
|
|
85
|
+
</Button>
|
|
86
86
|
);
|
|
87
87
|
};
|
|
88
88
|
|
|
@@ -22,7 +22,7 @@ export const UpgradeScreen: React.FC< {
|
|
|
22
22
|
const { tracks } = useAnalytics();
|
|
23
23
|
const { recordEvent: recordTracksEvent } = tracks;
|
|
24
24
|
const upgradeMessageFeature = __(
|
|
25
|
-
'
|
|
25
|
+
'The logo generator requires a paid Jetpack AI plan. Upgrade your plan to access exclusive features, including logo generation. The upgrade will also increase the amount of requests you can use in all AI-powered features.',
|
|
26
26
|
'jetpack-ai-client'
|
|
27
27
|
);
|
|
28
28
|
|
|
@@ -46,7 +46,7 @@ export const UpgradeScreen: React.FC< {
|
|
|
46
46
|
</span>
|
|
47
47
|
|
|
48
48
|
<Button variant="link" href="https://jetpack.com/ai/" target="_blank">
|
|
49
|
-
{ __( 'Learn more', 'jetpack-ai-client' ) }
|
|
49
|
+
{ __( 'Learn more about Jetpack AI.', 'jetpack-ai-client' ) }
|
|
50
50
|
</Button>
|
|
51
51
|
</div>
|
|
52
52
|
<div className="jetpack-ai-logo-generator-modal__notice-actions">
|
|
@@ -17,7 +17,7 @@ import type React from 'react';
|
|
|
17
17
|
|
|
18
18
|
export const VisitSiteBanner: React.FC< {
|
|
19
19
|
className?: string;
|
|
20
|
-
onVisitBlankTarget
|
|
20
|
+
onVisitBlankTarget?: () => void;
|
|
21
21
|
} > = ( { className = null, onVisitBlankTarget } ) => {
|
|
22
22
|
return (
|
|
23
23
|
<div className={ clsx( 'jetpack-ai-logo-generator-modal-visit-site-banner', className ) }>
|
|
@@ -42,7 +42,7 @@ export const VisitSiteBanner: React.FC< {
|
|
|
42
42
|
variant="link"
|
|
43
43
|
href="https://jetpack.com/redirect/?source=logo_generator_learn_more_about_jetpack_ai"
|
|
44
44
|
target="_blank"
|
|
45
|
-
onClick={ onVisitBlankTarget }
|
|
45
|
+
onClick={ onVisitBlankTarget ? onVisitBlankTarget : null }
|
|
46
46
|
>
|
|
47
47
|
{ __( 'Learn more about Jetpack AI', 'jetpack-ai-client' ) }
|
|
48
48
|
<Icon icon={ external } size={ 20 } />
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External dependencies
|
|
3
3
|
*/
|
|
4
|
+
import {
|
|
5
|
+
isAtomicSite,
|
|
6
|
+
isSimpleSite,
|
|
7
|
+
getSiteFragment,
|
|
8
|
+
} from '@automattic/jetpack-shared-extension-utils';
|
|
4
9
|
import { useSelect } from '@wordpress/data';
|
|
5
10
|
import debugFactory from 'debug';
|
|
6
11
|
/**
|
|
@@ -15,23 +20,33 @@ import type { Selectors } from '../store/types.js';
|
|
|
15
20
|
const debug = debugFactory( 'ai-client:logo-generator:use-checkout' );
|
|
16
21
|
|
|
17
22
|
export const useCheckout = () => {
|
|
18
|
-
const { nextTier
|
|
23
|
+
const { nextTier } = useSelect( select => {
|
|
19
24
|
const selectors: Selectors = select( STORE_NAME );
|
|
20
25
|
return {
|
|
21
26
|
nextTier: selectors.getAiAssistantFeature().nextTier,
|
|
22
|
-
siteDetails: selectors.getSiteDetails(),
|
|
23
27
|
};
|
|
24
28
|
}, [] );
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Use the Jetpack redirect URL to open the checkout page
|
|
32
|
+
*/
|
|
33
|
+
const wpcomCheckoutUrl = new URL( `https://jetpack.com/redirect/` );
|
|
34
|
+
wpcomCheckoutUrl.searchParams.set( 'source', 'jetpack-ai-yearly-tier-upgrade-nudge' );
|
|
35
|
+
wpcomCheckoutUrl.searchParams.set( 'site', getSiteFragment() as string );
|
|
36
|
+
wpcomCheckoutUrl.searchParams.set( 'path', `jetpack_ai_yearly:-q-${ nextTier?.limit }` );
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Open the product interstitial page
|
|
40
|
+
*/
|
|
41
|
+
const jetpackCheckoutUrl = `${ window?.Jetpack_Editor_Initial_State?.adminUrl }admin.php?redirect_to_referrer=1&page=my-jetpack#/add-jetpack-ai`;
|
|
42
|
+
|
|
43
|
+
const nextTierCheckoutURL =
|
|
44
|
+
isAtomicSite() || isSimpleSite() ? wpcomCheckoutUrl.toString() : jetpackCheckoutUrl;
|
|
45
|
+
|
|
46
|
+
debug( 'Next tier checkout URL: ', nextTierCheckoutURL );
|
|
32
47
|
|
|
33
48
|
return {
|
|
34
|
-
nextTierCheckoutURL
|
|
49
|
+
nextTierCheckoutURL,
|
|
35
50
|
hasNextTier: !! nextTier,
|
|
36
51
|
};
|
|
37
52
|
};
|
|
@@ -162,5 +162,7 @@ export async function clearDeletedMedia( siteId: string ) {
|
|
|
162
162
|
responses
|
|
163
163
|
.filter( ( { exists } ) => ! exists )
|
|
164
164
|
.forEach( ( { mediaId } ) => removeLogo( { siteId, mediaId } ) );
|
|
165
|
-
} catch ( error ) {
|
|
165
|
+
} catch ( error ) {
|
|
166
|
+
// Assume that the media exists if there was a network error and do nothing to avoid data loss.
|
|
167
|
+
}
|
|
166
168
|
}
|