From 17587d8a0cd969adf70150017f0fe859fb40eb93 Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Sun, 15 Dec 2019 23:53:04 +0530 Subject: [PATCH] [Enhancement] Group widget messages by users (#367) * Remove thumbnail * Show grouped messages --- .rubocop.yml | 1 + .../dashboard/assets/scss/_woot.scss | 1 - .../assets/scss/widgets/_thumbnail.scss | 18 ------ .../components/widgets/Thumbnail.vue | 24 +++++++ .../widget/components/AgentMessage.vue | 56 +++++++++-------- .../widget/components/ChatMessage.vue | 12 +++- .../widget/components/ConversationWrap.vue | 11 ++-- .../widget/components/UserMessage.vue | 6 -- .../widget/store/modules/conversation.js | 28 ++++++++- .../specs/conversation/getters.spec.js | 62 +++++++++++-------- app/models/user.rb | 12 +++- config/environments/development.rb | 3 +- config/environments/production.rb | 16 ++--- config/environments/staging.rb | 2 + config/environments/test.rb | 1 + 15 files changed, 157 insertions(+), 96 deletions(-) delete mode 100644 app/javascript/dashboard/assets/scss/widgets/_thumbnail.scss diff --git a/.rubocop.yml b/.rubocop.yml index b2fa0de3a..3f3bb3e83 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -39,3 +39,4 @@ AllCops: - vendor/**/* - node_modules/**/* - lib/tasks/auto_annotate_models.rake + - config/environments/**/* diff --git a/app/javascript/dashboard/assets/scss/_woot.scss b/app/javascript/dashboard/assets/scss/_woot.scss index 3fcb0c2e2..c85012e9f 100644 --- a/app/javascript/dashboard/assets/scss/_woot.scss +++ b/app/javascript/dashboard/assets/scss/_woot.scss @@ -21,7 +21,6 @@ @import 'widgets/states'; @import 'widgets/status-bar'; @import 'widgets/tabs'; -@import 'widgets/thumbnail'; @import 'widgets/woot-tables'; @import 'views/settings/inbox'; diff --git a/app/javascript/dashboard/assets/scss/widgets/_thumbnail.scss b/app/javascript/dashboard/assets/scss/widgets/_thumbnail.scss deleted file mode 100644 index 6a6533780..000000000 --- a/app/javascript/dashboard/assets/scss/widgets/_thumbnail.scss +++ /dev/null @@ -1,18 +0,0 @@ -.user-thumbnail-box { - @include flex-shrink; - position: relative; - - .user-thumbnail { - border-radius: 50%; - height: 100%; - width: 100%; - } - - .source-badge { - bottom: -$space-micro / 2; - height: $space-slab; - position: absolute; - right: $zero; - width: $space-slab; - } -} diff --git a/app/javascript/dashboard/components/widgets/Thumbnail.vue b/app/javascript/dashboard/components/widgets/Thumbnail.vue index 5d0185380..ac6653cfc 100644 --- a/app/javascript/dashboard/components/widgets/Thumbnail.vue +++ b/app/javascript/dashboard/components/widgets/Thumbnail.vue @@ -76,3 +76,27 @@ export default { }, }; + + diff --git a/app/javascript/widget/components/AgentMessage.vue b/app/javascript/widget/components/AgentMessage.vue index c6ece7945..dbb1c07f9 100755 --- a/app/javascript/widget/components/AgentMessage.vue +++ b/app/javascript/widget/components/AgentMessage.vue @@ -1,31 +1,38 @@ @@ -35,10 +42,10 @@ export default { @import '~widget/assets/scss/variables.scss'; .conversation-wrap { .agent-message { + align-items: flex-end; display: flex; flex-direction: row; justify-content: flex-start; - align-items: flex-end; margin: 0 0 $space-micro $space-small; max-width: 88%; @@ -48,14 +55,6 @@ export default { .chat-bubble { border-top-left-radius: $space-smaller; } - - .user-avatar { - visibility: hidden; - } - - .agent-name { - display: none; - } } & + .user-message { @@ -63,23 +62,28 @@ export default { } .avatar-wrap { - flex-shrink: 1; - flex-grow: 0; + height: $space-medium; + width: $space-medium; + + .user-thumbnail-box { + margin-top: -$space-large; + } } .message-wrap { - max-width: 90%; - flex-shrink: 0; flex-grow: 1; + flex-shrink: 0; margin-left: $space-small; - - .agent-name { - font-weight: $font-weight-medium; - margin-bottom: $space-smaller; - margin-left: $space-two; - color: $color-body; - } + max-width: 90%; } } + + .agent-name { + color: $color-body; + font-size: $font-size-default; + font-weight: $font-weight-medium; + margin-bottom: $space-small; + margin-top: $space-small; + } } diff --git a/app/javascript/widget/components/ChatMessage.vue b/app/javascript/widget/components/ChatMessage.vue index 9a23f1458..7be15da31 100755 --- a/app/javascript/widget/components/ChatMessage.vue +++ b/app/javascript/widget/components/ChatMessage.vue @@ -4,7 +4,13 @@ :message="message.content" :status="message.status" /> - + diff --git a/app/javascript/widget/components/ConversationWrap.vue b/app/javascript/widget/components/ConversationWrap.vue index 51c978471..fbd37fd81 100755 --- a/app/javascript/widget/components/ConversationWrap.vue +++ b/app/javascript/widget/components/ConversationWrap.vue @@ -4,10 +4,10 @@
-
- +
+ @@ -33,7 +33,7 @@ export default { Spinner, }, props: { - groupedMessages: Object, + groupedMessages: Array, }, data() { return { @@ -48,9 +48,6 @@ export default { isFetchingList: 'conversation/getIsFetchingList', conversationSize: 'conversation/getConversationSize', }), - conversationDates() { - return Object.keys(this.groupedMessages); - }, }, watch: { allMessagesLoaded() { diff --git a/app/javascript/widget/components/UserMessage.vue b/app/javascript/widget/components/UserMessage.vue index e6cebc8e2..cf59feab0 100755 --- a/app/javascript/widget/components/UserMessage.vue +++ b/app/javascript/widget/components/UserMessage.vue @@ -43,12 +43,6 @@ export default { .chat-bubble { border-top-right-radius: $space-smaller; } - .user-avatar { - visibility: hidden; - } - .agent-name { - display: none; - } } & + .agent-message { margin-top: $space-normal; diff --git a/app/javascript/widget/store/modules/conversation.js b/app/javascript/widget/store/modules/conversation.js index 8a334e4a4..c38f52471 100755 --- a/app/javascript/widget/store/modules/conversation.js +++ b/app/javascript/widget/store/modules/conversation.js @@ -45,9 +45,33 @@ export const getters = { return {}; }, getGroupedConversation: _state => { - return groupBy(Object.values(_state.conversations), message => - new DateHelper(message.created_at).format() + const conversationGroupedByDate = groupBy( + Object.values(_state.conversations), + message => new DateHelper(message.created_at).format() ); + + return Object.keys(conversationGroupedByDate).map(date => { + const messages = conversationGroupedByDate[date].map((message, index) => { + let showAvatar = false; + if (index === conversationGroupedByDate[date].length - 1) { + showAvatar = true; + } else { + const nextMessage = conversationGroupedByDate[date][index + 1]; + const currentSender = message.sender ? message.sender.name : ''; + const nextSender = nextMessage.sender ? nextMessage.sender.name : ''; + showAvatar = currentSender !== nextSender; + } + return { + showAvatar, + ...message, + }; + }); + + return { + date, + messages, + }; + }); }, getIsFetchingList: _state => _state.uiFlags.isFetchingList, }; diff --git a/app/javascript/widget/store/modules/specs/conversation/getters.spec.js b/app/javascript/widget/store/modules/specs/conversation/getters.spec.js index 2efd3b185..57efafa19 100644 --- a/app/javascript/widget/store/modules/specs/conversation/getters.spec.js +++ b/app/javascript/widget/store/modules/specs/conversation/getters.spec.js @@ -79,31 +79,41 @@ describe('#getters', () => { }, }, }; - expect(getters.getGroupedConversation(state)).toEqual({ - 'Nov 18, 2019': [ - { - id: 1, - content: 'Thanks for the help', - created_at: 1574075964, - }, - { - id: 2, - content: 'Yes, It makes sense', - created_at: 1574092218, - }, - ], - 'Dec 14, 2019': [ - { - id: 3, - content: 'Hey', - created_at: 1576340623, - }, - { - id: 4, - content: 'How may I help you', - created_at: 1576340626, - }, - ], - }); + expect(getters.getGroupedConversation(state)).toEqual([ + { + date: 'Nov 18, 2019', + messages: [ + { + id: 1, + content: 'Thanks for the help', + created_at: 1574075964, + showAvatar: false, + }, + { + id: 2, + content: 'Yes, It makes sense', + created_at: 1574092218, + showAvatar: true, + }, + ], + }, + { + date: 'Dec 14, 2019', + messages: [ + { + id: 3, + content: 'Hey', + created_at: 1576340623, + showAvatar: false, + }, + { + id: 4, + content: 'How may I help you', + created_at: 1576340626, + showAvatar: true, + }, + ], + }, + ]); }); }); diff --git a/app/models/user.rb b/app/models/user.rb index 376be9567..75a73a479 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -47,6 +47,7 @@ class User < ApplicationRecord include DeviseTokenAuth::Concerns::User include Events::Types include Pubsubable + include Rails.application.routes.url_helpers devise :database_authenticatable, :registerable, @@ -103,9 +104,18 @@ class User < ApplicationRecord Rails.configuration.dispatcher.dispatch(AGENT_REMOVED, Time.zone.now, account: account) end + def avatar_url + if avatar.attached? && avatar.representable? + url_for(avatar.representation(resize: '250x250')) + else + '' + end + end + def push_event_data { - name: name + name: name, + avatar_url: avatar_url } end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 798264da8..6e70ff0b2 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -40,6 +40,8 @@ Rails.application.configure do config.action_mailer.delivery_method = :letter_opener config.action_mailer.perform_deliveries = true + Rails.application.routes.default_url_options = { host: 'localhost', port: 3000 } + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log @@ -67,7 +69,6 @@ Rails.application.configure do # Disable host check during development config.hosts = nil - # Bullet configuration to fix the N+1 queries config.after_initialize do Bullet.enable = true diff --git a/config/environments/production.rb b/config/environments/production.rb index 5ce971b5a..d88c78c1b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -56,16 +56,18 @@ Rails.application.configure do # config.active_job.queue_name_prefix = "chatwoot_production" config.action_mailer.perform_caching = false - config.action_mailer.default_url_options = { :host => ENV['FRONTEND_URL'] } + config.action_mailer.default_url_options = { host: ENV['FRONTEND_URL'] } config.action_mailer.smtp_settings = { - :address => ENV['SMTP_ADDRESS'], - :port => 587, - :user_name => ENV["SMTP_USERNAME"], - :password => ENV["SMTP_PASSWORD"], - :authentication => :login, - :enable_starttls_auto => true + address: ENV['SMTP_ADDRESS'], + port: 587, + user_name: ENV['SMTP_USERNAME'], + password: ENV['SMTP_PASSWORD'], + authentication: :login, + enable_starttls_auto: true } + Rails.application.routes.default_url_options = { host: ENV['FRONTEND_URL'] } + # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 24023448b..61e262c32 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -66,6 +66,8 @@ Rails.application.configure do enable_starttls_auto: true } + Rails.application.routes.default_url_options = { host: ENV['FRONTEND_URL'] } + # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 24ba068af..d34f78668 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -21,6 +21,7 @@ Rails.application.configure do 'Cache-Control' => "public, max-age=#{1.hour.to_i}" } config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } + Rails.application.routes.default_url_options = { host: 'localhost', port: 3000 } # Show full error reports and disable caching. config.consider_all_requests_local = true