SumOfUs/Champaign

View on GitHub
app/javascript/plugins/email_pension/EmailPensionView.js

Summary

Maintainability
F
1 wk
Test Coverage
//
import React, { Component } from 'react';
import { isEmpty, find, template, merge, each, pick, join } from 'lodash';

import { connect } from 'react-redux';
import Select from '../../components/SweetSelect/SweetSelect';
import Input from '../../components/SweetInput/SweetInput';
import Button from '../../components/Button/Button';
import SelectCountry from '../../components/SelectCountry/SelectCountry';
import FormGroup from '../../components/Form/FormGroup';
import EmailEditor from '../../components/EmailEditor/EmailEditor';
import { FormattedMessage, injectIntl } from 'react-intl';
import SelectPensionFund from './SelectPensionFund';
import './EmailPensionView.scss';
import ConsentComponent from '../../components/consent/ConsentComponent';
import consent from '../../modules/consent/consent';

import {
  changeBody,
  changeSubject,
  changeSubmitting,
  changePensionFunds,
  changeEmail,
  changeName,
  changeFund,
  changeConsented,
} from '../../state/email_pension/actions';
import {
  changeConsent,
  changeIsRequiredNew,
  showConsentRequired,
} from '../../state/consent/index';
import {
  convertHtmlToPlainText,
  copyToClipboard,
  composeEmailLink,
  buildToEmailForCompose,
} from '../../util/util';
import { MailerClient } from '../../util/ChampaignClient';
import URI from 'urijs';
import { resetMember } from '../../state/member/reducer';

class EmailPensionView extends Component {
  constructor(props) {
    super(props);
    this.defaultTemplateVars = {
      fundContact: this.props.intl.formatMessage({
        id: 'email_tool.template_defaults.fund_contact',
      }),
      fundEmail: this.props.intl.formatMessage({
        id: 'email_tool.template_defaults.fund_email',
      }),
      fund: this.props.intl.formatMessage({
        id: 'email_tool.template_defaults.fund',
      }),
      name: this.props.intl.formatMessage({
        id: 'email_tool.template_defaults.name',
      }),
    };

    this.state = {
      shouldShowFundSuggestion: false,
      newPensionFundName: '',
      isSubmittingNewPensionFundName: false,
      newPensionFundSuggested: false,
      clickedCopyBodyButton: false,
      errors: {},
    };
    this.store = window.champaign.store;
  }

  validateForm() {
    const errors = {};

    const fields = ['country', 'emailSubject', 'name', 'email', 'fund'];

    fields.forEach(field => {
      if (isEmpty(this.props[field])) {
        const location = `email_tool.form.errors.${field}`;
        const message = <FormattedMessage id={location} />;
        errors[field] = message;
      }
    });
    // For GDPR countries alone this field should have value
    if (this.props.isRequiredNew && this.props.consented === null) {
      this.props.showConsentRequired(true);
      errors['consented'] = true;
    }
    this.setState({ errors: errors });
    return isEmpty(errors);
  }

  templateVars() {
    let vars = pick(this.props, [
      'name',
      'fund',
      'fundContact',
      'fundEmail',
      'email',
      'country',
      'postal',
    ]);

    each(this.defaultTemplateVars, (val, key) => {
      if (vars[key] === undefined || vars[key] === '') {
        vars[key] = val;
      }
    });
    return vars;
  }

  onEmailEditorUpdate = ({ subject, body }) => {
    this.props.changeSubject(subject);
    this.setState(state => ({ ...state, body }));
  };

  onEmailChange = value => {
    this.props.changeEmail(value);
    if (window.champaign.personalization.member)
      window.champaign.store.dispatch(resetMember());
    if (this.props.consent !== null) {
      this.props.changeConsent(null);
      this.props.changeIsRequiredNew(
        consent.isRequired(
          this.props.countryCode,
          window.champaign.personalization.member
        )
      );
    }
  };

  validateFormBeforeCopying = () => {
    if (!this.validateForm()) {
      alert('Form has errors. Please fix before copying.');
    }
  };

  handleCopyTargetEmailButton = e => {
    e.preventDefault();
    this.validateFormBeforeCopying();
    copyToClipboard(
      buildToEmailForCompose(
        this.composeTargetAddress(),
        this.state.emailService
      )
    );
  };

  handleCopyBodyButton = e => {
    e.preventDefault();
    this.validateFormBeforeCopying();
    copyToClipboard(convertHtmlToPlainText(this.state.body));
    this.setState({ clickedCopyBodyButton: true });
  };

  handleCopySubjectButton = e => {
    e.preventDefault();
    this.validateFormBeforeCopying();
    copyToClipboard(convertHtmlToPlainText(this.props.emailSubject));
  };

  composeTargetAddress() {
    return [{ name: this.props.fundContact, email: this.props.fundEmail }];
  }

