From 3b3e3ff4f8a3afd1677be4da94b4382277ffaf8e Mon Sep 17 00:00:00 2001 From: xTEddie Date: Fri, 19 Mar 2021 09:46:27 -0700 Subject: [PATCH] Expose Init Context (#14) * Expose init context from OCSDK * Add ability to override initContext completely * Add tests * Fix eslint * Update README.md * Update CHANGELOG.md --- CHANGELOG.md | 1 + README.md | 24 +++++-- __tests__/OmnichannelChatSDK.spec.ts | 95 ++++++++++++++++++++++++++++ src/OmnichannelChatSDK.ts | 25 ++++++++ src/core/IStartChatOptionalParams.ts | 11 +++- 5 files changed, 149 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11768f9..63be984 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. - React Native sample app using Omnichannel Chat SDK with [react-native-gifted-chat](https://github.com/FaridSafi/react-native-gifted-chat) - Escalation to Voice & View support (Web Only) - React sample app using Omnichannel Chat SDK with [BotFramework-WebChat](https://github.com/microsoft/BotFramework-WebChat) +- Expose `sessiontInit`'s `initContext` on `startChat`'s optional paramaters ### Changed - Uptake [@microsoft/ocsdk@0.1.1](https://www.npmjs.com/package/@microsoft/ocsdk/v/0.1.1) diff --git a/README.md b/README.md index 4569075..c05c196 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,20 @@ Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel Services. +## Table of Contents +- [API Reference](#api-reference) +- [API Examples](#api-examples) +- [Sample Apps](samples/) +- [Common Scenarios](#common-scenarios) +- [Feature Comparisons](#feature-comparisons) + ## Installation ``` npm install @microsoft/omnichannel-chat-sdk --save ``` -## API - -### High Level Overview +## API Reference | Method | Description | Notes | | ------ | ----------- | ----- | @@ -38,6 +43,8 @@ Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel | OmnichannelChatSDK.createChatAdapter() | Get IC3Adapter | **Web only** | | OmnichannelChatSDK.getVoiceVideoCalling() | Get VoiceVideoCall SDK for Escalation to Voice & Video| **Web only** | +## API examples + ### Import ```ts import OmnichannelChatSDK from '@microsoft/omnichannel-chat-sdk'; @@ -95,9 +102,16 @@ Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel ### Start Chat ```ts + const customContext = { + 'contextKey1': {'value': 'contextValue1', 'isDisplayable': true}, + 'contextKey2': {'value': 12.34, 'isDisplayable': false}, + 'contextKey3': {'value': true} + }; + const optionalParams = { preChatResponse: '', // PreChatSurvey response - liveChatContext: {} // EXISTING chat context data + liveChatContext: {}, // EXISTING chat context data + customContext // Custom Context }; await chatSDK.startChat(optionalParams); ``` @@ -197,7 +211,7 @@ Headless Chat SDK to build your own chat widget against Dynamics 365 Omnichannel await chatSDK.emailLiveChatTranscript(body); ``` -## Samples +## Common Scenarios ### PreChatSurvey diff --git a/__tests__/OmnichannelChatSDK.spec.ts b/__tests__/OmnichannelChatSDK.spec.ts index 1d30245..03ae5d6 100644 --- a/__tests__/OmnichannelChatSDK.spec.ts +++ b/__tests__/OmnichannelChatSDK.spec.ts @@ -305,6 +305,101 @@ describe('Omnichannel Chat SDK', () => { expect(chatSDK.OCClient.sessionInit.mock.calls[0][1]).toMatchObject(sessionInitOptionalParams); }); + it('ChatSDK.startChat() with customContext, browser, os, locale, device defined in sessionInitOptionalParams should pass it to OCClient.sessionInit() call\'s optional parameters', async() => { + const chatSDK = new OmnichannelChatSDK(omnichannelConfig); + chatSDK.getChatConfig = jest.fn(); + + await chatSDK.initialize(); + + chatSDK.IC3Client = { + initialize: jest.fn(), + joinConversation: jest.fn() + } + + const optionaParams = { + preChatResponse: 'preChatResponse', + customContext: {}, + browser: 'browser', + os: 'os', + locale: 'locale', + device: 'device' + } + + jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({ + ChatId: '', + Token: '', + RegionGtms: '{}' + })); + + jest.spyOn(chatSDK.OCClient, 'sessionInit').mockResolvedValue(Promise.resolve()); + + await chatSDK.startChat(optionaParams); + + const sessionInitOptionalParams = { + initContext: { + preChatResponse: optionaParams.preChatResponse, + browser: optionaParams.browser, + os: optionaParams.os, + locale: optionaParams.locale, + device: optionaParams.device + } + } + + expect(chatSDK.OCClient.sessionInit.mock.calls[0][1]).toMatchObject(sessionInitOptionalParams); + }); + + it('ChatSDK.startChat() with initContext defined should override IStartChatOptionalParams', async() => { + const chatSDK = new OmnichannelChatSDK(omnichannelConfig); + chatSDK.getChatConfig = jest.fn(); + + await chatSDK.initialize(); + + chatSDK.IC3Client = { + initialize: jest.fn(), + joinConversation: jest.fn() + } + + const optionaParams = { + preChatResponse: 'preChatResponse', + customContext: {}, + browser: 'browser', + os: 'os', + locale: 'locale', + device: 'device', + initContext: { + preChatResponse: 'override', + customContext: 'override', + browser: 'override', + os: 'override', + locale: 'override', + device: 'override' + } + } + + jest.spyOn(chatSDK.OCClient, 'getChatToken').mockResolvedValue(Promise.resolve({ + ChatId: '', + Token: '', + RegionGtms: '{}' + })); + + jest.spyOn(chatSDK.OCClient, 'sessionInit').mockResolvedValue(Promise.resolve()); + + await chatSDK.startChat(optionaParams); + + const sessionInitOptionalParams = { + initContext: { + preChatResponse: optionaParams.initContext.preChatResponse, + customContext: optionaParams.initContext.customContext, + browser: optionaParams.initContext.browser, + os: optionaParams.initContext.os, + locale: optionaParams.initContext.locale, + device: optionaParams.initContext.device + } + } + + expect(chatSDK.OCClient.sessionInit.mock.calls[0][1]).toMatchObject(sessionInitOptionalParams); + }); + it('ChatSDK.startChat() with authenticatedUserToken should pass it to OCClient.sessionInit() call\'s optional parameters', async() => { const chatSDKConfig = { getAuthToken: async () => { diff --git a/src/OmnichannelChatSDK.ts b/src/OmnichannelChatSDK.ts index 5bddc59..f1eaf07 100644 --- a/src/OmnichannelChatSDK.ts +++ b/src/OmnichannelChatSDK.ts @@ -104,10 +104,35 @@ class OmnichannelChatSDK { initContext: {} as InitContext }; + if (optionalParams.customContext) { + (sessionInitOptionalParams.initContext! as any).customContextData = optionalParams.customContext; // eslint-disable-line @typescript-eslint/no-explicit-any + } + + if (optionalParams.browser) { + sessionInitOptionalParams.initContext!.browser = optionalParams.browser; + } + + if (optionalParams.os) { + sessionInitOptionalParams.initContext!.os = optionalParams.os; + } + + if (optionalParams.locale) { + sessionInitOptionalParams.initContext!.locale = optionalParams.locale; + } + + if (optionalParams.device) { + sessionInitOptionalParams.initContext!.device = optionalParams.device; + } + if (optionalParams.preChatResponse) { sessionInitOptionalParams.initContext!.preChatResponse = optionalParams.preChatResponse; } + // Override initContext completely + if (optionalParams.initContext) { + sessionInitOptionalParams.initContext = optionalParams.initContext; + } + if (this.authenticatedUserToken) { sessionInitOptionalParams.authenticatedUserToken = this.authenticatedUserToken; } diff --git a/src/core/IStartChatOptionalParams.ts b/src/core/IStartChatOptionalParams.ts index 5eaeafa..922d78a 100644 --- a/src/core/IStartChatOptionalParams.ts +++ b/src/core/IStartChatOptionalParams.ts @@ -1,6 +1,13 @@ +import InitContext from "@microsoft/ocsdk/lib/Model/InitContext"; import ILiveChatContext from "./ILiveChatContext"; export default interface IStartChatOptionalParams { - liveChatContext?: ILiveChatContext - preChatResponse?: object + liveChatContext?: ILiveChatContext; + preChatResponse?: object; + customContext?: object; + browser?: string; + os?: string; + locale?: string; + device?: string; + initContext?: InitContext; } \ No newline at end of file