Skip to content

Commit

Permalink
unify the way we connect sites on My Jetpack
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeyGuyDylan committed Dec 16, 2024
1 parent d5a79b1 commit e82cdcd
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 136 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { useDispatch } from '@wordpress/data';
import { __, sprintf } from '@wordpress/i18n';
import { Icon, info, check, lockOutline } from '@wordpress/icons';
import clsx from 'clsx';
import { useState, useCallback, useMemo, useContext } from 'react';
import { NoticeContext } from '../../context/notices/noticeContext';
import { NOTICE_SITE_CONNECTION_ERROR } from '../../context/notices/noticeTemplates';
import { useState, useCallback, useMemo } from 'react';
import { useAllProducts } from '../../data/products/use-product';
import useProductsByOwnership from '../../data/products/use-products-by-ownership';
import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state';
import getProductSlugsThatRequireUserConnection from '../../data/utils/get-product-slugs-that-require-user-connection';
import useAnalytics from '../../hooks/use-analytics';
import useConnectSite from '../../hooks/use-connect-site';
import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
import cloud from './cloud.svg';
import emptyAvatar from './empty-avatar.svg';
Expand Down Expand Up @@ -210,18 +208,11 @@ const ConnectionStatusCard: ConnectionStatusCardType = ( {
const { isRegistered, isUserConnected, userConnectionData } = useMyJetpackConnection( {
redirectUri,
} );
const { handleRegisterSite, siteIsRegistering } = useMyJetpackConnection( {
const { siteIsRegistering } = useMyJetpackConnection( {
skipUserConnection: true,
redirectUri,
} );
const { setNotice, resetNotice } = useContext( NoticeContext );
const { lifecycleStats, siteSuffix, adminUrl } = getMyJetpackWindowInitialState();
const connectAfterCheckoutUrl = `?connect_after_checkout=true&admin_url=${ encodeURIComponent(
adminUrl
) }&from_site_slug=${ siteSuffix }&source=my-jetpack`;
const query = `${ connectAfterCheckoutUrl }${ redirectUri }&unlinked=1`;
const jetpackPlansPath = getRedirectUrl( 'jetpack-my-jetpack-site-only-plans', { query } );
const { refetch: refetchOwnershipData } = useProductsByOwnership();
const { lifecycleStats } = getMyJetpackWindowInitialState();
const { recordEvent } = useAnalytics();
const [ isManageConnectionDialogOpen, setIsManageConnectionDialogOpen ] = useState( false );
const { setConnectionStatus, setUserIsConnecting } = useDispatch( CONNECTION_STORE_ID );
Expand Down Expand Up @@ -298,39 +289,13 @@ const ConnectionStatusCard: ConnectionStatusCardType = ( {
[ connectUserFn, recordEvent, tracksEventData ]
);

const handleConnectSite = useCallback(
async ( e: MouseEvent< HTMLButtonElement > ) => {
e && e.preventDefault();
window.scrollTo( {
top: 0,
left: 0,
behavior: 'smooth',
} );
recordEvent( 'jetpack_myjetpack_connection_connect_site_click', tracksEventData );

try {
await handleRegisterSite();

recordEvent( 'jetpack_myjetpack_connection_connect_site_success', tracksEventData );

// Redirect user to the plans page after connection
window.location.href = jetpackPlansPath;
} catch {
setNotice( NOTICE_SITE_CONNECTION_ERROR, resetNotice );
} finally {
refetchOwnershipData();
}
const { connectSite: handleConnectSite } = useConnectSite( {
tracksInfo: {
event: 'jetpack_myjetpack_connection_connect_site',
properties: tracksEventData,
},
[
handleRegisterSite,
jetpackPlansPath,
recordEvent,
refetchOwnershipData,
resetNotice,
setNotice,
tracksEventData,
]
);
shouldScrollToTop: true,
} );

const getConnectionLineStyles = () => {
if ( isRegistered ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,69 +1,24 @@
import { Col, Button, Text, TermsOfService, getRedirectUrl } from '@automattic/jetpack-components';
import { Col, Button, Text, TermsOfService } from '@automattic/jetpack-components';
import { __ } from '@wordpress/i18n';
import { useCallback, useContext } from 'react';
import { NoticeContext } from '../../context/notices/noticeContext';
import { NOTICE_SITE_CONNECTION_ERROR } from '../../context/notices/noticeTemplates';
import useProductsByOwnership from '../../data/products/use-products-by-ownership';
import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state';
import useAnalytics from '../../hooks/use-analytics';
import useConnectSite from '../../hooks/use-connect-site';
import styles from './style.module.scss';
import { WelcomeFlowExperiment } from '.';
import type { Dispatch, SetStateAction } from 'react';

type ConnectionStepProps = {
onActivateSite: ( e?: Event ) => Promise< void >;
onUpdateWelcomeFlowExperiment?: Dispatch< SetStateAction< WelcomeFlowExperiment > >;
isActivating: boolean;
};

/**
* Component that renders the Welcome banner on My Jetpack.
*
* @param {object} props - ConnectioStepProps
* @param {Function} props.onActivateSite - Alias for handleRegisterSite
* @param {boolean} props.isActivating - Alias for siteIsRegistering
* @return {object} The ConnectionStep component.
*/
const ConnectionStep = ( { onActivateSite, isActivating }: ConnectionStepProps ) => {
const { recordEvent } = useAnalytics();
const { setNotice, resetNotice } = useContext( NoticeContext );

const { siteSuffix, adminUrl } = getMyJetpackWindowInitialState();
const connectAfterCheckoutUrl = `?connect_after_checkout=true&admin_url=${ encodeURIComponent(
adminUrl
) }&from_site_slug=${ siteSuffix }&source=my-jetpack`;
const redirectUri = `&redirect_to=${ encodeURIComponent( window.location.href ) }`;
const query = `${ connectAfterCheckoutUrl }${ redirectUri }&unlinked=1`;
const jetpackPlansPath = getRedirectUrl( 'jetpack-my-jetpack-site-only-plans', { query } );

const ConnectionStep = ( { isActivating }: ConnectionStepProps ) => {
const activationButtonLabel = __( 'Activate Jetpack in one click', 'jetpack-my-jetpack' );
const { refetch: refetchOwnershipData } = useProductsByOwnership();

const onConnectSiteClick = useCallback( async () => {
resetNotice();

recordEvent( 'jetpack_myjetpack_welcome_banner_connect_site_click' );

try {
await onActivateSite();

recordEvent( 'jetpack_myjetpack_welcome_banner_connect_site_success' );

// Redirect user to the plans page after connection
window.location.href = jetpackPlansPath;
} catch {
setNotice( NOTICE_SITE_CONNECTION_ERROR, resetNotice );
} finally {
refetchOwnershipData();
}
}, [
jetpackPlansPath,
onActivateSite,
recordEvent,
refetchOwnershipData,
resetNotice,
setNotice,
] );
const { connectSite: onConnectSiteClick } = useConnectSite( {
tracksInfo: {
event: 'jetpack_myjetpack_welcome_banner_connect_site',
properties: {},
},
} );

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,10 @@ const WelcomeFlow: FC< Props > = ( {
const { dismissWelcomeBanner } = useWelcomeBanner();
const { recommendedModules, submitEvaluation, saveEvaluationResult } =
useEvaluationRecommendations();
const {
siteIsRegistered,
siteIsRegistering,
isUserConnected,
isSiteConnected,
handleRegisterSite,
} = useMyJetpackConnection( {
skipUserConnection: true,
} );
const { siteIsRegistered, siteIsRegistering, isUserConnected, isSiteConnected } =
useMyJetpackConnection( {
skipUserConnection: true,
} );
const [ isProcessingEvaluation, setIsProcessingEvaluation ] = useState( false );
const [ prevStep, setPrevStep ] = useState( '' );

Expand Down Expand Up @@ -162,7 +157,6 @@ const WelcomeFlow: FC< Props > = ( {
>
{ 'connection' === currentStep && (
<ConnectionStep
onActivateSite={ handleRegisterSite }
onUpdateWelcomeFlowExperiment={ setWelcomeFlowExperiment }
isActivating={ siteIsRegistering || welcomeFlowExperiment.isLoading }
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,6 @@ import { Notice } from './types';

export const WELCOME_BANNER_NOTICE_IDS: string[] = [ 'site-connection-success-notice' ];

export const NOTICE_SITE_CONNECTED: Notice = {
message: __( 'Your site has been successfully connected.', 'jetpack-my-jetpack' ),
options: {
id: 'site-connection-success-notice',
level: 'success',
actions: [],
priority: NOTICE_PRIORITY_HIGH,
hideCloseButton: false,
},
};

export const NOTICE_SITE_CONNECTION_ERROR: Notice = {
message: __( 'Site connection failed. Please try again.', 'jetpack-my-jetpack' ),
options: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { useCallback, useEffect } from 'react';
import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state';
import useMyJetpackConnection from '../use-my-jetpack-connection';

type TracksRecordEvent = (
event: `jetpack_${ string }`, // Enforces the event name to start with "jetpack_"
properties?: Record< Lowercase< string >, unknown >
) => void;
export type TracksEvent = `jetpack_${ string }`; // Enforces the event name to start with "jetpack_"
export type TracksProperties = Record< Lowercase< string >, unknown >; // Defines the shape of the properties object

type TracksRecordEvent = ( event: TracksEvent, properties?: TracksProperties ) => void;

const useAnalytics = () => {
const {
Expand Down
83 changes: 83 additions & 0 deletions projects/packages/my-jetpack/_inc/hooks/use-connect-site/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { getRedirectUrl } from '@automattic/jetpack-components';
import { useCallback, useContext } from 'react';
import { NoticeContext } from '../../context/notices/noticeContext';
import { NOTICE_SITE_CONNECTION_ERROR } from '../../context/notices/noticeTemplates';
import useProductsByOwnership from '../../data/products/use-products-by-ownership';
import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state';
import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
import useAnalytics from '../use-analytics';
import type { TracksEvent, TracksProperties } from '../use-analytics';
import type { MouseEvent } from 'react';

interface useConnectSiteProps {
tracksInfo: {
event: TracksEvent;
properties: TracksProperties;
};
shouldScrollToTop?: boolean;
}

const useConnectSite = ( { tracksInfo, shouldScrollToTop = false }: useConnectSiteProps ) => {
const { event, properties: tracksEventData } = tracksInfo;

const { setNotice, resetNotice } = useContext( NoticeContext );

const { recordEvent } = useAnalytics();
const { refetch: refetchOwnershipData } = useProductsByOwnership();

const { siteSuffix, adminUrl, myJetpackCheckoutUri } = getMyJetpackWindowInitialState();
const redirectUri = `&redirect_to=${ myJetpackCheckoutUri }`;

const connectAfterCheckoutUrl = `?connect_after_checkout=true&admin_url=${ encodeURIComponent(
adminUrl
) }&from_site_slug=${ siteSuffix }&source=my-jetpack`;
const query = `${ connectAfterCheckoutUrl }${ redirectUri }&unlinked=1`;
const jetpackPlansPath = getRedirectUrl( 'jetpack-my-jetpack-site-only-plans', { query } );
const { handleRegisterSite } = useMyJetpackConnection( {
skipUserConnection: true,
redirectUri,
} );

const connectSite = useCallback(
async ( e: MouseEvent< HTMLButtonElement > ) => {
e && e.preventDefault();

if ( shouldScrollToTop ) {
window.scrollTo( {
top: 0,
left: 0,
behavior: 'smooth',
} );
}

recordEvent( `${ event }_click`, tracksEventData );

try {
await handleRegisterSite();

recordEvent( `${ event }_success`, tracksEventData );

window.location.href = jetpackPlansPath;
} catch {
setNotice( NOTICE_SITE_CONNECTION_ERROR, resetNotice );
} finally {
refetchOwnershipData();
}
},
[
handleRegisterSite,
jetpackPlansPath,
recordEvent,
refetchOwnershipData,
resetNotice,
setNotice,
tracksEventData,
event,
shouldScrollToTop,
]
);

return { connectSite };
};

export default useConnectSite;
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,34 @@ import { useContext, useEffect } from 'react';
import { MyJetpackRoutes } from '../../constants';
import { NOTICE_PRIORITY_HIGH } from '../../context/constants';
import { NoticeContext } from '../../context/notices/noticeContext';
import { NOTICE_SITE_CONNECTED } from '../../context/notices/noticeTemplates';
import { useAllProducts } from '../../data/products/use-product';
import useProductsByOwnership from '../../data/products/use-products-by-ownership';
import getProductSlugsThatRequireUserConnection from '../../data/utils/get-product-slugs-that-require-user-connection';
import useAnalytics from '../use-analytics';
import useConnectSite from '../use-connect-site';
import useMyJetpackConnection from '../use-my-jetpack-connection';
import useMyJetpackNavigate from '../use-my-jetpack-navigate';
import type { NoticeOptions } from '../../context/notices/types';
import type { MouseEvent } from 'react';

type RedBubbleAlerts = Window[ 'myJetpackInitialState' ][ 'redBubbleAlerts' ];

const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => {
const { recordEvent } = useAnalytics();
const { setNotice, resetNotice } = useContext( NoticeContext );
const { handleRegisterSite, siteIsRegistering } = useMyJetpackConnection( {
const { siteIsRegistering } = useMyJetpackConnection( {
skipUserConnection: true,
} );
const products = useAllProducts();
const navToConnection = useMyJetpackNavigate( MyJetpackRoutes.Connection );
const redBubbleSlug = 'missing-connection';
const connectionError = redBubbleAlerts[ redBubbleSlug ];
const { connectSite } = useConnectSite( {
tracksInfo: {
event: 'jetpack_my_jetpack_site_connection_notice_cta',
properties: {},
},
} );

const { refetch: refetchOwnershipData } = useProductsByOwnership();

Expand All @@ -37,20 +44,13 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => {
getProductSlugsThatRequireUserConnection( products );
const requiresUserConnection = connectionError.type === 'user';

const onActionButtonClick = () => {
const onActionButtonClick = ( { e }: { e: MouseEvent< HTMLButtonElement > } ) => {
if ( requiresUserConnection ) {
recordEvent( 'jetpack_my_jetpack_user_connection_notice_cta_click' );
navToConnection();
}

recordEvent( 'jetpack_my_jetpack_site_connection_notice_cta_click' );
handleRegisterSite().then( () => {
setNotice( NOTICE_SITE_CONNECTED, resetNotice );
delete redBubbleAlerts[ redBubbleSlug ];
window.myJetpackInitialState.redBubbleAlerts = redBubbleAlerts;

refetchOwnershipData();
} );
connectSite( e );
};

const oneProductMessage = sprintf(
Expand Down Expand Up @@ -121,7 +121,7 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => {
options: noticeOptions,
} );
}, [
handleRegisterSite,
connectSite,
navToConnection,
products,
recordEvent,
Expand Down

0 comments on commit e82cdcd

Please sign in to comment.