From a4f2ecb9a69767aedf1fdd8409f3fdec9ea7a106 Mon Sep 17 00:00:00 2001 From: Aleksander Nicacio da Silva Date: Thu, 27 Mar 2025 03:58:00 -0300 Subject: [PATCH] fix: Chat filtering breaks when "From" and "To" have the same date (#35616) --- .changeset/tidy-cups-smoke.md | 5 ++ .../chats/ChatsTable/useChatsQuery.ts | 6 +- ...annel-contact-center-chats-filters.spec.ts | 77 +++++++++++++++++++ ...mnichannel-contact-center-chats-filters.ts | 21 +++++ .../omnichannel-contact-center-chats.ts | 26 +++++++ 5 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 .changeset/tidy-cups-smoke.md create mode 100644 apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts create mode 100644 apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats-filters.ts create mode 100644 apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats.ts diff --git a/.changeset/tidy-cups-smoke.md b/.changeset/tidy-cups-smoke.md new file mode 100644 index 00000000000..d7220b0390a --- /dev/null +++ b/.changeset/tidy-cups-smoke.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Fixes Omnichannel Contact Center's chats filter not working when "From" and "To" fields have the same date diff --git a/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/useChatsQuery.ts b/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/useChatsQuery.ts index e1cfab9d366..04e2530578b 100644 --- a/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/useChatsQuery.ts +++ b/apps/meteor/client/views/omnichannel/directory/chats/ChatsTable/useChatsQuery.ts @@ -1,5 +1,5 @@ import { usePermission, useUserId } from '@rocket.chat/ui-contexts'; -import moment from 'moment'; +import { parse, endOfDay, startOfDay } from 'date-fns'; import { useCallback } from 'react'; import type { ChatsFiltersQuery } from '../../contexts/ChatsContext'; @@ -47,10 +47,10 @@ export const useChatsQuery = () => { if (from || to) { query.createdAt = JSON.stringify({ ...(from && { - start: moment(new Date(from)).set({ hour: 0, minutes: 0, seconds: 0 }).toISOString(), + start: startOfDay(parse(from, 'yyyy-MM-dd', new Date())).toISOString(), }), ...(to && { - end: moment(new Date(to)).set({ hour: 23, minutes: 59, seconds: 59 }).toISOString(), + end: endOfDay(parse(to, 'yyyy-MM-dd', new Date())).toISOString(), }), }); } diff --git a/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts new file mode 100644 index 00000000000..9a62b6b376f --- /dev/null +++ b/apps/meteor/tests/e2e/omnichannel/omnichannel-contact-center-chats-filters.spec.ts @@ -0,0 +1,77 @@ +import { faker } from '@faker-js/faker/locale/af_ZA'; + +import { Users } from '../fixtures/userStates'; +import { OmnichannelChats } from '../page-objects/omnichannel-contact-center-chats'; +import { setSettingValueById } from '../utils'; +import { createAgent, makeAgentAvailable } from '../utils/omnichannel/agents'; +import { createConversation } from '../utils/omnichannel/rooms'; +import { test, expect } from '../utils/test'; + +test.use({ storageState: Users.user1.state }); + +test.describe('OC - Contact Center - Chats', () => { + let conversations: Awaited>[]; + let agent: Awaited>; + + let poOmniChats: OmnichannelChats; + + const uuid = faker.string.uuid(); + const visitorA = `visitorA_${uuid}`; + const visitorB = `visitorB_${uuid}`; + + test.beforeAll(async ({ api }) => { + expect((await setSettingValueById(api, 'Livechat_Routing_Method', 'Auto_Selection')).status()).toBe(200); + }); + + test.beforeAll(async ({ api }) => { + agent = await createAgent(api, 'user1'); + + expect((await makeAgentAvailable(api, agent.data._id)).status()).toBe(200); + }); + + test.beforeAll(async ({ api }) => { + conversations = await Promise.all([ + createConversation(api, { agentId: `user1`, visitorName: visitorA }), + createConversation(api, { agentId: `user1`, visitorName: visitorB }), + ]); + }); + + test.beforeEach(async ({ page }) => { + poOmniChats = new OmnichannelChats(page); + + await page.goto('/omnichannel-directory/chats'); + }); + + test.afterEach(async ({ page }) => { + await page.close(); + }); + + test.afterAll(async ({ api }) => { + await Promise.all([...conversations.map((conversation) => conversation.delete()), agent.delete()]); + expect((await setSettingValueById(api, 'Livechat_Routing_Method', 'Auto_Selection')).status()).toBe(200); + }); + + test(`OC - Contact Center - Chats - Filter from and to same date`, async ({ page }) => { + await test.step('expect conversations to be visible', async () => { + await poOmniChats.inputSearch.fill(uuid); + await expect(poOmniChats.findRowByName(visitorA)).toBeVisible(); + await expect(poOmniChats.findRowByName(visitorB)).toBeVisible(); + }); + + await test.step('expect to filter [from] and [to] today', async () => { + const [chatA] = conversations.map((c) => c.data); + const [todayString] = new Date(chatA.room.ts).toISOString().split('T'); + await poOmniChats.btnFilters.click(); + await expect(page).toHaveURL('/omnichannel-directory/chats/filters'); + await poOmniChats.filters.inputFrom.fill(todayString); + await poOmniChats.filters.inputTo.fill(todayString); + await poOmniChats.filters.btnApply.click(); + await page.waitForResponse('**/api/v1/livechat/rooms*'); + }); + + await test.step('expect conversations to be visible', async () => { + await expect(poOmniChats.findRowByName(visitorA)).toBeVisible(); + await expect(poOmniChats.findRowByName(visitorB)).toBeVisible(); + }); + }); +}); diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats-filters.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats-filters.ts new file mode 100644 index 00000000000..c39f9e26d45 --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats-filters.ts @@ -0,0 +1,21 @@ +import type { Locator, Page } from '@playwright/test'; + +export class OmnichannelChatsFilters { + protected readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + get inputFrom(): Locator { + return this.page.locator('input[name="from"]'); + } + + get inputTo(): Locator { + return this.page.locator('input[name="to"]'); + } + + get btnApply(): Locator { + return this.page.locator('role=button[name="Apply"]'); + } +} diff --git a/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats.ts b/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats.ts new file mode 100644 index 00000000000..5cf0652890d --- /dev/null +++ b/apps/meteor/tests/e2e/page-objects/omnichannel-contact-center-chats.ts @@ -0,0 +1,26 @@ +import type { Locator, Page } from '@playwright/test'; + +import { OmnichannelChatsFilters } from './omnichannel-contact-center-chats-filters'; + +export class OmnichannelChats { + private readonly page: Page; + + filters: OmnichannelChatsFilters; + + constructor(page: Page) { + this.page = page; + this.filters = new OmnichannelChatsFilters(page); + } + + get btnFilters(): Locator { + return this.page.locator('role=button[name="Filters"]'); + } + + get inputSearch(): Locator { + return this.page.locator('role=textbox[name="Search"]'); + } + + findRowByName(contactName: string) { + return this.page.locator(`td >> text="${contactName}"`); + } +}