diff --git a/client/data/site-profiler/types.ts b/client/data/site-profiler/types.ts index 5089fef55afaf..da87237bc9566 100644 --- a/client/data/site-profiler/types.ts +++ b/client/data/site-profiler/types.ts @@ -112,6 +112,10 @@ export interface UrlBasicMetricsQueryResponse { token: string; } +export interface LeadMutationResponse { + success: boolean; +} + export interface UrlSecurityMetricsQueryResponse { wpscan: { report: { diff --git a/client/data/site-profiler/use-lead-query.ts b/client/data/site-profiler/use-lead-query.ts new file mode 100644 index 0000000000000..852a8fa07c10d --- /dev/null +++ b/client/data/site-profiler/use-lead-query.ts @@ -0,0 +1,20 @@ +import { useMutation } from '@tanstack/react-query'; +import { LeadMutationResponse } from 'calypso/data/site-profiler/types'; +import wp from 'calypso/lib/wp'; + +export const useLeadMutation = ( url?: string, hash?: string ) => { + return useMutation( { + mutationKey: [ 'lead', url, hash ], + mutationFn: (): Promise< LeadMutationResponse > => + wp.req.post( + { + path: '/site-profiler/lead', + apiNamespace: 'wpcom/v2', + }, + { + url, + hash, + } + ), + } ); +}; diff --git a/client/performance-profiler/components/dashboard-content/index.tsx b/client/performance-profiler/components/dashboard-content/index.tsx index 4268152483266..f230487abf3b7 100644 --- a/client/performance-profiler/components/dashboard-content/index.tsx +++ b/client/performance-profiler/components/dashboard-content/index.tsx @@ -13,11 +13,13 @@ import './style.scss'; type PerformanceProfilerDashboardContentProps = { performanceReport: PerformanceReport; url: string; + hash: string; }; export const PerformanceProfilerDashboardContent = ( { performanceReport, url, + hash, }: PerformanceProfilerDashboardContentProps ) => { const { overall_score, fcp, lcp, cls, inp, ttfb, tbt, audits, history, screenshots, is_wpcom } = performanceReport; @@ -41,7 +43,7 @@ export const PerformanceProfilerDashboardContent = ( { tbt={ tbt } history={ history } /> - + { audits && } diff --git a/client/performance-profiler/components/message-display/index.tsx b/client/performance-profiler/components/message-display/index.tsx new file mode 100644 index 0000000000000..3b04fb9ee7580 --- /dev/null +++ b/client/performance-profiler/components/message-display/index.tsx @@ -0,0 +1,55 @@ +import { Gridicon } from '@automattic/components'; +import { Button, IconType } from '@wordpress/components'; +import clsx from 'clsx'; +import { ReactNode } from 'react'; +import { Badge } from 'calypso/performance-profiler/components/badge'; + +import './style.scss'; + +type Props = { + title?: string; + message: string | ReactNode; + ctaText?: string; + ctaHref?: string; + secondaryMessage?: string; + displayBadge?: boolean; + ctaIcon?: string; + isErrorMessage?: boolean; +}; + +export const MessageDisplay = ( { + displayBadge = false, + title, + message, + ctaText, + ctaHref, + secondaryMessage, + ctaIcon = '', + isErrorMessage = false, +}: Props ) => { + return ( +
+
+
+ { displayBadge && } +
+ { isErrorMessage && } + { title &&

{ title }

} +

{ message }

+ { ctaText && ctaHref && ( + + ) } +
+ { secondaryMessage &&

{ secondaryMessage }

} +
+
+
+ ); +}; diff --git a/client/performance-profiler/components/message-display/style.scss b/client/performance-profiler/components/message-display/style.scss new file mode 100644 index 0000000000000..2c714d930c4ba --- /dev/null +++ b/client/performance-profiler/components/message-display/style.scss @@ -0,0 +1,105 @@ +@import "@wordpress/base-styles/breakpoints"; +@import "@automattic/typography/styles/variables"; + +$blueberry-color: #3858e9; + +.message-display { + color: #fff; + padding-top: 40px; + background: linear-gradient(180deg, var(--studio-gray-100) 25.44%, rgba(16, 21, 23, 0) 100%), url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iOCIgY3k9IjgiIHI9IjEiIGZpbGw9IndoaXRlIiBmaWxsLW9wYWNpdHk9IjAuMjUiLz4KPC9zdmc+Cg==) repeat, var(--studio-gray-100); + + a { + color: $blueberry-color; + + &:hover { + color: darken($blueberry-color, 10%); + text-decoration: underline; + } + + &.is-primary { + color: #fff; + background-color: $blueberry-color; + border-radius: 4px; + + &:hover:not(:disabled), + &:active:not(:disabled), + &:focus:not(:disabled) { + background-color: darken($blueberry-color, 10%); + border-color: darken($blueberry-color, 10%); + box-shadow: none; + } + } + } + + p { + margin: 0; + } + + .l-block-wrapper { + height: 100%; + max-width: 1056px; + } + + .message-wrapper { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 64px; + min-height: 700px; + width: 50%; + + .main-message { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: center; + gap: 16px; + + &.error { + border-radius: 4px; + border: 1px solid var(--studio-red-70); + background-color: var(--studio-red-70); + padding: 16px; + padding-left: 52px; + position: relative; + + .gridicon { + position: absolute; + top: 16px; + left: 16px; + } + + .cta-button { + margin: 0; + } + } + + .title { + font-family: $brand-serif; + font-size: $font-headline-medium; + line-height: $font-headline-large; + color: #fff; + } + + .message { + font-size: $font-body; + font-weight: 500; + line-height: $font-title-medium; + } + + .cta-button { + margin-top: 16px; + font-size: $font-body-small; + line-height: $font-title-small; + padding: 20px; + } + } + + .secondary-message { + font-size: $font-body-small; + line-height: $font-title-small; + color: var(--studio-gray-20); + } + } +} diff --git a/client/performance-profiler/components/newsletter-banner.tsx b/client/performance-profiler/components/newsletter-banner.tsx index 5bd635ccf77c1..bb550db01c769 100644 --- a/client/performance-profiler/components/newsletter-banner.tsx +++ b/client/performance-profiler/components/newsletter-banner.tsx @@ -34,7 +34,7 @@ const BlueberryButton = styled( Button )` } `; -export const NewsletterBanner = () => { +export const NewsletterBanner = ( { link }: { link: string } ) => { const translate = useTranslate(); return ( @@ -48,7 +48,7 @@ export const NewsletterBanner = () => { { translate( 'All you need is a free WordPress.com account to get started.' ) } - + { translate( 'Sign up for email reports' ) } diff --git a/client/performance-profiler/controller.tsx b/client/performance-profiler/controller.tsx index e9378d65770cd..fd3e5622ec5c0 100644 --- a/client/performance-profiler/controller.tsx +++ b/client/performance-profiler/controller.tsx @@ -7,6 +7,7 @@ import Main from 'calypso/components/main'; import { isUserLoggedIn } from 'calypso/state/current-user/selectors'; import { TabType } from './components/header'; import { PerformanceProfilerDashboard } from './pages/dashboard'; +import { WeeklyReport } from './pages/weekly-report'; export function PerformanceProfilerDashboardContext( context: Context, next: () => void ): void { const isLoggedIn = isUserLoggedIn( context.store.getState() ); @@ -41,6 +42,36 @@ export function PerformanceProfilerDashboardContext( context: Context, next: () next(); } +export function WeeklyReportContext( context: Context, next: () => void ): void { + const isLoggedIn = isUserLoggedIn( context.store.getState() ); + + if ( ! config.isEnabled( 'performance-profiler' ) ) { + page.redirect( '/' ); + return; + } + + if ( ! isLoggedIn ) { + window.location.href = '/log-in?redirect_to=' + encodeURIComponent( context.path ); + return; + } + + const url = context.query?.url?.startsWith( 'http' ) + ? context.query.url + : `https://${ context.query?.url ?? '' }`; + + context.primary = ( + <> +
+ +
+ + + + ); + + next(); +} + export const notFound = ( context: Context, next: () => void ) => { context.primary = ( ) } diff --git a/client/performance-profiler/pages/weekly-report/index.tsx b/client/performance-profiler/pages/weekly-report/index.tsx new file mode 100644 index 0000000000000..aa6583c802444 --- /dev/null +++ b/client/performance-profiler/pages/weekly-report/index.tsx @@ -0,0 +1,141 @@ +import styled from '@emotion/styled'; +import { useTranslate } from 'i18n-calypso'; +import { useEffect } from 'react'; +import DocumentHead from 'calypso/components/data/document-head'; +import { useLeadMutation } from 'calypso/data/site-profiler/use-lead-query'; +import { MessageDisplay } from 'calypso/performance-profiler/components/message-display'; + +type WeeklyReportProps = { + url: string; + hash: string; +}; + +const LoaderText = styled.span` + display: flex; + align-items: center; + font-size: 16px; + font-weight: 400; + line-height: 24px; + position: relative; + + &:before { + content: ''; + display: inline-block; + border-radius: 50%; + margin-right: 10px; + content: ''; + width: 16px; + height: 16px; + border: solid 2px #074ee8; + border-radius: 50%; + border-bottom-color: transparent; + -webkit-transition: all 0.5s ease-in; + -webkit-animation-name: rotate; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -webkit-animation-timing-function: linear; + + transition: all 0.5s ease-in; + animation-name: rotate; + animation-duration: 1s; + animation-iteration-count: infinite; + animation-timing-function: linear; + } + + @keyframes rotate { + from { + transform: rotate( 0deg ); + } + to { + transform: rotate( 360deg ); + } + } + + @-webkit-keyframes rotate { + from { + -webkit-transform: rotate( 0deg ); + } + to { + -webkit-transform: rotate( 360deg ); + } + } +`; + +const ErrorSecondLine = styled.span` + color: var( --studio-red-5 ); + font-weight: 400; + line-height: 20px; +`; + +export const WeeklyReport = ( props: WeeklyReportProps ) => { + const translate = useTranslate(); + const { url, hash } = props; + + const siteUrl = new URL( url ); + + const { mutate, isPending, isError, isSuccess } = useLeadMutation( url, hash ); + + useEffect( () => { + mutate(); + }, [ mutate ] ); + + const secondaryMessage = translate( + 'You can stop receiving performance reports at any time by clicking the Unsubscribe link in the email footer.' + ); + + return ( +
+ + + { isPending && ( + + { translate( 'Enabling email reports for %s', { + args: [ siteUrl.host ], + } ) } + + } + secondaryMessage={ secondaryMessage } + /> + ) } + { isError && ( + + { translate( 'Email reports could not be enabled for %s', { + args: [ siteUrl.host ], + } ) } +
+ + { translate( + 'Please try again or contact support if you continue to experience problems.' + ) } + + + } + ctaText={ translate( 'Enable email reports' ) } + ctaHref={ `/speed-test-tool/weekly-report?url=${ url }&hash=${ hash }` } + secondaryMessage={ secondaryMessage } + /> + ) } + { isSuccess && ( + } } + ) } + ctaText={ translate( '← Back to speed test' ) } + ctaHref="/speed-test" + ctaIcon="arrow-left" + secondaryMessage={ secondaryMessage } + /> + ) } +
+ ); +};