Skip to content

Commit

Permalink
AI Client: make fetch error retry optional (#39848)
Browse files Browse the repository at this point in the history
* make reload handler optional on fetch error notice

* changelog

* provide empty retry handler

* move condition process to modal initializer

* cleanup new open handler

Committed via a GitHub action: https://github.com/Automattic/jetpack/actions/runs/11465240162

Upstream-Ref: Automattic/jetpack@932747a
  • Loading branch information
CGastrell authored and matticbot committed Oct 22, 2024
1 parent 61412ef commit d94d3eb
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This is an alpha version! The changes listed here are not final.

### Changed
- AI Client: add types for AI assistant feature payload data branch featuresControl
- AI Client: make reload handler prop optional as it still works in a fuzzy way. The error notice (modal) will instruct to reload the page when the optional prop is not provided

### Fixed
- AI Client: fix initial state being mapped even when fetch fails, making the default state nonsensical
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
import type React from 'react';
export declare const FeatureFetchFailureScreen: React.FC<{
onCancel: () => void;
onRetry: () => void;
onRetry?: () => void;
}>;
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import { Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
export const FeatureFetchFailureScreen = ({ onCancel, onRetry }) => {
const errorMessage = __('We are sorry. There was an error loading your Jetpack AI plan data. Please, try again.', 'jetpack-ai-client');
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') })] })] }));
const errorMessageWithoutRetry = __('We are sorry. There was an error loading your Jetpack AI plan data. Please, reload the page and try again.', 'jetpack-ai-client');
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: onRetry ? errorMessage : errorMessageWithoutRetry }) }), _jsxs("div", { className: "jetpack-ai-logo-generator-modal__notice-actions", children: [_jsx(Button, { variant: "tertiary", onClick: onCancel, children: __('Cancel', 'jetpack-ai-client') }), onRetry && (_jsx(Button, { variant: "primary", onClick: onRetry, children: __('Try again', 'jetpack-ai-client') }))] })] }));
};
29 changes: 21 additions & 8 deletions build/ai-client/src/logo-generator/components/generator-modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { UpgradeScreen } from './upgrade-screen.js';
import { VisitSiteBanner } from './visit-site-banner.js';
import './generator-modal.scss';
const debug = debugFactory('jetpack-ai-calypso:generator-modal');
export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDetails, context, placement, }) => {
export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload = null, siteDetails, context, placement, }) => {
const { tracks } = useAnalytics();
const { recordEvent: recordTracksEvent } = tracks;
const { setSiteDetails, fetchAiAssistantFeature, loadLogoHistory, setIsLoadingHistory } = useDispatch(STORE_NAME);
Expand All @@ -41,7 +41,7 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDet
const [needsFeature, setNeedsFeature] = useState(false);
const [needsMoreRequests, setNeedsMoreRequests] = useState(false);
const { selectedLogo, getAiAssistantFeature, generateFirstPrompt, generateLogo, setContext, tierPlansEnabled, site, requireUpgrade, } = useLogoGenerator();
const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
const { featureFetchError, setFeatureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
const siteId = siteDetails?.ID;
const [logoAccepted, setLogoAccepted] = useState(false);
const { nextTierCheckoutURL: upgradeURL } = useCheckout();
Expand Down Expand Up @@ -70,6 +70,13 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDet
*/
const initializeModal = useCallback(async () => {
try {
if (!siteId) {
throw new Error('Site ID is missing');
}
if (!feature?.featuresControl?.['logo-generator']?.enabled) {
setFeatureFetchError('Failed to fetch feature data');
throw new Error('Failed to fetch feature data');
}
const hasHistory = !isLogoHistoryEmpty(String(siteId));
const logoCost = feature?.costs?.['jetpack-ai-logo-generator']?.logo ?? DEFAULT_LOGO_COST;
const promptCreationCost = 1;
Expand Down Expand Up @@ -135,6 +142,7 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDet
isLogoHistoryEmpty,
siteId,
requireUpgrade,
setFeatureFetchError,
]);
const handleModalOpen = useCallback(async () => {
setContext(context);
Expand All @@ -153,6 +161,14 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDet
setIsLoadingHistory(false);
recordTracksEvent(EVENT_MODAL_CLOSE, { context, placement });
};
const handleReload = useCallback(() => {
if (!onReload) {
return;
}
closeModal();
requestedFeatureData.current = false;
onReload();
}, [onReload, closeModal]);
const handleApplyLogo = (mediaId) => {
setLogoAccepted(true);
onApplyLogo?.(mediaId);
Expand All @@ -177,24 +193,21 @@ export const GeneratorModal = ({ isOpen, onClose, onApplyLogo, onReload, siteDet
// Handles modal opening logic
useEffect(() => {
// While the modal is not open, the siteId is not set, or the feature data is not available, do nothing.
if (!isOpen || !siteId || !feature?.costs) {
if (!isOpen) {
return;
}
// Prevent multiple calls of the handleModalOpen function
if (needsToHandleModalOpen.current) {
needsToHandleModalOpen.current = false;
handleModalOpen();
}
}, [isOpen, siteId, handleModalOpen, feature]);
}, [isOpen, handleModalOpen]);
let body;
if (loadingState) {
body = _jsx(FirstLoadScreen, { state: loadingState });
}
else if (featureFetchError || firstLogoPromptFetchError) {
body = (_jsx(FeatureFetchFailureScreen, { onCancel: closeModal, onRetry: () => {
closeModal();
onReload?.();
} }));
body = (_jsx(FeatureFetchFailureScreen, { onCancel: closeModal, onRetry: onReload ? handleReload : null }));
}
else if (needsFeature || needsMoreRequests) {
body = (_jsx(UpgradeScreen, { onCancel: closeModal, upgradeURL: upgradeURL, reason: needsFeature ? 'feature' : 'requests' }));
Expand Down
2 changes: 1 addition & 1 deletion build/ai-client/src/logo-generator/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface GeneratorModalProps {
isOpen: boolean;
onClose: () => void;
onApplyLogo: (mediaId: number) => void;
onReload: () => void;
onReload?: () => void;
context: string;
placement: string;
}
Expand Down
19 changes: 14 additions & 5 deletions src/logo-generator/components/feature-fetch-failure-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,34 @@ import type React from 'react';

export const FeatureFetchFailureScreen: React.FC< {
onCancel: () => void;
onRetry: () => void;
onRetry?: () => void;
} > = ( { onCancel, onRetry } ) => {
const errorMessage = __(
'We are sorry. There was an error loading your Jetpack AI plan data. Please, try again.',
'jetpack-ai-client'
);

const errorMessageWithoutRetry = __(
'We are sorry. There was an error loading your Jetpack AI plan data. Please, reload the page and try again.',
'jetpack-ai-client'
);

return (
<div className="jetpack-ai-logo-generator-modal__notice-message-wrapper">
<div className="jetpack-ai-logo-generator-modal__notice-message">
<span className="jetpack-ai-logo-generator-modal__loading-message">{ errorMessage }</span>
<span className="jetpack-ai-logo-generator-modal__loading-message">
{ onRetry ? errorMessage : errorMessageWithoutRetry }
</span>
</div>
<div className="jetpack-ai-logo-generator-modal__notice-actions">
<Button variant="tertiary" onClick={ onCancel }>
{ __( 'Cancel', 'jetpack-ai-client' ) }
</Button>
<Button variant="primary" onClick={ onRetry }>
{ __( 'Try again', 'jetpack-ai-client' ) }
</Button>
{ onRetry && (
<Button variant="primary" onClick={ onRetry }>
{ __( 'Try again', 'jetpack-ai-client' ) }
</Button>
) }
</div>
</div>
);
Expand Down
33 changes: 25 additions & 8 deletions src/logo-generator/components/generator-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
isOpen,
onClose,
onApplyLogo,
onReload,
onReload = null,
siteDetails,
context,
placement,
Expand Down Expand Up @@ -73,7 +73,8 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
site,
requireUpgrade,
} = useLogoGenerator();
const { featureFetchError, firstLogoPromptFetchError, clearErrors } = useRequestErrors();
const { featureFetchError, setFeatureFetchError, firstLogoPromptFetchError, clearErrors } =
useRequestErrors();
const siteId = siteDetails?.ID;
const [ logoAccepted, setLogoAccepted ] = useState( false );
const { nextTierCheckoutURL: upgradeURL } = useCheckout();
Expand Down Expand Up @@ -105,6 +106,15 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
*/
const initializeModal = useCallback( async () => {
try {
if ( ! siteId ) {
throw new Error( 'Site ID is missing' );
}

if ( ! feature?.featuresControl?.[ 'logo-generator' ]?.enabled ) {
setFeatureFetchError( 'Failed to fetch feature data' );
throw new Error( 'Failed to fetch feature data' );
}

const hasHistory = ! isLogoHistoryEmpty( String( siteId ) );

const logoCost = feature?.costs?.[ 'jetpack-ai-logo-generator' ]?.logo ?? DEFAULT_LOGO_COST;
Expand Down Expand Up @@ -179,6 +189,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
isLogoHistoryEmpty,
siteId,
requireUpgrade,
setFeatureFetchError,
] );

const handleModalOpen = useCallback( async () => {
Expand All @@ -201,6 +212,15 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
recordTracksEvent( EVENT_MODAL_CLOSE, { context, placement } );
};

const handleReload = useCallback( () => {
if ( ! onReload ) {
return;
}
closeModal();
requestedFeatureData.current = false;
onReload();
}, [ onReload, closeModal ] );

const handleApplyLogo = ( mediaId: number ) => {
setLogoAccepted( true );
onApplyLogo?.( mediaId );
Expand Down Expand Up @@ -229,7 +249,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
// Handles modal opening logic
useEffect( () => {
// While the modal is not open, the siteId is not set, or the feature data is not available, do nothing.
if ( ! isOpen || ! siteId || ! feature?.costs ) {
if ( ! isOpen ) {
return;
}

Expand All @@ -238,7 +258,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
needsToHandleModalOpen.current = false;
handleModalOpen();
}
}, [ isOpen, siteId, handleModalOpen, feature ] );
}, [ isOpen, handleModalOpen ] );

let body: React.ReactNode;

Expand All @@ -248,10 +268,7 @@ export const GeneratorModal: React.FC< GeneratorModalProps > = ( {
body = (
<FeatureFetchFailureScreen
onCancel={ closeModal }
onRetry={ () => {
closeModal();
onReload?.();
} }
onRetry={ onReload ? handleReload : null }
/>
);
} else if ( needsFeature || needsMoreRequests ) {
Expand Down
2 changes: 1 addition & 1 deletion src/logo-generator/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export interface GeneratorModalProps {
isOpen: boolean;
onClose: () => void;
onApplyLogo: ( mediaId: number ) => void;
onReload: () => void;
onReload?: () => void;
context: string;
placement: string;
}
Expand Down

0 comments on commit d94d3eb

Please sign in to comment.