Skip to content

Commit

Permalink
New Feature: My Jetpack Welcome Flow (#38534)
Browse files Browse the repository at this point in the history
* Set WelcomeFlow structure and update WelcomeBanner (async site-only connection) (#37715)

* Enhance TermsOfService component

* Update MyJetpack connection hook and its usage

* Update WelcomeBanner text and add async site registration on click

* changelog

* Add events and banner dismissal upon connection success

* Update versions

* Add WelcomeFlow (separate code) structure

* Revert WelcomeBanner code

* Update banner

* Update versions

* Hide notices when welcome banner is active

* Code improvements

* Prevent reloading on site connection

* Introduce Notice templating (unify Notices)

* Improve displaying notices when welcome banner is active

* Improve styling of disabled 'x' button

* Add evaluation form to Welcome Flow (#37790)

* Enhance TermsOfService component

* Update MyJetpack connection hook and its usage

* Update WelcomeBanner text and add async site registration on click

* changelog

* Add events and banner dismissal upon connection success

* Update versions

* Add WelcomeFlow (separate code) structure

* Revert WelcomeBanner code

* Update banner

* Update versions

* Add evaluation form step

* Add evaluation processing step and styles

* Add evaluation steps to welcome flow

* Replace classnames with clsx

* Update image filename

* Hide notices when welcome banner is active

* Code improvements

* Prevent reloading on site connection

* Introduce Notice templating (unify Notices)

* Add 'currentStep' prop to dismiss Tracks event

* Add more info to dismiss Tracks event

* Code improvements

* Add /recommendations/evaluation endpoint handling (#38011)

* Enhance TermsOfService component

* Update MyJetpack connection hook and its usage

* Update WelcomeBanner text and add async site registration on click

* changelog

* Add events and banner dismissal upon connection success

* Update versions

* Add WelcomeFlow (separate code) structure

* Revert WelcomeBanner code

* Update banner

* Update versions

* Add evaluation form step

* Add evaluation processing step and styles

* Add evaluation steps to welcome flow

* Replace classnames with clsx

* Update image filename

* Hide notices when welcome banner is active

* Code improvements

* Prevent reloading on site connection

* Introduce Notice templating (unify Notices)

* Add 'currentStep' prop to dismiss Tracks event

* Add more info to dismiss Tracks event

* Code improvements

* Improve mutation hook code

* Add recommendations evaluation endpoint handling

* Implement saving evaluation recommendations

* Delete remaining reference

* Code improvements and analytics

* Fix code review comments

* Fix phan

* Fix phan 2

* Surpress other parameters

* Fix phan completely

* Improve Tracks events

* Add Evaluation Recommendations logic (#38171)

* Add ValueStore logic

* Add Evaluation Recommendations logic

* changelog

* Fix refactor leftover

* Improve querying evaluation endpoints

* Code review improvements

* Extend ProductCard component and create recommendations UI (#38319)

* Refactor ProductCard to ts, add 'recommendation' property

* Add price component and purchase button

* Refactor and cleanup code

* Fix backup card

* Revert to short descriptions

* Improve recommendation button names

* Fix additional actions typing

* Fix determining state of the recommended product

* Fix literal translation handling (transpilation bug)

* Fix checkout link redirect

* Fix purchase button

* Minor code review improvements

* Improve handling checkout urls

* Fix nitpicks

* Improve handling free offerings and upgrade urls

* Don't make admin flag required (as it's not required in every case now)

* Fix code splitting issue

* Activate plugins on 'start for free' action

* Add Evaluation Recommendations context menu (#38378)

* Refactor ProductCard to ts, add 'recommendation' property

* Add price component and purchase button

* Refactor and cleanup code

* Fix backup card

* Revert to short descriptions

* Improve recommendation button names

* Fix additional actions typing

* Fix determining state of the recommended product

* Fix literal translation handling (transpilation bug)

* Fix boost card popover

* Add delete endpoint, unify with others

* Extend functionality of Welcome Banner and Evaluation Recommendations hooks

* Add context menu to view layer

* Fix checkout link redirect

* Fix purchase button

* Minor code review improvements

* Improve handling checkout urls

* Code review improvements

* Fix nitpicks

* Improve handling free offerings and upgrade urls

* Don't make admin flag required (as it's not required in every case now)

* Fix code splitting issue

* Add recommendations initializer tweaks (#38452)

* Refactor ProductCard to ts, add 'recommendation' property

* Add price component and purchase button

* Refactor and cleanup code

* Fix backup card

* Revert to short descriptions

* Improve recommendation button names

* Fix additional actions typing

* Fix determining state of the recommended product

* Fix literal translation handling (transpilation bug)

* Fix boost card popover

* Add delete endpoint, unify with others

* Extend functionality of Welcome Banner and Evaluation Recommendations hooks

* Add context menu to view layer

* Add silent redBubble alerts - don't show in menu

* Hide recommendations when user purchases the product

* Fix checkout link redirect

* Fix purchase button

* Minor code review improvements

* Improve handling checkout urls

* Code review improvements

* Fix nitpicks

* Improve handling free offerings and upgrade urls

* Don't make admin flag required (as it's not required in every case now)

* Fix code splitting issue

* Leftover after merge conflict resolution

* Welcome Flow: Various tweaks and fixes (#38536)

* Various tweaks and fixes

* Improve layout of product card, hide boost tooltip on click

* Fix Protect tooltips dependency

* Display notices when in survey step

* Remove red dot on survey step, don't show survey step when user is not new

* Fix condition, and add comment

* Improve 'start for free' actions and small fixes

* Dismiss recommendations instead of deleting them

* Fix condition

* Redoing recommendations only happens locally

* Limit recommendations to 3

* Code review fixes and disabling 'start for free' functionality

* Change placement of Boost tooltip and revert click functionality

* Welcome Flow: fixes and improvements pt. 2 (#38589)

* Apply min-width 300px to cards

* Set loading state of site connection button

* Fix parsing active modules array

* Update changelogger

* Fix Tracks events code

* Update projects/packages/my-jetpack/_inc/components/product-card/index.tsx

Co-authored-by: Ian Ramos <[email protected]>

---------

Co-authored-by: jboland88 <[email protected]>
Co-authored-by: Ian Ramos <[email protected]>
  • Loading branch information
3 people authored Jul 30, 2024
1 parent f46c1aa commit 13650c1
Show file tree
Hide file tree
Showing 63 changed files with 1,758 additions and 416 deletions.
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Update Welcome Banner and set async site-only connection
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ const TermsOfService: React.FC< TermsOfServiceProps > = ( {
className,
multipleButtons,
agreeButtonLabel,
...textProps
} ) => (
<Text className={ clsx( className, 'terms-of-service' ) }>
<Text className={ clsx( className, 'terms-of-service' ) } { ...textProps }>
{ multipleButtons ? (
<MultipleButtonsText multipleButtonsLabels={ multipleButtons } />
) : (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { TextProps } from '../text/types';

type MultipleButtonsProps = {
/**
* Indicates whether there are multiple buttons present that would imply agreement if clicked.
Expand All @@ -22,9 +24,24 @@ type SingleButtonProps = {
agreeButtonLabel: string;
};

export type TermsOfServiceProps = {
/**
* Represents additional CSS classes to be added to the component's root.
*/
className?: string;
} & ( MultipleButtonsProps | SingleButtonProps );
export type TermsOfServiceProps = Pick<
TextProps,
| 'variant'
| 'm'
| 'mt'
| 'mr'
| 'mb'
| 'ml'
| 'mx'
| 'my'
| 'p'
| 'pt'
| 'pr'
| 'pb'
| 'pl'
| 'px'
| 'py'
| 'className'
| 'component'
> &
( MultipleButtonsProps | SingleButtonProps );
2 changes: 1 addition & 1 deletion projects/js-packages/components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@automattic/jetpack-components",
"version": "0.55.3",
"version": "0.55.4-alpha",
"description": "Jetpack Components Package",
"author": "Automattic",
"license": "GPL-2.0-or-later",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: added

Added support for 'recommendations_evaluation' Jetpack option"
2 changes: 2 additions & 0 deletions projects/packages/connection/legacy/class-jetpack-options.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ public static function get_option_names( $type = 'compact' ) {
'identity_crisis_url_secret', // (array) The IDC URL secret and its expiration date.
'identity_crisis_ip_requester', // (array) The IDC IP address and its expiration date.
'dismissed_welcome_banner', // (bool) Determines if the welcome banner has been dismissed or not.
'recommendations_evaluation', // (object) Catalog of recommended modules with corresponding score following successful site evaluation in Welcome Banner.
'dismissed_recommendations', // (bool) Determines if the recommendations have been dismissed or not.
'historically_active_modules', // (array) List of installed plugins/enabled modules that have at one point in time been active and working
);
}
Expand Down
2 changes: 1 addition & 1 deletion projects/packages/connection/src/class-package-version.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*/
class Package_Version {

const PACKAGE_VERSION = '2.11.2';
const PACKAGE_VERSION = '2.11.3-alpha';

const PACKAGE_SLUG = 'connection';

Expand Down
78 changes: 42 additions & 36 deletions projects/packages/my-jetpack/_inc/admin.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import JetpackAiProductPage from './components/product-interstitial/jetpack-ai/p
import RedeemTokenScreen from './components/redeem-token-screen';
import { MyJetpackRoutes } from './constants';
import NoticeContextProvider from './context/notices/noticeContext';
import ValueStoreContextProvider from './context/value-store/valueStoreContext';
import { getMyJetpackWindowInitialState } from './data/utils/get-my-jetpack-window-state';
import './style.module.scss';

Expand All @@ -53,42 +54,47 @@ const MyJetpack = () => {
return (
<ThemeProvider>
<NoticeContextProvider>
<QueryClientProvider client={ queryClient }>
<HashRouter>
<ScrollToTop />
<Routes>
<Route path={ MyJetpackRoutes.Home } element={ <MyJetpackScreen /> } />
<Route path={ MyJetpackRoutes.Connection } element={ <ConnectionScreen /> } />
<Route path={ MyJetpackRoutes.AddAkismet } element={ <AntiSpamInterstitial /> } />
{ /* Redirect the old route for Anti Spam */ }
<Route
path={ MyJetpackRoutes.AddAntiSpam }
element={ <Navigate replace to={ MyJetpackRoutes.AddAkismet } /> }
/>
<Route path={ MyJetpackRoutes.AddBackup } element={ <BackupInterstitial /> } />
<Route path={ MyJetpackRoutes.AddBoost } element={ <BoostInterstitial /> } />
<Route path={ MyJetpackRoutes.AddCRM } element={ <CRMInterstitial /> } />
<Route path={ MyJetpackRoutes.AddCreator } element={ <CreatorInterstitial /> } />
<Route path={ MyJetpackRoutes.AddJetpackAI } element={ <JetpackAiInterstitial /> } />
<Route path={ MyJetpackRoutes.AddExtras } element={ <ExtrasInterstitial /> } />
<Route path={ MyJetpackRoutes.AddProtect } element={ <ProtectInterstitial /> } />
<Route path={ MyJetpackRoutes.AddScan } element={ <ScanInterstitial /> } />
<Route path={ MyJetpackRoutes.AddSocial } element={ <SocialInterstitial /> } />
<Route path={ MyJetpackRoutes.AddSearch } element={ <SearchInterstitial /> } />
<Route
path={ MyJetpackRoutes.AddVideoPress }
element={ <VideoPressInterstitial /> }
/>
<Route path={ MyJetpackRoutes.AddStats } element={ <StatsInterstitial /> } />
{ loadAddLicenseScreen && (
<Route path={ MyJetpackRoutes.AddLicense } element={ <AddLicenseScreen /> } />
) }
<Route path={ MyJetpackRoutes.RedeemToken } element={ <RedeemTokenScreen /> } />
<Route path="/redeem-token" element={ <RedeemTokenScreen /> } />
<Route path="/jetpack-ai" element={ <JetpackAiProductPage /> } />
</Routes>
</HashRouter>
</QueryClientProvider>
<ValueStoreContextProvider>
<QueryClientProvider client={ queryClient }>
<HashRouter>
<ScrollToTop />
<Routes>
<Route path={ MyJetpackRoutes.Home } element={ <MyJetpackScreen /> } />
<Route path={ MyJetpackRoutes.Connection } element={ <ConnectionScreen /> } />
<Route path={ MyJetpackRoutes.AddAkismet } element={ <AntiSpamInterstitial /> } />
{ /* Redirect the old route for Anti Spam */ }
<Route
path={ MyJetpackRoutes.AddAntiSpam }
element={ <Navigate replace to={ MyJetpackRoutes.AddAkismet } /> }
/>
<Route path={ MyJetpackRoutes.AddBackup } element={ <BackupInterstitial /> } />
<Route path={ MyJetpackRoutes.AddBoost } element={ <BoostInterstitial /> } />
<Route path={ MyJetpackRoutes.AddCRM } element={ <CRMInterstitial /> } />
<Route path={ MyJetpackRoutes.AddCreator } element={ <CreatorInterstitial /> } />
<Route
path={ MyJetpackRoutes.AddJetpackAI }
element={ <JetpackAiInterstitial /> }
/>
<Route path={ MyJetpackRoutes.AddExtras } element={ <ExtrasInterstitial /> } />
<Route path={ MyJetpackRoutes.AddProtect } element={ <ProtectInterstitial /> } />
<Route path={ MyJetpackRoutes.AddScan } element={ <ScanInterstitial /> } />
<Route path={ MyJetpackRoutes.AddSocial } element={ <SocialInterstitial /> } />
<Route path={ MyJetpackRoutes.AddSearch } element={ <SearchInterstitial /> } />
<Route
path={ MyJetpackRoutes.AddVideoPress }
element={ <VideoPressInterstitial /> }
/>
<Route path={ MyJetpackRoutes.AddStats } element={ <StatsInterstitial /> } />
{ loadAddLicenseScreen && (
<Route path={ MyJetpackRoutes.AddLicense } element={ <AddLicenseScreen /> } />
) }
<Route path={ MyJetpackRoutes.RedeemToken } element={ <RedeemTokenScreen /> } />
<Route path="/redeem-token" element={ <RedeemTokenScreen /> } />
<Route path="/jetpack-ai" element={ <JetpackAiProductPage /> } />
</Routes>
</HashRouter>
</QueryClientProvider>
</ValueStoreContextProvider>
</NoticeContextProvider>
</ThemeProvider>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type { FC, ReactNode } from 'react';

interface ConnectedProductCardProps {
admin: boolean;
recommendation: boolean;
slug: string;
children: ReactNode;
isDataLoading?: boolean;
Expand All @@ -35,6 +36,7 @@ interface ConnectedProductCardProps {

const ConnectedProductCard: FC< ConnectedProductCardProps > = ( {
admin,
recommendation,
slug,
children,
isDataLoading,
Expand Down Expand Up @@ -125,6 +127,7 @@ const ConnectedProductCard: FC< ConnectedProductCardProps > = ( {
Description={ Description ? Description : DefaultDescription }
status={ status }
admin={ admin }
recommendation={ recommendation }
isFetching={ isActivating || isInstalling || isProductDataLoading }
isDataLoading={ isDataLoading }
isInstallingStandalone={ isInstalling }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Container, Col, Text } from '@automattic/jetpack-components';
import { DropdownMenu } from '@wordpress/components';
import { Flex } from '@wordpress/components';
import { FlexItem } from '@wordpress/components';
import { __, _n } from '@wordpress/i18n';
import { moreHorizontalMobile } from '@wordpress/icons';
import useEvaluationRecommendations from '../../data/evaluation-recommendations/use-evaluation-recommendations';
import { JetpackModuleToProductCard } from '../product-cards-section/all';
import styles from './style.module.scss';

const EvaluationRecommendations: React.FC = () => {
const { recommendedModules, redoEvaluation, removeEvaluationResult } =
useEvaluationRecommendations();

return (
<Container horizontalGap={ 2 } horizontalSpacing={ 6 }>
<Col>
<Flex>
<FlexItem>
<Text variant="headline-small" className={ styles.title }>
{ _n(
'Our recommendation for you',
'Our recommendations for you',
recommendedModules.length,
'jetpack-my-jetpack'
) }
</Text>
<Text>
{ __(
'Here are the features that will best help you with your site:',
'jetpack-my-jetpack'
) }
</Text>
</FlexItem>
<FlexItem>
<DropdownMenu
menuProps={ { className: styles[ 'dropdown-menu' ] } }
popoverProps={ { position: 'bottom left' } }
icon={ moreHorizontalMobile }
label={ __( 'Recommendations menu', 'jetpack-my-jetpack' ) }
controls={ [
{
title: __( 'Redo', 'jetpack-my-jetpack' ),
onClick: redoEvaluation,
},
{
title: __( 'Dismiss', 'jetpack-my-jetpack' ),
onClick: removeEvaluationResult,
},
] }
/>
</FlexItem>
</Flex>
</Col>
<Col>
<Container
tagName="ul"
className={ styles[ 'recommendations-list' ] }
horizontalGap={ 4 }
horizontalSpacing={ 2 }
fluid
>
{ recommendedModules.map( module => {
const Card = JetpackModuleToProductCard[ module ];
return (
Card && (
<Col tagName="li" key={ module } lg={ 4 }>
<Card recommendation />
</Col>
)
);
} ) }
</Container>
</Col>
</Container>
);
};

export default EvaluationRecommendations;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.title {
margin-bottom: 0.75rem;
}

.dropdown-menu {
width: 200px;
}

// Setting min-width of recommendation (product) cards to 300px; see: /components/product-cards-section/style.module.scss:62
@media screen and (min-width: 599px) and (max-width: 1290px) {
ul.recommendations-list {
grid-template-columns: repeat( auto-fill, minmax( 300px, 1fr ) );
> li {
grid-column-end: auto;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,20 @@ import {
QUERY_CHAT_AVAILABILITY_KEY,
QUERY_CHAT_AUTHENTICATION_KEY,
} from '../../data/constants';
import useEvaluationRecommendations from '../../data/evaluation-recommendations/use-evaluation-recommendations';
import useSimpleQuery from '../../data/use-simple-query';
import { getMyJetpackWindowInitialState } from '../../data/utils/get-my-jetpack-window-state';
import useWelcomeBanner from '../../data/welcome-banner/use-welcome-banner';
import useAnalytics from '../../hooks/use-analytics';
import useMyJetpackConnection from '../../hooks/use-my-jetpack-connection';
import useNotificationWatcher from '../../hooks/use-notification-watcher';
import ConnectionsSection from '../connections-section';
import EvaluationRecommendations from '../evaluation-recommendations';
import IDCModal from '../idc-modal';
import JetpackManageBanner from '../jetpack-manage-banner';
import PlansSection from '../plans-section';
import ProductCardsSection from '../product-cards-section';
import WelcomeBanner from '../welcome-banner';
import WelcomeFlow from '../welcome-flow';
import styles from './styles.module.scss';

const GlobalNotice = ( { message, title, options } ) => {
Expand Down Expand Up @@ -80,6 +83,8 @@ export default function MyJetpackScreen() {
const { jetpackManage = {}, adminUrl } = getMyJetpackWindowInitialState();

const { isWelcomeBannerVisible } = useWelcomeBanner();
const { isSectionVisible } = useEvaluationRecommendations();
const { siteIsRegistered } = useMyJetpackConnection();
const { currentNotice } = useContext( NoticeContext );
const {
message: noticeMessage,
Expand Down Expand Up @@ -137,20 +142,30 @@ export default function MyJetpackScreen() {
</Col>
</Container>
) }
<WelcomeBanner />
{ noticeMessage && ! isWelcomeBannerVisible && (
<Container horizontalSpacing={ 3 } horizontalGap={ 3 }>
<Col>
{
{ isWelcomeBannerVisible ? (
<WelcomeFlow>
{ noticeMessage && siteIsRegistered && (
<GlobalNotice
message={ noticeMessage }
title={ noticeTitle }
options={ noticeOptions }
/>
) }
</WelcomeFlow>
) : (
noticeMessage && (
<Container horizontalSpacing={ 3 } horizontalGap={ 3 }>
<Col>
<GlobalNotice
message={ noticeMessage }
title={ noticeTitle }
options={ noticeOptions }
/>
}
</Col>
</Container>
</Col>
</Container>
)
) }
{ isSectionVisible && <EvaluationRecommendations /> }

<ProductCardsSection />

Expand Down
Loading

0 comments on commit 13650c1

Please sign in to comment.