Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/fix-assessments' into 16…
Browse files Browse the repository at this point in the history
…22-ai-assessment-lock-icon
  • Loading branch information
mykola committed Jun 25, 2024
2 parents 0e1ea2a + bf40f17 commit 6608c2d
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Paper } from "yoastseo";
/* Internal dependencies */
import { ModalContent } from "./modal-content";
import { SparklesIcon } from "./sparkles-icon";
import { getAllBlocks } from "../../helpers/getAllBlocks";
import { ReactComponent as LockClosed } from "../../../images/lock-closed.svg";

/**
Expand All @@ -32,6 +33,17 @@ const AIAssessmentFixesButton = ( { id, isPremium } ) => {
const focusElementRef = useRef( null );
const [ buttonClass, setButtonClass ] = useState( "" );

// Only enable the button when the editor is in visual mode and all blocks are in visual mode.
const isEnabled = useSelect( ( select ) => {
const editorMode = select( "core/edit-post" ).getEditorMode();
if ( editorMode !== "visual" ) {
return false;
}

const blocks = getAllBlocks( select( "core/block-editor" ).getBlocks() );
return blocks.every( block => select( "core/block-editor" ).getBlockMode( block.clientId ) === "visual" );
}, [] );

/**
* Handles the button press state.
* @returns {void}
Expand Down Expand Up @@ -96,6 +108,7 @@ const AIAssessmentFixesButton = ( { id, isPremium } ) => {
id={ aiFixesId }
className={ `ai-button ${buttonClass}` }
pressed={ isButtonPressed }
disabled={ ! isEnabled }
>
{ ! isPremium && <LockClosed className="yst-fixes-button__lock-icon" /> }
<SparklesIcon pressed={ isButtonPressed } gradientId={ gradientId } />
Expand Down
16 changes: 16 additions & 0 deletions packages/js/src/helpers/getAllBlocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Returns all Gutenberg blocks given the (current) top-level blocks.
* @param {object[]} blocks The (current) top-level blocks.
* @returns {object[]} All blocks.
*/
export const getAllBlocks = ( blocks ) => {
let allBlocks = [ ...blocks ];

blocks.forEach( block => {
if ( block.innerBlocks && block.innerBlocks.length > 0 ) {
allBlocks = [ ...allBlocks, ...getAllBlocks( block.innerBlocks ) ];
}
} );

return allBlocks;
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ jest.mock( "@wordpress/data", () => {
/**
* Mock the useSelect function.
* @param {string} activeAIButton The active AI button ID.
* @param {string} editorMode The editor mode.
* @param {object[]} blocks The blocks.
* @returns {function} The mock.
*/
const mockSelect = ( activeAIButton ) => useSelect.mockImplementation( select => select( () => ( {
getActiveAIFixesButton: () => activeAIButton,
getActiveMarker: () => null,
} ) ) );
const mockSelect = ( activeAIButton, editorMode = "visual", blocks = [] ) =>
useSelect.mockImplementation( select => select( () => ( {
getActiveAIFixesButton: () => activeAIButton,
getActiveMarker: () => null,
getBlocks: () => blocks,
getBlockMode: ( clientId ) => clientId === "htmlTest" ? "html" : "visual",
getEditorMode: () => editorMode,
} ) ) );

describe( "AIAssessmentFixesButton", () => {
test( "should find the correct aria-label in the document", () => {
Expand Down Expand Up @@ -56,5 +62,28 @@ describe( "AIAssessmentFixesButton", () => {
const buttonWithTooltip = document.getElementsByClassName( "yoast-tooltip yoast-tooltip-w" );
expect( buttonWithTooltip ).toHaveLength( 0 );
} );

test( "should be enabled under the default circumstances", () => {
render( <AIAssessmentFixesButton id="keyphraseDensity" isPremium={ true } /> );
const button = screen.getByRole( "button" );
expect( button ).toBeInTheDocument();
expect( button.disabled ).toBeFalsy();
} );

test( "should be disabled in HTML editing mode", () => {
mockSelect( "keyphraseDensityAIFixes", "html", [ { clientId: "test" } ] );
render( <AIAssessmentFixesButton id="keyphraseDensity" isPremium={ true } /> );
const button = screen.getByRole( "button" );
expect( button ).toBeInTheDocument();
expect( button.disabled ).toBeTruthy();
} );

test( "should be disabled when one of the blocks is in HTML editing mode", () => {
mockSelect( "keyphraseDensityAIFixes", "visual", [ { clientId: "test" }, { clientId: "htmlTest" } ] );
render( <AIAssessmentFixesButton id="keyphraseDensity" isPremium={ true } /> );
const button = screen.getByRole( "button" );
expect( button ).toBeInTheDocument();
expect( button.disabled ).toBeTruthy();
} );
} );

18 changes: 18 additions & 0 deletions packages/js/tests/helpers/getAllBlocks.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { getAllBlocks } from "../../src/helpers/getAllBlocks";

describe( "getAllBlocks", () => {
it( "should return the same blocks when no inner blocks are defined", () => {
const blocks = [ { clientId: 1 }, { clientId: 2 }, { clientId: 3 } ];
const expected = [ 1, 2, 3 ];
expect( expected ).toEqual( getAllBlocks( blocks ).map( ( { clientId } ) => clientId ) );
} );

it( "should return all blocks when inner blocks are defined", () => {
const blocks = [
{ clientId: 1, innerBlocks: [ { clientId: 2 }, { clientId: 3, innerBlocks: [ { clientId: 4 } ] } ] },
{ clientId: 5, innerBlocks: [] },
];
const expected = [ 1, 2, 3, 4, 5 ];
expect( expected ).toEqual( getAllBlocks( blocks ).map( ( { clientId } ) => clientId ).sort() );
} );
} );
2 changes: 1 addition & 1 deletion packages/ui-library/src/components/notifications/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Notification.propTypes = {
title: PropTypes.string,
description: PropTypes.oneOfType( [ PropTypes.node, PropTypes.arrayOf( PropTypes.node ) ] ),
onDismiss: PropTypes.func,
autoDismiss: PropTypes.oneOfType( [ PropTypes.number, null ] ),
autoDismiss: PropTypes.number,
dismissScreenReaderLabel: PropTypes.string.isRequired,
};

Expand Down
2 changes: 1 addition & 1 deletion packages/ui-library/src/elements/toast/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Toast.propTypes = {
className: PropTypes.string,
position: PropTypes.string,
onDismiss: PropTypes.func,
autoDismiss: PropTypes.oneOfType( [ PropTypes.number, null ] ),
autoDismiss: PropTypes.number,
isVisible: PropTypes.bool.isRequired,
setIsVisible: PropTypes.func.isRequired,
};
Expand Down

0 comments on commit 6608c2d

Please sign in to comment.