From 4e23bc93d12fd7889c80c2bec7a7f724a8c0adb9 Mon Sep 17 00:00:00 2001 From: Ryan Pope Date: Wed, 2 Oct 2024 14:40:22 -0400 Subject: [PATCH] chat-core-zendesk: add support for session reinitialization (#53) Adds support for restoring a Zendesk agent conversation using the conversation ID. Requires reinitialization of the Zendesk client, which can only be triggered on the first message sent after the new page is loaded. This leads to a slight bit of extra lag on that first message, but otherwise everything seems to work as if the page was never reloaded. TEST=manual Used this locally with upcoming chat-headless change to support this new method, saw expected results across page loads and within the Zendesk platform. --- .../chat-core-aws-connect/THIRD-PARTY-NOTICES | 4 +-- ...hat-core-aws-connect.chatcoreawsconnect.md | 1 + ....chatcoreawsconnect.reinitializesession.md | 28 +++++++++++++++++++ .../etc/chat-core-aws-connect.api.md | 1 + .../src/infra/ChatCoreAwsConnectImpl.ts | 6 ++++ .../src/models/ChatCoreAwsConnect.ts | 10 +++++++ ...core-zendesk.chatcorezendesk.getsession.md | 4 +-- .../chat-core-zendesk.chatcorezendesk.init.md | 4 +-- .../docs/chat-core-zendesk.chatcorezendesk.md | 1 + ...esk.chatcorezendesk.reinitializesession.md | 24 ++++++++++++++++ ...endesksessioncredentials.conversationid.md | 13 +++++++++ ...ndesk.chatcorezendesksessioncredentials.md | 20 +++++++++++++ .../docs/chat-core-zendesk.md | 1 + .../etc/chat-core-zendesk.api.md | 10 +++++-- .../src/infra/ChatCoreZendeskImpl.ts | 28 ++++++++++++++++--- .../src/models/ChatCoreZendesk.ts | 12 ++++++-- .../ChatCoreZendeskSessionCredentials.ts | 12 ++++++++ .../chat-core-zendesk/src/models/index.ts | 1 + .../tests/ChatCoreZendesk.test.ts | 5 ++-- 19 files changed, 169 insertions(+), 16 deletions(-) create mode 100644 packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md create mode 100644 packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.reinitializesession.md create mode 100644 packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md create mode 100644 packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.md create mode 100644 packages/chat-core-zendesk/src/models/ChatCoreZendeskSessionCredentials.ts diff --git a/packages/chat-core-aws-connect/THIRD-PARTY-NOTICES b/packages/chat-core-aws-connect/THIRD-PARTY-NOTICES index 30fcf88..8e2741a 100644 --- a/packages/chat-core-aws-connect/THIRD-PARTY-NOTICES +++ b/packages/chat-core-aws-connect/THIRD-PARTY-NOTICES @@ -195,7 +195,7 @@ The following NPM packages may be included in this product: - @types/istanbul-lib-report@3.0.3 - @types/istanbul-reports@3.0.4 - @types/jsdom@20.0.1 - - @types/node@22.5.5 + - @types/node@22.7.4 - @types/stack-utils@2.0.3 - @types/tough-cookie@4.0.5 - @types/yargs-parser@21.0.3 @@ -1863,7 +1863,7 @@ SOFTWARE. The following NPM package may be included in this product: - - nwsapi@2.2.12 + - nwsapi@2.2.13 This package contains the following license and notice below: diff --git a/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.md b/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.md index 3858a0b..4bcb316 100644 --- a/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.md +++ b/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.md @@ -21,5 +21,6 @@ export interface ChatCoreAwsConnect | [init(messageResponse)](./chat-core-aws-connect.chatcoreawsconnect.init.md) | Initialize the Amazon Connect chat session using the credentials from the Chat API. | | [on(eventName, cb)](./chat-core-aws-connect.chatcoreawsconnect.on.md) | Register a callback for an event triggered within the Amazon Connect chat session. Supported events are: - message: A new message has been received. - typing: The agent is typing. - close: The chat session has been closed. | | [processMessage(request)](./chat-core-aws-connect.chatcoreawsconnect.processmessage.md) | Process a message sent by the user. | +| [reinitializeSession(\_)](./chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md) | Reinitialize the session using existing session data. | | [resetSession()](./chat-core-aws-connect.chatcoreawsconnect.resetsession.md) | Resets the [ChatCoreAwsConnect](./chat-core-aws-connect.chatcoreawsconnect.md) instance, clearing the underlying Amazon Connect session. | diff --git a/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md b/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md new file mode 100644 index 0000000..906f3e5 --- /dev/null +++ b/packages/chat-core-aws-connect/docs/chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md @@ -0,0 +1,28 @@ + + +[Home](./index.md) > [@yext/chat-core-aws-connect](./chat-core-aws-connect.md) > [ChatCoreAwsConnect](./chat-core-aws-connect.chatcoreawsconnect.md) > [reinitializeSession](./chat-core-aws-connect.chatcoreawsconnect.reinitializesession.md) + +## ChatCoreAwsConnect.reinitializeSession() method + +Reinitialize the session using existing session data. + +**Signature:** + +```typescript +reinitializeSession(_: unknown): Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| \_ | unknown | | + +**Returns:** + +Promise<void> + +## Remarks + +This is currently not supported for Amazon Connect. + diff --git a/packages/chat-core-aws-connect/etc/chat-core-aws-connect.api.md b/packages/chat-core-aws-connect/etc/chat-core-aws-connect.api.md index e03b3f8..863fe0e 100644 --- a/packages/chat-core-aws-connect/etc/chat-core-aws-connect.api.md +++ b/packages/chat-core-aws-connect/etc/chat-core-aws-connect.api.md @@ -27,6 +27,7 @@ export interface ChatCoreAwsConnect { init(messageResponse: MessageResponse): Promise; on(eventName: T, cb: EventCallback): void; processMessage(request: MessageRequest): Promise; + reinitializeSession(_: unknown): Promise; resetSession(): void; } diff --git a/packages/chat-core-aws-connect/src/infra/ChatCoreAwsConnectImpl.ts b/packages/chat-core-aws-connect/src/infra/ChatCoreAwsConnectImpl.ts index 37cdf82..ed35b30 100644 --- a/packages/chat-core-aws-connect/src/infra/ChatCoreAwsConnectImpl.ts +++ b/packages/chat-core-aws-connect/src/infra/ChatCoreAwsConnectImpl.ts @@ -145,4 +145,10 @@ export class ChatCoreAwsConnectImpl implements ChatCoreAwsConnect { this.session.disconnectParticipant(); this.session = undefined; } + + async reinitializeSession(_: unknown): Promise { + console.warn( + "Reinitializing chat session is currently not supported for AWS Connect" + ); + } } diff --git a/packages/chat-core-aws-connect/src/models/ChatCoreAwsConnect.ts b/packages/chat-core-aws-connect/src/models/ChatCoreAwsConnect.ts index 465890e..ba15a65 100644 --- a/packages/chat-core-aws-connect/src/models/ChatCoreAwsConnect.ts +++ b/packages/chat-core-aws-connect/src/models/ChatCoreAwsConnect.ts @@ -55,4 +55,14 @@ export interface ChatCoreAwsConnect { * Resets the {@link ChatCoreAwsConnect} instance, clearing the underlying Amazon Connect session. */ resetSession(): void; + + /** + * Reinitialize the session using existing session data. + * + * @param credentials - The credentials to use to reinitialize the session. + * + * @remarks + * This is currently not supported for Amazon Connect. + */ + reinitializeSession(_: unknown): Promise; } diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.getsession.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.getsession.md index 60f06ff..d145ac4 100644 --- a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.getsession.md +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.getsession.md @@ -9,9 +9,9 @@ Provide the current conversation ID for the chat session. **Signature:** ```typescript -getSession(): void; +getSession(): string | undefined; ``` **Returns:** -void +string \| undefined diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.init.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.init.md index 49a8f7b..d83cabd 100644 --- a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.init.md +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.init.md @@ -9,7 +9,7 @@ Initialize the Amazon Connect chat session using the credentials from the Chat A **Signature:** ```typescript -init(messageResponse: MessageResponse): Promise; +init(messageResponse: MessageResponse): Promise; ``` ## Parameters @@ -20,5 +20,5 @@ init(messageResponse: MessageResponse): Promise; **Returns:** -Promise<void> +Promise<[ChatCoreZendeskSessionCredentials](./chat-core-zendesk.chatcorezendesksessioncredentials.md)> diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.md index 5edf192..3c852f8 100644 --- a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.md +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.md @@ -21,5 +21,6 @@ export interface ChatCoreZendesk | [init(messageResponse)](./chat-core-zendesk.chatcorezendesk.init.md) | Initialize the Amazon Connect chat session using the credentials from the Chat API. | | [on(eventName, cb)](./chat-core-zendesk.chatcorezendesk.on.md) | Register a callback for an event triggered within the Zendesk chat session. Supported events are: - message: A new message has been received. - typing: The agent is typing. - close: The chat session has been closed (e.g. agent left or closed the ticket). | | [processMessage(request)](./chat-core-zendesk.chatcorezendesk.processmessage.md) | Process a message sent by the user. | +| [reinitializeSession(credentials)](./chat-core-zendesk.chatcorezendesk.reinitializesession.md) | Reinitialize the session using existing session data. | | [resetSession()](./chat-core-zendesk.chatcorezendesk.resetsession.md) | Reset the chat session by clearing the current conversation ID. | diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.reinitializesession.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.reinitializesession.md new file mode 100644 index 0000000..eeae624 --- /dev/null +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesk.reinitializesession.md @@ -0,0 +1,24 @@ + + +[Home](./index.md) > [@yext/chat-core-zendesk](./chat-core-zendesk.md) > [ChatCoreZendesk](./chat-core-zendesk.chatcorezendesk.md) > [reinitializeSession](./chat-core-zendesk.chatcorezendesk.reinitializesession.md) + +## ChatCoreZendesk.reinitializeSession() method + +Reinitialize the session using existing session data. + +**Signature:** + +```typescript +reinitializeSession(credentials: ChatCoreZendeskSessionCredentials): Promise; +``` + +## Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| credentials | [ChatCoreZendeskSessionCredentials](./chat-core-zendesk.chatcorezendesksessioncredentials.md) | The credentials to use to reinitialize the session. | + +**Returns:** + +Promise<void> + diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md new file mode 100644 index 0000000..de8c2d5 --- /dev/null +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [@yext/chat-core-zendesk](./chat-core-zendesk.md) > [ChatCoreZendeskSessionCredentials](./chat-core-zendesk.chatcorezendesksessioncredentials.md) > [conversationId](./chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md) + +## ChatCoreZendeskSessionCredentials.conversationId property + +The conversation ID for the current chat session. + +**Signature:** + +```typescript +conversationId: string; +``` diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.md new file mode 100644 index 0000000..ecaa78d --- /dev/null +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.chatcorezendesksessioncredentials.md @@ -0,0 +1,20 @@ + + +[Home](./index.md) > [@yext/chat-core-zendesk](./chat-core-zendesk.md) > [ChatCoreZendeskSessionCredentials](./chat-core-zendesk.chatcorezendesksessioncredentials.md) + +## ChatCoreZendeskSessionCredentials interface + +Credentials for the Zendesk session created by the [ChatCoreZendesk](./chat-core-zendesk.chatcorezendesk.md). Used for reinitializing the session across page reloads. + +**Signature:** + +```typescript +export interface ChatCoreZendeskSessionCredentials +``` + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [conversationId](./chat-core-zendesk.chatcorezendesksessioncredentials.conversationid.md) | | string | The conversation ID for the current chat session. | + diff --git a/packages/chat-core-zendesk/docs/chat-core-zendesk.md b/packages/chat-core-zendesk/docs/chat-core-zendesk.md index 9787d76..41cf1aa 100644 --- a/packages/chat-core-zendesk/docs/chat-core-zendesk.md +++ b/packages/chat-core-zendesk/docs/chat-core-zendesk.md @@ -16,4 +16,5 @@ | --- | --- | | [ChatCoreZendesk](./chat-core-zendesk.chatcorezendesk.md) | Provides methods for interacting with Chat's Zendesk integration. | | [ChatCoreZendeskConfig](./chat-core-zendesk.chatcorezendeskconfig.md) | Configuration for this instance of the [ChatCoreZendesk](./chat-core-zendesk.chatcorezendesk.md). | +| [ChatCoreZendeskSessionCredentials](./chat-core-zendesk.chatcorezendesksessioncredentials.md) | Credentials for the Zendesk session created by the [ChatCoreZendesk](./chat-core-zendesk.chatcorezendesk.md). Used for reinitializing the session across page reloads. | diff --git a/packages/chat-core-zendesk/etc/chat-core-zendesk.api.md b/packages/chat-core-zendesk/etc/chat-core-zendesk.api.md index c476ef7..128cae0 100644 --- a/packages/chat-core-zendesk/etc/chat-core-zendesk.api.md +++ b/packages/chat-core-zendesk/etc/chat-core-zendesk.api.md @@ -12,12 +12,13 @@ import { MessageResponse } from '@yext/chat-core'; // @public export interface ChatCoreZendesk { emit(eventName: T, data: EventMap[T]): void; - getSession(): void; - init(messageResponse: MessageResponse): Promise; + getSession(): string | undefined; + init(messageResponse: MessageResponse): Promise; // Warning: (ae-forgotten-export) The symbol "EventMap" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "EventCallback" needs to be exported by the entry point index.d.ts on(eventName: T, cb: EventCallback): void; processMessage(request: MessageRequest): Promise; + reinitializeSession(credentials: ChatCoreZendeskSessionCredentials): Promise; resetSession(): void; } @@ -27,6 +28,11 @@ export interface ChatCoreZendeskConfig { ticketTags?: string[]; } +// @public +export interface ChatCoreZendeskSessionCredentials { + conversationId: string; +} + // Warning: (ae-forgotten-export) The symbol "ChatCoreZendeskImpl" needs to be exported by the entry point index.d.ts // // @public diff --git a/packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts b/packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts index 9a52750..e4f1a5d 100644 --- a/packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts +++ b/packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { MessageRequest, MessageResponse } from "@yext/chat-core"; +import { ChatCoreZendesk } from "../models"; /** * Issue 1: Smooch Version @@ -32,6 +33,7 @@ const Smooch = (SmoochLib.default || SmoochLib) as typeof SmoochLib; import { ChatCoreZendeskConfig } from "../models/ChatCoreZendeskConfig"; import { EventCallback, EventMap } from "../models/EventCallback"; +import { ChatCoreZendeskSessionCredentials } from "../models/ChatCoreZendeskSessionCredentials"; const MetadataChatSDKKey = "YEXT_CHAT_SDK"; @@ -43,7 +45,7 @@ const MetadataChatSDKKey = "YEXT_CHAT_SDK"; * * @internal */ -export class ChatCoreZendeskImpl { +export class ChatCoreZendeskImpl implements ChatCoreZendesk { private eventListeners: { [T in keyof EventMap]?: EventCallback[] } = {}; private conversationId: string | undefined; private integrationId: string; @@ -63,7 +65,12 @@ export class ChatCoreZendeskImpl { * mode on the first invocation. Subsequent calls to this method will create a * new conversation session. */ - async init(messageRsp: MessageResponse): Promise { + async init(messageRsp: MessageResponse): Promise { + await this.initializeZendeskSdk(); + return this.createZendeskConversation(messageRsp); + } + + private async initializeZendeskSdk(): Promise { const divId = "yext-chat-core-zendesk-container"; if (!window.document.getElementById(divId)) { const div = window.document.createElement("div"); @@ -83,7 +90,6 @@ export class ChatCoreZendeskImpl { } this.setupEventListeners(); } - await this.setupSession(messageRsp); } /** @@ -91,7 +97,9 @@ export class ChatCoreZendeskImpl { * On ticket creation, the metadata is set to include the tag "yext-chat" * with the conversation summary as the initial message. */ - private async setupSession(messageRsp: MessageResponse) { + private async createZendeskConversation( + messageRsp: MessageResponse + ): Promise { const ticketFields: Record = {}; try { if (messageRsp.integrationDetails?.zendeskHandoff?.ticketFields) { @@ -133,6 +141,10 @@ export class ChatCoreZendeskImpl { }`, this.conversationId ); + + return { + conversationId: convo.id, + }; } private setupEventListeners() { @@ -208,6 +220,14 @@ export class ChatCoreZendeskImpl { } resetSession(): void { + // @ts-ignore - off() is not in the Smooch types, but does exist + Smooch.off(); this.conversationId = undefined; } + + async reinitializeSession(credentials: ChatCoreZendeskSessionCredentials): Promise { + this.conversationId = credentials.conversationId; + await this.initializeZendeskSdk(); + await Smooch.loadConversation(credentials.conversationId); + } } diff --git a/packages/chat-core-zendesk/src/models/ChatCoreZendesk.ts b/packages/chat-core-zendesk/src/models/ChatCoreZendesk.ts index e02cb51..8644f9a 100644 --- a/packages/chat-core-zendesk/src/models/ChatCoreZendesk.ts +++ b/packages/chat-core-zendesk/src/models/ChatCoreZendesk.ts @@ -1,5 +1,6 @@ import { MessageRequest, MessageResponse } from "@yext/chat-core"; import { EventCallback, EventMap } from "./EventCallback"; +import { ChatCoreZendeskSessionCredentials } from "./ChatCoreZendeskSessionCredentials"; /** * Provides methods for interacting with Chat's Zendesk integration. @@ -12,7 +13,7 @@ export interface ChatCoreZendesk { * * @param messageResponse - The response returned from a successful call to the Chat API. */ - init(messageResponse: MessageResponse): Promise; + init(messageResponse: MessageResponse): Promise; /** * Register a callback for an event triggered within the Zendesk chat session. @@ -46,10 +47,17 @@ export interface ChatCoreZendesk { /** * Provide the current conversation ID for the chat session. */ - getSession(): void; + getSession(): string | undefined; /** * Reset the chat session by clearing the current conversation ID. */ resetSession(): void; + + /** + * Reinitialize the session using existing session data. + * + * @param credentials - The credentials to use to reinitialize the session. + */ + reinitializeSession(credentials: ChatCoreZendeskSessionCredentials): Promise; } diff --git a/packages/chat-core-zendesk/src/models/ChatCoreZendeskSessionCredentials.ts b/packages/chat-core-zendesk/src/models/ChatCoreZendeskSessionCredentials.ts new file mode 100644 index 0000000..c147641 --- /dev/null +++ b/packages/chat-core-zendesk/src/models/ChatCoreZendeskSessionCredentials.ts @@ -0,0 +1,12 @@ +/** + * Credentials for the Zendesk session created by the {@link ChatCoreZendesk}. + * Used for reinitializing the session across page reloads. + * + * @public + */ +export interface ChatCoreZendeskSessionCredentials { + /** + * The conversation ID for the current chat session. + */ + conversationId: string; +} \ No newline at end of file diff --git a/packages/chat-core-zendesk/src/models/index.ts b/packages/chat-core-zendesk/src/models/index.ts index 0767bba..6ac772a 100644 --- a/packages/chat-core-zendesk/src/models/index.ts +++ b/packages/chat-core-zendesk/src/models/index.ts @@ -1,2 +1,3 @@ export { ChatCoreZendeskConfig } from "./ChatCoreZendeskConfig"; export { ChatCoreZendesk } from "./ChatCoreZendesk"; +export { ChatCoreZendeskSessionCredentials } from "./ChatCoreZendeskSessionCredentials"; diff --git a/packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts b/packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts index 71e2df9..02faa7a 100644 --- a/packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts +++ b/packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts @@ -33,6 +33,7 @@ jest.mock("smooch", () => ({ on: jest.fn(), startTyping: jest.fn(), stopTyping: jest.fn(), + off: jest.fn(), })); beforeEach(() => { @@ -58,11 +59,11 @@ describe("chat session initialization", () => { ); }); - it("returns no error when successfully connecting to chat session", async () => { + it("returns convo id and no error when successfully connecting to chat session", async () => { const chatCoreZendesk = provideChatCoreZendesk(mockConfig); await expect( chatCoreZendesk.init(mockMessageResponse()) - ).resolves.toBeUndefined(); + ).resolves.toStrictEqual({conversationId: "mock-conversation-id"}); }); it("avoid rendering smooch web widget on subsequent initialization", async () => {