diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png index 6cc68d740d4a..9113860dbd0f 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png index a1fcedf10f4e..f7f10e1f89a3 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png index 437b8bf8059b..603c3dbb305c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar has correct position (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png index f2ed7d38f78d..50e6c9799d2f 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png index 9e9c600ad217..15e2bc9bb657 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png index 61526b806d9f..fb5e85843073 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar sizes do not affect indentation between bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png index 35034c0b1223..ab720dd8a7fa 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png index 38b8cfdf6cfc..bfed395bc43c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png index 3abdba15ae06..79076f1ebed0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with image (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png index 91f3001c5051..2c0db88a1203 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png index 53371c9ede40..143a095a79f6 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png index 4670d4640e02..42933fd04ce3 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Avatar with two word initials (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png index 9bdbfb9cba05..6e5284f4985c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png index 9c8278d08690..602bb95f37fd 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png index 54a806a36a43..07d52fb1389e 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png index 0e719e70aa9d..a980902005c8 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png index 41729c653d14..c59f6b41f731 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png index 7abd3a0df465..0cd512f49b67 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Bubbles with long text with line breaks (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png index 369a0d087175..7fa272de690c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png index 5734caf294a4..1a2b6656e642 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png index 1da6cccce4a6..848505e7b11c 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Information row with long user name (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png index 58d914291556..35810cb82719 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png index d57bf68101c3..0ace0185d84d 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png index e1688adfc3c0..a50e0e636243 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in RTL mode (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png index 64699913edc7..d194ad2dcda1 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png index c53d0e54d04f..5ef4d8f32be4 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png index 44fe1524e7bc..76a033ad091d 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup appearance in disabled state (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png index bdb914ccb364..4375859afe37 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png index 2238ef6b33ad..cde1a2d08f59 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png index 63443e2361f4..767b36b41372 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 1 bubble (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png index a9fd09a62281..a63e03af7570 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png index 72c21cdb363d..c3450cb82793 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png index e829cad42d75..78f62ffc75f0 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 2 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png index 0de57f8f8d68..e7121a899632 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png index b21ac6274290..9f90ef26c755 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png index dfb7f88f124d..8c2a31bcbcea 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 3 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png index 20a685b46771..4b7d6547ead8 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png index ef5c15498653..979c6d320109 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png index 8f901755bebd..5dbe93970033 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagegroup with 4 bubbles (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png index 42d33b3249ed..b17fa73d8c46 100644 Binary files a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist scroll position after rendering in invisible container (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png new file mode 100644 index 000000000000..2338fe0e7789 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light)_mask.png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light)_mask.png new file mode 100644 index 000000000000..e60e68894026 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (fluent-blue-light)_mask.png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png new file mode 100644 index 000000000000..97ed47eab40c Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light)_mask.png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light)_mask.png new file mode 100644 index 000000000000..4fd3b385de01 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (generic-light)_mask.png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png new file mode 100644 index 000000000000..bd2a374b47b5 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light).png differ diff --git a/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light)_mask.png b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light)_mask.png new file mode 100644 index 000000000000..124e535c1be7 Binary files /dev/null and b/e2e/testcafe-devextreme/tests/chat/etalons/Messagelist with date headers (material-blue-light)_mask.png differ diff --git a/e2e/testcafe-devextreme/tests/chat/messageList.ts b/e2e/testcafe-devextreme/tests/chat/messageList.ts index 8859d6492f22..6f7381798c3a 100644 --- a/e2e/testcafe-devextreme/tests/chat/messageList.ts +++ b/e2e/testcafe-devextreme/tests/chat/messageList.ts @@ -104,6 +104,7 @@ test('Messagelist appearance with scrollbar', async (t) => { user: userSecond, width: 400, height: 600, + showDayHeaders: false, onMessageSend: (e) => { const { component, message } = e; @@ -150,3 +151,48 @@ test('Messagelist should scrolled to the latest messages after being rendered in }], }); }); + +test('Messagelist with date headers', async (t) => { + const { takeScreenshot, compareResults } = createScreenshotsComparer(t); + + await testScreenshot(t, takeScreenshot, 'Messagelist with date headers.png', { element: '#container' }); + + await t + .expect(compareResults.isValid()) + .ok(compareResults.errorMessages()); +}).before(async () => { + const userFirst = createUser(1, 'First'); + const userSecond = createUser(2, 'Second'); + const msInDay = 86400000; + const today = new Date().setHours(7, 22, 0, 0); + const yesterday = today - msInDay; + + const items = [{ + timestamp: new Date('05.01.2024'), + author: userFirst, + text: 'AAA', + }, { + timestamp: new Date('06.01.2024'), + author: userFirst, + text: 'BBB', + }, { + timestamp: new Date('06.01.2024'), + author: userSecond, + text: 'CCC', + }, { + timestamp: yesterday, + author: userSecond, + text: 'DDD', + }, { + timestamp: today, + author: userFirst, + text: 'EEE', + }]; + + return createWidget('dxChat', { + items, + user: userSecond, + width: 400, + height: 600, + }); +}); diff --git a/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_index.scss b/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_index.scss index 33e31e429754..674dcad5d7b3 100644 --- a/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_index.scss +++ b/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_index.scss @@ -39,3 +39,7 @@ border-radius: 999em; } +.dx-chat-messagelist-day-header { + text-align: center; +} + diff --git a/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_mixins.scss b/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_mixins.scss index 645707448c57..8588243202f0 100644 --- a/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_mixins.scss +++ b/packages/devextreme-scss/scss/widgets/base/chat/layout/chat-messagelist/_mixins.scss @@ -1,11 +1,25 @@ @use "sass:math"; -@mixin chat-messagelist($padding) { +@mixin chat-messagelist( + $padding, + $day-header-color, + $day-header-padding-bottom, + $day-header-first-padding-top, +) { .dx-chat-messagelist { .dx-scrollable-content { padding-inline: $padding; } } + + .dx-chat-messagelist-day-header { + padding-bottom: $day-header-padding-bottom; + color: $day-header-color; + + &:first-child { + padding-top: $day-header-first-padding-top; + } + } } @mixin chat-messagelist-empty( diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss index fe26d78cbaf6..60a3e33f01b7 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss @@ -14,6 +14,7 @@ $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: $base-border-color !default; $chat-information-color: null !default; +$chat-messagelist-day-header-color: null !default; $chat-messagelist-empty-icon-color: null !default; $chat-messagelist-empty-icon-background-color: null !default; $chat-messagelist-empty-message-color: $base-text-color !default; @@ -21,6 +22,7 @@ $chat-messagelist-empty-prompt-color: null !default; @if $mode == "light" { $chat-information-color: darken($base-bg, 56.08) !default; + $chat-messagelist-day-header-color: darken($base-bg, 56.08) !default; $chat-messagelist-empty-icon-color: lighten($base-icon-color, 32.16) !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 3.92) !default; $chat-messagelist-empty-prompt-color: darken($base-label-color, 5.88) !default; @@ -39,7 +41,8 @@ $chat-messagelist-empty-prompt-color: null !default; @if $mode == "dark" { $chat-bubble-background-color-primary: darken(desaturate(adjust-hue($base-accent, 356.3), 14.7), 49.4) !default; $chat-information-color: lighten($base-bg, 43.92) !default; - + + $chat-messagelist-day-header-color: lighten($base-bg, 43.92) !default; $chat-messagelist-empty-icon-color: darken($base-icon-color, 25.88) !default; $chat-messagelist-empty-icon-background-color: lighten($base-bg, 7.84) !default; $chat-messagelist-empty-prompt-color: lighten($base-label-color, 7.84) !default; diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss index dfd77eaeb3ba..983dc69cbe56 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss @@ -53,4 +53,9 @@ $chat-messagelist-empty-prompt-font-size, $chat-messagelist-empty-prompt-color, ); -@include chat-messagelist($chat-messagelist-padding); +@include chat-messagelist( + $chat-messagelist-padding, + $chat-messagelist-day-header-color, + $chat-messagelist-day-header-padding-bottom, + $chat-messagelist-day-header-first-padding-top, +); diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss index 6e011dd40dee..12857bdd858b 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss @@ -27,6 +27,8 @@ $chat-messagelist-empty-icon-margin-bottom: null !default; $chat-messagelist-empty-row-gap: null !default; $chat-messagelist-empty-message-font-size: null !default; $chat-messagelist-empty-prompt-font-size: null !default; +$chat-messagelist-day-header-padding-bottom: 12px !default; +$chat-messagelist-day-header-first-padding-top: 20px !default; @if $size == "default" { $chat-bubble-border-radius: $fluent-base-border-radius * 3 !default; diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss index e4eb2c7d8136..d5667c14d90e 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss @@ -8,12 +8,12 @@ $chat-background-color: $base-bg !default; $chat-border-color: $base-border-color !default; $chat-avatar-color: null !default; $chat-messagebox-border-color: $base-border-color !default; -$chat-avatar-background-color: null !default; $chat-bubble-color-primary: null !default; $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: null !default; $chat-information-color: null !default; +$chat-messagelist-day-header-color: null !default; $chat-messagelist-empty-icon-color: null !default; $chat-messagelist-empty-icon-background-color: null !default; $chat-messagelist-empty-message-color: null !default; @@ -28,6 +28,7 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-secondary: darken($base-element-bg, 4%) !default; $chat-information-color: darken($base-bg, 41.57) !default; + $chat-messagelist-day-header-color: darken($base-bg, 41.57) !default; $chat-messagelist-empty-icon-color: lighten($base-icon-color, 46.67) !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: darken($base-text-color, 6.67) !default; @@ -40,7 +41,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: lighten($base-element-bg, 4%) !default; $chat-information-color: lighten($base-bg, 32.55) !default; - + + $chat-messagelist-day-header-color: lighten($base-bg, 32.55) !default; $chat-messagelist-empty-icon-color: darken($base-icon-color, 37.25) !default; $chat-messagelist-empty-icon-background-color: lighten($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: lighten($base-text-color, 12.94) !default; @@ -53,7 +55,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: darken($base-element-bg, 4%) !default; $chat-information-color: darken($base-bg, 41.57) !default; - + + $chat-messagelist-day-header-color: darken($base-bg, 41.57) !default; $chat-messagelist-empty-icon-color: $base-icon-color !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: $base-text-color !default; @@ -66,7 +69,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: $base-inverted-bg !default; $chat-bubble-background-color-secondary: $base-hover-color !default; $chat-information-color: $base-text-color !default; - + + $chat-messagelist-day-header-color: $base-text-color !default; $chat-messagelist-empty-icon-color: $base-bg !default; $chat-messagelist-empty-icon-background-color: $base-inverted-bg !default; $chat-messagelist-empty-message-color: $base-text-color !default; @@ -79,7 +83,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: lighten($base-element-bg, 4%) !default; $chat-information-color: lighten($base-bg, 32.55) !default; - + + $chat-messagelist-day-header-color: lighten($base-bg, 32.55) !default; $chat-messagelist-empty-icon-color: $base-icon-color !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: $base-text-color !default; @@ -92,7 +97,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: lighten($base-element-bg, 4%) !default; $chat-information-color: lighten($base-bg, 32.55) !default; - + + $chat-messagelist-day-header-color: lighten($base-bg, 32.55) !default; $chat-messagelist-empty-icon-color: darken($base-icon-color, 37.25) !default; $chat-messagelist-empty-icon-background-color: lighten($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: lighten($base-text-color, 12.94) !default; @@ -104,7 +110,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: darken($base-element-bg, 4%) !default; $chat-information-color: darken($base-bg, 41.57) !default; - + + $chat-messagelist-day-header-color: darken($base-bg, 41.57) !default; $chat-messagelist-empty-icon-color: $base-icon-color !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: $base-text-color !default; @@ -117,7 +124,8 @@ $chat-avatar-background-color: $base-border-color !default; $chat-bubble-background-color-primary: color.change(darken($base-accent, 5%), $alpha: 0.1) !default; $chat-bubble-background-color-secondary: darken($base-element-bg, 4%) !default; $chat-information-color: darken($base-bg, 41.57) !default; - + + $chat-messagelist-day-header-color: darken($base-bg, 41.57) !default; $chat-messagelist-empty-icon-color: $base-icon-color !default; $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; $chat-messagelist-empty-message-color: $base-text-color !default; diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss index 35052790429b..bea8d00005a7 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss @@ -55,4 +55,9 @@ $chat-messagelist-empty-prompt-font-size, $chat-messagelist-empty-prompt-color, ); -@include chat-messagelist($chat-messagelist-padding); +@include chat-messagelist( + $chat-messagelist-padding, + $chat-messagelist-day-header-color, + $chat-messagelist-day-header-padding-bottom, + $chat-messagelist-day-header-first-padding-top, +); diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss index eb08f0b942cc..e44862a7d397 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss @@ -29,6 +29,8 @@ $chat-messagelist-empty-icon-margin-bottom: null !default; $chat-messagelist-empty-row-gap: null !default; $chat-messagelist-empty-message-font-size: null !default; $chat-messagelist-empty-prompt-font-size: null !default; +$chat-messagelist-day-header-padding-bottom: 12px !default; +$chat-messagelist-day-header-first-padding-top: 20px !default; @if $size == "default" { $chat-bubble-padding: 8px 12px !default; diff --git a/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss b/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss index 22d37346b27f..a8346f999512 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss @@ -14,6 +14,7 @@ $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: null !default; $chat-information-color: null !default; +$chat-messagelist-day-header-color: null !default; $chat-messagelist-empty-icon-color: rgba($base-inverted-bg, 0.38) !default; $chat-messagelist-empty-icon-background-color: rgba($base-inverted-bg, 0.08) !default; $chat-messagelist-empty-message-color: rgba($base-inverted-bg, 0.87) !default; @@ -23,10 +24,12 @@ $chat-messagelist-empty-prompt-color: rgba($base-inverted-bg, 0.6) !default; $chat-bubble-background-color-primary: rgba($base-accent, 0.08) !default; $chat-bubble-background-color-secondary: rgba($base-inverted-bg, 0.08) !default; $chat-information-color: rgba(darken($base-bg, 100.00), 0.6) !default; + $chat-messagelist-day-header-color: rgba(darken($base-bg, 100.00), 0.6) !default; } @else if $mode == "dark" { $chat-bubble-background-color-primary: rgba(lighten($base-accent, 19.22), 0.08) !default; $chat-bubble-background-color-secondary: rgba(lighten(desaturate(adjust-hue($base-bg, -240), 8.47), 76.86), 0.08) !default; $chat-information-color: rgba(lighten(desaturate(adjust-hue($base-bg, -240), 8.47), 76.86), 0.6) !default; + $chat-messagelist-day-header-color: rgba(lighten(desaturate(adjust-hue($base-bg, -240), 8.47), 76.86), 0.6) !default; } diff --git a/packages/devextreme-scss/scss/widgets/material/chat/_index.scss b/packages/devextreme-scss/scss/widgets/material/chat/_index.scss index dfd77eaeb3ba..983dc69cbe56 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_index.scss @@ -53,4 +53,9 @@ $chat-messagelist-empty-prompt-font-size, $chat-messagelist-empty-prompt-color, ); -@include chat-messagelist($chat-messagelist-padding); +@include chat-messagelist( + $chat-messagelist-padding, + $chat-messagelist-day-header-color, + $chat-messagelist-day-header-padding-bottom, + $chat-messagelist-day-header-first-padding-top, +); diff --git a/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss index 4560bc74a14e..8824d30e1aa6 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss @@ -26,6 +26,8 @@ $chat-messagelist-empty-icon-margin-bottom: null !default; $chat-messagelist-empty-row-gap: null !default; $chat-messagelist-empty-message-font-size: null !default; $chat-messagelist-empty-prompt-font-size: null !default; +$chat-messagelist-day-header-padding-bottom: 12px !default; +$chat-messagelist-day-header-first-padding-top: 20px !default; @if $size == "default" { $chat-messagebox-buton-gap: 10px !default; diff --git a/packages/devextreme/js/__internal/ui/chat/chat.ts b/packages/devextreme/js/__internal/ui/chat/chat.ts index 4a214ff9b74e..008235cbbbaf 100644 --- a/packages/devextreme/js/__internal/ui/chat/chat.ts +++ b/packages/devextreme/js/__internal/ui/chat/chat.ts @@ -21,7 +21,7 @@ import MessageList from './messagelist'; const CHAT_CLASS = 'dx-chat'; const TEXTEDITOR_INPUT_CLASS = 'dx-texteditor-input'; -type Properties = ChatProperties & { title: string }; +type Properties = ChatProperties & { title: string; showDayHeaders: boolean }; class Chat extends Widget { _chatHeader?: ChatHeader; @@ -43,6 +43,7 @@ class Chat extends Widget { dataSource: null, user: { id: new Guid().toString() }, onMessageSend: undefined, + showDayHeaders: true, }; } @@ -98,7 +99,7 @@ class Chat extends Widget { } _renderMessageList(): void { - const { items = [], user } = this.option(); + const { items = [], user, showDayHeaders } = this.option(); const currentUserId = user?.id; const $messageList = $('
'); @@ -108,6 +109,7 @@ class Chat extends Widget { this._messageList = this._createComponent($messageList, MessageList, { items, currentUserId, + showDayHeaders, }); } @@ -214,6 +216,9 @@ class Chat extends Widget { case 'onMessageSend': this._createMessageSendAction(); break; + case 'showDayHeaders': + this._messageList.option(name, value); + break; default: super._optionChanged(args); } diff --git a/packages/devextreme/js/__internal/ui/chat/messagelist.ts b/packages/devextreme/js/__internal/ui/chat/messagelist.ts index e21a2fef8232..549ac4bd8434 100644 --- a/packages/devextreme/js/__internal/ui/chat/messagelist.ts +++ b/packages/devextreme/js/__internal/ui/chat/messagelist.ts @@ -2,9 +2,10 @@ import Guid from '@js/core/guid'; import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import resizeObserverSingleton from '@js/core/resize_observer'; +import dateUtils from '@js/core/utils/date'; import dateSerialization from '@js/core/utils/date_serialization'; import { isElementInDom } from '@js/core/utils/dom'; -import { isDefined } from '@js/core/utils/type'; +import { isDate, isDefined } from '@js/core/utils/type'; import messageLocalization from '@js/localization/message'; import { getScrollTopMax } from '@js/renovation/ui/scroll_view/utils/get_scroll_top_max'; import type { Message } from '@js/ui/chat'; @@ -23,6 +24,7 @@ const CHAT_MESSAGELIST_EMPTY_VIEW_CLASS = 'dx-chat-messagelist-empty-view'; const CHAT_MESSAGELIST_EMPTY_IMAGE_CLASS = 'dx-chat-messagelist-empty-image'; const CHAT_MESSAGELIST_EMPTY_MESSAGE_CLASS = 'dx-chat-messagelist-empty-message'; const CHAT_MESSAGELIST_EMPTY_PROMPT_CLASS = 'dx-chat-messagelist-empty-prompt'; +const CHAT_MESSAGELIST_DAY_HEADER_CLASS = 'dx-chat-messagelist-day-header'; const SCROLLABLE_CONTAINER_CLASS = 'dx-scrollable-container'; export const MESSAGEGROUP_TIMEOUT = 5 * 1000 * 60; @@ -30,11 +32,14 @@ export const MESSAGEGROUP_TIMEOUT = 5 * 1000 * 60; export interface Properties extends WidgetOptions { items: Message[]; currentUserId: number | string | undefined; + showDayHeaders: boolean; } class MessageList extends Widget { private _messageGroups?: MessageGroup[]; + private _lastMessageDate?: null | string | number | Date; + private _containerClientHeight!: number; private _scrollable!: Scrollable; @@ -44,6 +49,7 @@ class MessageList extends Widget { ...super._getDefaultOptions(), items: [], currentUserId: '', + showDayHeaders: true, }; } @@ -51,6 +57,7 @@ class MessageList extends Widget { super._init(); this._messageGroups = []; + this._lastMessageDate = null; } _initMarkup(): void { @@ -169,6 +176,48 @@ class MessageList extends Widget { }); } + _shouldAddDayHeader(timestamp: undefined | string | number | Date): boolean { + const { showDayHeaders } = this.option(); + + if (!showDayHeaders) { + return false; + } + + const deserializedDate = dateSerialization.deserializeDate(timestamp); + + if (!isDate(deserializedDate) || isNaN(deserializedDate.getTime())) { + return false; + } + + return !dateUtils.sameDate(this._lastMessageDate, deserializedDate); + } + + _createDayHeader(timestamp: string | number | Date | undefined): void { + const deserializedDate = dateSerialization.deserializeDate(timestamp); + const today = new Date(); + const yesterday = new Date(new Date().setDate(today.getDate() - 1)); + this._lastMessageDate = deserializedDate; + + let headerDate = deserializedDate.toLocaleDateString(undefined, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }).replace(/[/-]/g, '.'); + + if (dateUtils.sameDate(deserializedDate, today)) { + headerDate = `${messageLocalization.format('Today')} ${headerDate}`; + } + + if (dateUtils.sameDate(deserializedDate, yesterday)) { + headerDate = `${messageLocalization.format('Yesterday')} ${headerDate}`; + } + + $('
') + .addClass(CHAT_MESSAGELIST_DAY_HEADER_CLASS) + .text(headerDate) + .appendTo(this._$content()); + } + _renderMessageListContent(): void { if (this._isEmpty()) { this._renderEmptyViewContent(); @@ -184,20 +233,28 @@ class MessageList extends Widget { items.forEach((item, index) => { const newMessageGroupItem = item ?? {}; const id = newMessageGroupItem.author?.id; - + const shouldCreateDayHeader = this._shouldAddDayHeader(newMessageGroupItem.timestamp); const isTimeoutExceeded = this._isTimeoutExceeded( currentMessageGroupItems[currentMessageGroupItems.length - 1] ?? {}, item, ); - if (id === currentMessageGroupUserId && !isTimeoutExceeded) { - currentMessageGroupItems.push(newMessageGroupItem); - } else { + const shouldCreateMessageGroup = (shouldCreateDayHeader && currentMessageGroupItems.length) + || isTimeoutExceeded + || id !== currentMessageGroupUserId; + + if (shouldCreateMessageGroup) { this._createMessageGroupComponent(currentMessageGroupItems, currentMessageGroupUserId); currentMessageGroupUserId = id; currentMessageGroupItems = []; currentMessageGroupItems.push(newMessageGroupItem); + } else { + currentMessageGroupItems.push(newMessageGroupItem); + } + + if (shouldCreateDayHeader) { + this._createDayHeader(item?.timestamp); } if (items.length - 1 === index) { @@ -207,18 +264,18 @@ class MessageList extends Widget { } _renderMessage(message: Message): void { - const { author } = message; + const { author, timestamp } = message; const lastMessageGroup = this._messageGroups?.[this._messageGroups.length - 1]; + const shouldCreateDayHeader = this._shouldAddDayHeader(timestamp); if (lastMessageGroup) { const { items } = lastMessageGroup.option(); const lastMessageGroupItem = items[items.length - 1]; const lastMessageGroupUserId = lastMessageGroupItem.author?.id; - const isTimeoutExceeded = this._isTimeoutExceeded(lastMessageGroupItem, message); - if (author?.id === lastMessageGroupUserId && !isTimeoutExceeded) { + if (author?.id === lastMessageGroupUserId && !isTimeoutExceeded && !shouldCreateDayHeader) { lastMessageGroup.renderMessage(message); this._scrollContentToLastMessage(); @@ -226,6 +283,10 @@ class MessageList extends Widget { } } + if (shouldCreateDayHeader) { + this._createDayHeader(timestamp); + } + this._createMessageGroupComponent([message], author?.id); this._scrollContentToLastMessage(); @@ -312,6 +373,7 @@ class MessageList extends Widget { _clean(): void { this._messageGroups = []; + this._lastMessageDate = null; super._clean(); } @@ -326,6 +388,9 @@ class MessageList extends Widget { case 'items': this._processItemsUpdating(value ?? [], previousValue ?? []); break; + case 'showDayHeaders': + this._invalidate(); + break; default: super._optionChanged(args); } diff --git a/packages/devextreme/js/localization/messages/ar.json b/packages/devextreme/js/localization/messages/ar.json index c4c6ea87fe8c..20f02b0c7f6e 100644 --- a/packages/devextreme/js/localization/messages/ar.json +++ b/packages/devextreme/js/localization/messages/ar.json @@ -12,6 +12,8 @@ "Search": "بحث", "Back": "رجوع", "OK": "حسنا", + "Today": "اليوم", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "لا توجد بيانات للعرض", diff --git a/packages/devextreme/js/localization/messages/ca.json b/packages/devextreme/js/localization/messages/ca.json index 7ecc4266af15..d24adff10801 100644 --- a/packages/devextreme/js/localization/messages/ca.json +++ b/packages/devextreme/js/localization/messages/ca.json @@ -12,6 +12,8 @@ "Search": "Cerca", "Back": "esquena", "OK": "D'acord", + "Today": "Avui", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "No hi ha dades a mostrar", diff --git a/packages/devextreme/js/localization/messages/cs.json b/packages/devextreme/js/localization/messages/cs.json index f0cebc81860c..569cf6be4c00 100644 --- a/packages/devextreme/js/localization/messages/cs.json +++ b/packages/devextreme/js/localization/messages/cs.json @@ -12,6 +12,8 @@ "Search": "Hledat", "Back": "Zpět", "OK": "OK", + "Today": "Dnes", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Žádná data k zobrazení", diff --git a/packages/devextreme/js/localization/messages/de.json b/packages/devextreme/js/localization/messages/de.json index 07658586bac0..538cebdc4b02 100644 --- a/packages/devextreme/js/localization/messages/de.json +++ b/packages/devextreme/js/localization/messages/de.json @@ -12,6 +12,8 @@ "Search": "Suchen...", "Back": "Zurück", "OK": "OK", + "Today": "Heute", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Keine Daten verfügbar", diff --git a/packages/devextreme/js/localization/messages/el.json b/packages/devextreme/js/localization/messages/el.json index 70459e5fb810..47d43c2123da 100644 --- a/packages/devextreme/js/localization/messages/el.json +++ b/packages/devextreme/js/localization/messages/el.json @@ -12,6 +12,8 @@ "Search": "Αναζήτηση", "Back": "Πίσω", "OK": "ΟΚ", + "Today": "Σήμερα", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Δεν υπάρχουν δεδομένα προς εμφάνιση", diff --git a/packages/devextreme/js/localization/messages/en.json b/packages/devextreme/js/localization/messages/en.json index 7b2c8ed5ea69..afb9d9621aa0 100644 --- a/packages/devextreme/js/localization/messages/en.json +++ b/packages/devextreme/js/localization/messages/en.json @@ -12,6 +12,8 @@ "Search": "Search", "Back": "Back", "OK": "OK", + "Today": "Today", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "No data to display", diff --git a/packages/devextreme/js/localization/messages/es.json b/packages/devextreme/js/localization/messages/es.json index 255c08e6f2c5..79b6d675945d 100644 --- a/packages/devextreme/js/localization/messages/es.json +++ b/packages/devextreme/js/localization/messages/es.json @@ -12,6 +12,8 @@ "Search": "Buscar", "Back": "Volver", "OK": "Aceptar", + "Today": "Hoy", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Sin datos para mostrar", diff --git a/packages/devextreme/js/localization/messages/fa.json b/packages/devextreme/js/localization/messages/fa.json index f847fda8bfdb..14871b5e192c 100644 --- a/packages/devextreme/js/localization/messages/fa.json +++ b/packages/devextreme/js/localization/messages/fa.json @@ -12,6 +12,8 @@ "Search": "جستجو", "Back": "بازگشت", "OK": "تایید", + "Today": "امروز", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "(داده ای برای نمایش موجود نمی باشد)", diff --git a/packages/devextreme/js/localization/messages/fi.json b/packages/devextreme/js/localization/messages/fi.json index 9fad8498a961..0db265749f8d 100644 --- a/packages/devextreme/js/localization/messages/fi.json +++ b/packages/devextreme/js/localization/messages/fi.json @@ -12,6 +12,8 @@ "Search": "Haku", "Back": "Takaisin", "OK": "OK", + "Today": "Tänään", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Ei näytettäviä tietoja", diff --git a/packages/devextreme/js/localization/messages/fr.json b/packages/devextreme/js/localization/messages/fr.json index d19f65b0c462..136a8b66ddbb 100644 --- a/packages/devextreme/js/localization/messages/fr.json +++ b/packages/devextreme/js/localization/messages/fr.json @@ -12,6 +12,8 @@ "Search": "Recherche", "Back": "Retour", "OK": "OK", + "Today": "Aujourd'hui", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Pas de données", diff --git a/packages/devextreme/js/localization/messages/hu.json b/packages/devextreme/js/localization/messages/hu.json index 2512cc06084c..6959aa29dec9 100644 --- a/packages/devextreme/js/localization/messages/hu.json +++ b/packages/devextreme/js/localization/messages/hu.json @@ -12,6 +12,8 @@ "Search": "Keresés", "Back": "Vissza", "OK": "OK", + "Today": "Ma", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Nincs megjeleníthető adat", diff --git a/packages/devextreme/js/localization/messages/it.json b/packages/devextreme/js/localization/messages/it.json index b3da08596acc..4da39038500e 100644 --- a/packages/devextreme/js/localization/messages/it.json +++ b/packages/devextreme/js/localization/messages/it.json @@ -12,6 +12,8 @@ "Search": "Cerca", "Back": "Indietro", "OK": "OK", + "Today": "Oggi", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Nessun dato da mostrare", diff --git a/packages/devextreme/js/localization/messages/ja.json b/packages/devextreme/js/localization/messages/ja.json index 5b15a410df1b..76762f508389 100644 --- a/packages/devextreme/js/localization/messages/ja.json +++ b/packages/devextreme/js/localization/messages/ja.json @@ -12,6 +12,8 @@ "Search": "検索", "Back": "戻る", "OK": "OK", + "Today": "今日", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "表示するデータがありません。", diff --git a/packages/devextreme/js/localization/messages/lt.json b/packages/devextreme/js/localization/messages/lt.json index d5de1177df91..ad6dd6e40d5d 100644 --- a/packages/devextreme/js/localization/messages/lt.json +++ b/packages/devextreme/js/localization/messages/lt.json @@ -12,6 +12,8 @@ "Search": "Paieška", "Back": "Atgal", "OK": "Gerai", + "Today": "Šiandien", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Nėra duomenų", diff --git a/packages/devextreme/js/localization/messages/lv.json b/packages/devextreme/js/localization/messages/lv.json index 1273f4066ed3..0ddfe883ec18 100644 --- a/packages/devextreme/js/localization/messages/lv.json +++ b/packages/devextreme/js/localization/messages/lv.json @@ -12,6 +12,8 @@ "Search": "Meklēt", "Back": "Atpakaļ", "OK": "OK", + "Today": "Šodien", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Nav datu ko attēlot", diff --git a/packages/devextreme/js/localization/messages/nb.json b/packages/devextreme/js/localization/messages/nb.json index 2b96f1b968b7..801b3022e708 100644 --- a/packages/devextreme/js/localization/messages/nb.json +++ b/packages/devextreme/js/localization/messages/nb.json @@ -12,6 +12,8 @@ "Search": "Søk", "Back": "Tilbake", "OK": "OK", + "Today": "I dag", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Ingen data å vise", diff --git a/packages/devextreme/js/localization/messages/nl.json b/packages/devextreme/js/localization/messages/nl.json index 10589962ded1..618c0af8c6c4 100644 --- a/packages/devextreme/js/localization/messages/nl.json +++ b/packages/devextreme/js/localization/messages/nl.json @@ -12,6 +12,8 @@ "Search": "Zoeken", "Back": "Terug", "OK": "OK", + "Today": "Vandaag", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Geen gegevens om te tonen", diff --git a/packages/devextreme/js/localization/messages/pl.json b/packages/devextreme/js/localization/messages/pl.json index 90ddb4392ff6..9281ea8e5d92 100644 --- a/packages/devextreme/js/localization/messages/pl.json +++ b/packages/devextreme/js/localization/messages/pl.json @@ -12,6 +12,8 @@ "Search": "Szukaj...", "Back": "Wróć...", "OK": "OK", + "Today": "Dzisiaj", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Brak dostępnych danych", diff --git a/packages/devextreme/js/localization/messages/pt.json b/packages/devextreme/js/localization/messages/pt.json index 08d75add9721..6e78279fa1f0 100644 --- a/packages/devextreme/js/localization/messages/pt.json +++ b/packages/devextreme/js/localization/messages/pt.json @@ -12,6 +12,8 @@ "Search": "Pesquisar ...", "Back": "Voltar", "OK": "OK", + "Today": "Hoje", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Sem dados", diff --git a/packages/devextreme/js/localization/messages/ro.json b/packages/devextreme/js/localization/messages/ro.json index 4addf3d705fb..18ad7bac983f 100644 --- a/packages/devextreme/js/localization/messages/ro.json +++ b/packages/devextreme/js/localization/messages/ro.json @@ -12,6 +12,8 @@ "Search": "Caută", "Back": "Înapoi", "OK": "OK", + "Today": "Astăzi", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Nu există date", diff --git a/packages/devextreme/js/localization/messages/ru.json b/packages/devextreme/js/localization/messages/ru.json index c3baa2ee9e8a..bb2e7d9c70df 100644 --- a/packages/devextreme/js/localization/messages/ru.json +++ b/packages/devextreme/js/localization/messages/ru.json @@ -12,6 +12,8 @@ "Search": "Поиск", "Back": "Назад", "OK": "OK", + "Today": "Сегодня", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Нет данных для отображения", diff --git a/packages/devextreme/js/localization/messages/sl.json b/packages/devextreme/js/localization/messages/sl.json index f8d6d9dd03fc..93f03b1aa136 100644 --- a/packages/devextreme/js/localization/messages/sl.json +++ b/packages/devextreme/js/localization/messages/sl.json @@ -12,6 +12,8 @@ "Search": "Išči", "Back": "Nazaj", "OK": "V redu", + "Today": "Danes", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Ni podatkov za prikaz", diff --git a/packages/devextreme/js/localization/messages/sv.json b/packages/devextreme/js/localization/messages/sv.json index 9fcaa492acee..7c1f9f5b5acd 100644 --- a/packages/devextreme/js/localization/messages/sv.json +++ b/packages/devextreme/js/localization/messages/sv.json @@ -12,6 +12,8 @@ "Search": "Sök", "Back": "Tillbaka", "OK": "OK", + "Today": "I dag", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Inget data att visa", diff --git a/packages/devextreme/js/localization/messages/tr.json b/packages/devextreme/js/localization/messages/tr.json index 62eca9b58c25..1a6b3464d29b 100644 --- a/packages/devextreme/js/localization/messages/tr.json +++ b/packages/devextreme/js/localization/messages/tr.json @@ -12,6 +12,8 @@ "Search": "Ara", "Back": "Geri", "OK": "Tamam", + "Today": "Bugün", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Gösterilecek bilgi yok", diff --git a/packages/devextreme/js/localization/messages/vi.json b/packages/devextreme/js/localization/messages/vi.json index ffa135dbff2f..552d23cd7846 100644 --- a/packages/devextreme/js/localization/messages/vi.json +++ b/packages/devextreme/js/localization/messages/vi.json @@ -12,6 +12,8 @@ "Search": "Tìm kiếm", "Back": "Quay lại", "OK": "OK", + "Today": "Hôm nay", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "Không có dữ liệu để hiển thị", diff --git a/packages/devextreme/js/localization/messages/zh-tw.json b/packages/devextreme/js/localization/messages/zh-tw.json index 917298d59cc6..14810b17a228 100644 --- a/packages/devextreme/js/localization/messages/zh-tw.json +++ b/packages/devextreme/js/localization/messages/zh-tw.json @@ -12,6 +12,8 @@ "Search": "搜尋", "Back": "返回", "OK": "確定", + "Today": "今天", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "沒有要顯示的資料", diff --git a/packages/devextreme/js/localization/messages/zh.json b/packages/devextreme/js/localization/messages/zh.json index 734ad7a75696..eae500fd08e1 100644 --- a/packages/devextreme/js/localization/messages/zh.json +++ b/packages/devextreme/js/localization/messages/zh.json @@ -12,6 +12,8 @@ "Search": "搜索", "Back": "返回", "OK": "确定", + "Today": "今天", + "Yesterday": "Yesterday", "dxCollectionWidget-noDataText": "没有要显示的数据", diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js index 0fd3daca147e..0dc5c61b5fc4 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chat.tests.js @@ -126,7 +126,11 @@ QUnit.module('Chat', moduleConfig, () => { }); }); - QUnit.module('MessageList integration', () => { + QUnit.module('MessageList integration', { + beforeEach: function() { + this.getMessageList = () => MessageList.getInstance(this.$element.find(`.${CHAT_MESSAGELIST_CLASS}`)); + } + }, () => { QUnit.test('passed currentUserId should be equal generated chat.user.id', function(assert) { const messageList = MessageList.getInstance(this.$element.find(`.${CHAT_MESSAGELIST_CLASS}`)); @@ -150,7 +154,7 @@ QUnit.module('Chat', moduleConfig, () => { items: messages }); - const messageList = MessageList.getInstance(this.$element.find(`.${CHAT_MESSAGELIST_CLASS}`)); + const messageList = this.getMessageList(); const expectedOptions = { items: messages, @@ -167,7 +171,7 @@ QUnit.module('Chat', moduleConfig, () => { this.instance.option({ user: { id: newUserID } }); - const messageList = MessageList.getInstance(this.$element.find(`.${CHAT_MESSAGELIST_CLASS}`)); + const messageList = this.getMessageList(); assert.deepEqual(messageList.option('currentUserId'), newUserID, 'currentUserId value is updated'); }); @@ -177,10 +181,32 @@ QUnit.module('Chat', moduleConfig, () => { this.instance.option('items', newItems); - const messageList = MessageList.getInstance(this.$element.find(`.${CHAT_MESSAGELIST_CLASS}`)); + const messageList = this.getMessageList(); assert.deepEqual(messageList.option('items'), newItems, 'items value is updated'); }); + + QUnit.test('Chat should pass showDayHeaders to messageList on init', function(assert) { + this.reinit({ + showDayHeaders: false, + }); + + const messageList = this.getMessageList(); + + assert.strictEqual(messageList.option('showDayHeaders'), false, 'showDayHeaders is passed on init'); + }); + + QUnit.test('Chat should pass showDayHeaders to messageList at runtime', function(assert) { + this.reinit({ + showDayHeaders: true, + }); + + const messageList = this.getMessageList(); + + this.instance.option('showDayHeaders', false); + + assert.strictEqual(messageList.option('showDayHeaders'), false, 'showDayHeaders is passed on runtime'); + }); }); QUnit.module('Events', () => { diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js index 1bcc29ba0943..aedaa33de593 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.tests.js @@ -17,9 +17,19 @@ const CHAT_MESSAGEBUBBLE_CLASS = 'dx-chat-messagebubble'; const CHAT_MESSAGELIST_EMPTY_MESSAGE_CLASS = 'dx-chat-messagelist-empty-message'; const CHAT_MESSAGELIST_EMPTY_PROMPT_CLASS = 'dx-chat-messagelist-empty-prompt'; +const CHAT_MESSAGELIST_DAY_HEADER_CLASS = 'dx-chat-messagelist-day-header'; const SCROLLABLE_CLASS = 'dx-scrollable'; +const MS_IN_DAY = 86400000; + +const getStringDate = (date) => { + return date.toLocaleDateString(undefined, { + day: '2-digit', + month: '2-digit', + year: 'numeric', + }).replace(/[/-]/g, '.'); +}; const moduleConfig = { beforeEach: function() { @@ -31,6 +41,7 @@ const moduleConfig = { this.$element = $(this.instance.$element()); this.getScrollable = () => Scrollable.getInstance(this.$element.find(`.${SCROLLABLE_CLASS}`)); + this.getDayHeaders = () => $(this.getScrollable().content()).find(`.${CHAT_MESSAGELIST_DAY_HEADER_CLASS}`); this.scrollable = this.getScrollable(); }; @@ -125,6 +136,237 @@ QUnit.module('MessageList', moduleConfig, () => { assert.strictEqual($messageGroups.length, 26); }); + + [ + { + date: new Date(), + scenario: 'today\'s date', + expectedDatePrefix: 'Today ', + }, + { + date: new Date(Date.now() - MS_IN_DAY), + scenario: 'yesterday\'s date', + expectedDatePrefix: 'Yesterday ', + }, + { + date: new Date(Date.now() - 2 * MS_IN_DAY), + scenario: 'some older date', + expectedDatePrefix: '', + }, + ].forEach(({ date, scenario, expectedDatePrefix }) => { + QUnit.test(`Day header should be rendered (message date is ${scenario}, on init)`, function(assert) { + const expectedText = `${expectedDatePrefix}${getStringDate(date)}`; + + this.reinit({ items: [{ timestamp: date, text: 'ABC' }] }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'day header was added'); + assert.strictEqual($dayHeaders.text(), expectedText, 'day header text is correct'); + }); + + QUnit.test(`Day header should be rendered (message date is ${scenario}, on runtime)`, function(assert) { + const expectedText = `${expectedDatePrefix}${getStringDate(date)}`; + + this.instance.option({ items: [{ timestamp: date, text: 'ABC' }] }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'day header was added'); + assert.strictEqual($dayHeaders.text(), expectedText, 'day header text is correct'); + }); + }); + + [ + { + date: undefined, + scenario: 'date is undefined', + showDayHeaders: true, + }, + { + date: new Date('invalid'), + scenario: 'date is invalid', + showDayHeaders: true, + }, + { + date: new Date(), + scenario: 'showDayHeaders=false', + showDayHeaders: false, + }, + ].forEach(({ date, scenario, showDayHeaders }) => { + QUnit.test(`Day header should not be rendered when ${scenario}`, function(assert) { + this.reinit({ + items: [{ timestamp: date, text: 'ABC' }], + showDayHeaders, + }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 0, 'day header was not added'); + }); + }); + + + QUnit.test('Day headers should be\'removed on runtime showDayHeaders disable', function(assert) { + const now = new Date().getTime(); + + this.reinit({ + items: [{ timestamp: now - MS_IN_DAY, text: 'ABC' }, { timestamp: now, text: 'CBA' }], + showDayHeaders: true, + }); + + this.instance.option({ showDayHeaders: false }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 0, 'day headers were removed'); + }); + + QUnit.test('Day headers should be added on runtime showDayHeaders enable', function(assert) { + const now = new Date().getTime(); + + this.reinit({ + items: [{ timestamp: now - MS_IN_DAY, text: 'ABC' }, { timestamp: now, text: 'CBA' }], + showDayHeaders: false, + }); + + this.instance.option({ showDayHeaders: true }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 2, 'day headers were added'); + }); + + [ + { + oldItemTimestamp: new Date().getTime() - MS_IN_DAY, + newItemTimestamp: new Date().getTime(), + scenario: 'items have different date', + expectedDayHeadersCount: 2, + }, + { + oldItemTimestamp: new Date().getTime(), + newItemTimestamp: new Date().getTime(), + scenario: 'items have the same date', + expectedDayHeadersCount: 1, + }, + { + oldItemTimestamp: undefined, + newItemTimestamp: new Date().getTime(), + scenario: 'first item has undefined date', + expectedDayHeadersCount: 1, + }, + { + oldItemTimestamp: new Date().getTime(), + newItemTimestamp: 'invalid', + scenario: 'second item has an invalid date', + expectedDayHeadersCount: 1, + }, + { + oldItemTimestamp: undefined, + newItemTimestamp: undefined, + scenario: 'dates are not defined for both items', + expectedDayHeadersCount: 0, + }, + ].forEach(({ oldItemTimestamp, newItemTimestamp, scenario, expectedDayHeadersCount }) => { + QUnit.test(`It should be ${expectedDayHeadersCount} day headers when add second item on runtime (${scenario})`, function(assert) { + const items = [{ + timestamp: oldItemTimestamp, + text: 'ABC' + }]; + + this.reinit({ + items, + }); + + const newMessage = { + timestamp: newItemTimestamp, + text: 'EFG', + }; + + this.instance.option({ items: [...items, newMessage] }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, expectedDayHeadersCount, 'day headers count is correct'); + }); + }); + + QUnit.test('Current message group should be rendered before day header is added', function(assert) { + this.reinit({ + items: [{ + text: 'ABC', + }, { + timestamp: new Date('11.10.2024'), + text: 'EFG', + }] + }); + + const $scrollableContent = $(this.scrollable.content()); + const $firstChild = $scrollableContent.children().first(); + + assert.strictEqual($firstChild.hasClass(CHAT_MESSAGEGROUP_CLASS), true, 'first message group is added before day header'); + }); + + QUnit.test('Only one day header should be added when there are two messages with the same date and undefined date between them (last day header was added for message in current messageGroup)', function(assert) { + this.reinit({ + items: [{ + timestamp: new Date('11.10.2024'), + author: { id: 1 }, + text: 'ABC', + }, { + author: { id: 2 }, + text: 'EFG', + }, { + timestamp: new Date('11.10.2024'), + author: { id: 1 }, + text: 'HIJ', + }], + }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'only one day header was added'); + }); + + QUnit.test('Only one day header should be added when there are two messages with the same date and and undefined date between them (last day header was added for message in older messageGroup)', function(assert) { + this.reinit({ + items: [{ + timestamp: new Date('11.10.2024'), + text: 'ABC', + }, { + text: 'EFG', + }, { + timestamp: new Date('11.10.2024'), + text: 'HIJ', + }], + }); + + const $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'only one day header was added'); + }); + + QUnit.test('Day header should not dissapear after component invalidate', function(assert) { + const items = [{ + timestamp: new Date('11.10.2024'), + text: 'ABC', + }]; + + this.reinit({ + items, + }); + + let $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'day header was aaded'); + + this.instance.option({ items }); + + $dayHeaders = this.getDayHeaders(); + + assert.strictEqual($dayHeaders.length, 1, 'day header is not removed after invalidate'); + }); }); QUnit.module('MessageGroup integration', () => { diff --git a/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js b/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js index 70c14aae1e52..1aead88821af 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui/defaultOptions.tests.js @@ -1348,6 +1348,7 @@ testComponentDefaults(Chat, title: '', onMessageSend: undefined, dataSource: undefined, + showDayHeaders: true, } ); @@ -1394,6 +1395,7 @@ testComponentDefaults(ChatMessageList, {}, { currentUserId: '', + showDayHeaders: true, } );