MetaPhase-Consulting/State-TalentMAP

View on GitHub
src/Components/AssignmentsSeparations/NotificationCard/Preview/Preview.jsx

Summary

Maintainability
B
4 hrs
Test Coverage
F
7%
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import Linkify from 'react-linkify';
import FA from 'react-fontawesome';
import PropTypes from 'prop-types';
import TextareaAutosize from 'react-textarea-autosize';
import { getGal, sendNotification } from 'actions/assignmentNotifications';
import { checkFlag } from 'flags';
import { ifEnter } from 'utilities';
import { EMPTY_FUNCTION } from 'Constants/PropTypes';
import { Row } from 'Components/Layout';
import Spinner from 'Components/Spinner';
import Alert from 'Components/Alert';
import NavTabs from 'Components/NavTabs';
import InteractiveElement from 'Components/InteractiveElement';
import { generateHTML, generatePDF, generateSoapXML, generateXML } from '../Common/Utilities';
import { createOpsLog, getOpsData, getOpsWsdl } from '../../../../actions/assignmentNotifications';

const useNotificationSend = () => checkFlag('flags.assignment_notification_send');
const useMemoSend = () => checkFlag('flags.assignment_memo_send');

const Preview = (props) => {
  const {
    note,
    cable,
    onCancel,
    memo,
    getCableValue,
    setEditMode,
    fetchData,
  } = props;

  const dispatch = useDispatch();

  const useSend = memo ? useMemoSend() : useNotificationSend();

  // ====================== Data Retrieval ======================

  const gal = useSelector(state => state.getGal);
  const galErrored = useSelector(state => state.getGalErrored);
  const galLoading = useSelector(state => state.getGalLoading);

  // const opsWsdl = useSelector(state => state.getOpsWsdl);
  // const opsWsdlErrored = useSelector(state => state.getOpsWsdlErrored);
  // const opsWsdlLoading = useSelector(state => state.getOpsWsdlLoading);

  const opsData = useSelector(state => state.getOpsData);
  // const opsDataErrored = useSelector(state => state.getOpsDataErrored);
  // const opsDataLoading = useSelector(state => state.getOpsDataLoading);

  const [recipientMode, setRecipientMode] = useState(false);
  const [galQuery, setGalQuery] = useState('');
  const [recipients, setRecipients] = useState([]);

  useEffect(() => {
    getOpsWsdl();
    getOpsData({ PV_NM_SEQ_NUM_I: note?.NM_SEQ_NUM });
  }, []);

  const getPreviewText = (fullPreview) => {
    if (!memo) {
      const notePreview = [
        `${getCableValue('CLASSIFICATION')}\n\n`,
        `${getCableValue('DRAFTING OFFICE')}`,
        `${getCableValue('DATE')} - ${getCableValue('TELEPHONE')}`,
        `${getCableValue('APPROVING OFFICE')}\n`,
        `${getCableValue('CLEARANCE')}\n`,
        // `${getCableValue('DISTRIBUTION')}\n`,
        // `${getCableValue('ACTION')}\n`,
        // `${getCableValue('INFORMATION')}\n`,
        `${getCableValue('SPECIAL HANDLING')}\n`,
        `${getCableValue('CAPTIONS')}\n`,
        `${getCableValue('E.O.')}\n`,
        `${getCableValue('TAGS')}\n`,
        `${getCableValue('SUBJECT')}\n`,
        `1. ${getCableValue('ASSIGNMENTS')}\n`,
        `2. ${getCableValue('COMBINED TOD')}\n`,
        `3. ${getCableValue('EFM')}\n`,
        `4. ${getCableValue('REMARKS')}\n`,
        `5. ${getCableValue('PARAGRAPHS')}\n`,
        `${getCableValue('EOM')}`,
      ];
      return notePreview.join('\n');
    }
    const memoPreview = [
      `${getCableValue('ASSIGNMENTS')}\n`,
      `${getCableValue('COMBINED TOD')}\n`,
      `${getCableValue('REMARKS')}\n`,
      `${getCableValue('PARAGRAPHS')}\n`,
    ];
    if (fullPreview) {
      const memoFullPreview = [
        '\n\n',
        'MEMORANDUM\n',
        `TO: ${getCableValue('TO_ADDRESS')}\n`,
        `FROM: ${getCableValue('FROM_ADDRESS')}\n`,
        `SUBJECT: ${getCableValue('SUBJECT')}\n`,
        `LAST SENT: ${cable?.O_LAST_SENT_DATE}\n`,
        ...memoPreview,
      ];
      return memoFullPreview.join('\n');
    }
    return memoPreview.join('\n');
  };

  const handleSend = () => {
    const nmSeqNum = note?.NM_SEQ_NUM;
    const type = memo ? 'M' : 'C';
    let now = new Date();
    now = now.toISOString();
    now = now.replace(/\D/g, '');
    const date = now.substring(0, 8);
    const time = now.substring(8, 14);
    const filename = `TMONE_${memo ? 'MEMO' : 'CABLE'}_${nmSeqNum}_${date}_${time}.pdf`;

    // ------------ Handle Send ------------

    generateXML(cable, getPreviewText(), getCableValue('SUBJECT'));
    generateHTML(getCableValue, cable?.O_LAST_SENT_DATE, getPreviewText());
    dispatch(sendNotification({
      I_NM_SEQ_NUM: nmSeqNum,
      I_NOTE_TYPE: type,
    }, fetchData, memo));

    // ------------ Handle PDF ------------ // Synchronous

    if (cable?.O_LAST_SENT_DATE) {
      generatePDF(getPreviewText, filename, memo); // TEMPORARY: Saves PDF locally for testing purposes
      dispatch(sendNotification({
        PV_NM_SEQ_NUM_I: nmSeqNum,
        PV_FILE_NAME_I: filename,
        PV_NOTE_TYPE_I: type,
      }, null, memo));
    }

    // ------------ Handle OPS ------------

    if (!memo) {
      const opsLogData = opsData?.PQRY_OTL_LOG_TM1_O?.[0];
      if (opsLogData) {
        dispatch(createOpsLog({
          PV_OTL_TM_DATA_I: generateSoapXML(opsLogData),
          PV_ETL_SEQ_NBR_I: opsLogData.ETL_SEQ_NUM,
        }, null));
      }
    }
  };

  const getOverlay = () => {
    let overlay;
    if (galLoading) {
      overlay = <Spinner type="small" size="small" />;
    } else if (galErrored) {
      overlay = <Alert type="error" title="Error loading results" messages={[{ body: 'Please try again.' }]} />;
    } else {
      return false;
    }
    return overlay;
  };

  if (recipientMode) {
    return (
      <Row fluid className="tabbed-card box-shadow-standard">
        <Row fluid className="tabbed-card--header">
          <NavTabs
            tabs={[{ text: 'Recipients', value: 'RECIPIENTS' }]}
            value="RECIPIENTS"
            styleVariant="lightBorderBottom"
          />
        </Row>
        <div className="position-content position-form notification-card">
          <div className="notification-card__header">
            <span>
              Memorandum
            </span>
            <span>
              Search by last name for a list of recipients to add to the email.
            </span>
          </div>
          <div className="gal-lookup">
            <div className="gal-lookup__input">
              <label htmlFor="gal-lookup" className="gal-label">GAL Lookup</label>
              <div>
                <input
                  id="gal-lookup"
                  name="gal-lookup"
                  placeholder="Last Name"
                  value={galQuery}
                  onChange={(e) => setGalQuery(e.target.value)}
                  onKeyUp={(e) => { if (ifEnter(e)) dispatch(getGal({ PV_LAST_NAME_I: galQuery })); }}
                />
                <button onClick={() => dispatch(getGal({ PV_LAST_NAME_I: galQuery }))}>
                  Search
                </button>
              </div>
            </div>
            <div className="recipients">
              <div className="recipients-list">
                <div className="gal-label">Recipient Results</div>
                {getOverlay() || (
                  gal?.length > 0 &&
                  <div className="gal-result">
                    {gal?.map(g => (
                      <div
                        key={g.GAL_SMTP_EMAIL_ADRS_TEXT}
                        tabIndex={0}
                        role="button"
                        className="gal-result__item clickable"
                        onClick={() => {
                          const match = recipients.find(r => r.GAL_SMTP_EMAIL_ADRS_TEXT === g.GAL_SMTP_EMAIL_ADRS_TEXT);
                          if (!match) {
                            setRecipients([...recipients, g]);
                          }
                        }}
                      >
                        {g.GAL_DISPLAY_NAME}
                      </div>
                    ))}
                  </div>
                )}
              </div>
              <div className="recipients-list">
                <div className="gal-label">Added Recipients</div>
                {recipients?.length > 0 &&
                  <div className="gal-result">
                    {recipients?.map(g => (
                      <div className="gal-result__item">
                        <div>{g.GAL_DISPLAY_NAME}</div>
                        <InteractiveElement
                          title={`Remove Recipient ${g.GAL_DISPLAY_NAME}`}
                          onClick={() => {
                            const removed = recipients.filter(r => r.GAL_SMTP_EMAIL_ADRS_TEXT !== g.GAL_SMTP_EMAIL_ADRS_TEXT);
                            setRecipients(removed);
                          }}
                          className="delete-button"
                        >
                          <FA name="trash" className="fa-lg" />
                        </InteractiveElement>
                      </div>
                    ))}
                  </div>
                }
              </div>
            </div>
          </div>
          <div className="position-form--actions">
            <button onClick={() => setRecipientMode(false)}>Back to Preview</button>
            <button onClick={() => handleSend()} disabled={recipients?.length === 0}>Email Memo</button>
          </div>
        </div>
      </Row>
    );
  }
  return (
    <Row fluid className="tabbed-card box-shadow-standard">
      <Row fluid className="tabbed-card--header">
        <NavTabs
          tabs={[{ text: 'Preview', value: 'PREVIEW' }]}
          value="PREVIEW"
          styleVariant="lightBorderBottom"
        />
      </Row>
      <div className="position-content position-form notification-card">
        <button className="toggle-edit-mode notification-card__rebuild" onClick={() => setEditMode(true)}>
          <FA name="pencil" />
          <div>Edit</div>
        </button>
        <div className="notification-card__header">
          {memo ?
            <>
              <span>
                Memorandum
              </span>
              <span className="notification-card__header-subtitle">To</span>
              <span>
                {getCableValue('TO_ADDRESS') ?? '---'}
              </span>
              <span className="notification-card__header-subtitle">From</span>
              <span>
                {getCableValue('FROM_ADDRESS') ?? '---'}
              </span>
              <span className="notification-card__header-subtitle">Subject</span>
              <span>
                {getCableValue('SUBJECT') ?? '---'}
              </span>
              <span className="notification-card__header-subtitle">Last Sent</span>
              <span>
                {cable?.O_LAST_SENT_DATE ?? '---'}
              </span>
              <span className="notification-card__header-subtitle">Body</span>
            </> :
            <>
              <span>
                Notification
              </span>
              <span>
                The Notification Cable for {getCableValue('EMPLOYEE FULL NAME')} will be emailed to the Dos Communications Center from the preparer {getCableValue('FROM_ADDRESS')}.
              </span>
            </>
          }
        </div>
        <Row fluid className="position-content--description">
          <Linkify properties={{ target: '_blank' }}>
            <TextareaAutosize
              maxRows={50}
              minRows={1}
              maxLength="500"
              name="preview-body"
              value={getPreviewText()}
              draggable={false}
              disabled
            />
          </Linkify>
          <div className="word-count">
            {getPreviewText()?.length} / 500
          </div>
        </Row>
        <div className="position-form--actions">
          {useSend ?
            <>
              <button onClick={onCancel}>Cancel</button>
              <button onClick={() => { if (memo) { setRecipientMode(true); } else { handleSend(); } }}>
                {memo ? 'Select Memo Recipients' : 'Send Cable'}
              </button>
            </> :
            <button onClick={onCancel}>Back</button>
          }
        </div>
      </div>
    </Row>
  );
};

Preview.propTypes = {
  note: PropTypes.shape({
    NM_SEQ_NUM: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  }),
  cable: PropTypes.shape({
    O_LAST_SENT_DATE: PropTypes.string,
  }),
  onCancel: PropTypes.func,
  memo: PropTypes.bool,
  getCableValue: PropTypes.func.isRequired,
  setEditMode: PropTypes.func.isRequired,
  fetchData: PropTypes.func.isRequired,
};

Preview.defaultProps = {
  note: undefined,
  cable: undefined,
  onCancel: EMPTY_FUNCTION,
  memo: false,
};

export default Preview;