Source

ui/components/admin/analytics/newsletter/AdminAnalyticsNewsletterWidget.tsx

import React, { useState } from 'react';
import { Segment, Header, Form, Button } from 'semantic-ui-react';
import { AutoForm, TextField, LongTextField, BoolField, NumField } from 'uniforms-semantic';
import { SimpleSchema2Bridge } from 'uniforms-bridge-simple-schema-2';
import SimpleSchema from 'simpl-schema';
import Swal from 'sweetalert2';
import { $ } from 'meteor/jquery';
import _ from 'lodash';
import { connect } from 'react-redux';
import AdminAnalyticsNewsletterMessagePreviewWidget from './AdminAnalyticsNewsletterMessagePreviewWidget';
import { StudentProfiles } from '../../../../../api/user/StudentProfileCollection';
import { sendEmailMethod } from '../../../../../api/analytic/Email.methods';
import { RadGradProperties } from '../../../../../api/radgrad/RadGradProperties';
import { analyticsActions } from '../../../../../redux/admin/analytics';
import { RootState } from '../../../../../redux/types';
import {
  getRecList,
  getStudentEmailsByLevel,
  EmailData,
} from './utilities/newsletter';

/* Technical Debt:
 *   * Redux is not indicated when the goal is to manage form-local state.
 */

/**
 * Schema for the form that controls sending email.
 */
const schema = new SimpleSchema({
  inputMessage: String,
  bcc: { type: String, optional: true },
  subjectLine: String,
  studentEmails: { type: String, optional: true, label: 'Student Emails' },
  level: {
    type: SimpleSchema.Integer,
    allowedValues: [1, 2, 3, 4, 5, 6],
    optional: true,
    label: 'Generate and send newsletters to students of the specified level',
  },
  sendToStudentsToo: { type: Boolean, optional: true },
  sendToLevels: { type: Boolean, optional: true, label: 'Check to confirm send' },
  sendToAll: { type: Boolean, optional: true, label: 'Check to confirm send' },
});
const formSchema = new SimpleSchema2Bridge(schema);

interface AdminAnalyticsNewsletterWidgetProps {
  startTestNewsletter: () => any;
  testNewsletterDone: () => any;
  testNewsletterWorking: boolean;
  startLevelNewsletter: () => any;
  levelNewsletterDone: () => any;
  levelNewsletterWorking: boolean;
  startAllNewsletter: () => any;
  allNewsletterDone: () => any;
  allNewsletterWorking: boolean;
}

const mapStateToProps = (state: RootState) => ({
  testNewsletterWorking: state.admin.analytics.newsletter.testNewsletter,
  levelNewsletterWorking: state.admin.analytics.newsletter.levelNewsletter,
  allNewsletterWorking: state.admin.analytics.newsletter.allNewsletter,
});

const mapDispatchToProps = (dispatch) => ({
  startTestNewsletter: () => dispatch(analyticsActions.startTestNewsletter()),
  testNewsletterDone: () => dispatch(analyticsActions.testNewsletterDone()),
  startLevelNewsletter: () => dispatch(analyticsActions.startLevelNewsletter()),
  levelNewsletterDone: () => dispatch(analyticsActions.levelNewsletterDone()),
  startAllNewsletter: () => dispatch(analyticsActions.startAllNewsletter()),
  allNewsletterDone: () => dispatch(analyticsActions.allNewsletterDone()),
});

