-
Notifications
You must be signed in to change notification settings - Fork 2k
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: checkout/whois form consolidation #19889
Conversation
50bbc39
to
20145dd
Compare
<div className="checkout__domain-details-contact-details-fields"> | ||
{ this.createField( 'organization', HiddenInput, { | ||
label: translate( 'Organization' ), | ||
text: translate( "+ Add your organization's name" ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I've found a possible matching string that has already been translated 15 times:
translate( 'Add Organization Name' )
ES Score: 7
Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).
5183f6e
to
b93ea94
Compare
<div className="contact-details-form-fields__container"> | ||
{ this.createField( 'organization', HiddenInput, { | ||
label: translate( 'Organization' ), | ||
text: translate( "+ Add your organization's name" ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I've found a possible matching string that has already been translated 15 times:
translate( 'Add Organization Name' )
ES Score: 7
Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).
b93ea94
to
613f135
Compare
HiddenInput, | ||
{ | ||
label: translate( 'Organization' ), | ||
text: labelTexts.organization || translate( '+ Add organization name' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I've found a possible matching string that has already been translated 15 times:
translate( 'Add Organization Name' )
ES Score: 17
See 1 additional suggestion in the PR translation status page
Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).
613f135
to
e0e8e6b
Compare
200b5b2
to
123a844
Compare
HiddenInput, | ||
{ | ||
label: translate( 'Organization' ), | ||
text: labelTexts.organization || translate( '+ Add organization name' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I've found a possible matching string that has already been translated 15 times:
translate( 'Add Organization Name' )
ES Score: 17
See 1 additional suggestion in the PR translation status page
Help me improve these suggestions: react with 👎 if the suggestion doesn't make any sense, or with 👍 if it's a particularly good one (even if not implemented).
a0faa3c
to
93c813c
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pure awesomeness 👍
Very well done - these two forms have gathered a lot of cruft and it's great to a major cleanup like this 🙇
I've noticed just a few regressions, but given the scope of this PR (and the vast responsibilities of both forms) it was expected. I've tested a few scenarios: registering a new domain, a new domain that does not support privacy, just G Suite, editing WHOIS for an HRS domain, editing WHOIS for a .nl
domain (mandatory fax field, weeeee), editing WHOIS for a WWD domain.
It seems it's not possible to update WHOIS info for a WWD domain. The reason is that fax
is not passed to the backend, so it defaults to null
when sent to WWD... and WWD fails with an error:
{
"raw_response": null,
"response": {
"code": "INVALID_BODY",
"message": "Request body doesn't fulfill schema, see details in `fields`",
"fields": [
{
"message": "is not a string",
"path": "contacts.contactRegistrant.fax",
"code": "UNEXPECTED_TYPE"
},
...
Either we should send empty fax or fix the backend.
Additionally, when saving WWD info if you change the email, a confirmation dialog is shown (to inform the user what will happen - that they need verify the change from both emails, etc.). However, when you hit Request Confirmation
button, the main area of Calypso goes blank and there's this confusing error in the console:
I'm guessing something is undefined.
Apart from what I've mentioned in the comments, I've noticed that the check introduced in #16240 was undone by this - we should not allow the user to re-save the same WHOIS info. They often did this thinking that it will allow them to lift the 60-day lock :/
Also worth noting: the PR needs a rebase 😁
}; | ||
``` | ||
|
||
### onContactDetailsChange {Func} (required) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably meant onSubmit
:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hawkeye!
Now that I'm reviewing it, I've actually noticed several mistakes in there ;)
Thanks!
@@ -243,7 +243,8 @@ class PhoneInput extends React.PureComponent { | |||
name={ this.props.name } | |||
ref={ this.setNumberInputRef } | |||
type="tel" | |||
className={ classnames( { 'is-error': this.props.isError } ) } | |||
disabled={ this.props.disabled } | |||
className={ this.props.isError && 'is-error' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing this line was added before #19940 😀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rebase fixed it! :)
export class ContactDetailsFormFields extends Component { | ||
static propTypes = { | ||
eventFormName: PropTypes.string, | ||
contactDetails: PropTypes.shape( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great usage of shape
! 👍
But the list of field names seems unnecessarily duplicated. Maybe it could be generated based on this.fieldNames
with some map
calls and the spread operator?
contactDetails: Object.assign( {}, ...this.fieldNames.map( ( field ) => ( { [field]: PropTypes.string } ) ) )
Similarly, defaultProps
can be written as:
contactDetails: Object.assign( {}, ...this.fieldNames.map( ( field ) => ( { [field]: '' } ) ) )
Or is that too magical? 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like less repetition :) It makes sense, since they are, and must be, equal.
We'd have to pull this.fieldNames
out of the constructor. Making it another static var would work (and we could access it through ContactDetailsFormFields.fieldNames
).
But now I reflect on it, this.fieldNames
is a definitive and immutable list of form fields. It might work better as a constant. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right, I did not think about the static/instance problem, but yup, you're right - it's a constant/immutable list anyway.
translate: identity, | ||
}; | ||
|
||
constructor() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should pass props
through the constructor to super
- otherwise this.props
will be undefined
. See https://reactjs.org/docs/react-component.html#constructor
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still no props
? 😢
} ); | ||
} | ||
|
||
loadFormState = fn => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you something more descriptive than fn
? 🙏 Initially I thought it was something from lodash
or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's legacy from the previous form-state
hydration. You're right, it's a little opaque. Will change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, should have noticed that, sorry about that. But, yeah, let's rename it to something more descriptive 🙇
@@ -243,7 +243,8 @@ class PhoneInput extends React.PureComponent { | |||
name={ this.props.name } | |||
ref={ this.setNumberInputRef } | |||
type="tel" | |||
className={ classnames( { 'is-error': this.props.isError } ) } | |||
disabled={ this.props.disabled } | |||
className={ this.props.isError && 'is-error' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that once there's a validation error in the phone field, it stays in the is-error
state 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely 🤔 ... Haven't been able to reproduce this yet. But I'm going to try!
@@ -344,117 +156,46 @@ export class DomainDetailsForm extends PureComponent { | |||
renderPrivacySection() { | |||
return ( | |||
<PrivacyProtection | |||
checkPrivacyRadio={ this.allDomainItemsHavePrivacy() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can I reproduce this?
FYI, I ditched most of the props on this component since countriesList
, disabled
, fields
, and onCheckboxChange
weren't being used by <PrivacyProtection />
at all.
And this.handleCheckboxChange
didn't even exist in the domain details component :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, I did not do anything special - just try to register a new domain that supports privacy. And try to check a different radio button - both will be checked as a result.
cartItems.getDomainRegistrationsWithoutPrivacy( this.props.cart ).length === 0 && | ||
cartItems.getDomainTransfersWithoutPrivacy( this.props.cart ).length === 0 | ||
); | ||
allDomainRegistrationsHavePrivacy() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why only domain registrations? Domain transfers are domains too! (or was this discussed with @aidvu?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is probably why it needs a rebase. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aaaah, damn GitHub, confusing me! 🤜 🤛
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Going to rebase as the first task 👍
@klimeryk Huge thanks for your review so far. Really helpful.
I had this on my radar, and I thought it was working. I must have broken my fix. :) Edit: You did, perhaps without knowing it, find the solution to the above for me:
I was deleting the fax (as we were doing in the original domain-details-form.jsx) and therefore the comparison check failed. 👍 |
My mistake. I wasn't caching the form values. Also noticed the effect of #16239 Domains: After updating, the WHOIS store is not automatically updated, whereby the button isn't disabled. I might take a look at that later, but I think we just need to do another |
93c813c
to
4ced986
Compare
That probably worked because we use Tucows for new domains, while this empty value seems to be required by WWD only 🤷♂️ |
4ced986
to
f545c20
Compare
We're looking at addressing the conflict in #21781, and then we can circle back to this. |
Thanks for the update @deBhal. |
30d97c2
to
42d9d95
Compare
Here are some bundle stats for this branch. TL;DR This PR adds circa 20k to the gzipped domains chunk mainly due to phone number validation code. Looks like it's adding about 20k to the gzipped payload in domains/components. From what I can tell, more than 3/4 of this comes down to Previously we were only pulling this component in the checkout chunk, but with the consolidated form it's now in domains. I experimented with loading the shared Instead, I'm inclined to see if we can load data.js asynchronously, and refactor the phone input to handle the case when no validation is present. I guess this depends on how crucial phone validation is to WordPress / the domain registrar. Overall, it's a slight step backwards in the quest to lower our bundle, but we might be able to claw back some of those bytes later. (?) |
42d9d95
to
d906e24
Compare
Review changes implemented some time ago
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing job, @ramonjd. Tested all the cases I could think of:
- Registering a gTLD
- Registering .ca
- Registering .fr
- Editing WHOIS for Tucows gTLD
- Editing WHOIS for WWD gTLD
- Editing WHOIS for .fr
- Purchasing a domain by a brand-new user.
- Purchasing G Suite for a mapped domain.
- Purchasing a domain in the domain-only flow.
Everything looks solid - really stellar job on this, @ramonjd 💖
One small request: please merge this when there are many HEs around, just in case there's a regression, so that it will be quickly reported and handled appropriately 🙇
translate: identity, | ||
}; | ||
|
||
constructor() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still no props
? 😢
Thanks @klimeryk !
Do you mean the
Will do. 🙇 |
That might be true, but in the future it might change and someone will get unpleasantly surprised ;) You're calling the parent constructor either way, might as well pass the props to it ¯\_(ツ)_/¯ |
Please merge this, @ramonjd, before it grows any more merge conflicts 😅 🌵 |
Fixed focus events and state field refresh
Hooked in contact details cache to form card Focussing on address field when country select changed Removing useless props from Privacy Protection Added README.md and moved component under component/domains Passing props to super :) Not deleting the fax field in the state so that we pass an empty value to the backend Creating a constant out of this.fieldNames and deconstructing into proptypes Fixed some some strange reoccurring formatting in the tracksData object Updated disable button check from PR #20549
…n arrow functions etc
…acy selection radio boxes, because the first name field stole the focus using the autofocus attribute
d906e24
to
cccafa3
Compare
Hi 👋 I noticed a couple of potential issues with this: Firstly, at ~900px or narrower the state and postcode fields merge into one. Also, the "Continue to Checkout" label has been renamed to a less descriptive "Continue" - was this intentional? I didn't see this mentioned in the PR. I'll raise the fields issue as a separate bug Now Previously |
@alisterscott Thanks for testing! Appreciate it. And for catching the classname change in the e2e tests. Totally slipped past me. (Even though I'd made a note of it in the PR :( ) I'll look into those issues today. |
This PR addresses issue #18808
Goals
The core objective is to consolidate the domain checkout and whois contact details form, which share common fields and functionality.
Because of the varying internal business logic of each form, there's no way to unify them completely, however we can attempt to reduce some of the repetition in the contact form itself.
First steps
<ContactDetailsFormFields />
common component<ContactDetailsFormFields />
TODO
Update the button class attribute value for the wp-e2e-test.
Screenshots
Domain checkout form
WHOIS form
Afterthoughts
This was a worthy exercise, not only because it exposed the idiosyncratic logic and dependencies of both form, but also highlighted areas of complexity, not limited to the following:
form-state
triggers a great deal of rendering and is a little wilyFurthermore, the effort required to consolidate the forms has been quite high, and might turn out to be disproportionate to the need for simplifying two contact forms.
As mentioned, the two forms perform separate tasks, though they share the same contact details requirements. Creating a common dependency could create more work should their internal logic diverge further later. Rather than instructing a swiss-army-like
<ContactDetailsFormFields />
to render a form permutations only it knows about, we might come to the conclusion that it would be better to instruct a form-builder component to construct a form using fields controls we specify.