diff --git a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/domain-step/index.tsx b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/domain-step/index.tsx
index 376d5ed7d11d1..47429ffd1c984 100644
--- a/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/domain-step/index.tsx
+++ b/apps/editing-toolkit/editing-toolkit-plugin/editor-site-launch/src/launch-steps/domain-step/index.tsx
@@ -22,15 +22,9 @@ import './styles.scss';
const DomainStep: React.FunctionComponent< LaunchStepProps > = ( { onPrevStep, onNextStep } ) => {
const { plan, domain } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() );
const { currentDomainName } = useSite();
- const { domainSearch } = useDomainSearch();
+ const { domainSearch, setDomainSearch } = useDomainSearch();
- const {
- setDomain,
- unsetDomain,
- setDomainSearch,
- unsetPlan,
- confirmDomainSelection,
- } = useDispatch( LAUNCH_STORE );
+ const { setDomain, unsetDomain, unsetPlan, confirmDomainSelection } = useDispatch( LAUNCH_STORE );
const handleNext = () => {
confirmDomainSelection();
diff --git a/packages/launch/jest.config.js b/packages/launch/jest.config.js
new file mode 100644
index 0000000000000..bc9ea12d23b55
--- /dev/null
+++ b/packages/launch/jest.config.js
@@ -0,0 +1,7 @@
+module.exports = {
+ preset: '../../test/packages/jest-preset.js',
+ testEnvironment: 'jsdom',
+ globals: {
+ __i18n_text_domain__: 'default',
+ },
+};
diff --git a/packages/launch/package.json b/packages/launch/package.json
index db9e3947a9acf..994dabb5714a5 100644
--- a/packages/launch/package.json
+++ b/packages/launch/package.json
@@ -30,11 +30,12 @@
"watch": "tsc --build ./tsconfig.json --watch"
},
"dependencies": {
- "@automattic/react-i18n": "^1.0.0-alpha.0",
+ "@automattic/calypso-analytics": "^1.0.0-alpha.1",
"@automattic/data-stores": "^1.0.0-alpha.1",
"@automattic/domain-picker": "^1.0.0-alpha.0",
"@automattic/onboarding": "^1.0.0",
"@automattic/plans-grid": "^1.0.0-alpha.0",
+ "@automattic/react-i18n": "^1.0.0-alpha.0",
"@wordpress/components": "^10.0.5",
"@wordpress/icons": "^2.4.0",
"@wordpress/url": "^2.17.0",
@@ -44,7 +45,8 @@
"devDependencies": {
"@automattic/typography": "^1.0.0",
"@wordpress/base-styles": "^2.0.1",
- "copyfiles": "^2.3.0"
+ "copyfiles": "^2.3.0",
+ "@testing-library/react": "^10.0.5"
},
"peerDependencies": {
"@wordpress/data": "^4.22.3",
diff --git a/packages/launch/src/constants.ts b/packages/launch/src/constants.ts
new file mode 100644
index 0000000000000..76e50dc50742f
--- /dev/null
+++ b/packages/launch/src/constants.ts
@@ -0,0 +1 @@
+export const FOCUSED_LAUNCH_FLOW_ID = 'focused-launch';
diff --git a/packages/launch/src/focused-launch/domain-details/index.tsx b/packages/launch/src/focused-launch/domain-details/index.tsx
index 780197d5d9db1..65afc87ced873 100644
--- a/packages/launch/src/focused-launch/domain-details/index.tsx
+++ b/packages/launch/src/focused-launch/domain-details/index.tsx
@@ -3,22 +3,76 @@
/**
* External dependencies
*/
-import React from 'react';
-import { Link } from 'react-router-dom';
+import * as React from 'react';
+import { useHistory } from 'react-router-dom';
+
import { __ } from '@wordpress/i18n';
+import DomainPicker, { ITEM_TYPE_BUTTON } from '@automattic/domain-picker';
+import { Title, SubTitle } from '@automattic/onboarding';
+import { recordTracksEvent } from '@automattic/calypso-analytics';
+import type { DomainSuggestions } from '@automattic/data-stores';
/**
* Internal dependencies
*/
-import { Route } from '../route';
+import { useSite, useDomainSearch, useDomainSelection } from '../../hooks';
+import { FOCUSED_LAUNCH_FLOW_ID } from '../../constants';
+import GoBackButton from '../go-back-button';
import './style.scss';
+const ANALYTICS_UI_LOCATION = 'domain_step';
+
const DomainDetails: React.FunctionComponent = () => {
+ const { currentDomainName } = useSite();
+ const { domainSearch, setDomainSearch } = useDomainSearch();
+ const { onDomainSelect, onExistingSubdomainSelect, selectedDomain } = useDomainSelection();
+ const history = useHistory();
+
+ const goBack = () => {
+ history.goBack();
+ };
+
+ const handleDomainSelect = ( suggestion: DomainSuggestions.DomainSuggestion ) => {
+ onDomainSelect( suggestion );
+ goBack();
+ };
+
+ const trackDomainSearchInteraction = ( query: string ) => {
+ recordTracksEvent( 'calypso_newsite_domain_search_blur', {
+ flow: FOCUSED_LAUNCH_FLOW_ID,
+ query,
+ where: ANALYTICS_UI_LOCATION,
+ } );
+ };
+
return (
-
-
{ __( 'Go back', __i18n_text_domain__ ) }
-
{ __( 'Choose a domain', __i18n_text_domain__ ) }
+
+
+
+
+
+
{ __( 'Choose a domain', __i18n_text_domain__ ) }
+
+ { __( 'Free for the first year with any paid plan.', __i18n_text_domain__ ) }
+
+
+
+
+
);
};
diff --git a/packages/launch/src/focused-launch/domain-details/style.scss b/packages/launch/src/focused-launch/domain-details/style.scss
index e69de29bb2d1d..cc126dbc2a390 100644
--- a/packages/launch/src/focused-launch/domain-details/style.scss
+++ b/packages/launch/src/focused-launch/domain-details/style.scss
@@ -0,0 +1,18 @@
+@import '~@automattic/onboarding/styles/mixins';
+
+.focused-launch-domain-details__header {
+ margin-bottom: 38px;
+
+ @include break-medium {
+ margin-bottom: 64px;
+ }
+
+ .focused-launch-domain-details__back-link {
+ button.action-buttons__back {
+ color: var( --studio-black );
+ margin-bottom: 16px;
+ display: flex;
+ align-items: center;
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/launch/src/focused-launch/domain-details/test/index.tsx b/packages/launch/src/focused-launch/domain-details/test/index.tsx
new file mode 100644
index 0000000000000..2cdc464d8fa62
--- /dev/null
+++ b/packages/launch/src/focused-launch/domain-details/test/index.tsx
@@ -0,0 +1,44 @@
+/**
+ * External dependencies
+ */
+import React from 'react';
+import { MemoryRouter as Router } from 'react-router-dom';
+import { render, screen } from '@testing-library/react';
+
+/**
+ * Internal dependencies
+ */
+import DomainStep from '../';
+
+describe( 'DomainStep', () => {
+ test( 'Has title and sub-title', () => {
+ render(
+
+
+
+ );
+
+ expect( screen.queryByText( /Choose a domain/i ) ).toBeTruthy();
+ expect( screen.queryByText( /Free for the first year with any paid plan/i ) ).toBeTruthy();
+ } );
+
+ test( 'Has domain search input', () => {
+ render(
+
+
+
+ );
+
+ expect( screen.queryByPlaceholderText( /Search for a domain/i ) ).toBeTruthy();
+ } );
+
+ test( 'Has a back button', () => {
+ render(
+
+
+
+ );
+
+ expect( screen.queryByText( /Go back/i ) ).toBeTruthy();
+ } );
+} );
diff --git a/packages/launch/src/focused-launch/style.scss b/packages/launch/src/focused-launch/style.scss
index e69de29bb2d1d..5d165cc32d792 100644
--- a/packages/launch/src/focused-launch/style.scss
+++ b/packages/launch/src/focused-launch/style.scss
@@ -0,0 +1,3 @@
+.focused-launch-container {
+ padding: 0 10px;
+}
\ No newline at end of file
diff --git a/packages/launch/src/focused-launch/summary/index.tsx b/packages/launch/src/focused-launch/summary/index.tsx
index 918c9f54ada7d..33f3b9bd3f766 100644
--- a/packages/launch/src/focused-launch/summary/index.tsx
+++ b/packages/launch/src/focused-launch/summary/index.tsx
@@ -20,10 +20,19 @@ import FocusedLaunchSummaryItem, {
* Internal dependencies
*/
import { Route } from '../route';
-import { useTitle, useDomainSearch, useSiteDomains, useSite, usePlans } from '../../hooks';
+import {
+ useTitle,
+ useDomainSearch,
+ useSiteDomains,
+ useDomainSelection,
+ useSite,
+ usePlans,
+} from '../../hooks';
+
import { LAUNCH_STORE } from '../../stores';
import LaunchContext from '../../context';
import { isDefaultSiteTitle } from '../../utils';
+import { FOCUSED_LAUNCH_FLOW_ID } from '../../constants';
import './style.scss';
@@ -181,8 +190,8 @@ const DomainStep: React.FunctionComponent< DomainStepProps > = ( {
onExistingSubdomainSelect={ onExistingSubdomainSelect }
initialDomainSearch={ initialDomainSearch }
showSearchField={ false }
- analyticsFlowId="focused-launch"
- analyticsUiAlgo="focused_launch_domain_picker"
+ analyticsFlowId={ FOCUSED_LAUNCH_FLOW_ID }
+ analyticsUiAlgo="summary_domain_step"
quantity={ 3 }
quantityExpanded={ 3 }
itemType="individual-item"
@@ -437,8 +446,8 @@ const Summary: React.FunctionComponent = () => {
const { title, updateTitle, saveTitle, isSiteTitleStepVisible, showSiteTitleStep } = useTitle();
const { sitePrimaryDomain, siteSubdomain, hasPaidDomain } = useSiteDomains();
+ const { onDomainSelect, onExistingSubdomainSelect } = useDomainSelection();
const selectedDomain = useSelect( ( select ) => select( LAUNCH_STORE ).getSelectedDomain() );
- const { setDomain, unsetDomain } = useDispatch( LAUNCH_STORE );
const { domainSearch, isLoading } = useDomainSearch();
const site = useSite();
@@ -483,14 +492,14 @@ const Summary: React.FunctionComponent = () => {
currentDomain={ selectedDomain?.domain_name ?? sitePrimaryDomain?.domain }
initialDomainSearch={ domainSearch }
hasPaidDomain={ hasPaidDomain }
- onDomainSelect={ setDomain }
isLoading={ isLoading }
+ onDomainSelect={ onDomainSelect }
/** NOTE: this makes the assumption that the user has a free domain,
* thus when they click the free domain, we just remove the value from the store
* this is a valid strategy in this context because they won't even see this step if
* they already have a paid domain
* */
- onExistingSubdomainSelect={ unsetDomain }
+ onExistingSubdomainSelect={ onExistingSubdomainSelect }
locale={ locale }
/>
);
diff --git a/packages/launch/src/hooks/index.ts b/packages/launch/src/hooks/index.ts
index 2791fbbdc7d02..c3352bc88acea 100644
--- a/packages/launch/src/hooks/index.ts
+++ b/packages/launch/src/hooks/index.ts
@@ -2,6 +2,7 @@ export * from './use-site';
export * from './use-on-launch';
export * from './use-domain-suggestion';
export * from './use-domain-search';
+export * from './use-domain-selection';
export * from './use-title';
export * from './use-site-domains';
export * from './use-plans';
diff --git a/packages/launch/src/hooks/use-domain-search.ts b/packages/launch/src/hooks/use-domain-search.ts
index fd48aa1a132f2..2ede9ac2f4d69 100644
--- a/packages/launch/src/hooks/use-domain-search.ts
+++ b/packages/launch/src/hooks/use-domain-search.ts
@@ -2,7 +2,7 @@
* External dependencies
*/
import { useSelect } from '@wordpress/data';
-
+import { useDispatch } from '@wordpress/data';
/**
* External dependencies
*/
@@ -10,10 +10,15 @@ import { LAUNCH_STORE } from '../stores';
import { useSite, useTitle } from './';
import { isDefaultSiteTitle } from '../utils';
-export function useDomainSearch(): { domainSearch: string; isLoading: boolean } {
+export function useDomainSearch(): {
+ domainSearch: string;
+ isLoading: boolean;
+ setDomainSearch: ( search: string ) => void;
+} {
const { domainSearch } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() );
const { title } = useTitle();
const { currentDomainName, isLoadingSite } = useSite();
+ const { setDomainSearch } = useDispatch( LAUNCH_STORE );
let search = domainSearch.trim() || title;
@@ -24,5 +29,6 @@ export function useDomainSearch(): { domainSearch: string; isLoading: boolean }
return {
domainSearch: search,
isLoading: isLoadingSite,
+ setDomainSearch,
};
}
diff --git a/packages/launch/src/hooks/use-domain-selection.ts b/packages/launch/src/hooks/use-domain-selection.ts
new file mode 100644
index 0000000000000..c7cbff0755375
--- /dev/null
+++ b/packages/launch/src/hooks/use-domain-selection.ts
@@ -0,0 +1,34 @@
+/**
+ * External dependencies
+ */
+import { useDispatch, useSelect } from '@wordpress/data';
+import type { DomainSuggestions } from '@automattic/data-stores';
+
+/**
+ * Internal dependencies
+ */
+import { LAUNCH_STORE } from '../stores';
+
+export function useDomainSelection() {
+ const { plan } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() );
+ const { setDomain, unsetDomain, unsetPlan, confirmDomainSelection } = useDispatch( LAUNCH_STORE );
+ const { domain: selectedDomain } = useSelect( ( select ) => select( LAUNCH_STORE ).getState() );
+
+ function onDomainSelect( suggestion: DomainSuggestions.DomainSuggestion ) {
+ confirmDomainSelection();
+ setDomain( suggestion );
+ if ( plan?.isFree ) {
+ unsetPlan();
+ }
+ }
+
+ function onExistingSubdomainSelect() {
+ unsetDomain();
+ }
+
+ return {
+ onDomainSelect,
+ onExistingSubdomainSelect,
+ selectedDomain,
+ };
+}
diff --git a/packages/launch/tsconfig.json b/packages/launch/tsconfig.json
index dd7d81c212a68..85c13d0e68efb 100644
--- a/packages/launch/tsconfig.json
+++ b/packages/launch/tsconfig.json
@@ -38,6 +38,7 @@
{ "path": "../components" },
{ "path": "../onboarding" },
{ "path": "../domain-picker" },
- { "path": "../plans-grid" }
+ { "path": "../plans-grid" },
+ { "path": "../calypso-analytics" }
]
}