Skip to content

Commit

Permalink
Site Dashboard: Add the Staging Sites tab (#91276)
Browse files Browse the repository at this point in the history
* Site Dashboard: Add the Staging Sites tab

* Refactor

* Add tests

* Fix types

* Update styles

* Fix styles

* Add the upsell nudge

* Redirect to dev tool for simple sites

* Redirect to overview when people want to manage the staging site
  • Loading branch information
arthur791004 authored May 31, 2024
1 parent f62995b commit 5cc52b0
Show file tree
Hide file tree
Showing 16 changed files with 321 additions and 11 deletions.
4 changes: 4 additions & 0 deletions client/components/hosting-card/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
border-radius: 4px;
box-shadow: none;
font-family: $font-sf-pro-text;

&.is-borderless {
border: none;
}
}

h3.hosting-card__title {
Expand Down
3 changes: 2 additions & 1 deletion client/controller/index.node.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ export const redirectLoggedOutToSignup = () => {};
export const redirectToDashboard = () => {};
export const redirectMyJetpack = () => {};
export const redirectWithoutLocaleParamIfLoggedIn = () => {};
export const redirectIfCurrentUserCannot = () => {};
// eslint-disable-next-line no-unused-vars
export const redirectIfCurrentUserCannot = ( capability ) => () => {};
export const redirectIfP2 = () => {};
export const redirectIfJetpackNonAtomic = () => {};
export const redirectToDevToolsPromoIfNotAtomic = () => {};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import classnames from 'classnames';
import { useTranslate } from 'i18n-calypso';
import { FunctionComponent, PropsWithChildren } from 'react';
import { FunctionComponent, ReactNode } from 'react';
import { HostingCard } from 'calypso/components/hosting-card';

export const CardContentWrapper: FunctionComponent< PropsWithChildren > = ( { children } ) => {
interface Props {
children: ReactNode;
className?: string;
}

export const CardContentWrapper: FunctionComponent< Props > = ( { children, className } ) => {
const translate = useTranslate();
return (
<HostingCard
className="staging-site-card"
className={ classnames( 'staging-site-card', className ) }
headingId="staging-site"
title={ translate( 'Staging site' ) }
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export const ManageStagingSiteCardContent = ( {
onClick={ () => {
if ( isEnabled( 'layout/dotcom-nav-redesign-v2' ) ) {
navigate(
`/hosting-config/${ urlToSlug( stagingSite.url ) }?search=${ urlToSlug(
`/overview/${ urlToSlug( stagingSite.url ) }?search=${ urlToSlug(
stagingSite.url
) }`,
false,
Expand Down
6 changes: 4 additions & 2 deletions client/my-sites/hosting/staging-site-card/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQueryClient } from '@tanstack/react-query';
import { sprintf } from '@wordpress/i18n';
import { useI18n } from '@wordpress/react-i18n';
import classnames from 'classnames';
import { localize } from 'i18n-calypso';
import { useState, useEffect, useCallback, useMemo } from 'react';
import { connect } from 'react-redux';
Expand Down Expand Up @@ -49,13 +50,14 @@ const stagingSiteDeleteFailureNoticeId = 'staging-site-remove-failure';

export const StagingSiteCard = ( {
currentUserId,
disabled,
disabled = false,
siteId,
siteOwnerId,
translate,
isJetpack,
isPossibleJetpackConnectionProblem,
dispatch,
isBorderless,
} ) => {
const { __ } = useI18n();
const queryClient = useQueryClient();
Expand Down Expand Up @@ -517,7 +519,7 @@ export const StagingSiteCard = ( {
}

return (
<CardContentWrapper>
<CardContentWrapper className={ classnames( { 'is-borderless': isBorderless } ) }>
{ isJetpack && isPossibleJetpackConnectionProblem && (
<JetpackConnectionHealthBanner siteId={ siteId } />
) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { isEnabled } from '@automattic/calypso-config';
import { Button, Card, Gridicon } from '@automattic/components';
import styled from '@emotion/styled';
import { useI18n } from '@wordpress/react-i18n';
import classnames from 'classnames';
import { localize } from 'i18n-calypso';
import { useEffect, useState } from 'react';
import { connect } from 'react-redux';
Expand Down Expand Up @@ -29,6 +30,25 @@ const ProductionCard = styled( Card )( {
paddingTop: '0',
backgroundImage: `url(${ dividerPattern })`,
backgroundRepeat: 'repeat-x',

'&.is-borderless': {
boxShadow: 'none',
},

'> .gridicon': {
display: 'inline-block',
marginInlineEnd: '16px',
marginBottom: '16px',
verticalAlign: 'middle',
},

'> .card-heading': {
display: 'inline-block',
marginTop: 0,
marginBottom: '16px',
verticalAlign: 'middle',
lineHeight: '32px',
},
} );

const ProductionCardIcon = styled( Gridicon )( {
Expand All @@ -52,12 +72,13 @@ const SyncActionsContainer = styled( ActionButtons )( {
} );

type CardProps = {
disabled: boolean;
disabled?: boolean;
siteId: number;
translate: ( text: string, args?: Record< string, unknown > ) => string;
isBorderless?: boolean;
};

function StagingSiteProductionCard( { disabled, siteId, translate }: CardProps ) {
function StagingSiteProductionCard( { disabled, siteId, translate, isBorderless }: CardProps ) {
const { __ } = useI18n();
const dispatch = useDispatch();
const [ syncError, setSyncError ] = useState< string | null >( null );
Expand Down Expand Up @@ -144,7 +165,7 @@ function StagingSiteProductionCard( { disabled, siteId, translate }: CardProps )
onClick={ () => {
if ( isEnabled( 'layout/dotcom-nav-redesign-v2' ) ) {
navigate(
`/hosting-config/${ urlToSlug( productionSite.url ) }?search=${ urlToSlug(
`/overview/${ urlToSlug( productionSite.url ) }?search=${ urlToSlug(
productionSite.url
) }`,
false,
Expand Down Expand Up @@ -189,8 +210,11 @@ function StagingSiteProductionCard( { disabled, siteId, translate }: CardProps )
)
);
}

return (
<ProductionCard className="staging-site-card">
<ProductionCard
className={ classnames( 'staging-site-card', { 'is-borderless': isBorderless } ) }
>
{
// eslint-disable-next-line wpcalypso/jsx-gridicon-size
<ProductionCardIcon icon="science" size={ 32 } />
Expand Down
6 changes: 6 additions & 0 deletions client/sections.js
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,12 @@ const sections = [
module: 'calypso/github-deployments',
group: 'sites',
},
{
name: 'staging-site',
paths: [ '/staging-site' ],
module: 'calypso/staging-site',
group: 'sites',
},
{
name: 'a8c-for-agencies',
paths: [ '/' ],
Expand Down
2 changes: 2 additions & 0 deletions client/sites-dashboard-v2/site-preview-pane/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const DOTCOM_SERVER_LOGS = 'dotcom-site-monitoring-web';
export const DOTCOM_GITHUB_DEPLOYMENTS = 'dotcom-github-deployments';
export const DOTCOM_HOSTING_CONFIG = 'dotcom-hosting-config';
export const DOTCOM_DEVELOPER_TOOLS = 'dotcom-developer-tools';
export const DOTCOM_STAGING_SITE = 'dotcom-staging-site';

export const FEATURE_TO_ROUTE_MAP: { [ feature: string ]: string } = {
[ DOTCOM_OVERVIEW ]: 'overview/:site',
Expand All @@ -14,4 +15,5 @@ export const FEATURE_TO_ROUTE_MAP: { [ feature: string ]: string } = {
[ DOTCOM_GITHUB_DEPLOYMENTS ]: 'github-deployments/:site',
[ DOTCOM_HOSTING_CONFIG ]: 'hosting-config/:site',
[ DOTCOM_DEVELOPER_TOOLS ]: 'dev-tools/:site',
[ DOTCOM_STAGING_SITE ]: 'staging-site/:site',
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
DOTCOM_SERVER_LOGS,
DOTCOM_GITHUB_DEPLOYMENTS,
DOTCOM_DEVELOPER_TOOLS,
DOTCOM_STAGING_SITE,
} from './constants';
import PreviewPaneHeaderButtons from './preview-pane-header-buttons';

Expand Down Expand Up @@ -104,6 +105,14 @@ const DotcomPreviewPane = ( {
setSelectedSiteFeature,
selectedSiteFeaturePreview
),
createFeaturePreview(
DOTCOM_STAGING_SITE,
__( 'Staging Site' ),
isAtomicSite && ! isPlanExpired,
selectedSiteFeature,
setSelectedSiteFeature,
selectedSiteFeaturePreview
),
],
[
__,
Expand Down
47 changes: 47 additions & 0 deletions client/staging-site/components/staging-site-upsell-nudge/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { PLAN_BUSINESS, getPlan, FEATURE_SITE_STAGING_SITES } from '@automattic/calypso-products';
import { addQueryArgs } from '@wordpress/url';
import { useTranslate } from 'i18n-calypso';
import UpsellNudge from 'calypso/blocks/upsell-nudge';
import InlineSupportLink from 'calypso/components/inline-support-link';
import { CardContentWrapper } from 'calypso/my-sites/hosting/staging-site-card/card-content/card-content-wrapper';
import { useSelector } from 'calypso/state';
import { getSelectedSiteId } from 'calypso/state/ui/selectors';

const StagingSiteUpsellNudge = () => {
const translate = useTranslate();
const siteId = useSelector( ( state ) => getSelectedSiteId( state ) ) ?? 0;
const href = addQueryArgs( `/checkout/${ siteId }/business`, {
redirect_to: `/staging-site/${ siteId }`,
} );

return (
<CardContentWrapper className="is-borderless">
<p>
{ translate(
'Your staging site lets you preview and troubleshoot changes before updating the production site. {{a}}Learn more{{/a}}.',
{
components: {
a: <InlineSupportLink supportContext="hosting-staging-site" showIcon={ false } />,
},
}
) }
</p>
<UpsellNudge
className="staging-site-upsell-nudge"
title={ translate( 'Upgrade to the %(businessPlanName)s plan to add a staging site.', {
args: { businessPlanName: getPlan( PLAN_BUSINESS )?.getTitle() ?? '' },
} ) }
tracksImpressionName="calypso_staging_site_upgrade_impression"
event="calypso_staging_site_upgrade_upsell"
tracksClickName="calypso_staging_site_upgrade_click"
href={ href }
callToAction={ translate( 'Upgrade' ) }
plan={ PLAN_BUSINESS }
showIcon
feature={ FEATURE_SITE_STAGING_SITES }
/>
</CardContentWrapper>
);
};

export default StagingSiteUpsellNudge;
32 changes: 32 additions & 0 deletions client/staging-site/components/staging-site/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { FEATURE_SITE_STAGING_SITES, WPCOM_FEATURES_ATOMIC } from '@automattic/calypso-products';
import StagingSiteCard from 'calypso/my-sites/hosting/staging-site-card';
import StagingSiteProductionCard from 'calypso/my-sites/hosting/staging-site-card/staging-site-production-card';
import { useSelector } from 'calypso/state';
import isSiteWpcomStaging from 'calypso/state/selectors/is-site-wpcom-staging';
import siteHasFeature from 'calypso/state/selectors/site-has-feature';
import { getSelectedSiteId } from 'calypso/state/ui/selectors';
import StagingSiteUpsellNudge from '../staging-site-upsell-nudge';
import './style.scss';

const StagingSite = () => {
const siteId = useSelector( ( state ) => getSelectedSiteId( state ) ) ?? 0;
const hasAtomicFeature = useSelector( ( state ) =>
siteHasFeature( state, siteId, WPCOM_FEATURES_ATOMIC )
);
const hasStagingSitesFeature = useSelector( ( state ) =>
siteHasFeature( state, siteId, FEATURE_SITE_STAGING_SITES )
);
const isWpcomStagingSite = useSelector( ( state ) => isSiteWpcomStaging( state, siteId ) );

if ( ! hasAtomicFeature && ! hasStagingSitesFeature ) {
return <StagingSiteUpsellNudge />;
}

if ( isWpcomStagingSite ) {
return <StagingSiteProductionCard siteId={ siteId } isBorderless />;
}

return <StagingSiteCard isBorderless />;
};

export default StagingSite;
23 changes: 23 additions & 0 deletions client/staging-site/components/staging-site/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.wpcom-site .is-section-staging-site .staging-site-card {
.hosting-card__title,
.card-heading {
margin-bottom: 4px;
font-size: 1.25rem;
line-height: 26px;
text-transform: capitalize;

& ~ p {
margin-bottom: 32px;
font-size: 0.875rem;
line-height: 20px;
color: var(--color-neutral-60);
}
}

> svg.gridicon.gridicons-science {
width: 24px;
height: 24px;
margin-inline-end: 8px;
margin-bottom: 4px;
}
}
7 changes: 7 additions & 0 deletions client/staging-site/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createElement } from 'react';
import StagingSite from './components/staging-site';

export function renderStagingSite( context, next ) {
context.primary = createElement( StagingSite );
next();
}
29 changes: 29 additions & 0 deletions client/staging-site/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import page from '@automattic/calypso-router';
import {
makeLayout,
render as clientRender,
redirectIfCurrentUserCannot,
redirectToDevToolsPromoIfNotAtomic,
} from 'calypso/controller';
import { navigation, siteSelection, sites } from 'calypso/my-sites/controller';
import { handleHostingPanelRedirect } from 'calypso/my-sites/hosting/controller';
import { siteDashboard } from 'calypso/sites-dashboard-v2/controller';
import { DOTCOM_STAGING_SITE } from 'calypso/sites-dashboard-v2/site-preview-pane/constants';
import { renderStagingSite } from './controller';

export default function () {
page( '/staging-site', siteSelection, sites, makeLayout, clientRender );

page(
'/staging-site/:site',
siteSelection,
navigation,
redirectToDevToolsPromoIfNotAtomic,
redirectIfCurrentUserCannot( 'manage_options' ),
handleHostingPanelRedirect,
renderStagingSite,
siteDashboard( DOTCOM_STAGING_SITE ),
makeLayout,
clientRender
);
}
Loading

0 comments on commit 5cc52b0

Please sign in to comment.