  handleSendEmail = () => {
    const emailParam = {
      emailService: this.state.emailService,
      toEmails: this.composeTargetAddress(),
      subject: this.props.emailSubject,
      body: convertHtmlToPlainText(this.state.body),
    };
    window.open(composeEmailLink(emailParam));
  };

  errorNotice = () => {
    if (!isEmpty(this.state.errors)) {
      return (
        <span className="error-msg left-align">
          <FormattedMessage id="email_tool.form.errors.message" />
        </span>
      );
    }
  };

  onSubmit = e => {
    e.preventDefault();
    const valid = this.validateForm();

    if (!valid) return;
    this.handleSendEmail();
    const payload = {
      body: this.state.body,
      subject: this.props.emailSubject,
      target_name: this.props.fund,
      country: this.props.country,
      from_name: this.props.name,
      from_email: this.props.email,
      to_name: this.props.fundContact,
      to_email: this.props.fundEmail,
      email_service: this.state.emailService,
      clicked_copy_body_button: this.state.clickedCopyBodyButton,
    };
    // For double optin consented field should not have a value
    if (this.props.consented !== null)
      payload.consented = this.props.consented ? 1 : 0;
    merge(payload, this.props.formValues);
    this.props.changeSubmitting(true);

    MailerClient.sendPensionEmail({ page_id: this.props.pageId, payload }).then(
      response => {
        window.location.href = URI(`${response.data.follow_up_page}`);
      },
      ({ errors }) => {
        this.setState(s => ({ ...s, errors }));
      }
    );
  };

  onEmailServiceChange = emailService => this.setState({ emailService });

