Skip to content

Commit

Permalink
Merge pull request #21417 from Yoast/ai-fix-assesment-upsell-introduc…
Browse files Browse the repository at this point in the history
…tion-model

Ai fix assessment upsell introduction modal
  • Loading branch information
mhkuu authored Jun 5, 2024
2 parents c8ff595 + c9b6356 commit 3f99d27
Show file tree
Hide file tree
Showing 12 changed files with 501 additions and 79 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"Yoast\\WP\\SEO\\Composer\\Actions::check_coding_standards"
],
"check-cs-thresholds": [
"@putenv YOASTCS_THRESHOLD_ERRORS=2527",
"@putenv YOASTCS_THRESHOLD_ERRORS=2525",
"@putenv YOASTCS_THRESHOLD_WARNINGS=253",
"Yoast\\WP\\SEO\\Composer\\Actions::check_cs_thresholds"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Modal, useToggleState } from "@yoast/ui-library";
import { Paper } from "yoastseo";

/* Internal dependencies */
import { ModalContent } from "../../ai-generator/components/modal-content";
import { ModalContent } from "./modal-content";

/**
* The AI Assessment Fixes button component.
Expand Down
47 changes: 47 additions & 0 deletions packages/js/src/ai-assessment-fixes/components/modal-content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/* eslint-disable complexity */
import { useDispatch, useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { AiFixAssessmentsUpsell } from "../../shared-admin/components";
import { __, sprintf } from "@wordpress/i18n";

const STORE = "yoast-seo/editor";

/**
* @returns {JSX.Element} The element.
*/
export const ModalContent = () => {
const learnMoreLink = useSelect( select => select( STORE ).selectLink( "https://yoa.st/ai-fix-assessments-learn-more" ), [] );
const upsellLinkPremium = useSelect( select => select( STORE ).selectLink( "https://yoa.st/ai-fix-assessments-upsell" ), [] );

const postModalprops = {
upsellLink: upsellLinkPremium,
title: __( "Fix assessments with AI!", "wordpress-seo" ),
upsellLabel: sprintf(
/* translators: %1$s expands to Yoast SEO Premium. */
__( "Unlock with %1$s", "wordpress-seo" ),
"Yoast SEO Premium"
),
};

const imageLink = useSelect( select => select( STORE ).selectImageLink( "ai-generator-preview.png" ), [] );
const thumbnail = useMemo( () => ( {
src: imageLink,
width: "432",
height: "244",
} ), [ imageLink ] );

const value = useSelect( select => select( STORE ).selectWistiaEmbedPermissionValue(), [] );
const status = useSelect( select => select( STORE ).selectWistiaEmbedPermissionStatus(), [] );
const { setWistiaEmbedPermission: set } = useDispatch( STORE );
const wistiaEmbedPermission = useMemo( () => ( { value, status, set } ), [ value, status, set ] );


return (
<AiFixAssessmentsUpsell
learnMoreLink={ learnMoreLink }
thumbnail={ thumbnail }
wistiaEmbedPermission={ wistiaEmbedPermission }
{ ...postModalprops }
/>
);
};
8 changes: 4 additions & 4 deletions packages/js/src/introductions/components/content.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useDispatch, useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { AiGenerateTitlesAndDescriptionsUpsell } from "../../shared-admin/components";
import { AiFixAssessmentsUpsell } from "../../shared-admin/components";
import { STORE_NAME_INTRODUCTIONS } from "../constants";

/**
* @returns {JSX.Element} The element.
*/
export const Content = () => {
const learnMoreLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-generator-learn-more" ), [] );
const upsellLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-generator-upsell" ), [] );
const learnMoreLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-fix-assessments-upsell-learn-more" ), [] );
const upsellLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-fix-assessments-upsell" ), [] );

const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-generator-preview.png" ), [] );
const thumbnail = useMemo( () => ( {
Expand All @@ -23,7 +23,7 @@ export const Content = () => {
const wistiaEmbedPermission = useMemo( () => ( { value, status, set } ), [ value, status, set ] );

return (
<AiGenerateTitlesAndDescriptionsUpsell
<AiFixAssessmentsUpsell
learnMoreLink={ learnMoreLink }
upsellLink={ upsellLink }
thumbnail={ thumbnail }
Expand Down
2 changes: 1 addition & 1 deletion packages/js/src/introductions/initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ domReady( () => {
isRtl: Boolean( get( window, `${ DATA_NAME }.isRtl`, false ) ),
};
const initialComponents = {
"ai-generate-titles-and-descriptions-upsell": Content,
"ai-fix-assessments-upsell": Content,
};

const root = document.createElement( "div" );
Expand Down
144 changes: 144 additions & 0 deletions packages/js/src/shared-admin/components/ai-fix-assessments-upsell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { LockOpenIcon } from "@heroicons/react/outline";
import { ArrowNarrowRightIcon } from "@heroicons/react/solid";
import { createInterpolateElement } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { Badge, Button, useModalContext } from "@yoast/ui-library";
import PropTypes from "prop-types";
import { OutboundLink, VideoFlow } from ".";

/**
* @param {string} learnMoreLink The learn more link.
* @param {Object} thumbnail The thumbnail: img props.
* @param {Object} wistiaEmbedPermission The value, status and set for the Wistia embed permission.
* @param {string} upsellLink The upsell link.
* @param {string} title The title.
* @param {string} upsellLabel The upsell label.
* @param {string} newToText The new to text.
* @param {string|JSX.Element } bundleNote The bundle note.
* @returns {JSX.Element} The element.
*/
export const AiFixAssessmentsUpsell = ( {
learnMoreLink,
thumbnail,
wistiaEmbedPermission,
upsellLink,
title,
upsellLabel,
newToText,
bundleNote,
} ) => {
const { onClose, initialFocus } = useModalContext();

const learnMoreLinkStructure = {
// eslint-disable-next-line jsx-a11y/anchor-has-content
a: <OutboundLink
href={ learnMoreLink }
className="yst-inline-flex yst-items-center yst-gap-1 yst-no-underline yst-font-medium"
variant="primary"
/>,
ArrowNarrowRightIcon: <ArrowNarrowRightIcon className="yst-w-4 yst-h-4 rtl:yst-rotate-180" />,
};

return (
<div className="yst-flex yst-flex-col yst-items-center yst-p-10">
<div className="yst-relative yst-w-full">
<VideoFlow
videoId="vmrahpfjxp"
thumbnail={ thumbnail }
wistiaEmbedPermission={ wistiaEmbedPermission }
/>
<Badge className="yst-absolute yst-top-0 yst-right-2 yst-mt-2 yst-ml-2" variant="info">Beta</Badge>
</div>
<div className="yst-mt-6 yst-text-xs yst-font-medium">
<span className="yst-introduction-modal-uppercase">
{ newToText }
</span>
</div>
<div className="yst-mt-4 yst-mx-1.5 yst-text-center">
<h3 className="yst-text-slate-900 yst-text-lg yst-font-medium">
{ title }
</h3>
<div className="yst-mt-2 yst-text-slate-600 yst-text-sm">
{ createInterpolateElement(
sprintf(
/* translators: %1$s and %2$s are anchor tags; %3$s is the arrow icon. */
__(
"Let AI fix assessments. %1$sLearn more%2$s%3$s",
"wordpress-seo"
),
"<a>",
"<ArrowNarrowRightIcon />",
"</a>"
),
learnMoreLinkStructure
) }
</div>
</div>
<div className="yst-w-full yst-flex yst-mt-10">
<Button
as="a"
className="yst-grow"
size="extra-large"
variant="upsell"
href={ upsellLink }
target="_blank"
ref={ initialFocus }
>
<LockOpenIcon className="yst--ml-1 yst-mr-2 yst-h-5 yst-w-5" />
{ upsellLabel }
<span className="yst-sr-only">
{
/* translators: Hidden accessibility text. */
__( "(Opens in a new browser tab)", "wordpress-seo" )
}
</span>
</Button>
</div>
{ bundleNote }
<Button
as="a"
className="yst-mt-4"
variant="tertiary"
onClick={ onClose }
>
{ __( "Close", "wordpress-seo" ) }
</Button>
</div>
);
};
AiFixAssessmentsUpsell.propTypes = {
learnMoreLink: PropTypes.string.isRequired,
upsellLink: PropTypes.string.isRequired,
thumbnail: PropTypes.shape( {
src: PropTypes.string.isRequired,
width: PropTypes.string,
height: PropTypes.string,
} ).isRequired,
wistiaEmbedPermission: PropTypes.shape( {
value: PropTypes.bool.isRequired,
status: PropTypes.string.isRequired,
set: PropTypes.func.isRequired,
} ).isRequired,
title: PropTypes.string,
upsellLabel: PropTypes.string,
newToText: PropTypes.string,
bundleNote: PropTypes.oneOfType( [
PropTypes.string,
PropTypes.element,
] ),
};

AiFixAssessmentsUpsell.defaultProps = {
title: __( "Use AI to fix assessments!", "wordpress-seo" ),
upsellLabel: sprintf(
/* translators: %1$s expands to Yoast SEO Premium. */
__( "Unlock with %1$s", "wordpress-seo" ),
"Yoast SEO Premium"
),
newToText: sprintf(
/* translators: %1$s expands to Yoast SEO Premium. */
__( "New in %1$s", "wordpress-seo" ),
"Yoast SEO Premium"
),
bundleNote: "",
};
1 change: 1 addition & 0 deletions packages/js/src/shared-admin/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { OutboundLink } from "./outbound-link";
export { PremiumUpsellCard } from "./premium-upsell-card";
export { RecommendationsSidebar } from "./recommendations-sidebar";
export { VideoFlow } from "./video-flow";
export { AiFixAssessmentsUpsell } from "./ai-fix-assessments-upsell";
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`AiFixAssessmentsUpsell renders the component correctly 1`] = `
<div>
<div
class="yst-flex yst-flex-col yst-items-center yst-p-10"
>
<div
class="yst-relative yst-w-full"
>
<div
class="yst-relative yst-w-full yst-h-0 yst-pt-[56.25%] yst-overflow-hidden yst-rounded-md yst-drop-shadow-md yst-bg-white"
>
<div
class="yst-absolute yst-w-full yst-h-full yst-top-0 yst-left-0"
>
<div
class="wistia_embed wistia_async_vmrahpfjxp videoFoam=true"
/>
</div>
</div>
<span
class="yst-badge yst-badge--info yst-absolute yst-top-0 yst-right-2 yst-mt-2 yst-ml-2"
>
Beta
</span>
</div>
<div
class="yst-mt-6 yst-text-xs yst-font-medium"
>
<span
class="yst-introduction-modal-uppercase"
>
Test New To Text
</span>
</div>
<div
class="yst-mt-4 yst-mx-1.5 yst-text-center"
>
<h3
class="yst-text-slate-900 yst-text-lg yst-font-medium"
>
Test Title
</h3>
<div
class="yst-mt-2 yst-text-slate-600 yst-text-sm"
>
Let AI fix assessments.
<a
class="yst-link yst-link--primary yst-inline-flex yst-items-center yst-gap-1 yst-no-underline yst-font-medium"
href="https://example.com/learn-more"
rel="noopener noreferrer"
target="_blank"
>
Learn more
<svg
aria-hidden="true"
class="yst-w-4 yst-h-4 rtl:yst-rotate-180"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
clip-rule="evenodd"
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
fill-rule="evenodd"
/>
</svg>
<span
class="yst-sr-only"
>
(Opens in a new browser tab)
</span>
</a>
</div>
</div>
<div
class="yst-w-full yst-flex yst-mt-10"
>
<a
class="yst-button yst-button--upsell yst-button--extra-large yst-grow"
href="https://example.com/upsell"
target="_blank"
>
<svg
aria-hidden="true"
class="yst--ml-1 yst-mr-2 yst-h-5 yst-w-5"
fill="none"
stroke="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 11V7a4 4 0 118 0m-4 8v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2z"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
Test Upsell Label
<span
class="yst-sr-only"
>
(Opens in a new browser tab)
</span>
</a>
</div>
Test Bundle Note
<a
class="yst-button yst-button--tertiary yst-mt-4"
>
Close
</a>
</div>
</div>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { render } from "../../test-utils";
import { AiFixAssessmentsUpsell } from "../../../src/shared-admin/components/ai-fix-assessments-upsell";

describe( "AiFixAssessmentsUpsell", () => {
const props = {
learnMoreLink: "https://example.com/learn-more",
thumbnail: {
src: "thumbnail.jpg",
width: "100",
height: "100",
},
wistiaEmbedPermission: {
value: true,
status: "granted",
set: jest.fn(),
},
upsellLink: "https://example.com/upsell",
title: "Test Title",
upsellLabel: "Test Upsell Label",
newToText: "Test New To Text",
bundleNote: "Test Bundle Note",
};

it( "renders the component correctly", () => {
const { container } = render( <AiFixAssessmentsUpsell { ...props } /> );
expect( container ).toMatchSnapshot();
} );
} );
Loading

0 comments on commit 3f99d27

Please sign in to comment.