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

A4A: add signup multiple steps form #99137

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { Gridicon } from '@automattic/components';
import { localizeUrl } from '@automattic/i18n-utils';
import { Button } from '@wordpress/components';
import { useTranslate } from 'i18n-calypso';
import { useState } from 'react';
import Form from 'calypso/a8c-for-agencies/components/form';
import FormField from 'calypso/a8c-for-agencies/components/form/field';
import QuerySmsCountries from 'calypso/components/data/query-countries/sms';
import FormPhoneInput from 'calypso/components/forms/form-phone-input';
import FormTextInput from 'calypso/components/forms/form-text-input';
import { useGetSupportedSMSCountries } from 'calypso/jetpack-cloud/sections/agency-dashboard/downtime-monitoring/contact-editor/hooks';
import './style.scss';
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved

type FormData = {
firstName: string;
lastName: string;
email: string;
agencyName: string;
businessUrl: string;
phoneNumber: string;
};

type Props = {
onContinue: () => void;
};

const SignupContactForm = ( { onContinue }: Props ) => {
const translate = useTranslate();

const countriesList = useGetSupportedSMSCountries();
const noCountryList = countriesList.length === 0;

const [ formData, setFormData ] = useState< FormData >( {
firstName: '',
lastName: '',
email: '',
agencyName: '',
businessUrl: '',
phoneNumber: '',
} );

const handlePhoneInputChange = ( data: { phoneNumberFull: string } ) => {
setFormData( ( prev ) => ( {
...prev,
phoneNumber: data.phoneNumberFull,
} ) );
};

const handleInputChange =
( field: keyof FormData ) => ( event: React.ChangeEvent< HTMLInputElement > ) => {
setFormData( ( prev ) => ( {
...prev,
[ field ]: event.target.value,
} ) );
};

const handleSubmit = ( e: React.FormEvent ) => {
e.preventDefault();
onContinue();
};

return (
<Form
className="signup-contact-form"
title={ translate( 'Sign up' ) }
description={ translate(
'Join 5000+ agencies and grow your business with Automattic for Agencies. It only takes two minutes!'
) }
>
<div className="signup-multi-step-form__fields">
<div className="signup-multi-step-form__name-fields">
<FormField label={ translate( 'Your first name' ) } isRequired>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use htmlFor for all the fields on this form?

We could use FormLabel that supports it or add the support on the FormField component

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for noting that. Let's address this one with one of the page tasks, to avoid growing this PR. What do you think?

<FormTextInput
name="firstName"
value={ formData.firstName }
onChange={ handleInputChange( 'firstName' ) }
/>
</FormField>

<FormField label={ translate( 'Last name' ) } isRequired>
<FormTextInput
name="lastName"
value={ formData.lastName }
onChange={ handleInputChange( 'lastName' ) }
/>
</FormField>
</div>

<FormField label={ translate( 'Email' ) } isRequired>
<FormTextInput
name="email"
type="email"
value={ formData.email }
onChange={ handleInputChange( 'email' ) }
/>
</FormField>

<FormField label={ translate( 'Agency name' ) } isRequired>
<FormTextInput
name="agencyName"
value={ formData.agencyName }
onChange={ handleInputChange( 'agencyName' ) }
/>
</FormField>

<FormField label={ translate( 'Business URL' ) } isRequired>
<FormTextInput
name="businessUrl"
value={ formData.businessUrl }
onChange={ handleInputChange( 'businessUrl' ) }
/>
</FormField>

{ noCountryList && <QuerySmsCountries /> }

<FormField label={ translate( 'Phone number' ) } showOptionalLabel>
<FormPhoneInput
countrySelectProps={ {
'data-testid': 'a4a-signup-country-code-select',
} }
phoneInputProps={ {
'data-testid': 'a4a-signup-phone-number-input',
} }
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
isDisabled={ noCountryList }
countriesList={ countriesList }
onChange={ handlePhoneInputChange }
className="contact-form__phone-input"
/>
</FormField>

<div className="signup-contact-form__tos">
<p>
{ translate(
"By clicking 'Continue', you agree to the{{break}}{{/break}}{{link}}Terms of the Automattic for Agencies Platform Agreement{{icon}}{{/icon}}{{/link}}.",
{
components: {
break: <br />,
link: (
<a
href={ localizeUrl(
'https://automattic.com/for-agencies/platform-agreement/'
) }
target="_blank"
rel="noopener noreferrer"
></a>
),
icon: <Gridicon icon="external" size={ 18 } />,
},
}
) }
</p>
</div>
<div className="company-details-form__controls">
<Button
variant="primary"
onClick={ handleSubmit }
className="company-details-form__submit"
>
{ translate( 'Continue' ) }
</Button>
</div>
</div>
</Form>
);
};

