Skip to content

Commit

Permalink
Merge pull request #21978 from Yoast/402-implement-site-kit-setup-flow
Browse files Browse the repository at this point in the history
402 implement site kit setup flow
  • Loading branch information
enricobattocchi authored Feb 7, 2025
2 parents eda01ba + 8a8bf94 commit 0a28ab5
Show file tree
Hide file tree
Showing 22 changed files with 910 additions and 77 deletions.
90 changes: 90 additions & 0 deletions packages/js/images/yoast-connect-google-site-kit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions packages/js/src/dashboard/components/dashboard.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Scores } from "../scores/components/scores";
import { PageTitle } from "./page-title";
import { SiteKitSetupWidget } from "./site-kit-setup-widget";
import { get } from "lodash";
import { useCallback } from "@wordpress/element";
import { useToggleState } from "@yoast/ui-library";
import { useSelect } from "@wordpress/data";

/**
* @type {import("../index").ContentType} ContentType
Expand All @@ -15,12 +20,39 @@ import { PageTitle } from "./page-title";
* @param {Endpoints} endpoints The endpoints.
* @param {Object<string,string>} headers The headers for the score requests.
* @param {Links} links The links.
*
* @returns {JSX.Element} The element.
*/
// The complexity is cause by the google site kit feature flag which is temporary.
// eslint-disable-next-line complexity
export const Dashboard = ( { contentTypes, userName, features, endpoints, headers, links } ) => {
const siteKitConfiguration = get( window, "wpseoScriptData.dashboard.siteKitConfiguration", {
isInstalled: false,
isActive: false,
isSetupCompleted: false,
isConnected: false,
installUrl: "",
activateUrl: "",
setupUrl: "",
isFeatureEnabled: false,
} );
const [ showGoogleSiteKit, , , , setRemoveGoogleSiteKit ] = useToggleState( true );
const learnMorelink = useSelect( select => select( "@yoast/general" ).selectLink( "https://yoa.st/google-site-kit-learn-more" ), [] );
const handleRemovePermanently = useCallback( ()=>{
/* eslint-disable-next-line */
// TODO: Implement the remove permanently functionality.
setRemoveGoogleSiteKit();
}, [ setRemoveGoogleSiteKit ] );

return (
<>
<PageTitle userName={ userName } features={ features } links={ links } />
{ showGoogleSiteKit && siteKitConfiguration.isFeatureEnabled && <SiteKitSetupWidget
{ ...siteKitConfiguration }
learnMoreLink={ learnMorelink }
onRemove={ setRemoveGoogleSiteKit }
onRemovePermanently={ handleRemovePermanently }
/> }
<div className="yst-flex yst-flex-col @7xl:yst-flex-row yst-gap-6 yst-my-6">
{ features.indexables && features.seoAnalysis && (
<Scores analysisType="seo" contentTypes={ contentTypes } endpoint={ endpoints.seoScores } headers={ headers } />
Expand Down
139 changes: 139 additions & 0 deletions packages/js/src/dashboard/components/site-kit-setup-widget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { Button, Paper, Stepper, Title, DropdownMenu } from "@yoast/ui-library";
import { ReactComponent as YoastConnectSiteKit } from "../../../images/yoast-connect-google-site-kit.svg";
import { __ } from "@wordpress/i18n";
import { CheckCircleIcon } from "@heroicons/react/solid";
import { ArrowRightIcon, XIcon, TrashIcon } from "@heroicons/react/outline";

const steps = [
__( "INSTALL", "wordpress-seo" ),
__( "ACTIVATE", "wordpress-seo" ),
__( "SET UP", "wordpress-seo" ),
__( "CONNECT", "wordpress-seo" ),
];

/**
* The google site kit connection guide widget.
*
* @param {boolean} isInstalled Whether the plugin is installed.
* @param {boolean} isActive Whether the feature is active.
* @param {boolean} isSetupCompleted Whether the setup is complete.
* @param {boolean} isConnected Whether the connection is active.
* @param {string} installUrl The URL to install Site Kit.
* @param {string} activateUrl The URL to activate Site Kit.
* @param {string} setupUrl The URL to setup Site Kit.
* @param {function} onRemove The function to call when the widget is removed.
* @param {function} onRemovePermanently The function to call when the widget is removed permanently.
* @param {string} learnMorelink The URL to learn more about the feature.
*
* @returns {JSX.Element} The widget.
*/
export const SiteKitSetupWidget = ( {
installUrl,
activateUrl,
setupUrl,
isConnected,
isActive,
isSetupCompleted,
isInstalled,
onRemove,
onRemovePermanently,
learnMorelink,
} ) => {
const stepsStatuses = [ isInstalled, isActive, isSetupCompleted, isConnected ];

let currentStep = stepsStatuses.findIndex( status => ! status );
const overAllCompleted = currentStep === -1;

if ( currentStep === -1 ) {
currentStep = steps.length - 1;
}

const buttonProps = [
{
children: __( "Install Site Kit by Google", "wordpress-seo" ),
href: installUrl,
as: "a",
},
{
children: __( "Activate Site Kit by Google", "wordpress-seo" ),
href: activateUrl,
as: "a",
},
{
children: __( "Set up Site Kit by Google", "wordpress-seo" ),
href: setupUrl,
as: "a",
},
{
children: __( "Connect Site Kit by Google", "wordpress-seo" ),
},
];

return <Paper className="yst-grow yst-max-w-screen-sm yst-p-8 yst-shadow-md yst-relative yst-mt-6">
<DropdownMenu as="span" className="yst-absolute yst-top-4 yst-end-4">
<DropdownMenu.IconTrigger screenReaderTriggerLabel={ __( "Open Site Kit widget dropdown menu", "wordpress-seo" ) } className="yst-float-end" />
<DropdownMenu.List className="yst-mt-6 yst-w-56">
<DropdownMenu.ButtonItem
className="yst-text-slate-600 yst-border-b yst-border-slate-200 yst-flex yst-py-2 yst-justify-start yst-gap-2 yst-px-4"
onClick={ onRemove }
>
<XIcon className="yst-w-4 yst-text-slate-400" />
{ __( "Remove until next visit", "wordpress-seo" ) }
</DropdownMenu.ButtonItem>
<DropdownMenu.ButtonItem
className="yst-text-red-500 yst-flex yst-py-2 yst-justify-start yst-gap-2 yst-px-4"
onClick={ onRemovePermanently }
>
<TrashIcon className="yst-w-4" />
{ __( "Remove permanently", "wordpress-seo" ) }
</DropdownMenu.ButtonItem>
</DropdownMenu.List>
</DropdownMenu>

<div className="yst-flex yst-justify-center yst-mb-6 yst-mt-4"><YoastConnectSiteKit /></div>
<Stepper steps={ steps } currentStep={ currentStep }>
{ steps.map( ( label, index ) => ( <Stepper.Step
key={ label }
isActive={ currentStep === index }
isComplete={ stepsStatuses[ index ] }
>
{ label }
</Stepper.Step> ) ) }
</Stepper>
<hr className="yst-bg-slate-200 yst-my-6" />
<Title size="2">{ __( "Expand your dashboard with insights from Google!", "wordpress-seo" ) }</Title>
<p className="yst-my-4">{ __( "Bring together powerful tools like Google Analytics and Search Console for a complete overview of your website's performance, all in one seamless dashboard.", "wordpress-seo" ) }</p>

<span className="yst-text-slate-800 yst-font-medium">{ __( "What you'll get:", "wordpress-seo" ) }</span>
<ul>
<li className="yst-gap-2 yst-flex yst-mt-2">
<CheckCircleIcon className="yst-w-5 yst-text-green-400" />
{ __( "Actionable insights into traffic, SEO, and user behavior to grow your audience.", "wordpress-seo" ) }
</li>
<li className="yst-gap-2 yst-flex yst-mt-2">
<CheckCircleIcon className="yst-w-5 yst-text-green-400" />
{ __( "Key performance metrics to fine-tune your website and optimize like a pro.", "wordpress-seo" ) }
</li>
</ul>
<div className="yst-flex yst-gap-1 yst-mt-6 yst-items-center">

{ overAllCompleted
? <>
<Button>
{ __( "Take a quick tour", "wordpress-seo" ) }
</Button>
<Button variant="tertiary" onClick={ onRemovePermanently }>{ __( "Dismiss", "wordpress-seo" ) }</Button>
</>
: <>
<Button { ...buttonProps[ currentStep ] } />
<Button as="a" variant="tertiary" href={ learnMorelink } className="yst-flex yst-items-center yst-gap-1">
{ __( "Learn more", "wordpress-seo" ) }
<ArrowRightIcon className="yst-w-3 yst-text-primary-500 rtl:yst-rotate-180" />
</Button>
</>
}
</div>
</Paper>;
};


10 changes: 5 additions & 5 deletions packages/js/src/integrations-page/recommended-integrations.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,14 @@ const RecommendedIntegrations = [
const siteKitProps = {
isInstalled: get( window, "wpseoIntegrationsData.site_kit_configuration.isInstalled", false ),
isActive: get( window, "wpseoIntegrationsData.site_kit_configuration.isActive", false ),
afterSetup: get( window, "wpseoIntegrationsData.site_kit_configuration.setup_completed", false ),
isSetupCompleted: get( window, "wpseoIntegrationsData.site_kit_configuration.isSetupCompleted", false ),
isConnected: get( window, "wpseoIntegrationsData.site_kit_configuration.isConnected", false ),
installUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.install_url", "" ),
activateUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.activate_url", "" ),
setupUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.setup_url", "" ),
installUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.installUrl", "" ),
activateUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.activateUrl", "" ),
setupUrl: get( window, "wpseoIntegrationsData.site_kit_configuration.setupUrl", "" ),
};

const isSiteKitFeatureEnabled = get( window, "wpseoIntegrationsData.site_kit_configuration.feature_enabled", false );
const isSiteKitFeatureEnabled = get( window, "wpseoIntegrationsData.site_kit_configuration.isFeatureEnabled", false );
if ( isSiteKitFeatureEnabled ) {
RecommendedIntegrations.push( <SiteKitIntegration key={ integrations.length } { ...siteKitProps } /> );
}
Expand Down
82 changes: 38 additions & 44 deletions packages/js/src/integrations-page/site-kit-integration.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { __, sprintf } from "@wordpress/i18n";
import { CheckIcon } from "@heroicons/react/solid";
import { createInterpolateElement, useCallback } from "@wordpress/element";
import { createInterpolateElement } from "@wordpress/element";
import PropTypes from "prop-types";
import { SimpleIntegration } from "./simple-integration";
import { ReactComponent as SiteKitLogo } from "../../images/site-kit-logo.svg";
Expand Down Expand Up @@ -49,7 +49,7 @@ const SuccessfullyConnected = () => {
* The Site Kit integration component.
*
* @param {boolean} isActive Whether the integration is active.
* @param {boolean} afterSetup Whether the integration has been set up.
* @param {boolean} isSetupCompleted Whether the integration has been set up.
* @param {boolean} isInstalled Whether the integration is installed.
* @param {boolean} isConnected Whether the integration is connected.
* @param {string} installUrl The installation url.
Expand All @@ -58,59 +58,53 @@ const SuccessfullyConnected = () => {
*
* @returns {WPElement} The Site Kit integration component.
*/
export const SiteKitIntegration = ( { isActive, afterSetup, isInstalled, isConnected, installUrl, activateUrl, setupUrl } ) => {
export const SiteKitIntegration = ( { isActive, isSetupCompleted, isInstalled, isConnected, installUrl, activateUrl, setupUrl } ) => {
const [ isModalOpen, toggleModal ] = useToggleState( false );
const [ isDisconnectModalOpen, toggleDisconnectModal ] = useToggleState( false );
const stepsStatuses = [ isInstalled, isActive, isSetupCompleted, isConnected ];
let currentStep = stepsStatuses.findIndex( status => ! status );
const successfullyConnected = currentStep === -1;

const getButtonProps = useCallback( () => {
if ( ! isInstalled ) {
return {
children: __( "Install Site Kit by Google", "wordpress-seo" ),
as: "a",
href: installUrl,
};
}
if ( ! isActive ) {
return {
children: __( "Activate Site Kit by Google", "wordpress-seo" ),
as: "a",
href: activateUrl,
};
}
if ( ! afterSetup ) {
return {
children: __( "Set up Site Kit by Google", "wordpress-seo" ),
as: "a",
href: setupUrl,
};
}
if ( ! isConnected ) {
return {
children: __( "Connect Site Kit by Google", "wordpress-seo" ),
as: "button",
onClick: toggleModal,
};
}

return {
children: __( "Disconnect", "wordpress-seo" ),
as: "button",
variant: "secondary",
onClick: toggleDisconnectModal,
};
}, [ isInstalled, isActive, afterSetup, isConnected, installUrl, activateUrl, toggleModal ] );
if ( currentStep === -1 ) {
currentStep = stepsStatuses.length - 1;
}

const buttonProps = [
{
children: __( "Install Site Kit by Google", "wordpress-seo" ),
href: installUrl,
as: "a",
},
{
children: __( "Activate Site Kit by Google", "wordpress-seo" ),
href: activateUrl,
as: "a",
},
{
children: __( "Set up Site Kit by Google", "wordpress-seo" ),
href: setupUrl,
as: "a",
},
{
children: __( "Connect Site Kit by Google", "wordpress-seo" ),
onClick: toggleModal,
},
];

const successfullyConnected = isInstalled && isActive && afterSetup && isConnected;
return (
<>
<SimpleIntegration
integration={ integration }
isActive={ successfullyConnected }
>
<span className="yst-flex yst-flex-col yst-flex-1">
{ successfullyConnected && <SuccessfullyConnected /> }
<Button className="yst-w-full" id="google-site-kit-button" { ...getButtonProps( isInstalled, isActive, afterSetup, isConnected ) } />
{ successfullyConnected ? <>
<SuccessfullyConnected />
<Button className="yst-w-full" id="site-kit-integration__button" variant="secondary" onClick={ toggleDisconnectModal }>
{ __( "Disconnect", "wordpress-seo" ) }
</Button>
</> : <Button className="yst-w-full" id="site-kit-integration__button" { ...buttonProps[ currentStep ] } /> }

</span>
</SimpleIntegration>

Expand All @@ -131,7 +125,7 @@ export const SiteKitIntegration = ( { isActive, afterSetup, isInstalled, isConne

SiteKitIntegration.propTypes = {
isActive: PropTypes.bool.isRequired,
afterSetup: PropTypes.bool.isRequired,
isSetupCompleted: PropTypes.bool.isRequired,
isInstalled: PropTypes.bool.isRequired,
isConnected: PropTypes.bool.isRequired,
installUrl: PropTypes.string.isRequired,
Expand Down
Loading

0 comments on commit 0a28ab5

Please sign in to comment.