Skip to content

Commit

Permalink
Domains: Create 100-Year domain transfer flow (#95634)
Browse files Browse the repository at this point in the history
* Add flow

* Add 100-year domain wrapper to flow variation + price bypass

* Add/fix specific styles

* Add specific 100-year domain copy/labels

* Change page title

* Future-proof flow steps

* Use specific 100-year domain price

* Pass `is_hundred_year_domain` to backend

* Fix navigation for new flow

* Add 100 volume to domain transfer product

* Include 100-year domain transfer variation to 100-year specific processing component

* Use vendor string instead of previous (and dated) hundred-year flag

* Use price coming from availability endpoint instead of override hack

* Hide sidebar price for transfers

* Fix linter error
  • Loading branch information
rafaelgallani authored Jan 23, 2025
1 parent bc5fd72 commit c2354ff
Show file tree
Hide file tree
Showing 14 changed files with 254 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { HUNDRED_YEAR_DOMAIN_TRANSFER } from '@automattic/onboarding';
import { translate } from 'i18n-calypso';
import { stepsWithRequiredLogin } from 'calypso/landing/stepper/utils/steps-with-required-login';
import { setSignupCompleteFlowName, setSignupCompleteSlug } from 'calypso/signup/storageUtils';
import domainTransfer from './domain-transfer';
import {
AssertConditionResult,
AssertConditionState,
Flow,
ProvidedDependencies,
} from './internals/types';

const hundredYearDomainTransfer: Flow = {
...domainTransfer,
variantSlug: HUNDRED_YEAR_DOMAIN_TRANSFER,
get title() {
return translate( '100-Year Domain' );
},

// Always start on the "domains" step, as we don't need what comes before it for the 100-year domain transfer flow.
// It doesn't make sense to show it as it contains additional cluttering information that doesn't matter
// specifically under the 100-year domain context - they'll also come from a different entry point.
useSteps() {
const transferSteps = domainTransfer.useSteps();
const domainsStepIndex = transferSteps.findIndex( ( step ) => step.slug === 'domains' );
return [
transferSteps[ domainsStepIndex ],
...stepsWithRequiredLogin( transferSteps.slice( domainsStepIndex ) ),
];
},

// Always allow the user to proceed with the transfer, as we assert that the user is logged in later.
useAssertConditions(): AssertConditionResult {
return { state: AssertConditionState.SUCCESS };
},

useStepNavigation( _currentStepSlug, navigate ) {
const flowName = this.name;

const submit = async ( providedDependencies: ProvidedDependencies = {} ) => {
switch ( _currentStepSlug ) {
case 'domains': {
// go to processing step without pushing it to history
// so the back button would go back to domains step
return navigate( 'processing', undefined );
}
case 'processing': {
setSignupCompleteSlug( providedDependencies?.siteSlug );
setSignupCompleteFlowName( flowName );

// 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 ) );

const checkoutBackURL = new URL(
'/setup/hundred-year-domain-transfer',
window.location.href
);

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

return { submit };
},
};

export default hundredYearDomainTransfer;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { recordTracksEvent } from '@automattic/calypso-analytics';
import { FormInputValidation, FormLabel, Gridicon } from '@automattic/components';
import formatCurrency from '@automattic/format-currency';
import { localizeUrl } from '@automattic/i18n-utils';
import { GOOGLE_TRANSFER } from '@automattic/onboarding';
import { GOOGLE_TRANSFER, HUNDRED_YEAR_DOMAIN_TRANSFER } from '@automattic/onboarding';
import { Button, Icon } from '@wordpress/components';
import { check, closeSmall } from '@wordpress/icons';
import { useI18n } from '@wordpress/react-i18n';
Expand Down Expand Up @@ -108,7 +108,10 @@ export function DomainCodePair( {
}: Props ) {
const { __ } = useI18n();

const validation = useValidationMessage( domain, auth, hasDuplicates );
const isHundredYearDomainsTransferFlow = HUNDRED_YEAR_DOMAIN_TRANSFER === variantSlug;
const validation = useValidationMessage( domain, auth, hasDuplicates, {
vendor: isHundredYearDomainsTransferFlow ? '100-year-domains' : undefined,
} );
const isGoogleDomainsTransferFlow = GOOGLE_TRANSFER === variantSlug;
const userCurrencyCode = useSelector( getCurrentUserCurrencyCode ) || 'USD';

Expand Down Expand Up @@ -195,9 +198,13 @@ export function DomainCodePair( {
} ) }
position="right"
>
{ __(
'Unique code proving ownership, needed for secure domain transfer between registrars.'
) }
{ isHundredYearDomainsTransferFlow
? __(
'Your secret key to unlock the domain transfer. Get yours from your current domain provider.'
)
: __(
'Unique code proving ownership, needed for secure domain transfer between registrars.'
) }
<div>
<Button
href={ localizeUrl(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { recordTracksEvent } from '@automattic/calypso-analytics';
import { isEnabled } from '@automattic/calypso-config';
import { DomainTransferData, DomainTransferForm } from '@automattic/data-stores';
import formatCurrency from '@automattic/format-currency';
import { useDataLossWarning } from '@automattic/onboarding';
import { HUNDRED_YEAR_DOMAIN_TRANSFER, useDataLossWarning } from '@automattic/onboarding';
import { Button } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { sprintf } from '@wordpress/i18n';
Expand Down Expand Up @@ -91,6 +91,8 @@ const Domains: React.FC< Props > = ( { onSubmit, variantSlug } ) => {
( { domain, auth } ) => domain.trim() || auth.trim()
);

const isHundredYearTransfer = variantSlug === HUNDRED_YEAR_DOMAIN_TRANSFER;

useDataLossWarning( hasAnyDomains && enabledDataLossWarning );

// create a string key representing the current state of the domains
Expand All @@ -110,7 +112,9 @@ const Domains: React.FC< Props > = ( { onSubmit, variantSlug } ) => {
auth_code: auth,
signup: false,
import_dns_records: true,
is_hundred_year_domain: isHundredYearTransfer,
},
volume: isHundredYearTransfer ? 100 : 1,
} )
);

Expand Down Expand Up @@ -258,7 +262,7 @@ const Domains: React.FC< Props > = ( { onSubmit, variantSlug } ) => {
/>
) ) }
<Button className="bulk-domain-transfer__add-domain" icon={ plus } onClick={ addDomain }>
{ __( 'Add more' ) }
{ isHundredYearTransfer ? __( 'Add another domain' ) : __( 'Add more' ) }
</Button>
<div className="bulk-domain-transfer__cta-container">
<Button
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { MaterialIcon } from '@automattic/components';
import { useHasEnTranslation } from '@automattic/i18n-utils';
import { GOOGLE_TRANSFER } from '@automattic/onboarding';
import { GOOGLE_TRANSFER, HUNDRED_YEAR_DOMAIN_TRANSFER } from '@automattic/onboarding';
import { useI18n } from '@wordpress/react-i18n';
import { StepContainer } from 'calypso/../packages/onboarding/src';
import ChatButton from 'calypso/components/chat-button';
import FormattedHeader from 'calypso/components/formatted-header';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import CalypsoShoppingCartProvider from 'calypso/my-sites/checkout/calypso-shopping-cart-provider';
import HundredYearPlanStepWrapper from '../hundred-year-plan-step-wrapper';
import { WIDE_BREAKPOINT } from '../hundred-year-plan-step-wrapper/constants';
import TransferDomains from './domains';
import type { Step } from '../../types';

Expand All @@ -22,25 +24,42 @@ const Intro: Step = function Intro( { navigation, flow, variantSlug } ) {
};

const isGoogleDomainsTransferFlow = GOOGLE_TRANSFER === variantSlug;
const isHundredYearDomainsTransferFlow = HUNDRED_YEAR_DOMAIN_TRANSFER === variantSlug;

const Container = isHundredYearDomainsTransferFlow ? HundredYearPlanStepWrapper : StepContainer;

const headerText = isHundredYearDomainsTransferFlow
? __( 'Transfer your Domain' )
: __( 'Add your domains' );

const regularFlowsSubheaderText = isGoogleDomainsTransferFlow
? __( 'Enter your domain names and transfer codes below.' )
: __( 'Enter your domain names and authorization codes below.' );

const hundredYearFlowsSubheaderText = __(
'Start building your legacy. Secure your domain for the next 100 years.'
);

const subHeaderText = isHundredYearDomainsTransferFlow
? hundredYearFlowsSubheaderText
: regularFlowsSubheaderText;

return (
<StepContainer
<Container
flowName={ flow }
variantSlug={ variantSlug }
mobileBreakpoint={ WIDE_BREAKPOINT }
stepName="domains"
goBack={ goBack }
isHorizontalLayout={ false }
isLargeSkipLayout={ false }
formattedHeader={
<FormattedHeader
id="domain-transfer-header"
headerText={ __( 'Add your domains' ) }
headerText={ headerText }
subHeaderText={
<>
<span>
{ isGoogleDomainsTransferFlow
? __( 'Enter your domain names and transfer codes below.' )
: __( 'Enter your domain names and authorization codes below.' ) }
</span>
<span>{ subHeaderText }</span>
</>
}
align="center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,39 @@
align-items: center;
gap: 30px;

&.hundred-year-domain-transfer {

&.step-route {
gap: 0;
width: 100%;
margin: 0;
max-width: none;
}

.domains {
.step-container__header {
@media (max-width: $break-wide) {
margin-top: 32px;
}
}
}

.bulk-domain-transfer__cta-container {
display: flex;
justify-content: center;
margin-bottom: 32px;

.bulk-domain-transfer__cta {
height: 48px;
width: 240px;

@media (max-width: $break-medium) {
width: 100%;
}
}
}
}

button:disabled {
pointer-events: none;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ import { useDebounce } from 'use-debounce';
import { useIsDomainCodeValid } from 'calypso/landing/stepper/hooks/use-is-domain-code-valid';
import { getAvailabilityNotice } from 'calypso/lib/domains/registration/availability-messages';

export function useValidationMessage( domain: string, auth: string, hasDuplicates: boolean ) {
export type DomainValidationOptions = {
vendor?: string;
};

export function useValidationMessage(
domain: string,
auth: string,
hasDuplicates: boolean,
options: DomainValidationOptions = {}
) {
const { __ } = useI18n();

const [ domainDebounced ] = useDebounce( domain, 500 );
Expand All @@ -25,6 +34,7 @@ export function useValidationMessage( domain: string, auth: string, hasDuplicate
{
domain: domainDebounced,
auth: authDebounced,
options,
},
{
enabled: Boolean( passedLocalValidation ),
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const SMALL_BREAKPOINT = 960;
export const WIDE_BREAKPOINT = 1280;
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ProductsList } from '@automattic/data-stores';
import { formatCurrency } from '@automattic/format-currency';
import {
HUNDRED_YEAR_DOMAIN_FLOW,
HUNDRED_YEAR_DOMAIN_TRANSFER,
HUNDRED_YEAR_PLAN_FLOW,
StepContainer,
} from '@automattic/onboarding';
Expand All @@ -21,10 +22,11 @@ import HundredYearPlanLogo from './hundred-year-plan-logo';
import InfoModal from './info-modal';

import './style.scss';

type Props = {
stepName: string;
flowName: string;
variantSlug?: string;
mobileBreakpoint?: number;
stepContent: ReactElement;
justifyStepContent?: string;
formattedHeader?: ReactElement;
Expand Down Expand Up @@ -210,10 +212,12 @@ function InfoColumn( {
isMobile,
openModal,
flowName,
variantSlug,
}: {
isMobile: boolean;
openModal: () => void;
flowName: string;
variantSlug?: string;
} ) {
const translate = useTranslate();

Expand Down Expand Up @@ -268,20 +272,29 @@ function InfoColumn( {
<Gridicon icon="info-outline" size={ 16 } />
</>
</LearnMore>
{ flowName !== HUNDRED_YEAR_DOMAIN_FLOW && (
<Price className={ ! displayCost ? 'is-price-loading' : '' }>{ displayCost }</Price>
) }
{ flowName !== HUNDRED_YEAR_DOMAIN_FLOW &&
variantSlug !== HUNDRED_YEAR_DOMAIN_TRANSFER && (
<Price className={ ! displayCost ? 'is-price-loading' : '' }>{ displayCost }</Price>
) }
</Info>
</InfoColumnContainer>
</>
);
}

function HundredYearPlanStepWrapper( props: Props ) {
const { stepContent, stepName, flowName, formattedHeader, justifyStepContent, hideInfoColumn } =
props;

const isMobile = useBreakpoint( `<${ SMALL_BREAKPOINT }px` );
const {
stepContent,
stepName,
flowName,
formattedHeader,
justifyStepContent,
hideInfoColumn,
variantSlug,
mobileBreakpoint,
} = props;

const isMobile = useBreakpoint( `<${ mobileBreakpoint ?? SMALL_BREAKPOINT }px` );
const [ isOpen, setOpen ] = useState( false );
const openModal = () => setOpen( true );
const closeModal = () => setOpen( false );
Expand All @@ -304,12 +317,19 @@ function HundredYearPlanStepWrapper( props: Props ) {
{ isOpen && <InfoModal flowName={ flowName } onClose={ closeModal } /> }
{ ! hideInfoColumn && (
<InfoColumnWrapper isMobile={ isMobile } flowName={ flowName }>
<InfoColumn isMobile={ isMobile } openModal={ openModal } flowName={ flowName } />
<InfoColumn
isMobile={ isMobile }
openModal={ openModal }
flowName={ flowName }
variantSlug={ variantSlug }
/>
</InfoColumnWrapper>
) }
<FlexWrapper justifyStepContent={ justifyStepContent }>
<div className="step-container__header">{ formattedHeader }</div>
{ stepContent }
<div className="hundred-year-plan-step-wrapper__step-container">
<div className="step-container__header">{ formattedHeader }</div>
{ stepContent }
</div>
</FlexWrapper>
</Container>
}
Expand Down
Loading

0 comments on commit c2354ff

Please sign in to comment.