diff --git a/source/js/buyers-guide/components/creep-vote/creep-vote.jsx b/source/js/buyers-guide/components/creep-vote/creep-vote.jsx index 53693b6943b..29a1559155b 100644 --- a/source/js/buyers-guide/components/creep-vote/creep-vote.jsx +++ b/source/js/buyers-guide/components/creep-vote/creep-vote.jsx @@ -2,7 +2,7 @@ import { Component, Fragment } from "react"; import Creepometer from "../creepometer/creepometer.jsx"; import CreepChart from "../creepiness-chart/creepiness-chart.jsx"; import SocialShare from "../social-share/social-share.jsx"; -import JoinUs from "../../../components/join/join.jsx"; +import DefaultLayoutSignup from "../../../components/newsletter-signup/organisms/default-layout-signup.jsx"; import { getText } from "../../../components/petition/locales"; import CREEPINESS_LABELS from "../creepiness-labels.js"; @@ -226,15 +226,30 @@ class CreepVote extends Component { > Close - this.handleSignUp(successState)} - /> +
+ + {getText(`Now that you’re on a roll, why not join Mozilla? We’re + not creepy (we promise). We actually fight back against creepy. + And we need more people like you.`)} +

+ } + apiUrl={this.props.joinUsApiUrl} + showQuitButton="true" + handleQuitButtonClick={(successState) => + this.handleSignUp(successState) + } + handleSubmissionSuccess={(successState) => + this.handleSignUp(successState) + } + /> +
); } diff --git a/source/js/components/join/join.jsx b/source/js/components/join/join.jsx index bec432b0707..fd0b67b1a99 100644 --- a/source/js/components/join/join.jsx +++ b/source/js/components/join/join.jsx @@ -253,10 +253,6 @@ class JoinUs extends Component { * Render the signup CTA. */ render() { - if (this.state.apiSuccess && this.state.apiSubmitted && this.isFlowForm()) { - this.props.handleSignUp(true); - } - let signupState = classNames({ "signup-success": this.state.apiSuccess && this.state.apiSubmitted, "signup-fail": !this.state.apiFailed && this.state.apiSubmitted, @@ -266,7 +262,6 @@ class JoinUs extends Component { "col-md-6": this.props.layout === `2-column` && !this.state.apiSuccess, "col-sm-12 col-md-8": this.props.layout === `2-column` && this.state.apiSuccess, - "col-md-11 m-auto": this.isFlowForm(), }); return ( @@ -277,24 +272,6 @@ class JoinUs extends Component { ); } - isFlowForm() { - return this.props.formPosition === "flow"; - } - - /** - * Render the CTA heading. - */ - renderFlowHeading() { - return [ -

- {this.props.flowHeading} -

, -

- {this.props.flowText} -

, - ]; - } - /** * Render the CTA heading. */ @@ -346,9 +323,6 @@ class JoinUs extends Component { * Render the CTA heading. */ renderFormHeading() { - if (this.isFlowForm()) { - return this.renderFlowHeading(); - } return this.renderSnippetHeading(); } @@ -382,18 +356,11 @@ class JoinUs extends Component { "tw-h-24": this.props.formStyle == `pni`, }); - let errorWrapperClasses = classNames("glyph-container", { - "d-none": this.isFlowForm(), - }); + let errorWrapperClasses = "glyph-container"; return (
- {this.isFlowForm() && ( - - )} (this.email = el)} onFocus={(evt) => this.onInputFocus(evt)} onInput={(evt) => this.toggleSubmitButton(evt)} - aria-label={!this.isFlowForm() ? "Email" : ""} + aria-label="Email" id={this.id.userEmail} /> {this.state.userTriedSubmitting && !emailValidation.valid && ( @@ -526,8 +493,7 @@ class JoinUs extends Component { {this.state.userTriedSubmitting && !this.state.apiSubmitted && - !this.privacy.checked && - !this.isFlowForm() && ( + !this.privacy.checked && ( )}
@@ -561,10 +527,7 @@ class JoinUs extends Component { ); buttonText = getText("Sign up"); } else { - classnames = classNames("tw-btn", "tw-btn-primary", { - "w-100": !this.isFlowForm(), - "tw-flex-1 tw-mr-8": this.isFlowForm(), - }); + classnames = "tw-btn tw-btn-primary w-100"; buttonText = getText("Sign up"); } @@ -596,10 +559,6 @@ class JoinUs extends Component { buttonsWrapperClass = `ml-md-3`; } - if (this.props.formPosition === `flow`) { - buttonsWrapperClass = `d-flex`; - } - if (this.props.formStyle === `pop`) { buttonsWrapperClass = `w-auto tw-text-right`; } @@ -622,18 +581,7 @@ class JoinUs extends Component { {this.renderLocaleFields()} {this.renderPrivacyField()}
-
- {this.renderSubmitButton()} - {this.isFlowForm() && ( - - )} -
+
{this.renderSubmitButton()}
); } diff --git a/source/js/components/newsletter-signup/atoms/button-quit.jsx b/source/js/components/newsletter-signup/atoms/button-quit.jsx new file mode 100644 index 00000000000..45c6afecaaa --- /dev/null +++ b/source/js/components/newsletter-signup/atoms/button-quit.jsx @@ -0,0 +1,34 @@ +import React from "react"; +import classNames from "classnames"; +import PropTypes from "prop-types"; + +const ButtonQuit = ({ + children, + buttonStyle = "primary", + widthClasses = `tw-w-full`, + handleQuitButtonClick, +}) => { + // [TODO] + // Ideally styling for this "atom" component should be pre-defined in a Tailwind config file. + // Because our design system still needs to be finalized, + // we are using hardcoded Tailwind classes directly here for now. + let classes = classNames( + `tw-btn tw-btn-${buttonStyle} btn-dismiss`, + widthClasses + ); + + return ( + + ); +}; + +ButtonQuit.propTypes = { + children: PropTypes.node.isRequired, + buttonStyle: PropTypes.oneOf(["primary", "secondary"]), + widthClasses: PropTypes.string, + handleQuitButtonClick: PropTypes.func.isRequired, +}; + +export default ButtonQuit; diff --git a/source/js/components/newsletter-signup/organisms/default-layout-signup.jsx b/source/js/components/newsletter-signup/organisms/default-layout-signup.jsx index f1fb3273e83..a0918f930b8 100644 --- a/source/js/components/newsletter-signup/organisms/default-layout-signup.jsx +++ b/source/js/components/newsletter-signup/organisms/default-layout-signup.jsx @@ -7,6 +7,7 @@ import InputText from "../atoms/input-text.jsx"; import Select from "../atoms/select.jsx"; import InputCheckboxWithLabel from "../molecules/input-checkbox-with-label.jsx"; import ButtonSubmit from "../atoms/button-submit.jsx"; +import ButtonQuit from "../atoms/button-quit.jsx"; import withSubmissionLogic from "./with-submission-logic.jsx"; import utility from "../../../utility.js"; import { ReactGA } from "../../../common"; @@ -47,7 +48,8 @@ class DefaultSignupForm extends Component { showCountryField: this.props.showCountryFieldByDefault?.toLowerCase() === "true", showLanguageField: - this.props.showCountryFieldByDefault?.toLowerCase() === "true", + this.props.showLanguageFieldByDefault?.toLowerCase() === "true", + showQuitButton: this.props.showQuitButton?.toLowerCase() === "true", submitButtonDisabled: this.props.disableSubmitButtonByDefault, }; } @@ -268,6 +270,43 @@ class DefaultSignupForm extends Component { ); } + renderButtons() { + let wrapperClasses = classNames({ + "tw-flex-shrink-0 tw-mt-8 medium:tw-mt-0": + this.style.buttonPosition !== "bottom", + "tw-mt-24 medium:tw-mt-12 tw-text-right": + this.style.buttonPosition === "bottom", + }); + + let submitButton = ( + + {this.buttonText} + + ); + + let buttons = submitButton; + + if (this.state.showQuitButton) { + buttons = ( +
+ {submitButton} + + {getText(`No thanks`)} + +
+ ); + } + + return
{buttons}
; + } + renderForm() { if (this.props.hideForm) return null; @@ -276,13 +315,6 @@ class DefaultSignupForm extends Component { this.style.buttonPosition !== "bottom", }); - let buttonWrapperClasses = classNames({ - "tw-flex-shrink-0 tw-mt-8 medium:tw-mt-0": - this.style.buttonPosition !== "bottom", - "tw-mt-24 medium:tw-mt-12 tw-text-right": - this.style.buttonPosition === "bottom", - }); - return (
{this.renderPrivacyCheckbox()}
-
- - {this.buttonText} - -
+ {this.renderButtons()}
); @@ -341,6 +364,9 @@ DefaultSignupForm.propTypes = { onSubmit: PropTypes.func.isRequired, noBrowserValidation: PropTypes.bool, hideForm: PropTypes.bool, + showCountryFieldByDefault: PropTypes.string, + showLanguageFieldByDefault: PropTypes.string, + showQuitButton: PropTypes.string, }; /** diff --git a/source/js/components/newsletter-signup/organisms/form-specific-style.js b/source/js/components/newsletter-signup/organisms/form-specific-style.js index 3cef9d2a6d0..832452408aa 100644 --- a/source/js/components/newsletter-signup/organisms/form-specific-style.js +++ b/source/js/components/newsletter-signup/organisms/form-specific-style.js @@ -99,6 +99,15 @@ export const FORM_STYLE = { descriptionClass: `medium:tw-w-4/5`, headingClass: "tw-h3-heading", }, + "pni-creep-vote": { + buttonPosition: "bottom", + buttonStyle: "primary", + buttonWidthClasses: "tw-w-1/2", + descriptionClass: "tw-text-center", + fieldStyle: "filled", + headingLevel: 2, + headingClass: "tw-h3-heading tw-text-center", + }, "pni-product-quiz": { fieldStyle: "filled", headingLevel: 4, diff --git a/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx b/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx index 1e2668a78a9..71b12d3e0fd 100644 --- a/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx +++ b/source/js/components/newsletter-signup/organisms/with-submission-logic.jsx @@ -271,7 +271,8 @@ function withSubmissionLogic(WrappedComponent) { WithSubmissionLogicComponent.propTypes = { apiUrl: PropTypes.string.isRequired, ctaHeader: PropTypes.string.isRequired, - ctaDescription: PropTypes.string.isRequired, + ctaDescription: PropTypes.oneOfType([PropTypes.string, PropTypes.node]) + .isRequired, formPosition: PropTypes.string, whenLoaded: PropTypes.func, };