Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions css/src/icons.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions css/src/introductions.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
.yst-introduction-gradient {
background: linear-gradient(180deg, rgba(166, 30, 105, 0.25) 10%, rgba(255, 255, 255, 0) 80%);
}

.yst-woo-introduction-gradient {
background: linear-gradient(180deg, rgba(0, 117, 179, 0.25) 10%, rgba(255, 255, 255, 0) 80%);
}
.yst-introduction-modal-uppercase {
letter-spacing: 0.8px;
@apply yst-uppercase yst-text-slate-500;
Expand All @@ -28,6 +32,18 @@
height: 17px;
}

.yst-cart-icon {
background-color: #0075B3;
mask-image: var(--yoast-svg-icon-cart);
-webkit-mask-image: var(--yoast-svg-icon-cart);
mask-size: 100% 100%;
-webkit-mask-size: 100% 100%;
width: 16px;
height: 16px;
transform: scaleX(-1);
-webkit-transform: scaleX(-1);
}

.yst-ai-insights-icon {
background-image: linear-gradient(97deg, #A61E69 0%, #6366F1 100%) !important;
mask-image: var(--yoast-svg-icon-yoast-insight-sparkle);
Expand Down
28 changes: 0 additions & 28 deletions packages/js/src/introductions/components/content.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/js/src/introductions/components/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export { Content } from "./content";
export { Introduction } from "./introduction";
export { Modal } from "./modal";
export { IntroductionProvider, useIntroductionsContext } from "./provider";
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { Button, useModalContext } from "@yoast/ui-library";
import PropTypes from "prop-types";
import { SparklesIcon } from "@heroicons/react/outline";
import { STORE_NAME_INTRODUCTIONS } from "../../constants";
import { Modal } from "../modal";

/**
* @param {Object} thumbnail The thumbnail: img props.
Expand All @@ -12,7 +15,7 @@ import { SparklesIcon } from "@heroicons/react/outline";
* @param {string} ctbId The click to buy to register for this upsell instance.
* @returns {JSX.Element} The element.
*/
export const AiBrandInsightsPreLaunch = ( {
const AiBrandInsightsPreLaunchContent = ( {
thumbnail,
buttonLink,
buttonLabel = __( "Join the waitlist", "wordpress-seo" ),
Expand Down Expand Up @@ -84,15 +87,26 @@ export const AiBrandInsightsPreLaunch = ( {
</>
);
};
AiBrandInsightsPreLaunch.propTypes = {
buttonLink: PropTypes.string.isRequired,
thumbnail: PropTypes.shape( {
src: PropTypes.string.isRequired,
width: PropTypes.string,
height: PropTypes.string,
} ).isRequired,
buttonLabel: PropTypes.string,
productName: PropTypes.string,
description: PropTypes.string,
ctbId: PropTypes.string,

/**
* @returns {JSX.Element} The element.
*/
export const AiBrandInsightsPreLaunch = () => {
const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.png" ), [] );
const joinWishlistLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/ai-brand-insights-introduction-pre-launch/" ), [] );

const thumbnail = useMemo( () => ( {
src: imageLink,
width: "432",
height: "243",
} ), [ imageLink ] );

return (
<Modal>
<AiBrandInsightsPreLaunchContent
buttonLink={ joinWishlistLink }
thumbnail={ thumbnail }
/>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";
import { Button, useModalContext } from "@yoast/ui-library";
import { LockOpenIcon } from "@heroicons/react/outline";
import { STORE_NAME_INTRODUCTIONS } from "../../constants";
import { Modal } from "../modal";
import { get } from "lodash";

/**
* @param {Object} thumbnail The thumbnail: img props.
* @param {string} buttonLink The button link.
* @param {Boolean} isWooEnabled Whether WooCommerce is enabled.
* @returns {JSX.Element} The element.
*/
const BlackFridayAnnouncementContent = ( {
thumbnail,
buttonLink,
isWooEnabled,
} ) => {
const { onClose, initialFocus } = useModalContext();

const productName = useMemo( () => {
return isWooEnabled ? "Yoast WooCommerce SEO" : "Yoast SEO Premium";
}, [ isWooEnabled ] );

const buttonLabel = useMemo( () => {
const product = isWooEnabled ? "WooCommerce SEO" : "Premium";

return sprintf(
/* translators: %1$s expands to either Premium or WooCommerce SEO. */
__( "Get %1$s with 30%% off", "wordpress-seo" ),
product
);
}, [ isWooEnabled ] );

const iconClass = useMemo( () => {
return isWooEnabled ? "yst-cart-icon" : "yst-logo-icon";
}, [ isWooEnabled ] );

const introductionClass = useMemo( () => {
return isWooEnabled ? "yst-woo-introduction-gradient" : "yst-introduction-gradient";
}, [ isWooEnabled ] );

const ctb = useMemo( () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const ctb = useMemo( () => {
const ctbId = useMemo( () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here.

return isWooEnabled ? "c7e7baa1-2020-420c-a427-89701700b607" : "f6a84663-465f-4cb5-8ba5-f7a6d72224b2";
}, [ isWooEnabled ] );

const description = useMemo( () => {
/* eslint-disable stylistic/max-len */
return isWooEnabled
? sprintf(
/* translators: %1$s expands to Premium, %2$s expands to Local, %3$s expands to News, %4$s expands to Video SEO, %5$s expands to Google. */
__( "We added even more value than ever this year: %1$s, %2$s, %3$s, %4$s, and seamless %5$s Docs add-on, all included. If you've been waiting to upgrade, now’s the time..", "wordpress-seo" ),
"Premium",
"Local",
"News",
"Video SEO",
"Google"
)
: sprintf(
/* translators: %1$s expands to Local, %2$s expands to News, %3$s expands to Video SEO, %4$s expands to Google. */
__( "We added even more value than ever this year: %1$s, %2$s, %3$s, and seamless %4$s Docs add-on, all included. If you've been waiting to upgrade, now’s the time.", "wordpress-seo" ),
"Local",
"News",
"Video SEO",
"Google"
);
/* eslint-enable stylistic/max-len */
}, [ isWooEnabled ] );

return (
<>
<div className={ `yst-px-10 yst-pt-10 yst-text-center ${introductionClass}` }>
<img
className="yst-w-full yst-h-auto yst-rounded-md yst-drop-shadow-md"
alt={ __( "Thumbnail for the Black Friday announcement", "wordpress-seo" ) }
loading="lazy"
decoding="async"
{ ...thumbnail }
/>
<div className="yst-mt-6 yst-text-xs yst-font-medium yst-flex yst-flex-col yst-items-center">
<span className="yst-introduction-modal-uppercase yst-flex yst-gap-2 yst-items-center">
<span className={ iconClass } />
{ productName }
</span>
</div>
</div>
<div className="yst-px-10 yst-pb-4 yst-flex yst-flex-col yst-items-center">
<div className="yst-mt-4 yst-mx-1.5 yst-text-center">
<h3 className="yst-text-slate-900 yst-text-lg yst-font-medium">
{
__( "Black Friday: Our biggest sale just dropped!", "wordpress-seo" )
}
</h3>
<div className="yst-mt-2 yst-text-slate-600 yst-text-sm">
<p>{ description }</p>
</div>
</div>
<div className="yst-w-full yst-flex yst-mt-6">
<Button
as="a"
className="yst-grow yst-border-slate-200"
size="extra-large"
variant="upsell"
href={ buttonLink }
target="_blank"
ref={ initialFocus }
data-action="load-nfd-ctb"
data-ctb-id={ ctb }
>
<LockOpenIcon className="yst--ms-1 yst-me-2 yst-h-5 yst-w-5" />
{ buttonLabel }
<span className="yst-sr-only">
{
/* translators: Hidden accessibility text. */
__( "(Opens in a new browser tab)", "wordpress-seo" )
}
</span>
</Button>
</div>
<Button
className="yst-mt-2"
variant="tertiary"
onClick={ onClose }
>
{ __( "Close", "wordpress-seo" ) }
</Button>
</div>
</>
);
};

/**
* @returns {JSX.Element} The element.
*/
export const BlackFridayAnnouncement = () => {
const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "ai-brand-insights-pre-launch.png" ), [] );
const isWooEnabled = useMemo( () => Boolean( get( window, "wpseoIntroductions.isWooEnabled", false ) ), [] );
const buttonPremiumLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/black-friday-modal-premium/" ), [] );
const buttonWooLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/black-friday-modal-ecommerce/" ), [] );

const thumbnail = useMemo( () => ( {
src: imageLink,
width: "432",
height: "243",
} ), [ imageLink ] );

return (
<Modal>
<BlackFridayAnnouncementContent
buttonLink={ isWooEnabled ? buttonWooLink : buttonPremiumLink }
thumbnail={ thumbnail }
isWooEnabled={ isWooEnabled }
/>
</Modal>
);
};
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { LockOpenIcon } from "@heroicons/react/outline";
import { __, sprintf } from "@wordpress/i18n";
import { Button, useModalContext } from "@yoast/ui-library";
import PropTypes from "prop-types";
import { STORE_NAME_INTRODUCTIONS } from "../../constants";
import { Modal } from "../modal";
import { get } from "lodash";

/**
* @param {Object} thumbnail The thumbnail: img props.
* @param {string} buttonLink The button link.
* @param {string} buttonLabel The button label.
* @param {string} productName The product name.
* @param {string} freeCopy The copy for the free version.
* @param {string} premiumCopy The copy for the premium version.
* @param {boolean} isPremium Whether the user has a premium license.
* @param {string} ctbId The click to buy to register for this upsell instance.
* @returns {JSX.Element} The element.
*/
// eslint-disable-next-line complexity
export const GoogleDocsAddonUpsell = ( {
const GoogleDocsAddonUpsellContent = ( {
thumbnail,
buttonLink,
buttonLabel = sprintf(
Expand Down Expand Up @@ -125,15 +121,43 @@ export const GoogleDocsAddonUpsell = ( {
</>
);
};
GoogleDocsAddonUpsell.propTypes = {
buttonLink: PropTypes.string.isRequired,
thumbnail: PropTypes.shape( {
src: PropTypes.string.isRequired,
width: PropTypes.string,
height: PropTypes.string,
} ).isRequired,
buttonLabel: PropTypes.string,
productName: PropTypes.string,
isPremium: PropTypes.bool,
ctbId: PropTypes.string,

/**
* @returns {JSX.Element} The element.
*/
export const GoogleDocsAddonUpsell = () => {
const imageLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectImageLink( "google-docs-addon-thumbnail.png" ), [] );
const isPremium = useMemo( () => Boolean( get( window, "wpseoIntroductions.isPremium", false ) ), [] );
const upsellLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/google-docs-add-on-introduction-upsell/" ), [] );
const premiumLink = useSelect( select => select( STORE_NAME_INTRODUCTIONS ).selectLink( "https://yoa.st/google-docs-add-on-introduction-get-started/" ), [] );

const thumbnail = useMemo( () => ( {
src: imageLink,
width: "432",
height: "243",
} ), [ imageLink ] );

const buttonLabel = useMemo( () => {
if ( isPremium ) {
return __( "Activate your free seat", "wordpress-seo" );
}

return sprintf(
/* translators: %1$s expands to Yoast SEO Premium. */
__( "Unlock with %1$s", "wordpress-seo" ),
"Yoast SEO Premium"
);
}
, [ isPremium ] );

return (
<Modal>
<GoogleDocsAddonUpsellContent
buttonLink={ isPremium ? premiumLink : upsellLink }
thumbnail={ thumbnail }
buttonLabel={ buttonLabel }
isPremium={ isPremium }
/>
</Modal>
);
};
7 changes: 5 additions & 2 deletions packages/js/src/introductions/initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { createRoot } from "@wordpress/element";
import { Root } from "@yoast/ui-library";
import { get, isEmpty, find } from "lodash";
import { LINK_PARAMS_NAME, PLUGIN_URL_NAME, WISTIA_EMBED_PERMISSION_NAME } from "../shared-admin/store";
import { Content, Introduction, IntroductionProvider } from "./components";
import { Introduction, IntroductionProvider } from "./components";
import { AiBrandInsightsPreLaunch } from "./components/modals/ai-brand-insights-pre-launch";
import { BlackFridayAnnouncement } from "./components/modals/black-friday-announcement";
import { STORE_NAME_INTRODUCTIONS } from "./constants";
import { registerStore } from "./store";

Expand All @@ -19,7 +21,8 @@ domReady( () => {
}

const initialComponents = {
"ai-brand-insights-pre-launch": Content,
"ai-brand-insights-pre-launch": AiBrandInsightsPreLaunch,
"black-friday-announcement": BlackFridayAnnouncement,
};

if ( location.href.indexOf( "page=wpseo_dashboard#/first-time-configuration" ) !== -1 ) {
Expand Down
Loading