const AdminAnalyticsNewsletterWidget: React.FC<AdminAnalyticsNewsletterWidgetProps> = ({ startAllNewsletter, allNewsletterDone, allNewsletterWorking, levelNewsletterDone, levelNewsletterWorking, startLevelNewsletter, startTestNewsletter, testNewsletterDone, testNewsletterWorking }) => {
  const [subjectLine, setSubjectLine] = useState<string>('');
  const [bcc, setBcc] = useState<string>('');
  const [inputMessage, setInputMessage] = useState<string>('');
  const [onSubmitInputMessage, setOnSubmitInputMessage] = useState<string>('');
  const [studentEmails, setStudentEmails] = useState<string>('');
  const [sendToStudentsToo, setSendToStudentsToo] = useState<boolean>(false);
  const [level, setLevel] = useState<number>(0);
  const [sendToLevels, setSendToLevels] = useState<boolean>(false);
  const [sendToAll, setSendToAll] = useState<boolean>(false);

  const emailDelayMs = 500; // the delay between sending student emails in milliseconds.

  /** Auto Forms */
  // check on this https://stackoverflow.com/questions/38558200/react-setstate-not-updating-immediately
  const handleChange = (name, value) => {
    switch (name) {
      case 'inputMessage':
        setInputMessage(value);
        break;
      case 'onSubmitInputMessage':
        setOnSubmitInputMessage(value);
        break;
      case 'bcc':
        setBcc(value);
        break;
      case 'subjectLine':
        setSubjectLine(value);
        break;
      case 'studentEmails':
        setStudentEmails(value);
        break;
      case 'sendToStudentsToo':
        setSendToStudentsToo(value);
        break;
      case 'level':
        setLevel(parseInt(value, 10));
        break;
      case 'sendToLevels':
        setSendToLevels(value);
        break;
      case 'sendToAll':
        setSendToAll(value);
        break;
      default:
        // do nothing
    }
  };

  /**
   * Sets the Admin's message.
   */
  const onClickPreviewSave = () => {
    setOnSubmitInputMessage(inputMessage);
  };

  /**
   * Sends test emails to the admin and optionally the student(s).
   */
  const onClickSendStudentsToo = () => {
    if (onSubmitInputMessage.length !== 0 && subjectLine.length !== 0) {
      startTestNewsletter();
      const studentEmailsArr = studentEmails.split(',');
      const bccListArray = _.map(bcc.split(','), email => email.trim());
      const adminEmail = RadGradProperties.getAdminEmail();
      const from = RadGradProperties.getNewsletterFrom();
      const adminMessage = $('.adminMessage').html();
      _.forEach(studentEmailsArr, (studentEmail) => {
        setTimeout(() => {
          const student = StudentProfiles.findByUsername(studentEmail);
          if (student) {
            const suggestedRecs = getRecList(student);
            const sendList = [];
            sendList.push(adminEmail); // always send to admin
            if (sendToStudentsToo) {
              sendList.push(studentEmail);
            }
            const emailData: EmailData = {
              to: sendList,
              bcc: bccListArray,
              from: from,
              replyTo: RadGradProperties.getAdminEmail(),
              subject: `Newsletter View For ${student.firstName} ${student.lastName}`,
              templateData: {
                adminMessage,
                firstName: student.firstName,
                firstRec: suggestedRecs[0],
                secondRec: suggestedRecs[1],
                thirdRec: suggestedRecs[2],
              },
              filename: 'newsletter2.html',
            };
            sendEmailMethod.call(emailData, (error) => {
              if (error) {
                console.error('Error sending email.', error);
              }
            });
          }
        }, emailDelayMs);
      });
      let numEmails = studentEmailsArr.length;
      if (sendToStudentsToo) {
        numEmails *= 2;
      }
      Swal.fire({
        title: 'Emails Succesfully Sent',
        icon: 'success',
        text: `${numEmails} emails sent!`,
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
      testNewsletterDone();
    } else {
      Swal.fire({
        title: 'Subject Line and Input Message Required',
        icon: 'error',
        text: 'You forgot to fill out either the Subject Line and/or the Input Message for the Emails!',
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
    }
  };

  const onClickSendLevels = () => {
    if (onSubmitInputMessage.length !== 0 && subjectLine.length !== 0 && level !== 0) {
      startLevelNewsletter();
      const studentEmailsArr = getStudentEmailsByLevel(level);
      const bccListArray = _.map(bcc.split(','), email => email.trim());
      const from = RadGradProperties.getNewsletterFrom();
      const adminMessage = $('.adminMessage').html();
      _.forEach(studentEmailsArr, (studentEmail) => {
        setTimeout(() => {
          const student = StudentProfiles.findByUsername(studentEmail);
          if (student) {
            const suggestedRecs = getRecList(student);
            const emailData: EmailData = {
              to: studentEmail,
              bcc: bccListArray,
              from: from,
              replyTo: RadGradProperties.getAdminEmail(),
              subject: subjectLine,
              templateData: {
                adminMessage,
                firstName: student.firstName,
                firstRec: suggestedRecs[0],
                secondRec: suggestedRecs[1],
                thirdRec: suggestedRecs[2],
              },
              filename: 'newsletter2.html',
            };
            sendEmailMethod.call(emailData, (error) => {
              if (error) {
                console.error('Error sending email.', error);
              }
            });
          }
        }, emailDelayMs);
      });
      Swal.fire({
        title: 'Emails Succesfully Sent',
        icon: 'success',
        text: `${studentEmailsArr.length} emails sent!`,
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
      levelNewsletterDone();
    } else {
      Swal.fire({
        title: 'Subject Line and Input Message Required',
        icon: 'error',
        text: 'You forgot to fill out either the Subject Line and/or the Input Message for the Emails!',
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
    }
  };

  const onClickSendToAll = () => {
    if (onSubmitInputMessage.length !== 0 && subjectLine.length !== 0) {
      startAllNewsletter();
      const profiles = StudentProfiles.find({ isAlumni: false }).fetch();
      const studentEmailsArr = _.map(profiles, (p) => p.username);
      const bccListArray = _.map(bcc.split(','), email => email.trim());
      const from = RadGradProperties.getNewsletterFrom();
      const adminMessage = $('.adminMessage').html();
      _.forEach(studentEmailsArr, (studentEmail) => {
        setTimeout(() => {
          const student = StudentProfiles.findByUsername(studentEmail);
          if (student) {
            const suggestedRecs = getRecList(student);
            const emailData: EmailData = {
              to: studentEmail,
              bcc: bccListArray,
              from: from,
              replyTo: RadGradProperties.getAdminEmail(),
              subject: subjectLine,
              templateData: {
                adminMessage,
                firstName: student.firstName,
                firstRec: suggestedRecs[0],
                secondRec: suggestedRecs[1],
                thirdRec: suggestedRecs[2],
              },
              filename: 'newsletter2.html',
            };
            sendEmailMethod.call(emailData, (error) => {
              if (error) {
                console.error('Error sending email.', error);
              }
            });
          }
        }, emailDelayMs);
      });
      Swal.fire({
        title: 'Emails Succesfully Sent',
        icon: 'success',
        text: `${studentEmailsArr.length} emails sent!`,
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
      allNewsletterDone();
    } else {
      Swal.fire({
        title: 'Subject Line and Input Message Required',
        icon: 'error',
        text: 'You forgot to fill out either the Subject Line and/or the Input Message for the Emails!',
        allowOutsideClick: false,
        allowEscapeKey: false,
        allowEnterKey: false,
      });
    }
  };

  return (
    <Segment padded>
      <Header dividing as="h4">NEWSLETTER OPTIONS</Header>
      <AutoForm schema={formSchema} onChange={handleChange}>
        <TextField name="subjectLine" />
        <TextField name="bcc" />
        <Form.Group widths="equal">
          <LongTextField name="inputMessage" />
          <AdminAnalyticsNewsletterMessagePreviewWidget message={onSubmitInputMessage} />
        </Form.Group>
        <Button color="green" basic onClick={onClickPreviewSave}>Preview And Save</Button>
        <Header as="h4" dividing>SEND NEWSLETTER</Header>
        <Segment>
          <TextField name="studentEmails" />
          <BoolField name="sendToStudentsToo" />
          <Button basic color="green" loading={testNewsletterWorking} onClick={onClickSendStudentsToo}>
            Send To Admin
          </Button>
        </Segment>
        <Segment>
          <NumField name="level" placeholder="level" />
          <BoolField name="sendToLevels" />
          <Button disabled={!sendToLevels} loading={levelNewsletterWorking} onClick={onClickSendLevels}>
            Send To Students
          </Button>
        </Segment>
        <Segment>
          <Form.Field label="Generate To Send To All Users" />
          <BoolField name="sendToAll" />
          <Button disabled={!sendToAll} loading={allNewsletterWorking} onClick={onClickSendToAll}>
            Send To All
          </Button>
        </Segment>
      </AutoForm>
    </Segment>
  );
};

const AdminAnalyticsNewsletterWidgetContainer = connect(mapStateToProps, mapDispatchToProps)(AdminAnalyticsNewsletterWidget);
export default AdminAnalyticsNewsletterWidgetContainer;