/// <reference path="../../common/sdkConfig.ts"/>
/// <reference path="../../utils/http.ts"/>
/// <reference path="../../utils/object.ts"/>
/// <reference path="../../utils/typecheck.ts"/>
/// <reference path="modalityConfig.ts"/>
/// <reference path="callbackModality.ts"/>
/// <reference path="chatModality.ts"/>
/// <reference path="phoneModality.ts"/>
/// <reference path="scheduleCallbackModality.ts"/>
/// <reference path="modalitiesResponse.ts"/>
/// <reference path="modalityRequestContent.ts"/>
/// <reference path="renderingContext.ts"/>
/**
* @module API
* @submodule API Modalities
* @namespace api
*/
namespace internal.api.modalities {
const DEPENDENCY_NAME = "SupportChannels";
const GET_MODALITIES_DEPENDENCY_OPERATION_NAME = "Get modalities v1.0";
const GET_MODALITIES_V2_DEPENDENCY_OPERATION_NAME = "Get modalities v2.0";
const MODALITY_ENDPOINT_PATH = "/api/products/[product]/issues/[issue]/modalities/v1.0";
const GET_MODALITIES_OPERATION_NAME = "api.modalities.get";
const MODALITY_V2_ENDPOINT_PATH = "/api/v1.0/modalities";
const GET_MODALITIES_V2_OPERATION_NAME = "api.modalities.getv2";
/**
* Modalities API
* @class modalities
* @static
*/
export class API {
/**
* Gets support options configured for a product and issue in a specified lang-loc
* @method get
* @static
* @param {object} config A config object to define the types of modalities required
* @param {string} config.environment A value from {{#crossLink "api.modalities.Environment"}}{{/crossLink}} (default is api.modalities.Environment.PRODUCTION)
* @param {string} config.product The product for the set of modalities being requested
* @param {string} config.issue The issue for the set of modalities being requested
* @param {string} config.language A two-character string of the language the modalities should be in
* @param {string} config.country A two-character string representing the country the modalities should be in
* @param {string} config.accessibility One of the values from {{#crossLink "api.modalities.Accessibility"}}{{/crossLink}} (default is api.modalities.Accessibility.NONE)
* @param {string} config.mode A string that points chat at a pool of testers instead of production agents
* @param {boolean} config.preview A boolean that says whether you want to fetch modalities that are currently in preview mode
* @return {Promise | Array} A promise that resolves to an array of modality objects (defined in the {{#crossLinkModule "API Modalities"}}{{/crossLinkModule}} module)
* @example
*
* var config = {
* environment: {{#crossLink "api.modalities.Environment"}}MsSupportSdk.api.modalities.Environment.DEV{{/crossLink}} // change this to PRODUCTION in PROD
* product: "windows",
* issue: "setup",
* language: "en",
* country: "us",
* mode: "test" // test mode. DO NOT set this value in PROD
* };
*
* // call sdk.api.modalities.get() to get modalities
* MsSupportSdk.api.modalities.get(config).then(
* function(modalities){
* // save the modalities response, which will be used later by {{#crossLink "ui.chat"}}Chat{{/crossLink}}
* window.savedModalities = modalities;
* },
* function(err){
* console.log(err.message);
* });
*
*/
static get(config: ModalityConfig): JQueryPromise<Array<ModalityObject>> {
verifyModalityConfig(config);
let deferred = jQuery.Deferred();
let url = buildModalitiesUrl(config.environment, config.product, config.issue);
let queryParams: any = {};
queryParams[`${internal.SDK_QUERY_PARAM_NAME.PARTNER_ID}`] = SdkConfig.current.partnerId;
queryParams["platform"] = SdkConfig.current.platform;
queryParams["language"] = config.language;
queryParams["country"] = config.country;
config.accessibility && (queryParams["accessibility"] = config.accessibility);
config.mode && (queryParams["mode"] = config.mode);
config.preview && (queryParams["preview"] = config.preview);
// TODO: define queryParams Type
let requestOptions: HttpRequestOptions = {
operationName: GET_MODALITIES_OPERATION_NAME,
url: url,
queryParams: queryParams,
dependencyName: DEPENDENCY_NAME,
dependencyOperationName: GET_MODALITIES_DEPENDENCY_OPERATION_NAME
};
utils.httpRequest.get(requestOptions).then(
function (result) {
let modalities = parseResponseModalities(result);
deferred.resolve(modalities);
},
function (error) {
deferred.reject("Could not fetch modality information: " + utils.stringify(error));
});
return <JQueryPromise<Array<ModalityObject>>> deferred.promise();
}
/**
* Gets support options configured for a product and issue in a specified lang-loc
* @method getv2
* @static
* @param {object} config A config object to define the types of modalities required
* @param {string} config.environment A value from {{#crossLink "api.modalities.Environment"}}{{/crossLink}} (default is api.modalities.Environment.PRODUCTION)
* @param {string} config.product The product for the set of modalities being requested
* @param {string} config.issue The issue for the set of modalities being requested
* @param {string} config.language A two-character string of the language the modalities should be in
* @param {string} config.country A two-character string representing the country the modalities should be in
* @param {string} config.accessibility One of the values from {{#crossLink "api.modalities.Accessibility"}}{{/crossLink}} (default is api.modalities.Accessibility.NONE)
* @param {string} config.mode A string that points chat at a pool of testers instead of production agents
* @param {boolean} config.preview A boolean that says whether you want to fetch modalities that are currently in preview mode
* @param {object} config.enhancedRoutingContext An object that contains key/value pairs for enhanced routing input
* @return {Promise | Object} A promise that resolves to an object containing modalities and rendering context
* @example
*
* var config = {
* environment: {{#crossLink "api.modalities.Environment"}}MsSupportSdk.api.modalities.Environment.DEV{{/crossLink}} // change this to PRODUCTION in PROD
* product: "windows",
* issue: "setup",
* language: "en",
* country: "us",
* mode: "test" // test mode. DO NOT set this value in PROD
* };
*
* // call sdk.api.modalities.get() to get modalities
* MsSupportSdk.api.modalities.get(config).then(
* function(modalities){
* // save the modalities response, which will be used later by {{#crossLink "ui.chat"}}Chat{{/crossLink}}
* window.savedModalities = modalities;
* },
* function(err){
* console.log(err.message);
* });
*
*/
static getv2(config: ModalityConfig): JQueryPromise<ModalitiesResponse> {
verifyModalityConfig(config);
let deferred = jQuery.Deferred();
let url = buildModalitiesV2Url(config.environment);
let requestContent = new ModalityRequestContent(
config.product,
config.issue,
SdkConfig.current.partnerId,
SdkConfig.current.platform,
config.language,
config.country,
config.accessibility || undefined,
config.preview,
config.mode,
config.enhancedRoutingContext
);
let requestOptions: HttpRequestOptions = {
operationName: GET_MODALITIES_V2_OPERATION_NAME,
url: url,
content: requestContent,
dependencyName: DEPENDENCY_NAME,
dependencyOperationName: GET_MODALITIES_V2_DEPENDENCY_OPERATION_NAME
};
utils.httpRequest.post(requestOptions).then(
function (result) {
let modalitiesResponse = new ModalitiesResponse(
parseResponseModalities(result),
parseResponseRenderingContext(result)
);
deferred.resolve(modalitiesResponse);
},
function (error) {
deferred.reject("Could not fetch modality information: " + utils.stringify(error));
});
return <JQueryPromise<ModalitiesResponse>> deferred.promise();
}
}
function verifyModalityConfig(config: ModalityConfig): void {
if (config) {
utils.verifyString("environment", config.environment, true);
utils.verifyString("product", config.product, true);
utils.verifyString("issue", config.issue, true);
utils.verifyString("language", config.language, true);
utils.verifyString("country", config.country, true);
utils.verifyString("accessibility", config.accessibility);
utils.verifyString("mode", config.mode);
utils.verifyBoolean("preview", config.preview);
} else {
throw new Error("config is a mandatory parameter");
}
}
function buildModalitiesUrl(environment: string, product: string, issue: string): string {
let path = MODALITY_ENDPOINT_PATH.replace("[product]", product);
path = path.replace("[issue]", issue);
return "https://" + environment + path;
}
function buildModalitiesV2Url(environment: string): string {
return "https://" + environment + MODALITY_V2_ENDPOINT_PATH;
}
function parseResponseModalities(response: any): Array<ModalityObject> {
let modalities = new Array<ModalityObject>();
if (response && response.Modalities && response.Modalities.length > 0) {
for (let i = 0; i < response.Modalities.length; i++) {
// catch error inside the for loop so that we can continue parsing other modality object from the collection
try {
let modality: ModalityObject;
let modalityName = (!response.Modalities[i].Name) ? undefined : response.Modalities[i].Name.toLowerCase();
switch (modalityName) {
case Modality.CHAT:
case Modality.HELPSHIFT:
modality = new ChatModality(response.Modalities[i]);
break;
case Modality.CALLBACK:
modality = new CallbackModality(response.Modalities[i]);
break;
case Modality.SCHEDULE_CALLBACK:
modality = new ScheduleCallbackModality(response.Modalities[i]);
break;
case Modality.TOLL_FREE:
modality = new PhoneModality(response.Modalities[i]);
break;
default:
modality = new LinkModality(response.Modalities[i]);
break;
}
modalities.push(modality);
}
catch (e) {
// TODO: log telemetry here
// telemetry.captureError(`Could not parse modalities response. Error: ${e}`);
console.log(`Could not parse modalities response. Error: ${e}`);
}
}
}
return modalities;
}
function parseResponseRenderingContext(response: any): RenderingContext {
if (!response || !response.RenderingContext) {
return undefined;
}
return new RenderingContext(
response.RenderingContext.ConfirmationTextId,
response.RenderingContext.WarningTextId,
response.RenderingContext.ModalityLinkValues
);
}
}