diff --git a/packages/js/src/ai-consent/components/revoke-consent.js b/packages/js/src/ai-consent/components/revoke-consent.js
index a6e77330cae..140022c5f1c 100644
--- a/packages/js/src/ai-consent/components/revoke-consent.js
+++ b/packages/js/src/ai-consent/components/revoke-consent.js
@@ -14,26 +14,22 @@ import { STORE_NAME_AI_CONSENT } from "../constants";
* @returns {JSX.Element} The element.
*/
export const RevokeConsent = ( { onClose } ) => {
- const { storeAiGeneratorConsent } = useDispatch( STORE_NAME_AI_CONSENT );
+ const { storeAiGeneratorConsent, giveAiGeneratorConsent } = useDispatch( STORE_NAME_AI_CONSENT );
const endpoint = useSelect( select => select( STORE_NAME_AI_CONSENT ).selectAiGeneratorConsentEndpoint(), [] );
const [ isLoading, setIsLoading ] = useState( false );
- const [ error, setError ] = useState( false );
const handleRevokeConsent = useCallback( async() => {
- setError( false );
setIsLoading( true );
- const response = await storeAiGeneratorConsent( false, endpoint );
- if ( response.consent === false ) {
- setError( true );
- setIsLoading( false );
- return;
- }
+ await storeAiGeneratorConsent( false, endpoint );
+ // The backend always revokes consent locally, even when the remote call fails, so the
+ // local store must reflect that regardless of the request's outcome.
+ giveAiGeneratorConsent( false );
onClose();
setIsLoading( false );
- }, [ storeAiGeneratorConsent, setIsLoading, onClose, endpoint ] );
+ }, [ storeAiGeneratorConsent, giveAiGeneratorConsent, setIsLoading, onClose, endpoint ] );
return (
@@ -52,12 +48,6 @@ export const RevokeConsent = ( { onClose } ) => {
>
{ __( "Revoke AI consent", "wordpress-seo" ) }
- { error &&
- { __( "Something went wrong, please try again later.", "wordpress-seo" ) }
- }
{ }
{ __( "By revoking your consent, you will no longer have access to Yoast AI features. Are you sure you want to revoke your consent?", "wordpress-seo" ) }
diff --git a/packages/js/src/ai-consent/initialize.js b/packages/js/src/ai-consent/initialize.js
index ffd64adbc77..93d4bd6a83e 100644
--- a/packages/js/src/ai-consent/initialize.js
+++ b/packages/js/src/ai-consent/initialize.js
@@ -5,7 +5,7 @@ import { __ } from "@wordpress/i18n";
import { Modal, useToggleState } from "@yoast/ui-library";
import classNames from "classnames";
import { get } from "lodash";
-import { HAS_AI_GENERATOR_CONSENT_NAME, PLUGIN_URL_NAME, LINK_PARAMS_NAME } from "../shared-admin/store";
+import { ADMIN_URL_NAME, HAS_AI_GENERATOR_CONSENT_NAME, PLUGIN_URL_NAME, LINK_PARAMS_NAME } from "../shared-admin/store";
import { GrantConsent } from "./components/grant-consent";
import { RevokeConsent } from "./components/revoke-consent";
import { STORE_NAME_AI_CONSENT } from "./constants";
@@ -19,6 +19,7 @@ domReady( () => {
},
[ PLUGIN_URL_NAME ]: get( window, "wpseoAiConsent.pluginUrl", "" ),
[ LINK_PARAMS_NAME ]: get( window, "wpseoAiConsent.linkParams", {} ),
+ [ ADMIN_URL_NAME ]: get( window, "wpseoAiConsent.adminUrl", "" ),
} );
/**
diff --git a/packages/js/src/ai-consent/store/index.js b/packages/js/src/ai-consent/store/index.js
index 735aae4382a..f39692cde85 100644
--- a/packages/js/src/ai-consent/store/index.js
+++ b/packages/js/src/ai-consent/store/index.js
@@ -1,6 +1,11 @@
import { combineReducers, createReduxStore, register } from "@wordpress/data";
import { merge } from "lodash";
import {
+ ADMIN_URL_NAME,
+ adminUrlActions,
+ adminUrlReducer,
+ adminUrlSelectors,
+ getInitialAdminUrlState,
getInitialHasAiGeneratorConsentState,
getInitialLinkParamsState,
getInitialPluginUrlState,
@@ -32,11 +37,13 @@ const createStore = ( initialState ) => {
...hasAiGeneratorConsentActions,
...pluginUrlActions,
...linkParamsActions,
+ ...adminUrlActions,
},
selectors: {
...hasAiGeneratorConsentSelectors,
...pluginUrlSelectors,
...linkParamsSelectors,
+ ...adminUrlSelectors,
},
initialState: merge(
{},
@@ -44,6 +51,7 @@ const createStore = ( initialState ) => {
[ HAS_AI_GENERATOR_CONSENT_NAME ]: getInitialHasAiGeneratorConsentState(),
[ PLUGIN_URL_NAME ]: getInitialPluginUrlState(),
[ LINK_PARAMS_NAME ]: getInitialLinkParamsState(),
+ [ ADMIN_URL_NAME ]: getInitialAdminUrlState(),
},
initialState
),
@@ -51,6 +59,7 @@ const createStore = ( initialState ) => {
[ HAS_AI_GENERATOR_CONSENT_NAME ]: hasAiGeneratorConsentReducer,
[ PLUGIN_URL_NAME ]: pluginUrlReducer,
[ LINK_PARAMS_NAME ]: linkParamsReducer,
+ [ ADMIN_URL_NAME ]: adminUrlReducer,
} ),
controls: {
...hasAiGeneratorConsentControls,
diff --git a/packages/js/src/ai-generator/components/errors/generic-alert.js b/packages/js/src/ai-generator/components/errors/generic-alert.js
index f687ab4c0c3..67619cbe23e 100644
--- a/packages/js/src/ai-generator/components/errors/generic-alert.js
+++ b/packages/js/src/ai-generator/components/errors/generic-alert.js
@@ -1,16 +1,22 @@
import { useSelect } from "@wordpress/data";
import { __, sprintf } from "@wordpress/i18n";
import { Alert } from "@yoast/ui-library";
+import PropTypes from "prop-types";
import { safeCreateInterpolateElement } from "../../../helpers/i18n";
import { OutboundLink } from "../../../shared-admin/components";
import { STORE_NAME_EDITOR } from "../../constants";
/**
+ * @param {string} [linkStoreName] The store to read the common-errors and support links from.
+ * Defaults to the block editor's store; pass a different store
+ * name when rendering outside the block editor (e.g. the AI
+ * consent screen on the user profile page).
+ *
* @returns {JSX.Element} The element.
*/
-export const GenericAlert = () => {
- const commonErrorsLink = useSelect( select => select( STORE_NAME_EDITOR ).selectLink( "https://yoa.st/ai-common-errors" ), [] );
- const supportLink = useSelect( select => select( STORE_NAME_EDITOR ).selectAdminLink( "?page=wpseo_page_support" ), [] );
+export const GenericAlert = ( { linkStoreName = STORE_NAME_EDITOR } ) => {
+ const commonErrorsLink = useSelect( select => select( linkStoreName ).selectLink( "https://yoa.st/ai-common-errors" ), [ linkStoreName ] );
+ const supportLink = useSelect( select => select( linkStoreName ).selectAdminLink( "?page=wpseo_page_support" ), [ linkStoreName ] );
return (
@@ -35,3 +41,6 @@ export const GenericAlert = () => {
);
};
+GenericAlert.propTypes = {
+ linkStoreName: PropTypes.string,
+};
diff --git a/packages/js/src/shared-admin/components/ai-consent.js b/packages/js/src/shared-admin/components/ai-consent.js
index dcd2843980f..f7f411d310b 100644
--- a/packages/js/src/shared-admin/components/ai-consent.js
+++ b/packages/js/src/shared-admin/components/ai-consent.js
@@ -1,6 +1,7 @@
import ArrowNarrowRightIcon from "@heroicons/react/solid/ArrowNarrowRightIcon";
-import { useMemo, useCallback } from "@wordpress/element";
+import { useMemo, useCallback, useState } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
+import { GenericAlert } from "../../ai-generator/components/errors";
import { Button, useModalContext, useToggleState, Spinner } from "@yoast/ui-library";
import PropTypes from "prop-types";
import { OutboundLink } from ".";
@@ -14,6 +15,7 @@ import { safeCreateInterpolateElement } from "../../helpers/i18n";
* @param {string} privacyPolicyLink The privacy policy link.
* @param {string} termsOfServiceLink The terms of service link.
* @param {Object} imageLink The thumbnail: img props.
+ * @param {string} linkStoreName The store to read the error alert's links from.
*
* @returns {JSX.Element} The element.
*/
@@ -23,9 +25,11 @@ export const AiConsent = ( {
privacyPolicyLink,
termsOfServiceLink,
imageLink,
+ linkStoreName,
} ) => {
const { onClose, initialFocus } = useModalContext();
const [ consent, toggleConsent ] = useToggleState( false );
+ const [ error, setError ] = useState( false );
const thumbnail = useMemo( () => ( {
src: imageLink,
@@ -55,7 +59,10 @@ export const AiConsent = ( {
const [ loading, toggleLoading ] = useToggleState( false );
const handleConsentChange = useCallback( async() => {
toggleLoading();
- await onGiveConsent();
+
+ const response = await onGiveConsent();
+ setError( response === false );
+
toggleLoading();
}, [ onGiveConsent ] );
@@ -128,15 +135,18 @@ export const AiConsent = ( {
{ checkboxLabel }
+ { error &&
+
+ }