Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Domains: Create 100-Year Domain flow #95081

Merged
merged 38 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
74bdffb
Signup: Submit the domains step on checkout back button click (#94859)
allilevine Sep 30, 2024
17b7c6f
Add styling and checks for the flow in the releavnt steps
leonardost Oct 1, 2024
27572cb
Move CSS class
leonardost Oct 1, 2024
8e6a4d4
Add domain to the shopping cart, WIP
leonardost Oct 1, 2024
7ee7f6c
Remove free WPCOM subdomain from generated suggestions
leonardost Oct 2, 2024
9aef942
Skip availability check for FQDN in 1--year domain flow if it's not c…
leonardost Oct 2, 2024
c1f458c
Small refactor
leonardost Oct 2, 2024
08b950c
Set vendor string to `1oo-year-domains` in the 100-year domain flow
leonardost Oct 2, 2024
d84de94
Show price without "/year" for 100-year domains
leonardost Oct 2, 2024
ee06ed1
Update layout of domain search page in the 100-year domain flow
leonardost Oct 2, 2024
e1b2ff0
Hardcode $2000 price just for testing
leonardost Oct 9, 2024
cbd3235
Fix CSS styling
leonardost Oct 9, 2024
01dfd5c
Add `is_hundred_year_domain` flag to domain bought in 100-year domain…
leonardost Oct 9, 2024
9a5fce3
Remove unused variables and add TODOs
leonardost Oct 10, 2024
0f5c74c
Replace 'hundred-year-domain' strings by HUNDRED_YEAR_DOMIN_FLOW cons…
leonardost Oct 10, 2024
55e23ea
Fix typo in constant name
leonardost Oct 10, 2024
4e48a3d
Small refactors
leonardost Oct 10, 2024
93cf947
Fix flow to work with logged out users
leonardost Oct 10, 2024
df1c64b
Remove unnecessary code to add domain to shopping cart
leonardost Oct 10, 2024
a28c102
Add `is_hundred_year_domain` flag when a domain is selected in the 10…
leonardost Oct 10, 2024
85d3a3b
Update "Learn More" modal title in 100-Year domain flow
leonardost Oct 10, 2024
0b08d84
Improve back navigation inside the 100-Year domain flow
leonardost Oct 10, 2024
44d33a2
Revert unwanted change
leonardost Oct 10, 2024
6b904b5
Remove commented CSS
leonardost Oct 10, 2024
38d3f45
Move const definition outside function
leonardost Oct 10, 2024
60ac351
Do not create site for the 100-year domain flow
leonardost Oct 11, 2024
d5d233d
Add delay in the "Processing" step to show the Earth video for a while
leonardost Oct 11, 2024
dd890b5
Update flow name check
leonardost Oct 11, 2024
95f0522
Update TLD restriction error message with code review suggestion
leonardost Oct 11, 2024
f2770c6
Fix mobile CSS styling
leonardost Oct 11, 2024
d2783e2
After logging in, redirect user to `processing` step
leonardost Oct 11, 2024
b5a4110
Fix 100-year domain flow when starting logged-out
leonardost Oct 14, 2024
7f029cd
Enable 100-year domain flow only for dev and staging environments
leonardost Oct 14, 2024
55931ca
Remove unneeded CSS code
leonardost Oct 14, 2024
0fd483f
Enable `100-year-domain` feature flag in `wpcalypso` env
leonardost Oct 14, 2024
8cc35b8
Fix left white margin in smaller viewports
leonardost Oct 16, 2024
214dcd3
Fix incorrect domain name layout in smaller viewports
leonardost Oct 16, 2024
d4e0192
Add "busy" state to the domain selection button
leonardost Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions client/components/domains/domain-product-price/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,18 @@ class DomainProductPrice extends Component {
);
}

