From 16fe912fbdef3a1f0d5569aed39a80f4d7de9a4e Mon Sep 17 00:00:00 2001
From: Pranav Raj S
Date: Tue, 29 Oct 2019 12:50:54 +0530
Subject: [PATCH] [Feature] Website live chat (#187)
Co-authored-by: Nithin David Thomas
Co-authored-by: Sojan Jose
---
.scss-lint.yml | 4 +
Gemfile | 2 +
Gemfile.lock | 2 +
.../api/v1/widget/inboxes_controller.rb | 26 +++
.../api/v1/widget/messages_controller.rb | 74 ++++++--
app/controllers/widgets_controller.rb | 47 +++++
app/finders/message_finder.rb | 10 +-
.../dashboard/api/channel/webChannel.js | 9 +
.../assets/images/channels/website.png | Bin 0 -> 6037 bytes
.../assets/scss/_foundation-custom.scss | 11 ++
.../dashboard/components/ChatList.vue | 2 +-
.../components/layout/SidebarItem.vue | 2 +-
.../components/widgets/ChannelItem.vue | 52 ++++--
app/javascript/dashboard/constants.js | 3 -
.../dashboard/helper/actionCable.js | 23 +--
.../dashboard/i18n/locale/en/inboxMgmt.json | 13 ++
.../dashboard/settings/inbox/ChannelList.vue | 22 +--
.../routes/dashboard/settings/inbox/Index.vue | 9 +-
.../dashboard/settings/inbox/Settings.vue | 34 +++-
.../settings/inbox/channel-factory.js | 26 +--
.../inbox/{ => channels}/Facebook.vue | 9 +-
.../settings/inbox/channels/Website.vue | 83 +++++++++
.../dashboard/store/modules/sidebar.js | 17 +-
app/javascript/packs/application.js | 7 +
app/javascript/packs/sdk.js | 160 ++++++++++++++++++
app/javascript/packs/widget.js | 19 +++
.../helpers/BaseActionCableConnector.js | 26 +++
app/javascript/widget/App.vue | 25 +++
app/javascript/widget/api/auth.js | 12 ++
app/javascript/widget/api/conversation.js | 16 ++
app/javascript/widget/api/endPoints.js | 17 ++
.../widget/assets/images/defaultUser.png | Bin 0 -> 3856 bytes
.../widget/assets/images/message-send.svg | 11 ++
app/javascript/widget/assets/images/send.png | Bin 0 -> 1795 bytes
.../widget/assets/scss/_buttons.scss | 57 +++++++
app/javascript/widget/assets/scss/_forms.scss | 71 ++++++++
.../widget/assets/scss/_mixins.scss | 20 +++
app/javascript/widget/assets/scss/_reset.scss | 54 ++++++
.../widget/assets/scss/_variables.scss | 90 ++++++++++
app/javascript/widget/assets/scss/sdk.css | 65 +++++++
app/javascript/widget/assets/scss/woot.scss | 16 ++
.../widget/components/AgentMessage.vue | 83 +++++++++
.../widget/components/AgentMessageBubble.vue | 27 +++
.../widget/components/ChatFooter.vue | 33 ++++
.../widget/components/ChatHeaderExpanded.vue | 51 ++++++
.../widget/components/ChatInputArea.vue | 29 ++++
.../widget/components/ChatInputWrap.vue | 65 +++++++
.../widget/components/ChatMessage.vue | 38 +++++
.../widget/components/ChatSendButton.vue | 63 +++++++
.../widget/components/ConversationWrap.vue | 33 ++++
.../widget/components/HelloWorld.vue | 31 ++++
app/javascript/widget/components/Spinner.vue | 52 ++++++
.../widget/components/UserAvatar.vue | 46 +++++
.../widget/components/UserMessage.vue | 55 ++++++
.../widget/components/UserMessageBubble.vue | 36 ++++
app/javascript/widget/helpers/actionCable.js | 16 ++
app/javascript/widget/helpers/axios.js | 15 ++
app/javascript/widget/helpers/constants.js | 12 ++
app/javascript/widget/helpers/utils.js | 10 ++
app/javascript/widget/router.js | 24 +++
app/javascript/widget/store/index.js | 11 ++
.../widget/store/modules/conversation.js | 60 +++++++
app/javascript/widget/views/About.vue | 5 +
app/javascript/widget/views/Home.vue | 78 +++++++++
app/listeners/action_cable_listener.rb | 8 +
app/models/account.rb | 1 +
app/models/channel/web_widget.rb | 17 ++
app/views/api/v1/inboxes/index.json.jbuilder | 1 +
.../v1/widget/messages/index.json.jbuilder | 9 +
app/views/layouts/vueapp.html.erb | 2 +-
app/views/widgets/index.html.erb | 18 ++
config/application.rb | 4 +
config/routes.rb | 10 +-
config/webpack/development.js | 4 -
config/webpack/environment.js | 5 +
config/webpack/resolve.js | 1 +
...4062958_add_website_token_to_web_widget.rb | 6 +
db/schema.rb | 3 +-
package.json | 4 +-
yarn.lock | 34 +++-
80 files changed, 2040 insertions(+), 106 deletions(-)
create mode 100644 app/controllers/api/v1/widget/inboxes_controller.rb
create mode 100644 app/controllers/widgets_controller.rb
create mode 100644 app/javascript/dashboard/api/channel/webChannel.js
create mode 100644 app/javascript/dashboard/assets/images/channels/website.png
rename app/javascript/dashboard/routes/dashboard/settings/inbox/{ => channels}/Facebook.vue (96%)
create mode 100644 app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Website.vue
create mode 100755 app/javascript/packs/sdk.js
create mode 100644 app/javascript/packs/widget.js
create mode 100644 app/javascript/shared/helpers/BaseActionCableConnector.js
create mode 100755 app/javascript/widget/App.vue
create mode 100755 app/javascript/widget/api/auth.js
create mode 100755 app/javascript/widget/api/conversation.js
create mode 100755 app/javascript/widget/api/endPoints.js
create mode 100755 app/javascript/widget/assets/images/defaultUser.png
create mode 100755 app/javascript/widget/assets/images/message-send.svg
create mode 100755 app/javascript/widget/assets/images/send.png
create mode 100755 app/javascript/widget/assets/scss/_buttons.scss
create mode 100755 app/javascript/widget/assets/scss/_forms.scss
create mode 100755 app/javascript/widget/assets/scss/_mixins.scss
create mode 100755 app/javascript/widget/assets/scss/_reset.scss
create mode 100755 app/javascript/widget/assets/scss/_variables.scss
create mode 100644 app/javascript/widget/assets/scss/sdk.css
create mode 100755 app/javascript/widget/assets/scss/woot.scss
create mode 100755 app/javascript/widget/components/AgentMessage.vue
create mode 100755 app/javascript/widget/components/AgentMessageBubble.vue
create mode 100755 app/javascript/widget/components/ChatFooter.vue
create mode 100755 app/javascript/widget/components/ChatHeaderExpanded.vue
create mode 100755 app/javascript/widget/components/ChatInputArea.vue
create mode 100755 app/javascript/widget/components/ChatInputWrap.vue
create mode 100755 app/javascript/widget/components/ChatMessage.vue
create mode 100755 app/javascript/widget/components/ChatSendButton.vue
create mode 100755 app/javascript/widget/components/ConversationWrap.vue
create mode 100755 app/javascript/widget/components/HelloWorld.vue
create mode 100755 app/javascript/widget/components/Spinner.vue
create mode 100755 app/javascript/widget/components/UserAvatar.vue
create mode 100755 app/javascript/widget/components/UserMessage.vue
create mode 100755 app/javascript/widget/components/UserMessageBubble.vue
create mode 100644 app/javascript/widget/helpers/actionCable.js
create mode 100755 app/javascript/widget/helpers/axios.js
create mode 100755 app/javascript/widget/helpers/constants.js
create mode 100755 app/javascript/widget/helpers/utils.js
create mode 100755 app/javascript/widget/router.js
create mode 100755 app/javascript/widget/store/index.js
create mode 100755 app/javascript/widget/store/modules/conversation.js
create mode 100755 app/javascript/widget/views/About.vue
create mode 100755 app/javascript/widget/views/Home.vue
create mode 100644 app/views/api/v1/widget/messages/index.json.jbuilder
create mode 100644 app/views/widgets/index.html.erb
create mode 100644 db/migrate/20191024062958_add_website_token_to_web_widget.rb
diff --git a/.scss-lint.yml b/.scss-lint.yml
index 59284ef1c..215e9c49e 100644
--- a/.scss-lint.yml
+++ b/.scss-lint.yml
@@ -1,3 +1,7 @@
linters:
LeadingZero:
enabled: false
+
+exclude:
+ - 'app/javascript/widget/assets/scss/_reset.scss'
+ - 'app/javascript/widget/assets/scss/sdk.css'
diff --git a/Gemfile b/Gemfile
index 893be6119..1fb109bbb 100644
--- a/Gemfile
+++ b/Gemfile
@@ -53,6 +53,8 @@ gem 'telegram-bot-ruby'
gem 'twitter'
# facebook client
gem 'koala'
+# Random name generator
+gem 'haikunator'
##--- gems for debugging and error reporting ---##
# static analysis
diff --git a/Gemfile.lock b/Gemfile.lock
index 205747213..c74e87f2d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -192,6 +192,7 @@ GEM
foreman (0.86.0)
globalid (0.4.2)
activesupport (>= 4.2.0)
+ haikunator (1.1.0)
hashie (3.6.0)
http (3.3.0)
addressable (~> 2.3)
@@ -455,6 +456,7 @@ DEPENDENCIES
faker
figaro
foreman
+ haikunator
hashie
jbuilder (~> 2.5)
kaminari
diff --git a/app/controllers/api/v1/widget/inboxes_controller.rb b/app/controllers/api/v1/widget/inboxes_controller.rb
new file mode 100644
index 000000000..2e0269db0
--- /dev/null
+++ b/app/controllers/api/v1/widget/inboxes_controller.rb
@@ -0,0 +1,26 @@
+class Api::V1::Widget::InboxesController < ApplicationController
+ def create
+ ActiveRecord::Base.transaction do
+ channel = web_widgets.create!(
+ website_name: permitted_params[:website_name],
+ website_url: permitted_params[:website_url]
+ )
+ inbox = inboxes.create!(name: permitted_params[:website_name], channel: channel)
+ render json: inbox
+ end
+ end
+
+ private
+
+ def inboxes
+ current_account.inboxes
+ end
+
+ def web_widgets
+ current_account.web_widgets
+ end
+
+ def permitted_params
+ params.fetch(:website).permit(:website_name, :website_url)
+ end
+end
diff --git a/app/controllers/api/v1/widget/messages_controller.rb b/app/controllers/api/v1/widget/messages_controller.rb
index 8bc2cf446..662fd927e 100644
--- a/app/controllers/api/v1/widget/messages_controller.rb
+++ b/app/controllers/api/v1/widget/messages_controller.rb
@@ -1,28 +1,68 @@
-class Api::V1::Widget::MessagesController < ApplicationController
- # TODO: move widget apis to different controller.
- skip_before_action :set_current_user, only: [:create_incoming]
- skip_before_action :check_subscription, only: [:create_incoming]
- skip_around_action :handle_with_exception, only: [:create_incoming]
+class Api::V1::Widget::MessagesController < ActionController::Base
+ before_action :set_conversation, only: [:create]
- def create_incoming
- builder = Integrations::Widget::IncomingMessageBuilder.new(incoming_message_params)
- builder.perform
- render json: builder.message
+ def index
+ @messages = conversation.nil? ? [] : message_finder.perform
end
- def create_outgoing
- builder = Integrations::Widget::OutgoingMessageBuilder.new(outgoing_message_params)
- builder.perform
- render json: builder.message
+ def create
+ @message = conversation.messages.new(message_params)
+ @message.save!
end
private
- def incoming_message_params
- params.require(:message).permit(:contact_id, :inbox_id, :content)
+ def conversation
+ @conversation ||= ::Conversation.find_by(
+ contact_id: cookie_params[:contact_id],
+ inbox_id: cookie_params[:inbox_id]
+ )
end
- def outgoing_message_params
- params.require(:message).permit(:user_id, :inbox_id, :content, :conversation_id)
+ def set_conversation
+ @conversation = ::Conversation.create!(conversation_params) if conversation.nil?
+ end
+
+ def message_params
+ {
+ account_id: conversation.account_id,
+ inbox_id: conversation.inbox_id,
+ message_type: :incoming,
+ content: permitted_params[:content]
+ }
+ end
+
+ def conversation_params
+ {
+ account_id: inbox.account_id,
+ inbox_id: inbox.id,
+ contact_id: cookie_params[:contact_id]
+ }
+ end
+
+ def inbox
+ @inbox ||= ::Inbox.find_by(id: cookie_params[:inbox_id])
+ end
+
+ def cookie_params
+ JSON.parse(cookies.signed[cookie_name]).symbolize_keys
+ end
+
+ def message_finder_params
+ {
+ filter_internal_messages: true
+ }
+ end
+
+ def message_finder
+ @message_finder ||= MessageFinder.new(conversation, message_finder_params)
+ end
+
+ def cookie_name
+ 'cw_conversation_' + params[:website_token]
+ end
+
+ def permitted_params
+ params.fetch(:message).permit(:content)
end
end
diff --git a/app/controllers/widgets_controller.rb b/app/controllers/widgets_controller.rb
new file mode 100644
index 000000000..733e99df4
--- /dev/null
+++ b/app/controllers/widgets_controller.rb
@@ -0,0 +1,47 @@
+class WidgetsController < ActionController::Base
+ before_action :set_web_widget
+ before_action :set_contact
+ before_action :build_contact
+
+ private
+
+ def set_web_widget
+ @web_widget = ::Channel::WebWidget.find_by!(website_token: permitted_params[:website_token])
+ end
+
+ def set_contact
+ return if cookie_params[:source_id].nil?
+
+ contact_inbox = ::ContactInbox.find_by(
+ inbox_id: @web_widget.inbox.id,
+ source_id: cookie_params[:source_id]
+ )
+
+ @contact = contact_inbox.contact
+ end
+
+ def build_contact
+ return if @contact.present?
+
+ contact_inbox = @web_widget.create_contact_inbox
+ @contact = contact_inbox.contact
+
+ cookies.signed[cookie_name] = JSON.generate(
+ source_id: contact_inbox.source_id,
+ contact_id: @contact.id,
+ inbox_id: @web_widget.inbox.id
+ ).to_s
+ end
+
+ def cookie_params
+ cookies.signed[cookie_name] ? JSON.parse(cookies.signed[cookie_name]).symbolize_keys : {}
+ end
+
+ def permitted_params
+ params.permit(:website_token)
+ end
+
+ def cookie_name
+ 'cw_conversation_' + permitted_params[:website_token]
+ end
+end
diff --git a/app/finders/message_finder.rb b/app/finders/message_finder.rb
index bcac94418..e839e4946 100644
--- a/app/finders/message_finder.rb
+++ b/app/finders/message_finder.rb
@@ -10,11 +10,17 @@ class MessageFinder
private
+ def messages
+ return @conversation.messages if @params[:filter_internal_messages].blank?
+
+ @conversation.messages.where.not('private = ? OR message_type = ?', true, 2)
+ end
+
def current_messages
if @params[:before].present?
- @conversation.messages.reorder('created_at desc').where('id < ?', @params[:before]).limit(20).reverse
+ messages.reorder('created_at desc').where('id < ?', @params[:before]).limit(20).reverse
else
- @conversation.messages.reorder('created_at desc').limit(20).reverse
+ messages.reorder('created_at desc').limit(20).reverse
end
end
end
diff --git a/app/javascript/dashboard/api/channel/webChannel.js b/app/javascript/dashboard/api/channel/webChannel.js
new file mode 100644
index 000000000..7fc5fb2db
--- /dev/null
+++ b/app/javascript/dashboard/api/channel/webChannel.js
@@ -0,0 +1,9 @@
+import ApiClient from '../ApiClient';
+
+class WebChannel extends ApiClient {
+ constructor() {
+ super('widget/inboxes');
+ }
+}
+
+export default new WebChannel();
diff --git a/app/javascript/dashboard/assets/images/channels/website.png b/app/javascript/dashboard/assets/images/channels/website.png
new file mode 100644
index 0000000000000000000000000000000000000000..fdc909bc28d0c0bfc2f458085bed5f2a5af85e28
GIT binary patch
literal 6037
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
literal 0
HcmV?d00001
diff --git a/app/javascript/dashboard/assets/scss/_foundation-custom.scss b/app/javascript/dashboard/assets/scss/_foundation-custom.scss
index 0a70eaf89..f918ed97c 100644
--- a/app/javascript/dashboard/assets/scss/_foundation-custom.scss
+++ b/app/javascript/dashboard/assets/scss/_foundation-custom.scss
@@ -25,3 +25,14 @@
border-radius: $space-smaller;
font-size: $font-size-mini;
}
+
+code {
+ border: 0;
+ font-family: 'Monaco';
+ font-size: $font-size-mini;
+
+ &.hljs {
+ background: $color-background;
+ padding: $space-two;
+ }
+}
diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue
index 2b771a973..a996aae43 100644
--- a/app/javascript/dashboard/components/ChatList.vue
+++ b/app/javascript/dashboard/components/ChatList.vue
@@ -121,7 +121,7 @@ export default {
fetchData() {
if (this.chatLists.length === 0) {
this.$store.dispatch('fetchAllConversations', {
- inbox: this.conversationInbox,
+ inboxId: this.conversationInbox ? this.conversationInbox : undefined,
assigneeStatus: this.allMessageType,
convStatus: this.activeStatusTab,
});
diff --git a/app/javascript/dashboard/components/layout/SidebarItem.vue b/app/javascript/dashboard/components/layout/SidebarItem.vue
index c48998ba8..087467616 100644
--- a/app/javascript/dashboard/components/layout/SidebarItem.vue
+++ b/app/javascript/dashboard/components/layout/SidebarItem.vue
@@ -22,7 +22,7 @@
+
+ <%= yield %>
+
+
diff --git a/app/views/widgets/index.html.erb b/app/views/widgets/index.html.erb
new file mode 100644
index 000000000..83f7d3e4e
--- /dev/null
+++ b/app/views/widgets/index.html.erb
@@ -0,0 +1,18 @@
+
+
+