From 941fbb0d72f38804a9a61683d4e732836c9ddd72 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Sun, 19 Apr 2020 23:40:28 +0530 Subject: [PATCH] Chore: Web widget Inbox Tech Debts (#738) * Chore: Webwidget Inbox Tech Debts * Additional customization options creating Web Widget * Changes to edit Page for Web Widget * Remove the WebWidget API end points * Minor chores Address: #680, #502 Co-authored-by: Pranav Raj Sreepuram --- .scss-lint.yml | 2 +- .../api/v1/accounts/callbacks_controller.rb | 22 +- .../api/v1/accounts/inboxes_controller.rb | 25 +- .../v1/accounts/widget/inboxes_controller.rb | 48 --- .../twitter/authorizations_controller.rb | 2 +- .../twitter/callbacks_controller.rb | 3 +- .../dashboard/api/channel/webChannel.js | 2 +- .../assets/scss/views/settings/inbox.scss | 88 +++--- .../components/SettingsFormHeader.vue | 69 ----- .../dashboard/components/SettingsSection.vue | 46 +++ .../dashboard/i18n/locale/en/inboxMgmt.json | 18 +- .../dashboard/i18n/locale/en/signup.json | 2 +- .../dashboard/settings/inbox/Settings.vue | 286 +++++++++++++----- .../settings/inbox/channels/Facebook.vue | 3 +- .../settings/inbox/channels/Website.vue | 80 ++++- .../dashboard/store/modules/inboxes.js | 13 +- .../modules/specs/inboxes/actions.spec.js | 28 +- app/javascript/sdk/IFrameHelper.js | 2 +- app/javascript/widget/App.vue | 2 +- .../widget/components/ChatHeaderExpanded.vue | 10 +- .../widget/store/modules/appConfig.js | 2 +- app/javascript/widget/views/Home.vue | 12 +- app/models/channel/facebook_page.rb | 7 +- app/models/channel/twitter_profile.rb | 6 - app/models/channel/web_widget.rb | 23 +- app/models/notification_setting.rb | 4 +- .../register_facebook_page.json.jbuilder | 7 + .../{widget => }/inboxes/create.json.jbuilder | 4 + .../v1/accounts/inboxes/index.json.jbuilder | 7 +- .../v1/accounts/inboxes/update.json.jbuilder | 11 + .../widget/inboxes/update.json.jbuilder | 7 - app/views/widgets/show.html.erb | 8 +- config/routes.rb | 5 +- ...0200417093432_remove_name_from_channels.rb | 35 +++ db/schema.rb | 8 +- db/seeds.rb | 2 +- .../v1/accounts/callbacks_controller_spec.rb | 2 +- .../v1/accounts/inboxes_controller_spec.rb | 43 ++- .../widget/inboxes_controller_spec.rb | 79 ----- spec/factories/channel/channel_widget.rb | 1 - spec/factories/channel/facebook_pages.rb | 1 - spec/factories/channel/twitter_profiles.rb | 1 - spec/factories/facebook_page.rb | 11 - .../facebook/send_reply_service_spec.rb | 2 +- swagger/paths/{widget => }/inboxes/create.yml | 0 swagger/paths/widget/inboxes/update.yml | 28 -- 46 files changed, 564 insertions(+), 503 deletions(-) delete mode 100644 app/controllers/api/v1/accounts/widget/inboxes_controller.rb delete mode 100644 app/javascript/dashboard/components/SettingsFormHeader.vue create mode 100644 app/javascript/dashboard/components/SettingsSection.vue create mode 100644 app/views/api/v1/accounts/callbacks/register_facebook_page.json.jbuilder rename app/views/api/v1/accounts/{widget => }/inboxes/create.json.jbuilder (55%) create mode 100644 app/views/api/v1/accounts/inboxes/update.json.jbuilder delete mode 100644 app/views/api/v1/accounts/widget/inboxes/update.json.jbuilder create mode 100644 db/migrate/20200417093432_remove_name_from_channels.rb delete mode 100644 spec/controllers/api/v1/accounts/widget/inboxes_controller_spec.rb delete mode 100644 spec/factories/facebook_page.rb rename swagger/paths/{widget => }/inboxes/create.yml (100%) delete mode 100644 swagger/paths/widget/inboxes/update.yml diff --git a/.scss-lint.yml b/.scss-lint.yml index eeaac4c52..9f5f4fe10 100644 --- a/.scss-lint.yml +++ b/.scss-lint.yml @@ -252,7 +252,7 @@ linters: enabled: false UnnecessaryParentReference: - enabled: true + enabled: false UrlFormat: enabled: true diff --git a/app/controllers/api/v1/accounts/callbacks_controller.rb b/app/controllers/api/v1/accounts/callbacks_controller.rb index ab276ba29..bf42b215a 100644 --- a/app/controllers/api/v1/accounts/callbacks_controller.rb +++ b/app/controllers/api/v1/accounts/callbacks_controller.rb @@ -4,16 +4,18 @@ class Api::V1::Accounts::CallbacksController < Api::BaseController def register_facebook_page user_access_token = params[:user_access_token] page_access_token = params[:page_access_token] - page_name = params[:page_name] page_id = params[:page_id] inbox_name = params[:inbox_name] - facebook_channel = current_account.facebook_pages.create!( - name: page_name, page_id: page_id, user_access_token: user_access_token, - page_access_token: page_access_token - ) - set_avatar(facebook_channel, page_id) - inbox = current_account.inboxes.create!(name: inbox_name, channel: facebook_channel) - render json: inbox + ActiveRecord::Base.transaction do + facebook_channel = current_account.facebook_pages.create!( + page_id: page_id, user_access_token: user_access_token, + page_access_token: page_access_token + ) + @facebook_inbox = current_account.inboxes.create!(name: inbox_name, channel: facebook_channel) + set_avatar(@facebook_inbox, page_id) + rescue StandardError => e + Rails.logger e + end end def facebook_pages @@ -72,13 +74,13 @@ class Api::V1::Accounts::CallbacksController < Api::BaseController end end - def set_avatar(facebook_channel, page_id) + def set_avatar(facebook_inbox, page_id) uri = get_avatar_url(page_id) return unless uri avatar_resource = LocalResource.new(uri) - facebook_channel.avatar.attach(io: avatar_resource.file, filename: avatar_resource.tmp_filename, content_type: avatar_resource.encoding) + facebook_inbox.avatar.attach(io: avatar_resource.file, filename: avatar_resource.tmp_filename, content_type: avatar_resource.encoding) end def get_avatar_url(page_id) diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index 6a3f9d5cc..4b3ed836e 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -1,14 +1,24 @@ class Api::V1::Accounts::InboxesController < Api::BaseController before_action :check_authorization - before_action :fetch_inbox, except: [:index] + before_action :fetch_inbox, except: [:index, :create] before_action :fetch_agent_bot, only: [:set_agent_bot] def index @inboxes = policy_scope(current_account.inboxes) end + def create + ActiveRecord::Base.transaction do + channel = web_widgets.create!(permitted_params[:channel].except(:type)) if permitted_params[:channel][:type] == 'web_widget' + @inbox = current_account.inboxes.build(name: permitted_params[:name], channel: channel) + @inbox.avatar.attach(permitted_params[:avatar]) + @inbox.save! + end + end + def update - @inbox.update(inbox_update_params) + @inbox.update(inbox_update_params.except(:channel)) + @inbox.channel.update!(inbox_update_params[:channel]) if @inbox.channel.is_a?(Channel::WebWidget) && inbox_update_params[:channel].present? end def set_agent_bot @@ -37,11 +47,20 @@ class Api::V1::Accounts::InboxesController < Api::BaseController @agent_bot = AgentBot.find(params[:agent_bot]) if params[:agent_bot] end + def web_widgets + current_account.web_widgets + end + def check_authorization authorize(Inbox) end + def permitted_params + params.permit(:id, :avatar, :name, channel: [:type, :website_url, :widget_color, :welcome_title, :welcome_tagline, :agent_away_message]) + end + def inbox_update_params - params.require(:inbox).permit(:enable_auto_assignment, :avatar) + params.permit(:enable_auto_assignment, :name, :avatar, channel: [:website_url, :widget_color, :welcome_title, + :welcome_tagline, :agent_away_message]) end end diff --git a/app/controllers/api/v1/accounts/widget/inboxes_controller.rb b/app/controllers/api/v1/accounts/widget/inboxes_controller.rb deleted file mode 100644 index f6305e4eb..000000000 --- a/app/controllers/api/v1/accounts/widget/inboxes_controller.rb +++ /dev/null @@ -1,48 +0,0 @@ -class Api::V1::Accounts::Widget::InboxesController < Api::BaseController - before_action :authorize_request - before_action :set_web_widget_channel, only: [:update] - before_action :set_inbox, only: [:update] - - def create - ActiveRecord::Base.transaction do - channel = web_widgets.create!( - website_name: permitted_params[:website][:website_name], - website_url: permitted_params[:website][:website_url], - widget_color: permitted_params[:website][:widget_color] - ) - @inbox = inboxes.create!(name: permitted_params[:website][:website_name], channel: channel) - end - end - - def update - @channel.update!( - widget_color: permitted_params[:website][:widget_color] - ) - end - - private - - def authorize_request - authorize ::Inbox - end - - def inboxes - current_account.inboxes - end - - def web_widgets - current_account.web_widgets - end - - def set_web_widget_channel - @channel = web_widgets.find_by(id: permitted_params[:id]) - end - - def set_inbox - @inbox = @channel.inbox - end - - def permitted_params - params.permit(:id, website: [:website_name, :website_url, :widget_color]) - end -end diff --git a/app/controllers/twitter/authorizations_controller.rb b/app/controllers/twitter/authorizations_controller.rb index 69145ff84..765e026fe 100644 --- a/app/controllers/twitter/authorizations_controller.rb +++ b/app/controllers/twitter/authorizations_controller.rb @@ -6,7 +6,7 @@ class Twitter::AuthorizationsController < Twitter::BaseController ::Redis::Alfred.setex(oauth_token, account.id) redirect_to oauth_authorize_endpoint(oauth_token) else - redirect_to app_new_twitter_inbox_url + redirect_to app_new_twitter_inbox_url(account_id: account.id) end end diff --git a/app/controllers/twitter/callbacks_controller.rb b/app/controllers/twitter/callbacks_controller.rb index fe55ba3a1..6065e3546 100644 --- a/app/controllers/twitter/callbacks_controller.rb +++ b/app/controllers/twitter/callbacks_controller.rb @@ -39,8 +39,7 @@ class Twitter::CallbacksController < Twitter::BaseController twitter_profile = account.twitter_profiles.create( twitter_access_token: parsed_body['oauth_token'], twitter_access_token_secret: parsed_body['oauth_token_secret'], - profile_id: parsed_body['user_id'], - name: parsed_body['screen_name'] + profile_id: parsed_body['user_id'] ) account.inboxes.create( name: parsed_body['screen_name'], diff --git a/app/javascript/dashboard/api/channel/webChannel.js b/app/javascript/dashboard/api/channel/webChannel.js index 5354787c3..81a145462 100644 --- a/app/javascript/dashboard/api/channel/webChannel.js +++ b/app/javascript/dashboard/api/channel/webChannel.js @@ -2,7 +2,7 @@ import ApiClient from '../ApiClient'; class WebChannel extends ApiClient { constructor() { - super('widget/inboxes', { accountScoped: true }); + super('inboxes', { accountScoped: true }); } } diff --git a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss index 0059816d8..438945920 100644 --- a/app/javascript/dashboard/assets/scss/views/settings/inbox.scss +++ b/app/javascript/dashboard/assets/scss/views/settings/inbox.scss @@ -31,42 +31,39 @@ .wizard-box { .item { @include padding($space-normal $space-normal $space-normal $space-medium); - position: relative; @include background-light; - cursor: pointer; - &:before, - &:after { - content: ''; - position: absolute; - width: 2px; - height: 100%; + cursor: pointer; + position: relative; + + &::before, + &::after { background: $color-border; + content: ''; + height: 100%; + position: absolute; top: $space-normal; + width: 2px; } - &:before { - top: $zero; + &::before { height: $space-normal; + top: $zero; } &:first-child { - &:before { + &::before { height: 0; } } &:last-child { - &:after { + &::after { height: $zero; } } &.active { - // left: 1px; - // @include background-white; - // @include border-light; - // border-right: 0; h3 { color: $color-woot; } @@ -78,7 +75,7 @@ &.over { - &:after { + &::after { background: $color-woot; } @@ -86,18 +83,18 @@ background: $color-woot; } - &+.item { - &:before { + & + .item { + &::before { background: $color-woot; } } } h3 { - font-size: $font-size-default; - padding-left: $space-medium; - line-height: 1; color: $color-body; + font-size: $font-size-default; + line-height: 1; + padding-left: $space-medium; .completed { color: $success-color; @@ -105,25 +102,25 @@ } p { - font-size: $font-size-small; color: $color-light-gray; - padding-left: $space-medium; + font-size: $font-size-small; margin: 0; + padding-left: $space-medium; } .step { - position: absolute; - left: $space-normal; - top: $space-normal; - font-size: $font-size-small; - font-weight: $font-weight-medium; background: $color-border; border-radius: 20px; - width: $space-normal; + color: $color-white; + font-size: $font-size-small; + font-weight: $font-weight-medium; height: $space-normal; - text-align: center; + left: $space-normal; line-height: $space-normal; - color: #fff; + position: absolute; + text-align: center; + top: $space-normal; + width: $space-normal; z-index: 999; i { @@ -141,10 +138,6 @@ } .inoboxes-list { - // @include margin(auto); - // @include background-white; - // @include border-light; - // width: 50%; .inbox-item { @include margin($space-normal); @@ -152,16 +145,18 @@ @include flex-shrink; @include padding($space-normal $space-normal); @include border-light-bottom(); - flex-direction: column; + background: $color-white; cursor: pointer; - width: 20%; + flex-direction: column; float: left; min-height: 10rem; + width: 20%; &:last-child { - margin-bottom: $zero; @include border-nil; + + margin-bottom: $zero; } &:hover { @@ -174,8 +169,8 @@ .switch { align-self: center; - margin-right: $space-normal; margin-bottom: $zero; + margin-right: $space-normal; } .item--details { @@ -187,15 +182,15 @@ } .item--sub { - margin-bottom: 0; font-size: $font-size-small; + margin-bottom: 0; } } .arrow { align-self: center; - font-size: $font-size-small; color: $medium-gray; + font-size: $font-size-small; opacity: .7; transform: translateX(0); transition: opacity 0.100s ease-in 0s, transform 0.200s ease-in 0.030s; @@ -204,18 +199,19 @@ } .settings--content { - @include margin($space-small $space-medium); + @include margin($space-small $space-larger); .title { font-weight: $font-weight-medium; } .code { + @include padding($space-one); + + background: $color-background; max-height: $space-mega; overflow: auto; white-space: nowrap; - @include padding($space-one); - background: $color-background; code { background: transparent; @@ -225,8 +221,8 @@ } .login-init { - text-align: center; padding-top: 30%; + text-align: center; p { @include padding($space-medium); diff --git a/app/javascript/dashboard/components/SettingsFormHeader.vue b/app/javascript/dashboard/components/SettingsFormHeader.vue deleted file mode 100644 index 795751612..000000000 --- a/app/javascript/dashboard/components/SettingsFormHeader.vue +++ /dev/null @@ -1,69 +0,0 @@ - - - - - diff --git a/app/javascript/dashboard/components/SettingsSection.vue b/app/javascript/dashboard/components/SettingsSection.vue new file mode 100644 index 000000000..ebf79bf3e --- /dev/null +++ b/app/javascript/dashboard/components/SettingsSection.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index 0dcdd60d5..e1c82a1ff 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -30,6 +30,18 @@ "LABEL": "Website Domain", "PLACEHOLDER": "Enter your website domain (eg: acme.com)" }, + "CHANNEL_WELCOME_TITLE": { + "LABEL": "Welcome Heading", + "PLACEHOLDER": "Hi there !" + }, + "CHANNEL_WELCOME_TAGLINE": { + "LABEL": "Welcome Tagline", + "PLACEHOLDER": "We make it simple to connect with us. Ask us anything, or share your feedback." + }, + "CHANNEL_AGENT_AWAY_MESSAGE": { + "LABEL": "Agents Away Message", + "PLACEHOLDER": "Acme Inc typically replies in a few hours." + }, "WIDGET_COLOR": { "LABEL": "Widget Color", "PLACEHOLDER": "Update the widget color used in widget" @@ -102,7 +114,7 @@ "VIEW": "View", "EDIT": { "API": { - "SUCCESS_MESSAGE": "Widget color updated successfully", + "SUCCESS_MESSAGE": "Inbox settings updated successfully", "AUTO_ASSIGNMENT_SUCCESS_MESSAGE": "Auto assignment updated successfully", "ERROR_MESSAGE": "Could not update widget color. Please try again later." }, @@ -132,7 +144,9 @@ "INBOX_AGENTS_SUB_TEXT": "Add or remove agents from this inbox", "UPDATE": "Update", "AUTO_ASSIGNMENT": "Enable auto assignment", - "AUTO_ASSIGNMENT_SUB_TEXT": "Enable or disable the automatic assignment of available agents on new conversations" + "INBOX_UPDATE_TITLE": "Inbox Settings", + "INBOX_UPDATE_SUB_TEXT": "Update your inbox settings", + "AUTO_ASSIGNMENT_SUB_TEXT": "Enable or disable the automatic assignment of new conversations to the agents added to this inbox." } } } diff --git a/app/javascript/dashboard/i18n/locale/en/signup.json b/app/javascript/dashboard/i18n/locale/en/signup.json index fa535b60d..e52705224 100644 --- a/app/javascript/dashboard/i18n/locale/en/signup.json +++ b/app/javascript/dashboard/i18n/locale/en/signup.json @@ -6,7 +6,7 @@ "ACCOUNT_NAME": { "LABEL": "Account Name", "PLACEHOLDER": "Wayne Enterprises", - "ERROR": "Account Name is too small" + "ERROR": "Account Name is too short" }, "EMAIL": { "LABEL": "Email", diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue index 5f3ad7937..a035c7631 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue @@ -4,79 +4,177 @@ :header-image="inbox.avatarUrl" :header-title="inboxName" /> + +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + + +
+
+ + + +
+ + + + + + +
- - - + +
- - - + +
-
- - - -
-
-
- - - -
-
- - -
@@ -88,12 +186,12 @@ import { mapGetters } from 'vuex'; import { createMessengerScript } from 'dashboard/helper/scriptGenerator'; import { Compact } from 'vue-color'; import configMixin from 'shared/mixins/configMixin'; -import SettingsFormHeader from '../../../../components/SettingsFormHeader.vue'; +import SettingsSection from '../../../../components/SettingsSection'; export default { components: { Compact, - SettingsFormHeader, + SettingsSection, }, mixins: [configMixin], data() { @@ -102,6 +200,10 @@ export default { autoAssignment: false, isUpdating: false, isAgentListUpdating: false, + channelWebsiteUrl: '', + channelWelcomeTitle: '', + channelWelcomeTagline: '', + channelAgentAwayMessage: '', }; }, computed: { @@ -145,6 +247,10 @@ export default { this.$store.dispatch('inboxes/get').then(() => { this.fetchAttachedAgents(); this.autoAssignment = this.inbox.enable_auto_assignment; + this.channelWebsiteUrl = this.inbox.website_url; + this.channelWelcomeTitle = this.inbox.welcome_title; + this.channelWelcomeTagline = this.inbox.welcome_tagline; + this.channelAgentAwayMessage = this.inbox.agent_away_message; }); }, async fetchAttachedAgents() { @@ -181,34 +287,23 @@ export default { } this.isAgentListUpdating = false; }, - async updateWidgetColor() { + async updateInbox() { try { - await this.$store.dispatch('inboxes/updateWebsiteChannel', { - id: this.inbox.channel_id, - website: { - widget_color: this.getWidgetColor(this.inbox.widget_color), - }, - }); - this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); - } catch (error) { - this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); - } - }, - async updateAutoAssignment() { - try { - await this.$store.dispatch('inboxes/updateAutoAssignment', { + await this.$store.dispatch('inboxes/updateInbox', { id: this.currentInboxId, - inbox: { - enable_auto_assignment: this.autoAssignment, + name: this.inboxName, + enable_auto_assignment: this.autoAssignment, + channel: { + widget_color: this.getWidgetColor(this.inbox.widget_color), + website_url: this.channelWebsiteUrl, + welcome_title: this.channelWelcomeTitle, + welcome_tagline: this.channelWelcomeTagline, + agent_away_message: this.channelAgentAwayMessage, }, }); - this.showAlert( - this.$t('INBOX_MGMT.EDIT.API.AUTO_ASSIGNMENT_SUCCESS_MESSAGE') - ); + this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); } catch (error) { - this.showAlert( - this.$t('INBOX_MGMT.EDIT.API.AUTO_ASSIGNMENT_SUCCESS_MESSAGE') - ); + this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE')); } }, getWidgetColor() { @@ -226,3 +321,26 @@ export default { }, }; + + diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Facebook.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Facebook.vue index 5a838814d..ca4ebdd24 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Facebook.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Facebook.vue @@ -221,9 +221,8 @@ export default { return { user_access_token: this.user_access_token, page_access_token: this.selectedPage.access_token, - page_name: this.selectedPage.name, page_id: this.selectedPage.id, - inbox_name: this.pageName, + inbox_name: this.selectedPage.name, }; }, diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Website.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Website.vue index 83bf17866..e6d93ae41 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Website.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Website.vue @@ -18,7 +18,7 @@