export default SignupContactForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
.signup-multi-step-form__fields {
display: flex;
flex-direction: column;
gap: 8px;
overflow-y: auto;
flex: 1;

// Customize scrollbar
&::-webkit-scrollbar {
width: 8px;
}

&::-webkit-scrollbar-track {
background: var(--studio-gray-0);
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
border-radius: 4px;
}

&::-webkit-scrollbar-thumb {
background: var(--studio-gray-20);
border-radius: 4px;

&:hover {
background: var(--studio-gray-30);
}
}
}

.signup-contact-form {
&.a4a-form {
gap: 1rem;
}
& .a4a-form__heading {
text-align: left;
margin-bottom: 0;

& .a4a-form__heading-description {
margin: 0;
}
}
}

.contact-form__phone-input {
display: flex;
flex-direction: row;
gap: 1rem;

.form-phone-input__country {
flex: 1;
}

.form-phone-input__phone-number {
flex: 1;
}
}

.signup-contact-form__tos {
p {
font-size: 0.875rem;
}
}

.signup-multi-step-form__name-fields {
display: flex;
flex-direction: row;
gap: 24px;

div {
flex-grow: 1;
}
}

.signup-multi-step-form__terms {
text-align: center;
font-size: 0.875rem;
color: var(--studio-gray-40);
margin-top: 16px;

a {
color: var(--studio-wordpress-blue);
text-decoration: none;

&:hover {
text-decoration: underline;
}
}
}

// Form field styles
.a4a-form__section-field {
margin-bottom: 0;
padding: 2px;

&-label {
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
font-size: 0.875rem;
font-weight: 500;
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
color: var(--studio-gray-80);
margin-bottom: 8px;
}

&-required {
color: var(--studio-red-50);
margin-left: 4px;
}

&-optional {
color: var(--studio-gray-20);
font-weight: normal;
margin-left: 4px;
}
}

.form-text-input {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--studio-gray-10);
border-radius: 4px;
font-size: 1rem;
transition: border-color 0.2s ease, box-shadow 0.2s ease;

&:focus {
border-color: var(--studio-wordpress-blue);
box-shadow: 0 0 0 2px var(--studio-wordpress-blue-20);
outline: none;
}

&.is-error {
border-color: var(--studio-red-50);
}
}

.a4a-form__error {
color: var(--studio-red-50);
font-size: 0.75rem;
margin-top: 4px;

&.hidden {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useTranslate } from 'i18n-calypso';
import { useMemo, useState } from 'react';
import StepProgress from '../step-progress';
import SignupContactForm from './contact-form';

import './style.scss';

const MultiStepForm = () => {
const translate = useTranslate();
const [ currentStep, setCurrentStep ] = useState( 1 );

const steps = [
{ label: translate( 'Sign up' ), isActive: currentStep === 1, isComplete: currentStep > 1 },
{ label: translate( 'Personalize' ), isActive: currentStep === 2, isComplete: currentStep > 2 },
{
label: translate( 'Complete setup' ),
isActive: currentStep === 3,
isComplete: currentStep > 3,
},
];

const currentForm = useMemo( () => {
switch ( currentStep ) {
case 1:
return <SignupContactForm onContinue={ () => setCurrentStep( 2 ) } />;
case 2:
return <SignupContactForm onContinue={ () => setCurrentStep( 3 ) } />;
case 3:
return <div>Finish</div>;
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
default:
return null;
}
}, [ currentStep ] );

return (
<div className="signup-multi-step-form">
<StepProgress steps={ steps } />

{ currentForm }
</div>
);
};

export default MultiStepForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
.signup-multi-step-form {
display: flex;
flex-direction: column;
height: 100vh;

.step-progress {
flex-shrink: 0;
}

.a4a-form {
flex: 1;
overflow: hidden;
display: flex;
flex-direction: column;
padding: 48px 24px;
max-width: 600px;
margin: 0 auto;
width: 100%;
}

.a4a-form__heading {
text-align: center;
margin-bottom: 40px;
flex-shrink: 0;

&-title {
andrii-lysenko marked this conversation as resolved.
Show resolved Hide resolved
font-size: 2rem;
font-weight: 600;
margin-bottom: 16px;
color: var(--studio-gray-100);
}

&-description {
font-size: 1rem;
color: var(--studio-gray-60);
max-width: 460px;
margin: 0 auto;
}
}
}
Loading