import {compact, each, findIndex, isNil, merge, sortBy} from "lodash"; import {APICursorHttpResponse} from "../../helpers/apiCursor.helper"; import {BaseDemultiplexedHttpChatsResource} from "../../resources/chats.resource"; import {StreamListener} from "../websockets/websocketManager"; import {ChatMessage, ChatMessageData, MultichatMessage} from "./message"; import {Observable, Observer} from 'rxjs'; export interface ChatCreationData { client?: number; type?: string; metadata?: { [key: string]: any } } export interface ChatData { client: { [key: string]: any }; created: string; current_agent: number; id: number; last_client_attribute_update_at: string; last_message_at: string; unread_count: number; uuid: string; type: { [key: string]: any }; client_attributes: ChatClientInfoAttribute[]; session: string; } export interface ChatResourceFilters { type?: string; last_message_after?: string; last_message_before?: string; amount_messages_gte?: string | number; amount_messages_lte?: string | number; created_before?: string; created_after?: string; amount_client_attributes_gte?: string | number; amount_client_attributes_lte?: string | number; status?: string; page_size?: string | number; } export interface ChatMessageResourceFilters { sent_before?: string; sent_after?: string; msg_interface?: string; page_size?: number; exclude_typing?: boolean; } export interface ChatClientInfoAttribute { key: string; value: string; utterance: string; } /** * A single chat. Uses StreamListeners to keep tabs on the Chat's status. * @constructor */ export class Chat extends BaseDemultiplexedHttpChatsResource { receivedMessages: ChatMessage[] = []; sortKey = "order"; _subResources = { "currentStatuses": { resource: "current-statuses", url: this.baseResource + "current-statuses", }, 'messages': { url: () => this.baseResource + this.resourceIdentifier + '/messages/', resource: 'messages', }, 'metadata': { url: () => this.baseResource + this.resourceIdentifier + '/metadata/' } }; /** * @param data * * @param sessionKey - The User's Session ID for the Multichat API */ constructor(data: ChatData, sessionKey: string) { super(merge(data, {session: sessionKey})); const that = this; // Send a 'received' message on receiving of messages to this Chat. this._callbacks['messages'].push((response?: { [key: string]: any }) => { if (response && 'data' in response && response.data.sent_by) { const action = response.action, pk = response.pk, id = that.data.id; if (action === 'create') { const listener = this._listeners.find(that._findMessagesListener); if (listener) { listener.send('received', { 'message': pk, chat: id }); } } } }); this.messagesObservable = Observable.create((observer: Observer) => { this.onMessage((m: ChatMessage) => { observer.next(m); }) }); // Track received messages internally this.onMessage((m: ChatMessage) => { this.receivedMessages.push(m); }) } public newMessage(data: MultichatMessage | ChatMessageData): ChatMessage { return new ChatMessage(this, data); }; public setMetaData(metadata: { [key: string]: any }): Promise { return this.requestSubResource('metadata', null, null, 'PUT', metadata); } public getMetaData(): Promise { return this.requestSubResource('metadata', null, null, 'GET'); } /** * @returns {ChatMessage[]} - All loaded messages, from pagination calls and also the received ones */ public get loadedMessages(): ChatMessage[] { return sortBy([].concat(this.messages, this.receivedMessages), ['order']); } /** * Add the passed messages to the messages in this chat. * @param messages */ mergeMessages(messages: Array) { this.messages.push.apply(this.messages, compact(messages.map(m => { return findIndex(this.messages, (m: ChatMessage) => { return !isNil(m) && m.order === m.order }) ? (m instanceof ChatMessage ? m : new ChatMessage(this, m)) : null }))); this.sortMessages(); } public requestMessages(uuid: string, filters?: ChatMessageResourceFilters): Promise> { let defaultFilters: ChatMessageResourceFilters = { exclude_typing: true }; filters = merge(defaultFilters, filters); return this.requestSubResource('messages', undefined, filters); } onMessage(callback: Function) { let that = this; return this.onAction('messages', function (r: { data: MultichatMessage }) { if (r && r.data) { return callback(new ChatMessage(that, r.data)) } }); } _findMainStreamListener(listener: StreamListener) { return listener.stream === 'chat'; }; /** * Listen for updates on one specific Chat instance */ listenForUpdates() { this.ensureListeningOnStream('chat', ['update']); return this; }; }