File: src\internal\ui\chat\component.ts
/// <reference path="../../api/modalities/chatModality.ts" />
/// <reference path="../../utils/modality.ts" />
/// <reference path="../../utils/object.ts" />
/// <reference path="../../utils/typeCheck.ts" />
/// <reference path="../../utils/url.ts" />
/// <reference path="../constants.ts" />
/// <reference path="../uiComponent.ts" />
/// <reference path="sdk.ts" />
/// <reference path="config.ts" />
/**
* @module UI
* @submodule UI Chat
* @namespace ui
*/
/**
* Chat UI Module
* @class chat
* @static
*/
namespace internal.ui.chat {
const LOAD_TIMEOUT_MS = 15000;
const REPORT_HEIGHT_CHANGES = false;
const CHAT_EVENT_PREFIX = "Chat";
const CHAT_MESSAGE_EVENT_NAME = "ChatMessage";
const CHAT_COMPONENT = "Chat";
/**
* Render the Chat UI
* @method render
* @static
* @param {ui.chat.Config} config A {{#crossLink "ui.chat.Config"}}{{/crossLink}} object
* @param {ui.UIInfo} [config.uiInfo] A {{#crossLink "ui.UIInfo"}}{{/crossLink}} object {{#crossLink "ui.UIInfo"}}{{/crossLink}}
* @param {ui.HostType} [config.uiInfo.type] A value in {{#crossLink "ui.HostType"}}{{/crossLink}} which indicates the type of UI to render e.g. IFRAME, POPUP.
* @param {String} [config.uiInfo.containerSelector] Only required for iframe -- a JQuery selector statement to define the element into which the iframe will be loaded
* @param {Number} [config.uiInfo.height] The height of the rendered UI
* @param {Number} [config.uiInfo.width] The width of the rendered UI
* @return {Promise} A promise that resolves to a {{#crossLink "ui.chat.SDK"}}{{/crossLink}} object when the UI component has successfully loaded
* @example
*
* // Modalities API must be called first to get the modalities object which is required to render chat.
* // Render chat as an IFRAME.
* // More UIInfo examples available {{#crossLink "ui.UIInfo"}}here{{/crossLink}}
* var uiInfo = {
* type: {{#crossLink "ui.HostType"}}MsSupportSdk.ui.HostType.IFRAME{{/crossLink}},
* containerSelector: "#iframe-container"
* };
*
* // Create a {{#crossLink "ui.chat.Config"}}chat config{{/crossLink}}
* var config = {
* uiInfo: uiInfo
* modalities: window.savedModalities, // See {{#crossLink "api.modalities"}}Modalities API examples{{/crossLink}} about how to get the modalities object
* onEstablished: function() {
* console.log("Chat established");
* },
* onQueued: function (e) {
* console.log("Chat queued.");
* },
* onQueueUpdated: function (e) {
* console.log("Chat queue position updated.");
* },
* onMessage: function (e) {
* console.log("Chat message received.");
* },
* onClosed: function () {
* console.log("Chat closed.");
* },
* onTransferred: function() {
* console.log("Chat transferred.");
* },
* onRejoinUrl: function (e) {
* console.log("Rejoin url received.");
* },
* onAgentDataReady: function() {
* console.log("AgentDataReady received");
* }
* };
*
* // Render chat UI
* MsSupportSdk.ui.chat.render(config).then(
* function(chatSDK) {
* // See {{#crossLink "ui.chat.SDK"}}ui.chat.SDK{{/crossLink}} for details about chatSDK.
* // chatSDK.updateContext({ foo: "bar" }); // Update context of the current chat session
* // chatSDK.sendMessage("Test message"); // Send a message to agent
* },
* function(err) {
* console.log(err.message);
* });
*/
export function render(config: Config): JQueryPromise<any> {
return ui.renderComponent(Component, config, CHAT_COMPONENT);
}
export class Component extends UIComponent {
private chatSDK: SDK;
private url: string;
constructor(config: Config) {
if (!config || (!config.modalities && !config.rejoinUrl)) {
throw new Error("Chat must be passed an object with available modalities from the API or a rejoin url.");
}
super(config, LOAD_TIMEOUT_MS, REPORT_HEIGHT_CHANGES);
}
public getComponentUrl(): string {
return (<Config>this.config).rejoinUrl || this.url || (this.url = getChatUrl(<Config>this.config));
}
public getComponentSdk(): SDK {
if (!this.chatSDK) {
this.chatSDK = {
sendMessage: (message: any) => sendChatMessage(this.proxy, message),
updateContext: () => updateChatContext()
};
}
return this.chatSDK;
}
public getXframeProxyUrl(): string {
return `${utils.getOriginFromUrl(this.getComponentUrl())}/xframeproxy/`;
}
protected getEventListeners(): Map<EventListener> {
return UIComponent.getEventListeners(this.config, CHAT_EVENT_PREFIX);
}
}
function getChatUrl(config: Config): string {
let modality = <api.modalities.ChatModality>utils.getModalityByType(config.modalities, api.modalities.Modality.CHAT);
if (!modality) {
throw new Error("Chat is not supported for this product/issue/langugage/country.");
}
let link = modality.link;
let values: any = {};
if (config.surveyType && config.surveyType === <any>SurveyType.NONE) {
values["surveyType"] = "NONE";
}
if (config.authInfo && config.authInfo.type === <any>AuthType.AAD) {
values["useAAD"] = true;
}
if (config.authInfo && config.authInfo.type === <any>AuthType.DELEGATED) {
values["authType"] = "DELEGATED";
}
if (config.context && utils.isArray(config.context)) {
values["context"] = utils.stringify(config.context);
}
// allow overwriting the subject to connect to a specific agent pool.
// We don't want to expose this to the public therefore it's not defined on the Config interface
if ((<any>config).subject) {
values["subject"] = (<any>config).subject;
}
return utils.appendParams(link, values, true);
}
function sendChatMessage(proxy: proxy.SdkClientProxy, message: any): JQueryPromise<any> {
proxy.dispatchEvent(CHAT_MESSAGE_EVENT_NAME, message);
return jQuery.Deferred().resolve();
}
function updateChatContext(): JQueryPromise<any> {
return jQuery.Deferred().reject("Not implemented");
}
}