/**
* Used to render the price of 100-year domains, which are a one time purchase
* TODO: Replace hardcoded value by 100-eyar domain product price when we have it
*/
renderOneTimePrice() {
return (
<div className="domain-product-price domain-product-single-price">
<span>$2,000</span>
</div>
);
}

render() {
if ( this.props.isLoading ) {
return (
Expand All @@ -278,6 +290,8 @@ class DomainProductPrice extends Component {
}

switch ( this.props.rule ) {
case 'ONE_TIME_PRICE':
return this.renderOneTimePrice();
case 'FREE_DOMAIN':
return this.renderFree();
case 'FREE_FOR_FIRST_YEAR':
Expand Down
11 changes: 11 additions & 0 deletions client/components/domains/register-domain-step/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import config from '@automattic/calypso-config';
import { isBlogger, isFreeWordPressComDomain } from '@automattic/calypso-products';
import page from '@automattic/calypso-router';
import { Button, CompactCard, ResponsiveToolbarGroup } from '@automattic/components';
import { isHundredYearDomainFlow } from '@automattic/onboarding';
import Search from '@automattic/search';
import { withShoppingCart } from '@automattic/shopping-cart';
import { Icon } from '@wordpress/icons';
Expand Down Expand Up @@ -1069,6 +1070,15 @@ class RegisterDomainStep extends Component {
return;
}

// Skip availability check for the 100-year domain flow if the domain is not com/net/org
if (
isHundredYearDomainFlow( this.props.flowName ) &&
! [ 'com', 'net', 'org' ].includes( getTld( domain ) )
) {
this.showSuggestionErrorMessage( domain, 'hundred_year_domain_tld_restriction', {} );
return;
}

return new Promise( ( resolve ) => {
checkDomainAvailability(
{ domainName: domain, blogId: get( this.props, 'selectedSite.ID', null ) },
Expand Down Expand Up @@ -1514,6 +1524,7 @@ class RegisterDomainStep extends Component {
this.props.onAddDomain( suggestion, position, previousState );
}

this.setState( { pendingCheckSuggestion: suggestion } );
Copy link
Contributor Author

@leonardost leonardost Oct 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was removed in #84171 but I'm not sure why. Without this, the "Select" domain button doesn't have a "busy" state when it's clicked.

const promise = this.preCheckDomainAvailability( domain )
.catch( () => [] )
.then( ( { status, trademarkClaimsNoticeInfo } ) => {
Expand Down
93 changes: 93 additions & 0 deletions client/landing/stepper/declarative-flow/hundred-year-domain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { OnboardSelect } from '@automattic/data-stores';
import { HUNDRED_YEAR_DOMAIN_FLOW, addProductsToCart } from '@automattic/onboarding';
import { MinimalRequestCartProduct } from '@automattic/shopping-cart';
import { useDispatch, useSelect } from '@wordpress/data';
import { translate } from 'i18n-calypso';
import { domainRegistration } from 'calypso/lib/cart-values/cart-items';
import {
clearSignupDestinationCookie,
setSignupCompleteSlug,
setSignupCompleteFlowName,
} from 'calypso/signup/storageUtils';
import { ONBOARD_STORE } from '../stores';
import { stepsWithRequiredLogin } from '../utils/steps-with-required-login';
import type { ProvidedDependencies, Flow } from './internals/types';

const HundredYearDomainFlow: Flow = {
name: HUNDRED_YEAR_DOMAIN_FLOW,
isSignupFlow: true,

get title() {
return translate( '100-Year Domain' );
},

useSteps() {
const steps = [
{
slug: 'domains',
asyncComponent: () => import( './internals/steps-repository/domains' ),
},
...stepsWithRequiredLogin( [
{
slug: 'processing',
asyncComponent: () => import( './internals/steps-repository/processing-step' ),
},
] ),
];

return steps;
},

useStepNavigation( _currentStep, navigate ) {
const flowName = this.name;
const checkoutBackUrl = new URL( `/setup/${ flowName }/domains`, window.location.href );

const { setDomainCartItem } = useDispatch( ONBOARD_STORE );

const { domainCartItem } = useSelect(
( select ) => ( {
domainCartItem: ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainCartItem(),
} ),
[]
);

async function submit( providedDependencies: ProvidedDependencies = {} ) {
const { domainName, productSlug } = providedDependencies;

const submittedDomainCartItem = domainRegistration( {
productSlug: productSlug as string,
domain: domainName as string,
extra: { is_hundred_year_domain: true },
} );

switch ( _currentStep ) {
case 'domains':
clearSignupDestinationCookie();
setDomainCartItem( submittedDomainCartItem );
return navigate( 'processing' );

case 'processing':
setSignupCompleteSlug( providedDependencies.siteSlug );
setSignupCompleteFlowName( flowName );

await addProductsToCart( 'no-site', flowName, [
domainCartItem as MinimalRequestCartProduct,
] );
// Delay to keep the "Setting up your legacy..." page showing for 2 seconds
// since there's nothing to actually process in that step
await new Promise( ( resolve ) => setTimeout( resolve, 2000 ) );

// use replace instead of assign to remove the processing URL from history
return window.location.replace(
`/checkout/no-site?signup=1&isDomainOnly=1&checkoutBackUrl=${ encodeURIComponent(
checkoutBackUrl.href
) }`
);
}
}

return { submit };
},
};

export default HundredYearDomainFlow;
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ button {
.update-design,
.update-options,
.hundred-year-plan,
.hundred-year-domain,
.link-in-bio-tld,
.entrepreneur,
.generate-content {
Expand All @@ -120,7 +121,8 @@ button {
@include break-small {
&.courses,
&.site-picker,
&.new-or-existing-site {
&.new-or-existing-site,
&.domains {
margin-top: -60px;
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
DOMAIN_UPSELL_FLOW,
HUNDRED_YEAR_DOMAIN_FLOW,
HUNDRED_YEAR_PLAN_FLOW,
isDomainUpsellFlow,
LINK_IN_BIO_TLD_FLOW,
Expand Down Expand Up @@ -103,6 +104,10 @@ export function DomainFormControl( {
includeWordPressDotCom = false;
}

if ( flow === HUNDRED_YEAR_DOMAIN_FLOW ) {
includeWordPressDotCom = false;
}

const domainsWithPlansOnly = true;
const isPlanSelectionAvailableLaterInFlow = true;
const domainSearchInQuery = useQuery().get( 'new' ); // following the convention of /start/domains
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
HUNDRED_YEAR_PLAN_FLOW,
isDomainUpsellFlow,
isSiteAssemblerFlow,
HUNDRED_YEAR_DOMAIN_FLOW,
} from '@automattic/onboarding';
import { useDispatch } from '@wordpress/data';
import { createInterpolateElement } from '@wordpress/element';
Expand Down Expand Up @@ -129,7 +130,11 @@ const DomainsStep: Step = function DomainsStep( { navigation, flow } ) {
changeSiteDomainIfNeeded( suggestion?.domain_name );
}

submit?.( { freeDomain: suggestion?.is_free, domainName: suggestion?.domain_name } );
submit?.( {
freeDomain: suggestion?.is_free,
domainName: suggestion?.domain_name,
productSlug: suggestion?.product_slug,
} );
};

const handleSkip = ( _googleAppsCartItem = undefined, shouldHideFreePlan = false ) => {
Expand Down Expand Up @@ -188,6 +193,7 @@ const DomainsStep: Step = function DomainsStep( { navigation, flow } ) {
case DOMAIN_UPSELL_FLOW:
return __( 'Enter some descriptive keywords to get started' );
case HUNDRED_YEAR_PLAN_FLOW:
case HUNDRED_YEAR_DOMAIN_FLOW:
return __( 'Secure your 100-Year domain and start building your legacy.' );
default:
return createInterpolateElement(
Expand All @@ -208,7 +214,7 @@ const DomainsStep: Step = function DomainsStep( { navigation, flow } ) {
return __( 'Your domain. Your identity.' );
}

if ( flow === HUNDRED_YEAR_PLAN_FLOW ) {
if ( [ HUNDRED_YEAR_PLAN_FLOW, HUNDRED_YEAR_DOMAIN_FLOW ].includes( flow ) ) {
return __( 'Find the perfect domain' );
}

Expand Down Expand Up @@ -298,7 +304,9 @@ const DomainsStep: Step = function DomainsStep( { navigation, flow } ) {
return ! isCopySiteFlow( flow );
};

const Container = flow === HUNDRED_YEAR_PLAN_FLOW ? HundredYearPlanStepWrapper : StepContainer;
const Container = [ HUNDRED_YEAR_PLAN_FLOW, HUNDRED_YEAR_DOMAIN_FLOW ].includes( flow )
? HundredYearPlanStepWrapper
: StepContainer;

return (
<Container
Expand All @@ -315,8 +323,16 @@ const DomainsStep: Step = function DomainsStep( { navigation, flow } ) {
formattedHeader={
<FormattedHeader
id="domains-header"
align={ flow === HUNDRED_YEAR_PLAN_FLOW ? 'center' : 'left' }
subHeaderAlign={ flow === HUNDRED_YEAR_PLAN_FLOW ? 'center' : undefined }
align={
[ HUNDRED_YEAR_PLAN_FLOW, HUNDRED_YEAR_DOMAIN_FLOW ].includes( flow )
? 'center'
: 'left'
}
subHeaderAlign={
[ HUNDRED_YEAR_PLAN_FLOW, HUNDRED_YEAR_DOMAIN_FLOW ].includes( flow )
? 'center'
: undefined
}
headerText={ getHeaderText() }
subHeaderText={ getSubHeaderText() }
/>
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not certain where best to comment, I think it's this file :) Everything I tested and looked at is working perfectly, it looks really great on all screen sizes. I just found one small inconsistency, a margin of 20px on the left at the 600px breakpoint, classes [.domains .step-container]

100-year-domain_left-margin.mov

Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,109 @@

}

.hundred-year-domain.step-route {
margin-top: -60px;
}

.hundred-year-domain.domains {
.step-container {
margin: 0;
}

.step-container__header {
.formatted-header {
.formatted-header__title {
font-size: rem(32px);
@include break-small {
font-size: rem(44px);
}
}
@include break-small {
margin-top: 60px;
margin-bottom: 0;
}
margin: 32px 0 16px;
}

margin-bottom: 32px;

@include break-small {
margin-bottom: 40px;
}
}

.domains__content {
width: 100%;
@include break-small {
max-width: 960px;
}

.domains__step-content {
padding: 0 16px;
@include break-small {
padding: 0 48px 0 32px;
}
}
// Change button styles
.button.is-primary {
@include primary-button-black-theme;
}

.domain-suggestion__content {
align-items: start;
gap: 0;

@include break-small {
align-items: center;
gap: 16px;
}

.domain-product-price {
margin-top: 0;
margin-bottom: 16px;

@include break-small {
align-items: flex-end;
align-self: center;
margin-bottom: 0;
}
}
}

.domain-suggestion.card.featured-domain-suggestion {
padding: 16px 0;

@include break-mobile {
padding: 16px 20px;
}

.domain-suggestion__content {
@include break-small {
flex-direction: row;
}
}

.domain-registration-suggestion__title-info {
width: auto;
margin-bottom: 4px;

@include break-small {
max-width: 55%;
margin-bottom: auto;
}
}
}

.domain-suggestion:not(.featured-domain-suggestion) {
padding: 16px 0;

@include break-small {
padding: 16px 20px;
}
}
}
}

// Hundred year plan flow
.hundred-year-plan.domains {
.step-container {
Expand Down
Loading
Loading