/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ import { Button } from "../../components/Button/Button"; import React from "react"; import { RichText } from "../../components/RichText/RichText"; import { safeURI } from "../../template-utils"; import { SimpleSnippet } from "../SimpleSnippet/SimpleSnippet"; import { SnippetBase } from "../../components/SnippetBase/SnippetBase"; import ConditionalWrapper from "../../components/ConditionalWrapper/ConditionalWrapper"; // Alt text placeholder in case the prop from the server isn't available const ICON_ALT_TEXT = ""; export class SubmitFormSnippet extends React.PureComponent { constructor(props) { super(props); this.expandSnippet = this.expandSnippet.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.handleSubmitAttempt = this.handleSubmitAttempt.bind(this); this.onInputChange = this.onInputChange.bind(this); this.state = { expanded: false, submitAttempted: false, signupSubmitted: false, signupSuccess: false, disableForm: false, }; } handleSubmitAttempt() { if (!this.state.submitAttempted) { this.setState({ submitAttempted: true }); } } async handleSubmit(event) { let json; if (this.state.disableForm) { return; } event.preventDefault(); this.setState({ disableForm: true }); this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", event_context: "conversion-subscribe-activation", id: "NEWTAB_FOOTER_BAR_CONTENT", }); if (this.props.form_method.toUpperCase() === "GET") { this.props.onBlock({ preventDismiss: true }); this.refs.form.submit(); return; } const { url, formData } = this.props.processFormData ? this.props.processFormData(this.refs.mainInput, this.props) : { url: this.refs.form.action, formData: new FormData(this.refs.form) }; try { const fetchRequest = new Request(url, { body: formData, method: "POST", credentials: "omit", }); const response = await fetch(fetchRequest); // eslint-disable-line fetch-options/no-fetch-credentials json = await response.json(); } catch (err) { console.error(err); } if (json && json.status === "ok") { this.setState({ signupSuccess: true, signupSubmitted: true }); if (!this.props.content.do_not_autoblock) { this.props.onBlock({ preventDismiss: true }); } this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", event_context: "subscribe-success", id: "NEWTAB_FOOTER_BAR_CONTENT", }); } else { console.error( "There was a problem submitting the form", json || "[No JSON response]" ); this.setState({ signupSuccess: false, signupSubmitted: true }); this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", event_context: "subscribe-error", id: "NEWTAB_FOOTER_BAR_CONTENT", }); } this.setState({ disableForm: false }); } expandSnippet() { this.props.sendUserActionTelemetry({ event: "CLICK_BUTTON", event_context: "scene1-button-learn-more", id: this.props.UISurface, }); this.setState({ expanded: true, signupSuccess: false, signupSubmitted: false, }); } renderHiddenFormInputs() { const { hidden_inputs } = this.props.content; if (!hidden_inputs) { return null; } return Object.keys(hidden_inputs).map((key, idx) => ( )); } renderDisclaimer() { const { content } = this.props; if (!content.scene2_disclaimer_html) { return null; } return (

); } renderFormPrivacyNotice() { const { content } = this.props; if (!content.scene2_privacy_html) { return null; } return (

); } renderSignupSubmitted() { const { content } = this.props; const isSuccess = this.state.signupSuccess; const successTitle = isSuccess && content.success_title; const bodyText = isSuccess ? { success_text: content.success_text } : { error_text: content.error_text }; const retryButtonText = content.retry_button_label; return (
{successTitle ? (

{successTitle}

) : null}

{isSuccess ? null : ( )}

); } onInputChange(event) { if (!this.props.validateInput) { return; } const hasError = this.props.validateInput( event.target.value, this.props.content ); event.target.setCustomValidity(hasError); } wrapSectionHeader(url) { return function (children) { return {children}; }; } renderInput() { const placholder = this.props.content.scene2_email_placeholder_text || this.props.content.scene2_input_placeholder; return ( ); } renderForm() { return (
{this.renderHiddenFormInputs()}
{this.renderInput()}
{this.renderFormPrivacyNotice() || this.renderDisclaimer()}
); } renderScene2Icon() { const { content } = this.props; if (!content.scene2_icon) { return null; } return (
{content.scene2_icon_alt_text {content.scene2_icon_alt_text
); } renderSignupView() { const { content } = this.props; const containerClass = `SubmitFormSnippet ${this.props.className}`; return ( {this.renderScene2Icon()}

{content.scene2_title && (

{content.scene2_title}

)}{" "} {content.scene2_text && ( )}

{this.renderForm()}
); } renderSectionHeader() { const { props } = this; // an icon and text must be specified to render the section header if (props.content.section_title_icon && props.content.section_title_text) { const sectionTitleIconLight = safeURI(props.content.section_title_icon); const sectionTitleIconDark = safeURI( props.content.section_title_icon_dark_theme || props.content.section_title_icon ); const sectionTitleURL = props.content.section_title_url; return (

{props.content.section_title_text}

); } return null; } renderSignupViewAlt() { const { content } = this.props; const containerClass = `SubmitFormSnippet ${this.props.className} scene2Alt`; return ( {this.renderSectionHeader()} {this.renderScene2Icon()}

{content.scene2_text && ( )}

{this.renderForm()}
); } getFirstSceneContent() { return Object.keys(this.props.content) .filter(key => key.includes("scene1")) .reduce((acc, key) => { acc[key.substr(7)] = this.props.content[key]; return acc; }, {}); } render() { const content = { ...this.props.content, ...this.getFirstSceneContent() }; if (this.state.signupSubmitted) { return this.renderSignupSubmitted(); } // Render only scene 2 (signup view). Must check before `renderSignupView` // to catch the Failure/Try again scenario where we want to return and render // the scene again. if (this.props.expandedAlt) { return this.renderSignupViewAlt(); } if (this.state.expanded) { return this.renderSignupView(); } return ( ); } }