department-of-veterans-affairs/vets-website

View on GitHub
src/applications/virtual-agent/utils/actions.js

Summary

Maintainability
A
0 mins
Test Coverage
import * as _ from 'lodash';
import recordEvent from '@department-of-veterans-affairs/platform-monitoring/record-event';
import piiReplace from './piiReplace';
import {
  getConversationIdKey,
  getInAuthExp,
  getIsRxSkill,
  getIsTrackingUtterances,
  getRecentUtterances,
  setIsRxSkill,
  setIsTrackingUtterances,
  setRecentUtterances,
} from './sessionStorage';
import { sendWindowEventWithActionPayload } from './events';
import submitForm from './submitForm';

const START_CONVERSATION = 'startConversation';
const EVENT = 'event';
const POST_ACTIVITY = 'DIRECT_LINE/POST_ACTIVITY';
const SEND_EVENT = 'WEB_CHAT/SEND_EVENT';

const joinActivity = {
  type: SEND_EVENT,
  payload: {
    name: 'webchat/join',
    value: { language: window.navigator.language },
  },
};

function getStartConversationActivity(value) {
  return {
    meta: { method: 'keyboard' },
    payload: {
      activity: {
        channelData: { postBack: true },
        name: START_CONVERSATION,
        type: EVENT,
        value: {
          csrfToken: value.csrfToken,
          apiSession: value.apiSession,
          apiURL: value.apiURL,
          baseURL: value.baseURL,
          userFirstName: value.userFirstName,
          userUuid: value.userUuid,
          currentConversationId: value.currentConversationId,
          isMobile: value.isMobile,
        },
      },
    },
    type: POST_ACTIVITY,
  };
}

function getEventName(action) {
  return action?.payload?.activity?.name ?? '';
}

function getEventValue(action) {
  return action?.payload?.activity?.value ?? '';
}

function isEventRxSkill(eventValue) {
  return eventValue === 'RX_Skill';
}

function handleSkillEvent(action, eventName, isRxSkillState) {
  const actionEventName = getEventName(action);
  const eventValue = getEventValue(action);

  if (actionEventName === eventName && isEventRxSkill(eventValue)) {
    setIsRxSkill(isRxSkillState);
    sendWindowEventWithActionPayload('rxSkill', action);
  }
}

function createSendMessageActivity(newUtterance) {
  return {
    type: 'WEB_CHAT/SEND_MESSAGE',
    payload: { type: 'message', text: newUtterance },
  };
}

function resetUtterances(dispatch) {
  const utterances = getRecentUtterances();
  const utterance = utterances ? utterances[0] : undefined;
  if (utterance) {
    dispatch(createSendMessageActivity(utterance));
    // Reset utterance array
    setRecentUtterances([]);
  }
}

// define thunks for actions
export const processActionConnectFulfilled = ({
  dispatch,
  ...options
}) => () => {
  const currentConversationId = getConversationIdKey();
  const startConversationActivity = getStartConversationActivity({
    ...options,
    currentConversationId,
  });

  dispatch(startConversationActivity);
  dispatch(joinActivity);
};

export const processSendMessageActivity = ({ action }) => () => {
  _.assign(action.payload, { text: piiReplace(action.payload.text) });
  const outgoingActivityEvent = new Event('bot-outgoing-activity');
  window.dispatchEvent(outgoingActivityEvent);
};

export const processIncomingActivity = ({
  action,
  dispatch,
  isComponentToggleOn,
}) => () => {
  const isAtBeginningOfConversation = !getIsTrackingUtterances();
  const data = action.payload.activity;
  const isMessageFromBot =
    data.type === 'message' && data.text && data.from.role === 'bot';
  const isFormPostButton = data.value?.type === 'FormPostButton';

  if (isAtBeginningOfConversation) {
    setIsTrackingUtterances(true);
  }

  if (isMessageFromBot) {
    const botWantsToSignInUser = data.text.includes(
      'Alright. Sending you to the sign-in page...',
    );

    const inAuthExp = getInAuthExp();
    const isNewAuthedConversation =
      data.text.includes('To get started') && inAuthExp === 'true';

    if (botWantsToSignInUser) {
      setIsTrackingUtterances(false);
      sendWindowEventWithActionPayload('webchat-auth-activity', action);
    } else if (isNewAuthedConversation) {
      resetUtterances(dispatch);
    }
  }

  if (isComponentToggleOn && isFormPostButton) {
    submitForm(data.value.url, data.value.body);
  }

  const trackingUtterances = getIsTrackingUtterances();
  if (trackingUtterances) {
    sendWindowEventWithActionPayload('webchat-message-activity', action);
  }

  handleSkillEvent(action, 'Skill_Entry', true);
  handleSkillEvent(action, 'Skill_Exit', false);
};

export const processMicrophoneActivity = ({ action }) => () => {
  const isRxSkill = getIsRxSkill();
  if (action.payload.dictateState === 3) {
    recordEvent({
      event: 'chatbot-microphone-enable',
      topic: isRxSkill ? 'prescriptions' : undefined,
    });
  } else if (action.payload.dictateState === 0) {
    recordEvent({
      event: 'chatbot-microphone-disable',
      topic: isRxSkill ? 'prescriptions' : undefined,
    });
  }
};

export function addActivityData(
  action,
  { apiSession, csrfToken, apiURL, userFirstName, userUuid },
) {
  const updatedAction = action;
  if (updatedAction.payload?.activity) {
    updatedAction.payload.activity.value = {
      ...updatedAction.payload.activity.value,
      apiSession,
      csrfToken,
      apiURL,
      userFirstName,
      userUuid,
    };
  }
  return updatedAction;
}