-
Notifications
You must be signed in to change notification settings - Fork 123
Adds newsletter subscription form to footer (closes #1521). #1620
Conversation
The button and input should maybe be shrunk down a bit at medium widths. |
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.
@chuckharmston looks like the form is leaking into some extra pages:
@chuckharmston also noticed it on the uninstall test pilot interstitial page |
Otherwise UX looks solid, i'll leave it to someone else to do a code review |
@chuckharmston one more nit... after the email, the string should be "We will only send you Test Pilot related information". |
<p data-l10n-id="emailFooterSuccessBody"> | ||
If you haven't previously confirmed a subscription to a Mozilla-related | ||
newsletter you may have to do so. Please check your inbox or your spam | ||
filter for an email from us. |
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 say "email" here, but you hyphenated ("e-mail") on line 27 above.
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.
@chuckharmston @pdehaan let's stick to email
<svg width="146px" height="127px" viewBox="0 0 146 127" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | ||
<!-- Generator: Sketch 40.2 (33826) - http://www.bohemiancoding.com/sketch --> | ||
<title>Email</title> | ||
<desc>Created with Sketch.</desc> |
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.
Probably want to run this file through SVGO or something.
emailFormSubmitButton = Sign Up Now | ||
emailFormSubmitButtonSubmitting = Submitting... | ||
|
||
emailFooterError = There was an error submitting your e-mail address. Try again? |
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.
e-mail -> email (for consistency w/ line 167 and 177.
$email-icon--responsive-unit: .66; | ||
|
||
.email-footer { | ||
background: $transparent-white-1; |
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.
Error in plugin 'sass'
Message:
frontend/src/styles/components/EmailFooter.scss
Error: Undefined variable: "$transparent-white-1".
on line 7 of frontend/src/styles/components/EmailFooter.scss
>> background: $transparent-white-1;
--------------^
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.
@johngruen had similar issues that were solved by blowing away some old node_modules
. This variable exists and is used all over.
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.
OK, I was just copy-pasta-ing that from Circle-CI, so we should see if we can blow away that cache.
} | ||
|
||
submitSucceeded() { | ||
return this.props.forms.email && this.props.forms.email.submitSucceeded; |
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 think we have some failing Circle-CI tests due to this line:
1) app/components/View should pass its props to child components:
TypeError: Cannot read property 'email' of undefined
at EmailFooter.submitSucceeded (src/app/components/EmailFooter.js:17:12)
at EmailFooter.getClassNames (src/app/components/EmailFooter.js:63:21)
at EmailFooter.render (src/app/components/EmailFooter.js:69:28)
at /home/ubuntu/testpilot/node_modules/react/lib/ReactCompositeComponent.js:793:21
at measureLifeCyclePerf (/home/ubuntu/testpilot/node_modules/react/lib/ReactCompositeComponent.js:74:12)
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.
Yeah, I haven't touched tests yet. As i noted in comment 0, I put this up there so John could do a UX review of it while I worked.
@johngruen Is that the correct email icon image? I vaguely recall a conversation at mozilla-services/screenshots#1650 (comment) where we were looking for a simpler image, due to poor "glance-ability". |
@pdehaan i think this one is good here now, it's internally consistent with our other email message |
); | ||
} | ||
|
||
subscribeToBasket(values) { |
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.
FWIW, we have a subscribeToBasket
helper in containers/App.js
that we pass in props for components/EmailDialog.js
and mock out in the test. Could probably use the same thing here?
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.
Yup, most of the code is lifted from there. As I mentioned in comment 0, I'm trying to appropriately encapsulate all the functionality in the form so it can be reused elsewhere without dependency. I'll likely remove that code when addressing #1551.
So, there's a really weird thing here:
This is a problem, because this component (and other forms we might create with the library) will be a child of all of our views. Some related bugs: enzymejs/enzyme#183 I spent most of the day getting to this point wherein the existing tests pass with my patch. I had to do some hackery, effectively not rendering the email footer in all tests. This is less than ideal, but @clouserw mentioned that there's some urgency in this bug, so I'm putting this out there for review now without any additional tests. Some ideas:
@lmorchard @dannycoates: would love to hear your thoughts here. |
Promising: I was able to get this working by setting the static |
I'd lean toward this. It's not a very complex form, is it? Maybe pass on this library until we need it? |
If the problem it creates is related to our testing stack, then I'd say that some investigating is warranted, at the least. |
I'm going to rewrite it without the library. For posterity, the commit with the passing tests was 413ddfb. |
Alright, this is updated, rolling it by hand. I'm not at all thrilled with the approach, especially compared to the relative simplicity of |
} | ||
}) | ||
|
||
export default Object.assign({}, actions, subscribeActions); |
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 sort of hacky, but it works.
The pattern is a little clearer when using vanilla redux for actions: http://redux.js.org/docs/advanced/AsyncActions.html#async-action-creators
if (!installed) { pollAddon(); } | ||
} | ||
}), | ||
(stateProps, dispatchProps, ownProps) => Object.assign({ |
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 was getting unwieldy. I broke into parts to make it clearer and to make the actual connect
call a one-liner.
The rewrite is now finished, other than the tests. @clouserw expressed interest in merging it without tests before the freeze, so I'd like to get this reviewed now. In the interim I'll get started on them. |
); | ||
|
||
const subscribeActions = createActions({ | ||
newsletterFormSubscribe: (dispatch, email) => { |
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.
dispatch
is added in mapDispatchToProps
here: https://github.com/mozilla/testpilot/pull/1620/files#diff-d1e3fb4bae03a0b6b298c56e7110d06fR159
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 do not like this but I'm not going to block it
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.
Yeah, I don't really like actions dispatching other actions like this.
Maybe the form should dispatch the newsletterFormSetSubmitting
and newsletterFormSubscribe
actions one after the other itself?
And then you can just yield an appropriate action payload describing success/fail at the end of the fetch without dispatching further actions. We kind of do this in fetchExperiments
, but sadly without good error handling.
But, this payload could just be for one single action (newsletterFormSubscribe
) that the reducer handles appropriately based on whether it has a statusSuccess==true
or statusFailed==true
property - or something like this.
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.
@lmorchard so, I think it does make sense for actions to dispatch other actions; this pattern is even featured in Redux's docs: http://redux.js.org/docs/advanced/AsyncActions.html#async-action-creators
The problem is in the redux-actions
library, which cuts some boilerplate at the cost of functionality.
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.
Eh, yeah, I think it just rubs me the wrong way for reasons I'm unable to really explain. But, this looks like a pretty textbook example from the docs. So, may just be I need to soak my head in more docs
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.
LGTM. Needs a followup for tests.
); | ||
|
||
const subscribeActions = createActions({ | ||
newsletterFormSubscribe: (dispatch, email) => { |
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 do not like this but I'm not going to block it
super(props); | ||
this.handleEmailChange = this.handleEmailChange.bind(this); | ||
this.handlePrivacyClick = this.handlePrivacyClick.bind(this); | ||
this.handleSubmit = this.handleSubmit.bind(this); |
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.
we aren't consistent in this repo wrt this vs e => this.foo(e)
and should eventually decide on one or the other
.then(() => dispatch(actions.newsletterFormSetSucceeded())) | ||
.catch(() => dispatch(actions.newsletterFormSetFailed())); | ||
} | ||
}) |
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.
☑️
</form> | ||
); | ||
} | ||
} |
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.
Please followup with PropTypes
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.
☑️
@johngruen's review doesn't count 😝
Still needs tests, but I thought I'd get it out for @johngruen to look at visuals Monday morning.
Some implementation notes:
TODO
email
tonewsletter
.mergeProps
argument toconnect
to namespacesetEmailForm*
to keep everything clean.subscribeToBasket
driven by a dispatched action, rather than a callback.Testing
Using the redux dev tools extension, you can simulate error and success states without submitting the form by dispatching the following action payloads:
Submitting
Error
Success
Screenshots
Default
After entering a character
When trying to submit with an empty email
When trying to submit with an invalid email
When trying to submit without agreeing to the privacy notice
At medium width
At small width
On success
On error