From 3d2db9541796223924d944e32a271425631a514a Mon Sep 17 00:00:00 2001 From: Nithin David Thomas Date: Wed, 6 Jan 2021 17:56:29 +0530 Subject: [PATCH] feat: Add preview for attachment messages (#1562) Add preview for pending messages and attachments Co-authored-by: Pranav Raj S --- app/javascript/dashboard/api/inbox/message.js | 28 +- app/javascript/dashboard/assets/scss/app.scss | 1 + .../scss/widgets/_conversation-view.scss | 40 +-- .../components/widgets/AttachmentsPreview.vue | 137 ++++++++++ .../widgets/conversation/Message.vue | 40 ++- .../widgets/conversation/ReplyBox.vue | 239 ++++++++++-------- .../widgets/conversation/bubble/Text.vue | 4 +- app/javascript/dashboard/helper/commons.js | 26 +- app/javascript/dashboard/helper/files.js | 11 + .../dashboard/helper/specs/commons.spec.js | 36 +-- .../dashboard/helper/specs/files.spec.js | 18 ++ .../store/modules/conversations/actions.js | 19 +- .../assets/stylesheets/border-radius.scss | 7 + .../widget/components/AgentMessage.vue | 18 +- app/javascript/widget/views/Unread.vue | 12 +- .../facebook/send_on_facebook_service.rb | 32 +-- .../facebook/send_on_facebook_service_spec.rb | 16 +- 17 files changed, 434 insertions(+), 250 deletions(-) create mode 100644 app/javascript/dashboard/components/widgets/AttachmentsPreview.vue create mode 100644 app/javascript/dashboard/helper/files.js create mode 100644 app/javascript/dashboard/helper/specs/files.spec.js create mode 100644 app/javascript/shared/assets/stylesheets/border-radius.scss diff --git a/app/javascript/dashboard/api/inbox/message.js b/app/javascript/dashboard/api/inbox/message.js index f745febfe..0020a4138 100644 --- a/app/javascript/dashboard/api/inbox/message.js +++ b/app/javascript/dashboard/api/inbox/message.js @@ -13,24 +13,14 @@ class MessageApi extends ApiClient { private: isPrivate, contentAttributes, echo_id: echoId, + file, }) { - return axios.post(`${this.url}/${conversationId}/messages`, { - content: message, - private: isPrivate, - echo_id: echoId, - content_attributes: contentAttributes, - }); - } - - getPreviousMessages({ conversationId, before }) { - return axios.get(`${this.url}/${conversationId}/messages`, { - params: { before }, - }); - } - - sendAttachment([conversationId, { file, isPrivate = false }, echoId]) { const formData = new FormData(); - formData.append('attachments[]', file, file.name); + if (file) formData.append('attachments[]', file, file.name); + if (message) formData.append('content', message); + if (contentAttributes) + formData.append('content_attributes', JSON.stringify(contentAttributes)); + formData.append('private', isPrivate); formData.append('echo_id', echoId); return axios({ @@ -39,6 +29,12 @@ class MessageApi extends ApiClient { data: formData, }); } + + getPreviousMessages({ conversationId, before }) { + return axios.get(`${this.url}/${conversationId}/messages`, { + params: { before }, + }); + } } export default new MessageApi(); diff --git a/app/javascript/dashboard/assets/scss/app.scss b/app/javascript/dashboard/assets/scss/app.scss index 55ca67aa1..f1c317e27 100644 --- a/app/javascript/dashboard/assets/scss/app.scss +++ b/app/javascript/dashboard/assets/scss/app.scss @@ -3,6 +3,7 @@ @import 'shared/assets/stylesheets/spacing'; @import 'shared/assets/stylesheets/font-size'; @import 'shared/assets/stylesheets/font-weights'; +@import 'shared/assets/stylesheets/border-radius'; @import 'variables'; @import '~spinkit/scss/spinners/7-three-bounce'; diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss index 28d150d80..44e6d3488 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-view.scss @@ -18,13 +18,6 @@ } } - .message-text { - &::after { - content: ' \00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0'; - display: inline; - } - } - .image { cursor: pointer; position: relative; @@ -201,6 +194,10 @@ color: $color-body; margin-right: auto; + &.is-image { + border-radius: var(--border-radius-large); + } + .link { color: $color-primary-dark; } @@ -257,6 +254,10 @@ top: $space-smaller + $space-micro; } } + + &.is-image { + border-radius: var(--border-radius-large); + } } +.left { @@ -296,30 +297,9 @@ border-radius: $space-smaller; font-size: $font-size-small; - p { - color: $color-heading; - margin-bottom: $zero; - - .ion-person { - color: $color-body; - font-size: $font-size-default; - margin-right: $space-small; - position: relative; - top: $space-micro; - } - - .message-text__wrap { - position: relative; - } - - .message-text { - &::after { - content: ' \00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0\00a0'; - display: inline; - } - } + .message-text__wrap { + display: inline-block; } - } } diff --git a/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue b/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue new file mode 100644 index 000000000..f8220db4d --- /dev/null +++ b/app/javascript/dashboard/components/widgets/AttachmentsPreview.vue @@ -0,0 +1,137 @@ + + + diff --git a/app/javascript/dashboard/components/widgets/conversation/Message.vue b/app/javascript/dashboard/components/widgets/conversation/Message.vue index 4d0cf589e..7323e3d22 100644 --- a/app/javascript/dashboard/components/widgets/conversation/Message.vue +++ b/app/javascript/dashboard/components/widgets/conversation/Message.vue @@ -14,8 +14,8 @@ > {{ $t('CONVERSATION.UPLOADING_ATTACHMENTS') }} - - +
+
- - +
+
diff --git a/app/javascript/dashboard/components/widgets/conversation/bubble/Text.vue b/app/javascript/dashboard/components/widgets/conversation/bubble/Text.vue index 1a8c44a6f..2ffa700cb 100644 --- a/app/javascript/dashboard/components/widgets/conversation/bubble/Text.vue +++ b/app/javascript/dashboard/components/widgets/conversation/bubble/Text.vue @@ -1,7 +1,7 @@ @@ -213,6 +223,10 @@ export default { .has-attachment { padding: 0; overflow: hidden; + + &.has-text { + margin-top: $space-smaller; + } } .agent-message-wrap { diff --git a/app/javascript/widget/views/Unread.vue b/app/javascript/widget/views/Unread.vue index fcedad401..70e9c26b3 100644 --- a/app/javascript/widget/views/Unread.vue +++ b/app/javascript/widget/views/Unread.vue @@ -15,7 +15,7 @@ v-for="message in unreadMessages" :key="message.id" :message-id="message.id" - :message="message.content" + :message="getMessageContent(message)" />
@@ -88,6 +88,16 @@ export default { }); } }, + getMessageContent(message) { + const { attachments, content } = message; + const hasAttachments = attachments && attachments.length; + + if (content) return content; + + if (hasAttachments) return `📑`; + + return ''; + }, }, }; diff --git a/app/services/facebook/send_on_facebook_service.rb b/app/services/facebook/send_on_facebook_service.rb index fdb6d1069..b8102c6fa 100644 --- a/app/services/facebook/send_on_facebook_service.rb +++ b/app/services/facebook/send_on_facebook_service.rb @@ -6,13 +6,18 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService end def perform_reply - result = FacebookBot::Bot.deliver(delivery_params, access_token: message.channel_token) - message.update!(source_id: JSON.parse(result)['message_id']) + send_message_to_facebook fb_text_message_params if message.content.present? + send_message_to_facebook fb_attachment_message_params if message.attachments.present? rescue Facebook::Messenger::FacebookError => e Rails.logger.info e channel.authorization_error! end + def send_message_to_facebook(delivery_params) + result = FacebookBot::Bot.deliver(delivery_params, access_token: message.channel_token) + message.update!(source_id: JSON.parse(result)['message_id']) + end + def fb_text_message_params { recipient: { id: contact.get_source_id(inbox.id) }, @@ -49,29 +54,6 @@ class Facebook::SendOnFacebookService < Base::SendOnChannelService end end - def delivery_params - if twenty_four_hour_window_over? - fb_message_params.merge(tag: 'ISSUE_RESOLUTION') - else - fb_message_params - end - end - - def twenty_four_hour_window_over? - return false unless after_24_hours? - return false if last_incoming_and_outgoing_message_after_one_day? - - true - end - - def last_incoming_and_outgoing_message_after_one_day? - last_incoming_message && sent_first_outgoing_message_after_24_hours? - end - - def after_24_hours? - (Time.current - last_incoming_message.created_at) / 3600 >= 24 - end - def sent_first_outgoing_message_after_24_hours? # we can send max 1 message after 24 hour window conversation.messages.outgoing.where('id > ?', last_incoming_message.id).count == 1 diff --git a/spec/services/facebook/send_on_facebook_service_spec.rb b/spec/services/facebook/send_on_facebook_service_spec.rb index a972a8973..e84319a26 100644 --- a/spec/services/facebook/send_on_facebook_service_spec.rb +++ b/spec/services/facebook/send_on_facebook_service_spec.rb @@ -58,7 +58,21 @@ describe Facebook::SendOnFacebookService do attachment.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png') message.save! ::Facebook::SendOnFacebookService.new(message: message).perform - expect(bot).to have_received(:deliver) + expect(bot).to have_received(:deliver).with({ + recipient: { id: contact_inbox.source_id }, + message: { text: message.content } + }, { access_token: facebook_channel.page_access_token }) + expect(bot).to have_received(:deliver).with({ + recipient: { id: contact_inbox.source_id }, + message: { + attachment: { + type: 'image', + payload: { + url: attachment.file_url + } + } + } + }, { access_token: facebook_channel.page_access_token }) end end end