RocketChat/Rocket.Chat

View on GitHub
packages/livechat/src/lib/triggerActions.ts

Summary

Maintainability
B
5 hrs
Test Coverage
import type { ILivechatSendMessageAction, ILivechatTriggerCondition, ILivechatUseExternalServiceAction } from '@rocket.chat/core-typings';
import { route } from 'preact-router';

import store from '../store';
import { normalizeAgent } from './api';
import { parentCall } from './parentCall';
import { createToken } from './random';
import { getAgent, removeMessage, requestTriggerMessages, upsertMessage } from './triggerUtils';
import Triggers from './triggers';

export const sendMessageAction = async (_: string, action: ILivechatSendMessageAction, condition: ILivechatTriggerCondition) => {
    const { token, minimized } = store.state;

    const agent = await getAgent(action);

    const message = {
        msg: action.params?.msg,
        token,
        u: agent,
        ts: new Date().toISOString(),
        _id: createToken(),
        trigger: true,
    };

    await upsertMessage(message);

    // Save the triggers for subsequent renders
    if (condition.name === 'after-guest-registration') {
        store.setState({
            renderedTriggers: [...store.state.renderedTriggers, message],
        });
    }

    if (agent && '_id' in agent) {
        await store.setState({ agent });
        parentCall('callback', 'assign-agent', normalizeAgent(agent));
    }

    if (minimized) {
        route('/trigger-messages');
        store.setState({ minimized: false });
    }

    if (condition.name !== 'after-guest-registration') {
        const onVisitorRegistered = async () => {
            await removeMessage(message._id);
            Triggers.callbacks?.off('chat-visitor-registered', onVisitorRegistered);
        };

        Triggers.callbacks?.on('chat-visitor-registered', onVisitorRegistered);
    }
};

export const sendMessageExternalServiceAction = async (
    triggerId: string,
    action: ILivechatUseExternalServiceAction,
    condition: ILivechatTriggerCondition,
) => {
    const { token, minimized, typing, iframe } = store.state;
    const metadata = iframe.guestMetadata || {};
    const agent = await getAgent(action);

    if (agent?.username) {
        store.setState({ typing: [...typing, agent.username] });
    }

    try {
        const { serviceFallbackMessage: fallbackMessage } = action.params || {};
        const triggerMessages = await requestTriggerMessages({
            token,
            triggerId,
            metadata,
            fallbackMessage,
        });

        const messages = triggerMessages
            .sort((a, b) => a.order - b.order)
            .map((item) => item.msg)
            .map((msg) => ({
                msg,
                token,
                u: agent,
                ts: new Date().toISOString(),
                _id: createToken(),
                trigger: true,
            }));

        await Promise.all(
            messages.map((message) => {
                if (condition.name === 'after-guest-registration') {
                    store.setState({
                        renderedTriggers: [...store.state.renderedTriggers, message],
                    });
                }

                return upsertMessage(message);
            }),
        );

        if (agent && '_id' in agent) {
            await store.setState({ agent });
            parentCall('callback', 'assign-agent', normalizeAgent(agent));
        }

        if (minimized) {
            route('/trigger-messages');
            store.setState({ minimized: false });
        }

        if (condition.name !== 'after-guest-registration') {
            const onVisitorRegistered = async () => {
                await Promise.all(messages.map((message) => removeMessage(message._id)));
                Triggers.callbacks?.off('chat-visitor-registered', onVisitorRegistered);
            };

            Triggers.callbacks?.on('chat-visitor-registered', onVisitorRegistered);
        }
    } finally {
        store.setState({
            typing: store.state.typing.filter((u) => u !== agent?.username),
        });
    }
};

export const actions = {
    'send-message': sendMessageAction,
    'use-external-service': sendMessageExternalServiceAction,
};