Handle CYS ai wizard API failures (#40430)

* Add error notice

* Handle api call loader errors

* Add docs

* Add changelog

* Fix untranslated text
This commit is contained in:
Chi-Hsuan Huang 2023-09-28 11:15:38 +08:00 committed by GitHub
parent 508b2d1615
commit 6d52afa5e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 28 deletions

View File

@ -196,6 +196,17 @@ const spawnSaveDescriptionToOption = assign<
),
} );
const assignAPICallLoaderError = assign<
designWithAiStateMachineContext,
designWithAiStateMachineEvents
>( {
apiCallLoader: () => {
return {
hasErrors: true,
};
},
} );
const logAIAPIRequestError = () => {
// log AI API request error
// eslint-disable-next-line no-console
@ -275,6 +286,7 @@ export const actions = {
assignHeader,
assignFooter,
assignHomepageTemplate,
assignAPICallLoaderError,
logAIAPIRequestError,
updateQueryStep,
recordTracksStepViewed,

View File

@ -1,10 +1,10 @@
/**
* External dependencies
*/
import { Button } from '@wordpress/components';
import { Button, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { ProgressBar } from '@woocommerce/components';
import { useState } from '@wordpress/element';
import { useState, createInterpolateElement } from '@wordpress/element';
/**
* Internal dependencies
@ -59,6 +59,14 @@ export const ToneOfVoice = ( {
? choices[ 0 ].key
: context.toneOfVoice.choice
);
const onContinue = () => {
sendEvent( {
type: 'TONE_OF_VOICE_COMPLETE',
payload: sound,
} );
};
return (
<div>
<ProgressBar
@ -82,6 +90,33 @@ export const ToneOfVoice = ( {
'woocommerce'
) }
</h1>
{ context.apiCallLoader.hasErrors && (
<Notice
className="woocommerce-cys-design-with-ai__error-notice"
isDismissible={ false }
status="error"
>
{ createInterpolateElement(
__(
'Oops! We encountered a problem while generating your store. <retryButton/>',
'woocommerce'
),
{
retryButton: (
<Button
onClick={ onContinue }
variant="tertiary"
>
{ __(
'Please try again',
'woocommerce'
) }
</Button>
),
}
) }
</Notice>
) }
<div className="choices">
{ choices.map( ( { title, subtitle, key } ) => {
return (
@ -99,16 +134,7 @@ export const ToneOfVoice = ( {
);
} ) }
</div>
<Button
variant="primary"
onClick={ () => {
sendEvent( {
type: 'TONE_OF_VOICE_COMPLETE',
payload: sound,
} );
} }
>
<Button variant="primary" onClick={ onContinue }>
{ __( 'Continue', 'woocommerce' ) }
</Button>
</div>

View File

@ -7,7 +7,7 @@ import { __experimentalRequestJetpackToken as requestJetpackToken } from '@wooco
import apiFetch from '@wordpress/api-fetch';
import { recordEvent } from '@woocommerce/tracks';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { Sender, assign, createMachine } from 'xstate';
import { Sender, assign, createMachine, actions } from 'xstate';
import { dispatch, resolveSelect } from '@wordpress/data';
// @ts-ignore No types for this exist yet.
import { store as coreStore } from '@wordpress/core-data';
@ -26,6 +26,8 @@ import {
} from '../assembler-hub/hooks/use-home-templates';
import { HOMEPAGE_TEMPLATES } from '../data/homepageTemplates';
const { escalate } = actions;
const browserPopstateHandler =
() => ( sendBack: Sender< { type: 'EXTERNAL_URL_UPDATE' } > ) => {
const popstateHandler = () => {
@ -163,7 +165,13 @@ export const queryAiEndpoint = createMachine(
always: [
{
cond: ( context ) => context.retryCount >= 3,
target: 'failed',
target: 'querying',
actions: [
// Throw an error to be caught by the parent machine.
escalate( () => ( {
data: 'Max retries exceeded',
} ) ),
],
},
{
target: 'querying',
@ -173,12 +181,6 @@ export const queryAiEndpoint = createMachine(
},
],
},
failed: {
type: 'final',
data: {
result: 'failed',
},
},
success: {
type: 'final',
data: ( context ) => {

View File

@ -75,10 +75,16 @@ export const designWithAiStateMachineDefinition = createMachine(
choice: '',
},
aiSuggestions: {
defaultColorPalette: {} as ColorPaletteResponse,
fontPairing: '' as FontPairing[ 'pair_name' ],
// Default color palette, font pairing are used as fallbacks when the AI endpoint fails.
defaultColorPalette: {
default: 'Ancient Bronze',
} as ColorPaletteResponse,
fontPairing: 'Rubik + Inter' as FontPairing[ 'pair_name' ],
homepageTemplate: '' as HomepageTemplate[ 'homepage_template' ],
},
apiCallLoader: {
hasErrors: false,
},
},
initial: 'navigate',
states: {
@ -307,6 +313,10 @@ export const designWithAiStateMachineDefinition = createMachine(
],
target: 'success',
},
// If there's an error we don't want to block the user from proceeding.
onError: {
target: 'success',
},
},
},
success: { type: 'final' },
@ -338,6 +348,10 @@ export const designWithAiStateMachineDefinition = createMachine(
],
target: 'success',
},
// If there's an error we don't want to block the user from proceeding.
onError: {
target: 'success',
},
},
},
success: { type: 'final' },
@ -369,6 +383,12 @@ export const designWithAiStateMachineDefinition = createMachine(
],
target: 'success',
},
onError: {
actions: [
'assignAPICallLoaderError',
],
target: '#toneOfVoice',
},
},
},
success: { type: 'final' },
@ -384,8 +404,10 @@ export const designWithAiStateMachineDefinition = createMachine(
target: 'success',
},
onError: {
// TODO: handle error
target: 'success',
actions: [
'assignAPICallLoaderError',
],
target: '#toneOfVoice',
},
},
},
@ -408,16 +430,16 @@ export const designWithAiStateMachineDefinition = createMachine(
target: 'done',
},
onError: {
target: 'failed',
actions: [
'assignAPICallLoaderError',
],
target: '#toneOfVoice',
},
},
},
done: {
type: 'final',
},
failed: {
type: 'final', // If there's an error we should not block the user from proceeding. They'll just not see the AI suggestions, but that's better than being stuck
},
},
},
saveAiResponse: {

View File

@ -30,6 +30,9 @@ export type designWithAiStateMachineContext = {
fontPairing: FontPairing[ 'pair_name' ];
homepageTemplate: HomepageTemplate[ 'homepage_template' ];
};
apiCallLoader: {
hasErrors: boolean;
};
// If we require more data from options, previously provided core profiler details,
// we can retrieve them in preBusinessInfoDescription and then assign them here
spawnSaveDescriptionToOptionRef?: ReturnType< typeof spawn >;

View File

@ -116,3 +116,25 @@ body.woocommerce-customize-store.js.is-fullscreen-mode {
gap: 16px;
}
}
.woocommerce-cys-design-with-ai__error-notice.is-error {
background: #fce2e4;
padding: $gap-small;
// gap: 12px;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 24px;
color: $gray-900;
margin: 0 0 60px;
width: 615px;
.components-notice__content {
margin: 0;
}
.components-button {
padding: 0;
height: initial;
}
}

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Handle CYS ai wizard API failures