From 99d6d0fa8ce3cdd95732ef5cc749375d1d8766c3 Mon Sep 17 00:00:00 2001 From: MartinSchoeler Date: Mon, 1 Jul 2024 14:21:48 -0300 Subject: [PATCH 1/4] feat(Livechat): new `transferChat` Livechat API endpoint --- .../omnichannel-livechat-api.spec.ts | 55 +++++++++++++++++++ packages/livechat/src/lib/hooks.ts | 21 +++++++ packages/livechat/src/widget.ts | 5 ++ 3 files changed, 81 insertions(+) diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts index 278df11f16cb..3fc71b4e0090 100644 --- a/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-livechat-api.spec.ts @@ -40,6 +40,7 @@ declare const window: Window & { setParentUrl: (url: string) => void; setTheme: (theme: { color?: string; fontColor?: string; iconColor?: string; title?: string; offlineTitle?: string }) => void; setLanguage: (language: string) => void; + transferChat: (department: string) => void; onChatMaximized: (callback: () => void) => void; onChatMinimized: (callback: () => void) => void; onChatStarted: (callback: () => void) => void; @@ -406,6 +407,60 @@ test.describe('OC - Livechat API', () => { }); }); + test.describe('OC - Livechat API - transferChat', () => { + let poAuxContext2: { page: Page; poHomeOmnichannel: HomeOmnichannel }; + + test.beforeEach(async ({ browser }) => { + const { page: pageCtx2 } = await createAuxContext(browser, Users.user2); + poAuxContext2 = { page: pageCtx2, poHomeOmnichannel: new HomeOmnichannel(pageCtx2) }; + }); + + test.afterEach(async () => { + await poAuxContext2.page.close(); + }); + + test('transferChat - Called during ongoing conversation', async () => { + const [departmentA, departmentB] = departments.map(({ data }) => data); + const registerGuestVisitor = { + name: faker.person.firstName(), + email: faker.internet.email(), + token: faker.string.uuid(), + department: departmentA._id, + }; + + // Start Chat + await poLiveChat.page.evaluate(() => window.RocketChat.livechat.maximizeWidget()); + await expect(page.frameLocator('#rocketchat-iframe').getByText('Start Chat')).toBeVisible(); + + await poLiveChat.page.evaluate( + (registerGuestVisitor) => window.RocketChat.livechat.registerGuest(registerGuestVisitor), + registerGuestVisitor, + ); + + await expect(page.frameLocator('#rocketchat-iframe').getByText('Start Chat')).not.toBeVisible(); + + await poLiveChat.onlineAgentMessage.type('this_a_test_message_from_visitor'); + await poLiveChat.btnSendMessageToOnlineAgent.click(); + + await test.step('Expect registered guest to be in dep1', async () => { + await poAuxContext.poHomeOmnichannel.sidenav.openChat(registerGuestVisitor.name); + await expect(poAuxContext.poHomeOmnichannel.content.channelHeader).toContainText(registerGuestVisitor.name); + }); + + const depId = departmentB._id; + + await test.step('Expect chat to be transferred', async () => { + await poLiveChat.page.evaluate((depId) => window.RocketChat.livechat.transferChat(depId), depId); + + await poAuxContext2.page.locator('role=navigation >> role=button[name=Search]').click(); + await poAuxContext2.page.locator('role=search >> role=searchbox').fill(registerGuestVisitor.name); + await expect( + poAuxContext2.page.locator(`role=search >> role=listbox >> role=link >> text="${registerGuestVisitor.name}"`), + ).toBeVisible(); + }); + }); + }); + test('OC - Livechat API - registerGuest', async ({ browser }) => { const registerGuestVisitor = { name: faker.person.firstName(), diff --git a/packages/livechat/src/lib/hooks.ts b/packages/livechat/src/lib/hooks.ts index 480253a49b1e..e1a980fe65e3 100644 --- a/packages/livechat/src/lib/hooks.ts +++ b/packages/livechat/src/lib/hooks.ts @@ -247,6 +247,27 @@ const api = { }); }, + transferChat: async (department: string) => { + const { + config: { departments = [] }, + room, + } = store.state; + + const dep = departments.find((dep) => dep._id === department || dep.name === department)?._id || ''; + + if (!dep) { + throw new Error( + 'The selected department is invalid. Check departments configuration to ensure the department exists, is enabled and has at least 1 agent', + ); + } + if (!room) { + throw new Error("Conversation has not been started yet, can't transfer"); + } + + const { _id: rid } = room; + await Livechat.transferChat({ rid, department: dep }); + }, + setLanguage: async (language: StoreState['iframe']['language']) => { const { iframe } = store.state; await store.setState({ iframe: { ...iframe, language } }); diff --git a/packages/livechat/src/widget.ts b/packages/livechat/src/widget.ts index 530d5ac8be4e..47f073aaff0a 100644 --- a/packages/livechat/src/widget.ts +++ b/packages/livechat/src/widget.ts @@ -368,6 +368,10 @@ function setParentUrl(url: string) { callHook('setParentUrl', url); } +function transferChat(department: string) { + callHook('transferChat', department); +} + function setGuestMetadata(metadata: StoreState['iframe']['guestMetadata']) { if (typeof metadata !== 'object') { throw new Error('Invalid metadata'); @@ -550,6 +554,7 @@ const livechatWidgetAPI = { setGuestMetadata, clearAllCallbacks, setHiddenSystemMessages, + transferChat, // callbacks onChatMaximized(fn: () => void) { From db2dd83699df7724c2c69a8614773c4588b75a70 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 5 Jul 2024 11:01:06 -0300 Subject: [PATCH 2/4] Create afraid-guests-jog.md --- .changeset/afraid-guests-jog.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/afraid-guests-jog.md diff --git a/.changeset/afraid-guests-jog.md b/.changeset/afraid-guests-jog.md new file mode 100644 index 000000000000..0e8cf5cffd51 --- /dev/null +++ b/.changeset/afraid-guests-jog.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": patch +"@rocket.chat/livechat": patch +--- + +Created a transferChat Livechat API endpoint for transferring chats programmatically, the endpoint has all the limitations & permissions required that transferring via UI has From 59b8fe8b0c9c53e2bf5ff96907dfe4b003e252b5 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Fri, 5 Jul 2024 13:07:48 -0300 Subject: [PATCH 3/4] Update .changeset/afraid-guests-jog.md Co-authored-by: Marcos Spessatto Defendi --- .changeset/afraid-guests-jog.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/afraid-guests-jog.md b/.changeset/afraid-guests-jog.md index 0e8cf5cffd51..f365fac4ce47 100644 --- a/.changeset/afraid-guests-jog.md +++ b/.changeset/afraid-guests-jog.md @@ -1,6 +1,6 @@ --- -"@rocket.chat/meteor": patch -"@rocket.chat/livechat": patch +"@rocket.chat/meteor": minor +"@rocket.chat/livechat": minor --- Created a transferChat Livechat API endpoint for transferring chats programmatically, the endpoint has all the limitations & permissions required that transferring via UI has From 60235d76b5c57ea0fe614697e015abd4472c3b58 Mon Sep 17 00:00:00 2001 From: Martin Schoeler Date: Tue, 9 Jul 2024 10:29:27 -0300 Subject: [PATCH 4/4] Update .changeset/afraid-guests-jog.md Co-authored-by: Kevin Aleman --- .changeset/afraid-guests-jog.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/afraid-guests-jog.md b/.changeset/afraid-guests-jog.md index f365fac4ce47..420b9bb5d329 100644 --- a/.changeset/afraid-guests-jog.md +++ b/.changeset/afraid-guests-jog.md @@ -3,4 +3,4 @@ "@rocket.chat/livechat": minor --- -Created a transferChat Livechat API endpoint for transferring chats programmatically, the endpoint has all the limitations & permissions required that transferring via UI has +Created a `transferChat` Livechat API endpoint for transferring chats programmatically, the endpoint has all the limitations & permissions required that transferring via UI has