  render() {
    return (
      <div className="email-target">
        <div className="email-target-form">
          <form onSubmit={this.onSubmit} className="action-form form--big">
            <SelectPensionFund
              country={this.props.country}
              fund={this.props.fundId}
              onChange={changeFund}
              errors={{
                country: this.state.errors.country,
                fund: this.state.errors.fund,
              }}
            />
            <div className="email-target-action">
              <h3>
                <FormattedMessage
                  id="email_tool.section.compose"
                  defaultMessage="Compose Your Email"
                />
              </h3>

              <FormGroup>
                <Input
                  name="name"
                  label={
                    <FormattedMessage
                      id="email_tool.form.your_name"
                      defaultMessage="Your name"
                    />
                  }
                  value={this.props.name}
                  errorMessage={this.state.errors.name}
                  onChange={value => this.props.changeName(value)}
                />
              </FormGroup>

              <FormGroup>
                <Input
                  name="email"
                  type="email"
                  label={
                    <FormattedMessage
                      id="email_tool.form.your_email"
                      defaultMessage="Your email"
                    />
                  }
                  value={this.props.email}
                  errorMessage={this.state.errors.email}
                  onChange={this.onEmailChange}
                />
              </FormGroup>

              <EmailEditor
                errors={this.state.errors}
                body={this.props.emailBody}
                header={this.props.emailHeader}
                footer={this.props.emailFooter}
                subject={this.props.emailSubject}
                templateVars={this.templateVars()}
                onUpdate={this.onEmailEditorUpdate}
              />
            </div>

            <div className="EmailToolView-note">
              <div className="section title">
                <FormattedMessage
                  id="email_tool.form.choose_email_service"
                  defaultMessage="If you have not set up an email client or the above button does not open your email, please use the following instructions."
                />
              </div>

              <div className="section">
                <div className="title">
                  <span>
                    <FormattedMessage
                      id="email_tool.form.mobile_desktop_apps"
                      defaultMessage="Mobile &amp; Desktop Apps"
                    />
                  </span>
                </div>
                <div>
                  <label>
                    <input
                      disabled={this.state.emailService === 'in_app_send'}
                      type="radio"
                      checked={this.state.emailService === 'email_client'}
                      onChange={e => this.onEmailServiceChange('email_client')}
                    />
                    <FormattedMessage
                      id="email_tool.form.email_client"
                      defaultMessage="Email Client"
                    />
                  </label>
                </div>
                <div className="title">
                  <span>
                    <FormattedMessage
                      id="email_tool.form.web_browser"
                      defaultMessage="Web Browser"
                    />
                  </span>
                </div>
                <div>
                  <label>
                    <input
                      disabled={this.state.emailService === 'in_app_send'}
                      type="radio"
                      checked={this.state.emailService === 'gmail'}
                      onChange={e => this.onEmailServiceChange('gmail')}
                    />
                    Gmail
                  </label>
                </div>

                <div>
                  <label>
                    <input
                      disabled={this.state.emailService === 'in_app_send'}
                      type="radio"
                      checked={this.state.emailService === 'outlook'}
                      onChange={e => this.onEmailServiceChange('outlook')}
                    />
                    Outlook / Live / Hotmail
                  </label>
                </div>

                <div>
                  <label>
                    <input
                      disabled={this.state.emailService === 'in_app_send'}
                      type="radio"
                      checked={this.state.emailService === 'yahoo'}
                      onChange={e => this.onEmailServiceChange('yahoo')}
                    />
                    Yahoo Mail
                  </label>
                </div>
                <div className="title">
                  <span>
                    <FormattedMessage
                      id="email_tool.form.manual"
                      defaultMessage="Manual"
                    />
                  </span>
                </div>
                <div>
                  <label>
                    <input
                      disabled={this.state.emailService === 'in_app_send'}
                      type="radio"
                      checked={
                        this.state.emailService === 'other_email_services'
                      }
                      onChange={e =>
                        this.onEmailServiceChange('other_email_services')
                      }
                    />
                    <FormattedMessage
                      id="email_tool.form.others"
                      defaultMessage="Others"
                    />
                  </label>
                </div>
              </div>

              {this.state.emailService === 'other_email_services' && (
                <React.Fragment>
                  <div className="section">
                    <FormattedMessage
                      id="email_tool.form.title_for_no_email_client"
                      defaultMessage="If you have not set up an email client or the above button does not open your email, please use the following instructions."
                    />
                  </div>
                  <div className="section">
                    <table>
                      <tbody>
                        <tr>
                          <td>
                            <span>
                              <FormattedMessage
                                id="email_tool.form.copy_target_email_address"
                                defaultMessage="Copy Target Email Address"
                              />
                            </span>
                          </td>
                          <td>
                            <span>
                              <Button
                                className="copy-button"
                                onClick={this.handleCopyTargetEmailButton}
                              >
                                <i className="fa fa-copy"></i>
                              </Button>
                            </span>
                          </td>
                        </tr>
                        <tr>
                          <td>
                            <span>
                              <FormattedMessage
                                id="email_tool.form.copy_email_subject"
                                defaultMessage="Copy Email Subject"
                              />
                            </span>
                          </td>
                          <td>
                            <span>
                              <Button
                                className="copy-button"
                                onClick={this.handleCopySubjectButton}
                              >
                                <i className="fa fa-copy"></i>
                              </Button>
                            </span>
                          </td>
                        </tr>
                        <tr>
                          <td>
                            <span>
                              <FormattedMessage
                                id="email_tool.form.copy_email_body"
                                defaultMessage="Copy Email Body"
                              />
                            </span>
                          </td>
                          <td>
                            <span>
                              <Button
                                className="copy-button"
                                onClick={this.handleCopyBodyButton}
                              >
                                <i className="fa fa-copy"></i>
                              </Button>
                            </span>
                          </td>
                        </tr>
                      </tbody>
                    </table>
                  </div>
                </React.Fragment>
              )}
            </div>
            {consent.isRequired(
              this.props.countryCode,
              window.champaign.personalization.member
            ) && (
              <ConsentComponent
                alwaysShow={true}
                isRequired={
                  this.props.isRequiredNew || this.props.isRequiredExisting
                }
              />
            )}
            <div className="form__group">
              <Button
                disabled={this.state.isSubmitting || !this.state.emailService}
                className="button action-form__submit-button"
              >
                {this.state.emailService === 'other_email_services' ? (
                  <FormattedMessage
                    id="email_tool.form.submit"
                    defaultMessage="Submit Action"
                  />
                ) : (
                  <FormattedMessage
                    // id="email_tool.form.submit_action"
                    id="email_tool.form.submit_and_send_email"
                    defaultMessage="Submit Action &amp; Send Email"
                  />
                )}
              </Button>
              {this.errorNotice()}
            </div>
          </form>
        </div>
      </div>
    );
  }
}

export const mapStateToProps = ({ emailTarget, consent }) => {
  const {
    email,
    name,
    country,
    emailSubject,
    isSubmitting,
    fundContact,
    fundEmail,
    fund,
    fundId,
  } = emailTarget;
  const { countryCode, consented, isRequiredNew, isRequiredExisting } = consent;
  return {
    email,
    name,
    country,
    emailSubject,
    isSubmitting,
    fundContact,
    fundEmail,
    fund,
    fundId,
    countryCode,
    consented,
    isRequiredNew,
    isRequiredExisting,
  };
};

export const mapDispatchToProps = dispatch => ({
  changeSubmitting: value => dispatch(changeSubmitting(true)),
  changeSubject: subject => dispatch(changeSubject(subject)),
  changeName: name => {
    dispatch(changeName(name));
  },
  changeEmail: email => {
    dispatch(changeEmail(email));
  },
  changeConsent: value => dispatch(changeConsent(value)),
  changeIsRequiredNew: value => dispatch(changeIsRequiredNew(value)),
  showConsentRequired: consentRequired =>
    dispatch(showConsentRequired(consentRequired)),
});

export default injectIntl(
  connect(mapStateToProps, mapDispatchToProps)(EmailPensionView)
);