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 f93525a55cee..c62c1e0d2236 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 @@ -1,3 +1,5 @@ +@use "../../../icons" as *; + .dx-chat-message-list { flex-grow: 1; overflow: hidden; @@ -7,3 +9,20 @@ flex-direction: column; } } + +.dx-chat-message-list-empty { + .dx-chat-empty-view { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex-grow: 1; + } + + .dx-chat-empty-image { + @include dx-icon(chat); + + border-radius: 999em; + } +} + 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 517a0d524d9c..f933ac2bf7d9 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,3 +1,5 @@ +@use "sass:math"; + @mixin chat-messagelist($padding) { .dx-chat-message-list { .dx-scrollable-content { @@ -5,3 +7,43 @@ } } } + +@mixin chat-messagelist-empty( + $messagelist-empty-icon-box-size, + $messagelist-empty-icon-size, + $messagelist-empty-icon-margin-bottom, + $messagelist-empty-row-gap, + $messagelist-empty-icon-color, + $messagelist-empty-icon-background-color, + $messagelist-empty-message-font-size, + $messagelist-empty-message-color, + $messagelist-empty-prompt-font-size, + $messagelist-empty-prompt-color, +) { + .dx-chat-message-list-empty { + .dx-chat-empty-view { + row-gap: $messagelist-empty-row-gap; + } + + .dx-chat-empty-image { + color: $messagelist-empty-icon-color; + background-color: $messagelist-empty-icon-background-color; + padding: math.div($messagelist-empty-icon-box-size - $messagelist-empty-icon-size, 2); + margin-bottom: $messagelist-empty-icon-margin-bottom; + + &::before { + font-size: $messagelist-empty-icon-size; + } + } + + .dx-chat-empty-message { + font-size: $messagelist-empty-message-font-size; + color: $messagelist-empty-message-color; + } + + .dx-chat-empty-prompt { + font-size: $messagelist-empty-prompt-font-size; + color: $messagelist-empty-prompt-color; + } + } +} diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss index 53c2df8acc29..e0e756928beb 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_colors.scss @@ -12,11 +12,20 @@ $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: null !default; $chat-information-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; +$chat-messagelist-empty-prompt-color: null !default; + @if $mode == "light" { $chat-avatar-background-color: darken($base-bg, 12.16) !default; // #E0E0E0 $chat-bubble-background-color-primary: lighten(desaturate(adjust-hue($base-accent, 4), 11.38), 55.49) !default; // #EBF3FC $chat-bubble-background-color-secondary: darken($base-bg, 3.92) !default; // #F5F5F5 $chat-information-color: darken($base-bg, 56.08) !default; // #707070 + + $chat-messagelist-empty-icon-color: lighten($base-icon-color, 32.16) !default; // #B3B3B3 + $chat-messagelist-empty-icon-background-color: darken($base-bg, 3.92) !default; // #F5F5F5 + $chat-messagelist-empty-prompt-color: darken($base-label-color, 5.88) !default; // #616161 } @else if $mode == "dark" { @@ -24,4 +33,8 @@ $chat-information-color: null !default; $chat-bubble-background-color-primary: darken(desaturate(adjust-hue($base-accent, -4), 14.69), 49.41) !default; // #082338 $chat-bubble-background-color-secondary: lighten($base-bg, 7.84) !default; // #3D3D3D $chat-information-color: lighten($base-bg, 43.92) !default; // #999 + + $chat-messagelist-empty-icon-color: darken($base-icon-color, 25.88) !default; // #6B6B6B + $chat-messagelist-empty-icon-background-color: lighten($base-bg, 7.84) !default; // #3D3D3D + $chat-messagelist-empty-prompt-color: lighten($base-label-color, 7.84) !default; // #ADADAD } diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss index 844aa807b9aa..d6e59d41bf04 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_index.scss @@ -35,4 +35,16 @@ $chat-information-color, $chat-information-gap ); +@include chat-messagelist-empty( + $chat-messagelist-empty-icon-box-size, + $chat-messagelist-empty-icon-size, + $chat-messagelist-empty-icon-margin-bottom, + $chat-messagelist-empty-row-gap, + $chat-messagelist-empty-icon-color, + $chat-messagelist-empty-icon-background-color, + $chat-messagelist-empty-message-font-size, + $chat-messagelist-empty-message-color, + $chat-messagelist-empty-prompt-font-size, + $chat-messagelist-empty-prompt-color, +); @include chat-messagelist($chat-messagelist-padding); diff --git a/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss index 5a6ec93ecb22..3f60912b8150 100644 --- a/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/fluent/chat/_sizes.scss @@ -21,12 +21,26 @@ $chat-messagegroup-alignment-start-gap: 12px !default; $chat-header-padding: 20px !default; $chat-information-font-size: 12px !default; +$chat-messagelist-empty-icon-box-size: null !default; +$chat-messagelist-empty-icon-size: null !default; +$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; + @if $size == "default" { $chat-bubble-border-radius: $fluent-base-border-radius * 3 !default; $chat-bubble-padding: 8px 12px !default; $chat-messagebox-padding: 20px !default; $chat-messagelist-padding: 0 20px !default; $chat-messagegroup-padding: 24px !default; + + $chat-messagelist-empty-icon-box-size: 64px !default;; + $chat-messagelist-empty-icon-size: 40px !default; + $chat-messagelist-empty-icon-margin-bottom: 12px !default; + $chat-messagelist-empty-row-gap: 4px !default; + $chat-messagelist-empty-message-font-size: 18px !default; + $chat-messagelist-empty-prompt-font-size: 14px !default; } @else if $size == "compact" { @@ -35,4 +49,11 @@ $chat-information-font-size: 12px !default; $chat-messagebox-padding: 16px !default; $chat-messagelist-padding: 0 16px !default; $chat-messagegroup-padding: 12px !default; + + $chat-messagelist-empty-icon-box-size: 48px !default;; + $chat-messagelist-empty-icon-size: 32px !default; + $chat-messagelist-empty-icon-margin-bottom: 14px !default; + $chat-messagelist-empty-row-gap: 2px !default; + $chat-messagelist-empty-message-font-size: 14px !default; + $chat-messagelist-empty-prompt-font-size: 12px !default; } diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss index 9e1f69d5767a..b3f87001d83e 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_colors.scss @@ -12,11 +12,21 @@ $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: null !default; $chat-information-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; +$chat-messagelist-empty-prompt-color: null !default; + @if $color == "light" { $chat-avatar-background-color: darken($base-bg, 13.33) !default; // #DDDDDD $chat-bubble-background-color-primary: rgba(darken(saturate($base-accent, 0.32), 5.10), 0.1) !default; // #2D6DA31A $chat-bubble-background-color-secondary: darken($base-bg, 3.92) !default; // #F5F5F5 $chat-information-color: darken($base-bg, 41.57) !default; // #959595 + + $chat-messagelist-empty-icon-color: lighten($base-icon-color, 46.67) !default; // #AAAAAA + $chat-messagelist-empty-icon-background-color: darken($base-bg, 7.84) !default; // #EBEBEB + $chat-messagelist-empty-message-color: darken($base-text-color, 6.67) !default; // #222222 + $chat-messagelist-empty-prompt-color: lighten($base-label-color, 38.43) !default; // #959595 } @else if $color == "dark" { @@ -24,4 +34,9 @@ $chat-information-color: null !default; $chat-bubble-background-color-primary: rgba(darken(saturate($base-accent, 0.07), 5.10), 0.1) !default; // #1997C61A $chat-bubble-background-color-secondary: lighten($base-bg, 3.92) !default; // #343434 $chat-information-color: lighten($base-bg, 32.55) !default; // #7D7D7D + + $chat-messagelist-empty-icon-color: darken(#dedede, 37.25) !default; // #7F7F7F + $chat-messagelist-empty-icon-background-color: lighten($base-bg, 7.84) !default; // #3E3E3E + $chat-messagelist-empty-message-color: lighten($base-text-color, 12.94) !default; // #FFFFFF + $chat-messagelist-empty-prompt-color: darken($base-label-color, 38.04) !default; // #7D7D7D } diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss index 844aa807b9aa..d6e59d41bf04 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_index.scss @@ -35,4 +35,16 @@ $chat-information-color, $chat-information-gap ); +@include chat-messagelist-empty( + $chat-messagelist-empty-icon-box-size, + $chat-messagelist-empty-icon-size, + $chat-messagelist-empty-icon-margin-bottom, + $chat-messagelist-empty-row-gap, + $chat-messagelist-empty-icon-color, + $chat-messagelist-empty-icon-background-color, + $chat-messagelist-empty-message-font-size, + $chat-messagelist-empty-message-color, + $chat-messagelist-empty-prompt-font-size, + $chat-messagelist-empty-prompt-color, +); @include chat-messagelist($chat-messagelist-padding); diff --git a/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss index 5cdb0bce4da8..97592df9e0dd 100644 --- a/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/generic/chat/_sizes.scss @@ -22,11 +22,25 @@ $chat-messagegroup-alignment-start-gap: 12px !default; $chat-header-padding: 20px !default; $chat-information-font-size: 12px !default; +$chat-messagelist-empty-icon-box-size: null !default; +$chat-messagelist-empty-icon-size: null !default; +$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; + @if $size == "default" { $chat-bubble-padding: 8px 12px !default; $chat-messagebox-padding: 20px !default; $chat-messagelist-padding: 0 20px !default; $chat-messagegroup-padding: 24px !default; + + $chat-messagelist-empty-icon-box-size: 64px !default;; + $chat-messagelist-empty-icon-size: 40px !default; + $chat-messagelist-empty-icon-margin-bottom: 12px !default; + $chat-messagelist-empty-row-gap: 4px !default; + $chat-messagelist-empty-message-font-size: 18px !default; + $chat-messagelist-empty-prompt-font-size: 14px !default; } @else if $size == "compact" { @@ -34,4 +48,11 @@ $chat-information-font-size: 12px !default; $chat-messagebox-padding: 16px !default; $chat-messagelist-padding: 0 16px !default; $chat-messagegroup-padding: 12px !default; + + $chat-messagelist-empty-icon-box-size: 48px !default;; + $chat-messagelist-empty-icon-size: 32px !default; + $chat-messagelist-empty-icon-margin-bottom: 14px !default; + $chat-messagelist-empty-row-gap: 2px !default; + $chat-messagelist-empty-message-font-size: 14px !default; + $chat-messagelist-empty-prompt-font-size: 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 170c06bde2f6..39bd50b4eb25 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_colors.scss @@ -12,6 +12,11 @@ $chat-bubble-background-color-primary: null !default; $chat-bubble-background-color-secondary: null !default; $chat-information-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; +$chat-messagelist-empty-prompt-color: rgba($base-inverted-bg, 0.6) !default; + @if $mode == "light" { $chat-avatar-background-color: darken($base-bg, 12.16) !default; // #E0E0E0 $chat-bubble-background-color-primary: rgba($base-accent, 0.08) !default; // #03A9F414 diff --git a/packages/devextreme-scss/scss/widgets/material/chat/_index.scss b/packages/devextreme-scss/scss/widgets/material/chat/_index.scss index 844aa807b9aa..d6e59d41bf04 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_index.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_index.scss @@ -35,4 +35,16 @@ $chat-information-color, $chat-information-gap ); +@include chat-messagelist-empty( + $chat-messagelist-empty-icon-box-size, + $chat-messagelist-empty-icon-size, + $chat-messagelist-empty-icon-margin-bottom, + $chat-messagelist-empty-row-gap, + $chat-messagelist-empty-icon-color, + $chat-messagelist-empty-icon-background-color, + $chat-messagelist-empty-message-font-size, + $chat-messagelist-empty-message-color, + $chat-messagelist-empty-prompt-font-size, + $chat-messagelist-empty-prompt-color, +); @include chat-messagelist($chat-messagelist-padding); diff --git a/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss b/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss index 99febd089c69..a589f4844417 100644 --- a/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss +++ b/packages/devextreme-scss/scss/widgets/material/chat/_sizes.scss @@ -20,6 +20,13 @@ $chat-messagegroup-alignment-start-gap: 12px !default; $chat-header-padding: 20px !default; $chat-information-font-size: 12px !default; +$chat-messagelist-empty-icon-box-size: null !default; +$chat-messagelist-empty-icon-size: null !default; +$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; + @if $size == "default" { $chat-messagebox-buton-gap: 10px !default; $chat-bubble-border-radius: 8px !default; @@ -27,6 +34,13 @@ $chat-information-font-size: 12px !default; $chat-messagebox-padding: 20px !default; $chat-messagelist-padding: 0 20px !default; $chat-messagegroup-padding: 24px !default; + + $chat-messagelist-empty-icon-box-size: 64px !default;; + $chat-messagelist-empty-icon-size: 40px !default; + $chat-messagelist-empty-icon-margin-bottom: 12px !default; + $chat-messagelist-empty-row-gap: 4px !default; + $chat-messagelist-empty-message-font-size: 18px !default; + $chat-messagelist-empty-prompt-font-size: 14px !default; } @else if $size == "compact" { @@ -36,4 +50,11 @@ $chat-information-font-size: 12px !default; $chat-messagebox-padding: 16px !default; $chat-messagelist-padding: 0 16px !default; $chat-messagegroup-padding: 12px !default; + + $chat-messagelist-empty-icon-box-size: 48px !default;; + $chat-messagelist-empty-icon-size: 32px !default; + $chat-messagelist-empty-icon-margin-bottom: 14px !default; + $chat-messagelist-empty-row-gap: 2px !default; + $chat-messagelist-empty-message-font-size: 14px !default; + $chat-messagelist-empty-prompt-font-size: 12px !default; } diff --git a/packages/devextreme/js/__internal/ui/chat/chat_message_list.ts b/packages/devextreme/js/__internal/ui/chat/chat_message_list.ts index b67b6b858005..5e98701dd445 100644 --- a/packages/devextreme/js/__internal/ui/chat/chat_message_list.ts +++ b/packages/devextreme/js/__internal/ui/chat/chat_message_list.ts @@ -1,6 +1,6 @@ -import type { dxElementWrapper } from '@js/core/renderer'; import $ from '@js/core/renderer'; import { hasWindow } from '@js/core/utils/window'; +import messageLocalization from '@js/localization/message'; import type { Message } from '@js/ui/chat'; import Scrollable from '@js/ui/scroll_view/ui.scrollable'; import type { WidgetOptions } from '@js/ui/widget/ui.widget'; @@ -12,6 +12,12 @@ import MessageGroup from './chat_message_group'; const CHAT_MESSAGE_LIST_CLASS = 'dx-chat-message-list'; +const CHAT_MESSAGE_LIST_EMPTY_CLASS = 'dx-chat-message-list-empty'; +const CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS = 'dx-chat-empty-view'; +const CHAT_MESSAGE_LIST_EMPTY_IMAGE_CLASS = 'dx-chat-empty-image'; +const CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS = 'dx-chat-empty-message'; +const CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS = 'dx-chat-empty-prompt'; + export interface Properties extends WidgetOptions { items: Message[]; currentUserId: number | string | undefined; @@ -20,9 +26,7 @@ export interface Properties extends WidgetOptions { class MessageList extends Widget { _messageGroups?: MessageGroup[]; - private _$content!: dxElementWrapper; - - private _scrollable?: Scrollable; + private _scrollable!: Scrollable; _getDefaultOptions(): Properties { return { @@ -43,12 +47,53 @@ class MessageList extends Widget { super._initMarkup(); - this._renderMessageListContent(); this._renderScrollable(); + this._renderMessageListContent(); + + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this._scrollable.update(); + this._scrollContentToLastMessageGroup(); } + _renderEmptyViewContent(): void { + const $emptyView = $('
') + .addClass(CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS); + + $('
') + .appendTo($emptyView) + .addClass(CHAT_MESSAGE_LIST_EMPTY_IMAGE_CLASS); + + const messageText = messageLocalization.format('dxChat-emptyListMessage'); + $('
') + .appendTo($emptyView) + .addClass(CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS) + .text(messageText); + + const promptText = messageLocalization.format('dxChat-emptyListPrompt'); + $('
') + .appendTo($emptyView) + .addClass(CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS) + .text(promptText); + + $emptyView.appendTo(this._scrollable.content()); + } + + _removeEmptyView(): void { + $(this._scrollable.content()).empty(); + } + + _toggleEmptyStateClass(state: boolean): void { + this.$element().toggleClass(CHAT_MESSAGE_LIST_EMPTY_CLASS, state); + } + + _isEmpty(): boolean { + const { items } = this.option(); + + return items.length === 0; + } + _isCurrentUser(id: string | number | undefined): boolean { const { currentUserId } = this.option(); @@ -60,8 +105,7 @@ class MessageList extends Widget { } _createMessageGroupComponent(items: Message[], userId: string | number | undefined): void { - const $messageGroupContainer = this._scrollable ? this._scrollable.content() : this._$content; - const $messageGroup = $('
').appendTo($messageGroupContainer); + const $messageGroup = $('
').appendTo(this._scrollable.content()); const messageGroup = this._createComponent($messageGroup, MessageGroup, { items, @@ -72,21 +116,24 @@ class MessageList extends Widget { } _renderScrollable(): void { - this._scrollable = this._createComponent(this._$content, Scrollable, { + const $scrollable = $('
') + .appendTo(this.$element()); + + this._scrollable = this._createComponent($scrollable, Scrollable, { useNative: true, }); } _renderMessageListContent(): void { - const { items } = this.option(); + if (this._isEmpty()) { + this._toggleEmptyStateClass(true); + this._renderEmptyViewContent(); - this._$content = $('
') - .appendTo(this.$element()); - - if (!items?.length) { return; } + const { items } = this.option(); + let currentMessageGroupUserId = items[0]?.author?.id; let currentMessageGroupItems: Message[] = []; @@ -111,11 +158,9 @@ class MessageList extends Widget { }); } - _renderMessage(message: Message, newItems: Message[]): void { + _renderMessage(message: Message): void { const sender = message.author; - this._setOptionWithoutOptionChange('items', newItems); - const lastMessageGroup = this._messageGroups?.[this._messageGroups.length - 1]; if (lastMessageGroup) { @@ -142,12 +187,11 @@ class MessageList extends Widget { const lastMessageGroup = this._messageGroups[this._messageGroups.length - 1]; const element = lastMessageGroup.$element()[0]; - this._scrollable?.scrollToElement(element); + this._scrollable.scrollToElement(element); } _clean(): void { this._messageGroups = []; - this._scrollable = undefined; super._clean(); } @@ -179,9 +223,15 @@ class MessageList extends Widget { if (shouldItemsBeUpdatedCompletely) { this._invalidate(); } else { + this._toggleEmptyStateClass(false); + + if (!previousValue.length) { + this._removeEmptyView(); + } + const newMessage = value[value.length - 1]; - this._renderMessage(newMessage ?? {}, value); + this._renderMessage(newMessage ?? {}); } } diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.markup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.markup.tests.js index 7ade906c8e63..93fa635d87e8 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.markup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/messageList.markup.tests.js @@ -4,6 +4,14 @@ import MessageList from '__internal/ui/chat/chat_message_list'; const CHAT_MESSAGE_LIST_CLASS = 'dx-chat-message-list'; const SCROLLABLE_CLASS = 'dx-scrollable'; +const SCROLLABLE_CONTENT_CLASS = 'dx-scrollable-content'; + +const CHAT_MESSAGE_LIST_EMPTY_CLASS = 'dx-chat-message-list-empty'; +const CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS = 'dx-chat-empty-view'; +const CHAT_MESSAGE_LIST_EMPTY_IMAGE_CLASS = 'dx-chat-empty-image'; +const CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS = 'dx-chat-empty-message'; +const CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS = 'dx-chat-empty-prompt'; + const moduleConfig = { beforeEach: function() { @@ -26,13 +34,87 @@ const moduleConfig = { }; QUnit.module('MessageList', moduleConfig, () => { - QUnit.module('Classes', moduleConfig, () => { - QUnit.test('root element should have correct class', function(assert) { + QUnit.module('Root element', () => { + QUnit.test('should have correct class', function(assert) { assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_CLASS), true); }); - QUnit.test('root element should contain scrollable element', function(assert) { + QUnit.test('should contain scrollable element', function(assert) { assert.strictEqual(this.$element.children().first().hasClass(SCROLLABLE_CLASS), true); }); + + QUnit.test('should have empty class if there are no messages', function(assert) { + assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_EMPTY_CLASS), true); + }); + + QUnit.test('should not have empty class if there are messages', function(assert) { + this.reinit({ + items: [{}] + }); + + assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_EMPTY_CLASS), false); + }); + + QUnit.test('empty class should be updated after items are added or removed at runtime', function(assert) { + this.reinit({ + items: [] + }); + + assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_EMPTY_CLASS), true, 'element has empty class'); + + this.instance.option('items', [{}]); + + assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_EMPTY_CLASS), false, 'element does not have empty class'); + + this.instance.option('items', []); + + assert.strictEqual(this.$element.hasClass(CHAT_MESSAGE_LIST_EMPTY_CLASS), true, 'element has empty class'); + }); + }); + + QUnit.module('Empty view', () => { + QUnit.test('element should be placed inside of a scrollable content', function(assert) { + assert.strictEqual(this.$element.find(`.${SCROLLABLE_CONTENT_CLASS}`).children().first().hasClass(CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS), true); + }); + + QUnit.test('container should be rendered if there are no messages', function(assert) { + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`).length, 1); + }); + + QUnit.test('container should not be rendered if there are messages', function(assert) { + this.reinit({ + items: [{}] + }); + + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`).length, 0); + }); + + QUnit.test('container should be removed or rendered after items are updated at runtime', function(assert) { + this.instance.option('items', [{}]); + + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`).length, 0); + + this.instance.option('items', []); + + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`).length, 1); + }); + + QUnit.test('image should be rendered inside empty view', function(assert) { + const $emptyView = this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`); + + assert.strictEqual($emptyView.find(`.${CHAT_MESSAGE_LIST_EMPTY_IMAGE_CLASS}`).length, 1); + }); + + QUnit.test('message should be rendered inside empty view', function(assert) { + const $emptyView = this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`); + + assert.strictEqual($emptyView.find(`.${CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS}`).length, 1); + }); + + QUnit.test('prompt should be rendered inside empty view', function(assert) { + const $emptyView = this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_VIEW_CLASS}`); + + assert.strictEqual($emptyView.find(`.${CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS}`).length, 1); + }); }); }); 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 b2a8dcd963d3..22c7af466b23 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 @@ -10,9 +10,14 @@ import { MOCK_CURRENT_USER_ID, } from './chat.tests.js'; import MessageGroup from '__internal/ui/chat/chat_message_group'; +import localization from 'localization'; const CHAT_MESSAGE_GROUP_CLASS = 'dx-chat-message-group'; const CHAT_MESSAGE_BUBBLE_CLASS = 'dx-chat-message-bubble'; + +const CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS = 'dx-chat-empty-message'; +const CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS = 'dx-chat-empty-prompt'; + const SCROLLABLE_CLASS = 'dx-scrollable'; @@ -427,6 +432,32 @@ QUnit.module('MessageList', moduleConfig, () => { }); }); }); + + QUnit.module('localization', moduleConfig, () => { + QUnit.test('message, prompt texts should be equal custom localized values from the dictionary', function(assert) { + const defaultLocale = localization.locale(); + + const localizedEmptyListMessageText = '空のテキスト'; + const localizedEmptyListPromptText = '空のプロンプト'; + + try { + localization.loadMessages({ + 'ja': { + 'dxChat-emptyListMessage': localizedEmptyListMessageText, + 'dxChat-emptyListPrompt': localizedEmptyListPromptText + } + }); + localization.locale('ja'); + + this.reinit(); + + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_MESSAGE_CLASS}`).text(), localizedEmptyListMessageText, 'emptyListMessage'); + assert.strictEqual(this.$element.find(`.${CHAT_MESSAGE_LIST_EMPTY_PROMPT_CLASS}`).text(), localizedEmptyListPromptText, 'emptyListPrompt'); + } finally { + localization.locale(defaultLocale); + } + }); + }); });