Skip to content

Commit

Permalink
chat-core-zendesk: add support for session reinitialization
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
popestr committed Sep 24, 2024
1 parent 288c1b1 commit 8c16902
Show file tree
Hide file tree
Showing 10 changed files with 46 additions and 6 deletions.
2 changes: 1 addition & 1 deletion packages/chat-core-aws-connect/THIRD-PARTY-NOTICES
Original file line number Diff line number Diff line change
Expand Up @@ -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.6.1
- @types/stack-utils@2.0.3
- @types/tough-cookie@4.0.5
- @types/yargs-parser@21.0.3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: - <code>message</code>: A new message has been received. - <code>typing</code>: The agent is typing. - <code>close</code>: 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. |

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface ChatCoreAwsConnect {
init(messageResponse: MessageResponse): Promise<void>;
on<T extends keyof EventMap>(eventName: T, cb: EventCallback<T>): void;
processMessage(request: MessageRequest): Promise<void>;
reinitializeSession(_: unknown): Promise<void>;
resetSession(): void;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,10 @@ export class ChatCoreAwsConnectImpl implements ChatCoreAwsConnect {
this.session.disconnectParticipant();
this.session = undefined;
}

async reinitializeSession(_: unknown): Promise<void> {
console.warn(
"Reinitializing chat session is currently not supported for AWS Connect"
);
}
}
10 changes: 10 additions & 0 deletions packages/chat-core-aws-connect/src/models/ChatCoreAwsConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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: - <code>message</code>: A new message has been received. - <code>typing</code>: The agent is typing. - <code>close</code>: 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. |

1 change: 1 addition & 0 deletions packages/chat-core-zendesk/etc/chat-core-zendesk.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface ChatCoreZendesk {
// Warning: (ae-forgotten-export) The symbol "EventCallback" needs to be exported by the entry point index.d.ts
on<T extends keyof EventMap>(eventName: T, cb: EventCallback<T>): void;
processMessage(request: MessageRequest): Promise<void>;
reinitializeSession(credentials: string): Promise<void>;
resetSession(): void;
}

Expand Down
19 changes: 16 additions & 3 deletions packages/chat-core-zendesk/src/infra/ChatCoreZendeskImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,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<void> {
async init(messageRsp: MessageResponse): Promise<string> {
await this.initializeZendeskSdk();
return await this.createZendeskConversation(messageRsp);
}

private async initializeZendeskSdk(): Promise<void> {
const divId = "yext-chat-core-zendesk-container";
if (!window.document.getElementById(divId)) {
const div = window.document.createElement("div");
Expand All @@ -83,15 +88,16 @@ export class ChatCoreZendeskImpl {
}
this.setupEventListeners();
}
await this.setupSession(messageRsp);
}

/**
* Set up a new session by creating a new conversation with the Smooch SDK.
* 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<string> {
const ticketFields: Record<string, unknown> = {};
try {
if (messageRsp.integrationDetails?.zendeskHandoff?.ticketFields) {
Expand Down Expand Up @@ -133,6 +139,7 @@ export class ChatCoreZendeskImpl {
}`,
this.conversationId
);
return this.conversationId;
}

private setupEventListeners() {
Expand Down Expand Up @@ -210,4 +217,10 @@ export class ChatCoreZendeskImpl {
resetSession(): void {
this.conversationId = undefined;
}

async reinitializeSession(conversationId: string): Promise<void> {
this.conversationId = conversationId;
await this.initializeZendeskSdk();
await Smooch.loadConversation(conversationId);
}
}
7 changes: 7 additions & 0 deletions packages/chat-core-zendesk/src/models/ChatCoreZendesk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,11 @@ export interface ChatCoreZendesk {
* 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: string): Promise<void>;
}
4 changes: 2 additions & 2 deletions packages/chat-core-zendesk/tests/ChatCoreZendesk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,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.toBe("mock-conversation-id");
});

it("avoid rendering smooch web widget on subsequent initialization", async () => {
Expand Down

0 comments on commit 8c16902

Please sign in to comment.