diff --git a/client/signup/config/flows-pure.js b/client/signup/config/flows-pure.js index 8ed7227aea4c0..aaff2f0219291 100644 --- a/client/signup/config/flows-pure.js +++ b/client/signup/config/flows-pure.js @@ -395,7 +395,7 @@ export function generateFlows( { }, { name: 'setup-site', - steps: [ 'intent', 'site-options', 'starting-point', 'design-setup-site' ], + steps: [ 'intent', 'site-options', 'starting-point', 'courses', 'design-setup-site' ], destination: getDestinationFromIntent, description: 'Sets up a site that has already been created and paid for (if purchases were made)', diff --git a/client/signup/config/step-components.js b/client/signup/config/step-components.js index 4820c0506e363..f587b276ce2b5 100644 --- a/client/signup/config/step-components.js +++ b/client/signup/config/step-components.js @@ -7,6 +7,7 @@ const stepNameToModuleName = { 'clone-jetpack': 'clone-jetpack', 'clone-ready': 'clone-ready', 'clone-cloning': 'clone-cloning', + courses: 'courses', 'creds-confirm': 'creds-confirm', 'creds-complete': 'creds-complete', 'creds-permission': 'creds-permission', diff --git a/client/signup/config/steps-pure.js b/client/signup/config/steps-pure.js index afd7f325bcc04..97db33d61628e 100644 --- a/client/signup/config/steps-pure.js +++ b/client/signup/config/steps-pure.js @@ -792,6 +792,9 @@ export function generateSteps( { apiRequestFunction: addPlanToCart, delayApiRequestUntilComplete: true, }, + courses: { + stepName: 'courses', + }, // ↓ importer steps list: { diff --git a/client/signup/icons/index.tsx b/client/signup/icons/index.tsx index bcbf0d5d32907..b36cdee857852 100644 --- a/client/signup/icons/index.tsx +++ b/client/signup/icons/index.tsx @@ -54,6 +54,12 @@ export const write: ReactElement = ( ); +export const play: ReactElement = ( + + + +); + export const design: ReactElement = ( { icon: React.ReactElement; value: T; actionText: TranslateResult; + hidden?: boolean; } interface Props< T > { diff --git a/client/signup/step-wrapper/index.jsx b/client/signup/step-wrapper/index.jsx index 0d3640ec990f5..4a244550029f8 100644 --- a/client/signup/step-wrapper/index.jsx +++ b/client/signup/step-wrapper/index.jsx @@ -28,6 +28,8 @@ class StepWrapper extends Component { isLargeSkipLayout: PropTypes.bool, isExternalBackUrl: PropTypes.bool, headerButton: PropTypes.node, + isWideLayout: PropTypes.bool, + isFullLayout: PropTypes.bool, isHorizontalLayout: PropTypes.bool, queryParams: PropTypes.object, }; @@ -166,6 +168,7 @@ class StepWrapper extends Component { hideNext, isLargeSkipLayout, isWideLayout, + isFullLayout, skipButtonAlign, align, headerImageUrl, @@ -182,6 +185,7 @@ class StepWrapper extends Component { const classes = classNames( 'step-wrapper', this.props.className, { 'is-horizontal-layout': isHorizontalLayout, 'is-wide-layout': isWideLayout, + 'is-full-layout': isFullLayout, 'is-large-skip-layout': isLargeSkipLayout, 'has-navigation': hasNavigation, } ); diff --git a/client/signup/step-wrapper/style.scss b/client/signup/step-wrapper/style.scss index dc29603c95956..40d5b09071858 100644 --- a/client/signup/step-wrapper/style.scss +++ b/client/signup/step-wrapper/style.scss @@ -55,7 +55,7 @@ @mixin unstick { position: absolute; - top: 2px; + top: 1px; left: 11px; right: 16px; padding: 0; @@ -77,11 +77,17 @@ .step-wrapper__navigation-link { font-size: 0.875rem; - font-weight: 500; /* stylelint-disable-line */ + font-weight: 500; &.button.is-primary { - border-radius: 4px; /* stylelint-disable-line scales/radii */ + border-radius: 4px; box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.05 ); + + .signup__step.is-courses & { + color: #101517; + background-color: #ffffff; + border-color: transparent; + } } &.has-underline { @@ -120,6 +126,11 @@ max-width: 1040px; } + // Some steps (like courses) have their width limitation + &.is-full-layout { + max-width: unset; + } + // Some steps (intent gathering) use a horizontal layout &.is-horizontal-layout { align-items: flex-start; diff --git a/client/signup/steps/courses/footer.tsx b/client/signup/steps/courses/footer.tsx new file mode 100644 index 0000000000000..a1153bb944562 --- /dev/null +++ b/client/signup/steps/courses/footer.tsx @@ -0,0 +1,31 @@ +import { Button } from '@automattic/components'; +import { useTranslate } from 'i18n-calypso'; +import React from 'react'; + +interface Props { + isCourseComplete?: boolean; + onStartWriting: () => void; +} + +const CoursesFooter: React.FC< Props > = ( { isCourseComplete, onStartWriting } ) => { + const translate = useTranslate(); + + if ( ! isCourseComplete ) { + return null; + } + + return ( +
+
+ { translate( + "You did it! Now it's time to put your skills to work and draft your first post." + ) } + +
+
+ ); +}; + +export default CoursesFooter; diff --git a/client/signup/steps/courses/header.tsx b/client/signup/steps/courses/header.tsx new file mode 100644 index 0000000000000..6739123e6bb5d --- /dev/null +++ b/client/signup/steps/courses/header.tsx @@ -0,0 +1,10 @@ +import WordPressLogo from 'calypso/components/wordpress-logo'; +import type { ReactElement } from 'react'; + +const CoursesHeader = (): ReactElement => ( +
+ +
+); + +export default CoursesHeader; diff --git a/client/signup/steps/courses/index.tsx b/client/signup/steps/courses/index.tsx new file mode 100644 index 0000000000000..a1bb1bec8eef2 --- /dev/null +++ b/client/signup/steps/courses/index.tsx @@ -0,0 +1,61 @@ +import { useViewportMatch } from '@wordpress/compose'; +import { useTranslate } from 'i18n-calypso'; +import React from 'react'; +import { useDispatch } from 'react-redux'; +import VideosUi from 'calypso/components/videos-ui'; +import { COURSE_SLUGS, useCourseData } from 'calypso/data/courses'; +import StepWrapper from 'calypso/signup/step-wrapper'; +import { saveSignupStep, submitSignupStep } from 'calypso/state/signup/progress/actions'; +import CoursesFooter from './footer'; +import CoursesHeader from './header'; +import './style.scss'; + +interface Props { + stepName: string; + goToNextStep: () => void; +} + +export default function CoursesStep( props: Props ): React.ReactNode { + const dispatch = useDispatch(); + const translate = useTranslate(); + const { stepName, goToNextStep } = props; + const isMobile = useViewportMatch( 'small', '<' ); + const courseSlug = COURSE_SLUGS.BLOGGING_QUICK_START; + const { isCourseComplete } = useCourseData( courseSlug ); + const hideSkip = isMobile && isCourseComplete; + + const onStartWriting = () => { + dispatch( submitSignupStep( { stepName } ) ); + goToNextStep(); + }; + + React.useEffect( () => { + dispatch( saveSignupStep( { stepName } ) ); + }, [] ); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + ( + + ) } + /> + } + hideSkip={ hideSkip } + hideNext={ ! hideSkip } + skipLabelText={ translate( 'Draft your first post' ) } + skipButtonAlign="top" + nextLabelText={ translate( 'Start writing' ) } + { ...props } + /> + ); +} diff --git a/client/signup/steps/courses/style.scss b/client/signup/steps/courses/style.scss new file mode 100644 index 0000000000000..86ac7f27f3f71 --- /dev/null +++ b/client/signup/steps/courses/style.scss @@ -0,0 +1,103 @@ +@import '@wordpress/base-styles/_breakpoints.scss'; +@import '@wordpress/base-styles/_mixins.scss'; + +.courses { + // Not good but this way can easily change the background color for courses step + &::before { + content: ''; + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: #101517; + } + + .courses__header { + position: absolute; + top: -60px; + left: 0; + right: 0; + height: 60px; + display: flex; + align-items: center; + padding: 0 20px; + background-color: #151b1e; + + .courses__header-logo { + margin-top: 4px; + fill: #fff; + stroke: #fff; + } + + @include break-small { + padding: 0 24px; + } + } + + .action-buttons { + border: 0; + box-shadow: 0 -1px 0 #2c3234; + background-color: #101517; + + .button.navigation-link.is-borderless { + color: #fff !important; + + svg { + fill: #fff !important; + } + } + + @include break-small { + box-shadow: none; + } + } + + .videos-ui { + position: relative; + width: 100%; + min-height: calc( 100vh - 60px ); + margin-top: 12px; + } + + .courses__footer { + display: none; + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 0 20px; + box-shadow: 0 -1px 0 #2c3234; + background-color: #101517; + animation: appear 0.3s ease-in-out; + @include reduce-motion( 'animation' ); + + .courses__footer-content { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + height: 72px; + max-width: 1160px; + margin: 0 auto; + } + + .courses__footer-button { + flex-shrink: 0; + margin-left: 20px; + border-radius: 4px; + border-color: transparent; + color: #101517; + font-weight: 500; + transition: opacity 0.2s ease-out; + + &:hover { + opacity: 0.9; + } + } + + @include break-small { + display: block; + } + } +} diff --git a/client/signup/steps/intent/index.tsx b/client/signup/steps/intent/index.tsx index 3fcdefa155df5..0f25da30d02ba 100644 --- a/client/signup/steps/intent/index.tsx +++ b/client/signup/steps/intent/index.tsx @@ -26,7 +26,7 @@ interface Props { const EXCLUDE_STEPS: { [ key: string ]: string[] } = { write: [], - build: [ 'site-options', 'starting-point' ], + build: [ 'site-options', 'starting-point', 'courses' ], }; const EXTERNAL_FLOW: { [ key: string ]: string } = { diff --git a/client/signup/steps/starting-point/index.tsx b/client/signup/steps/starting-point/index.tsx index 01220c5484f04..8f14c44553889 100644 --- a/client/signup/steps/starting-point/index.tsx +++ b/client/signup/steps/starting-point/index.tsx @@ -17,11 +17,11 @@ interface Props { initialContext: any; } -// TODO: Adding take the masterclass const EXCLUDE_STEPS: { [ key in StartingPointFlag ]: string[] } = { - write: [ 'design-setup-site' ], - design: [], - 'skip-to-my-home': [ 'design-setup-site' ], + write: [ 'courses', 'design-setup-site' ], + courses: [ 'design-setup-site' ], + design: [ 'courses' ], + 'skip-to-my-home': [ 'courses', 'design-setup-site' ], }; export default function StartingPointStep( props: Props ): React.ReactNode { diff --git a/client/signup/steps/starting-point/starting-point.tsx b/client/signup/steps/starting-point/starting-point.tsx index 019843edb7570..64f502ab86d60 100644 --- a/client/signup/steps/starting-point/starting-point.tsx +++ b/client/signup/steps/starting-point/starting-point.tsx @@ -1,6 +1,7 @@ +import { isEnabled } from '@automattic/calypso-config'; import { localize, LocalizeProps } from 'i18n-calypso'; import React from 'react'; -import { write, design } from '../../icons'; +import { write, play, design } from '../../icons'; import SelectItems, { SelectItem } from '../../select-items'; import type { StartingPointFlag } from './types'; @@ -21,6 +22,15 @@ const useStartingPoints = ( { translate }: Pick< Props, 'translate' > ): Startin value: 'write', actionText: translate( 'Start writing' ), }, + { + key: 'courses', + title: translate( 'Watch Blogging videos' ), + description: translate( ' Learn the blogging basics in minutes ' ), + icon: play, + value: 'courses', + actionText: translate( 'Start learning' ), + hidden: ! isEnabled( 'signup/starting-point-courses' ), + }, { key: 'design', title: translate( 'Choose a design' ), @@ -35,7 +45,12 @@ const useStartingPoints = ( { translate }: Pick< Props, 'translate' > ): Startin const StartingPoint: React.FC< Props > = ( { onSelect, translate } ) => { const startingPoints = useStartingPoints( { translate } ); - return ; + return ( +