diff --git a/.bundler-audit.yml b/.bundler-audit.yml new file mode 100644 index 000000000..afe8702ac --- /dev/null +++ b/.bundler-audit.yml @@ -0,0 +1,3 @@ +--- +ignore: + - CVE-2021-41098 # https://github.com/chatwoot/chatwoot/issues/3097 (update once azure blob storage is updated) diff --git a/Gemfile b/Gemfile index 1dddb482c..c65f89d4c 100644 --- a/Gemfile +++ b/Gemfile @@ -56,8 +56,7 @@ gem 'activerecord-import' gem 'dotenv-rails' gem 'foreman' gem 'puma' -gem 'rack-timeout' -gem 'webpacker', '~> 5.x' +gem 'webpacker', '~> 5.4.0' # metrics on heroku gem 'barnes' @@ -122,6 +121,11 @@ gem 'hairtrigger' gem 'procore-sift' +group :production, :staging do + # we dont want request timing out in development while using byebug + gem 'rack-timeout' +end + group :development do gem 'annotate' gem 'bullet' diff --git a/Gemfile.lock b/Gemfile.lock index 45a7b9133..4372219ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -247,6 +247,7 @@ GEM google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) + google-protobuf (3.17.3) google-protobuf (3.17.3-universal-darwin) google-protobuf (3.17.3-x86_64-linux) googleapis-common-protos (1.3.11) @@ -264,6 +265,9 @@ GEM signet (~> 0.14) groupdate (5.2.2) activesupport (>= 5) + grpc (1.38.0) + google-protobuf (~> 3.15) + googleapis-common-protos-types (~> 1.0) grpc (1.38.0-universal-darwin) google-protobuf (~> 3.15) googleapis-common-protos-types (~> 1.0) @@ -346,6 +350,7 @@ GEM mime-types-data (3.2021.0704) mini_magick (4.11.0) mini_mime (1.1.1) + mini_portile2 (2.5.3) minitest (5.14.4) mock_redis (0.28.0) ruby2_keywords @@ -360,6 +365,9 @@ GEM netrc (0.11.0) newrelic_rpm (7.2.0) nio4r (2.5.8) + nokogiri (1.11.7) + mini_portile2 (~> 2.5.0) + racc (~> 1.4) nokogiri (1.11.7-arm64-darwin) racc (~> 1.4) nokogiri (1.11.7-x86_64-darwin) @@ -617,6 +625,7 @@ GEM PLATFORMS arm64-darwin-20 + ruby x86_64-darwin-18 x86_64-darwin-20 x86_64-darwin-21 @@ -714,7 +723,7 @@ DEPENDENCIES valid_email2 web-console webmock - webpacker (~> 5.x) + webpacker (~> 5.4.0) webpush wisper (= 2.0.0) diff --git a/app/builders/messages/facebook/message_builder.rb b/app/builders/messages/facebook/message_builder.rb index 23c9d92b4..29579fd54 100644 --- a/app/builders/messages/facebook/message_builder.rb +++ b/app/builders/messages/facebook/message_builder.rb @@ -148,6 +148,14 @@ class Messages::Facebook::MessageBuilder } end + def process_contact_params_result(result) + { + name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}", + account_id: @inbox.account_id, + remote_avatar_url: result['profile_pic'] || '' + } + end + def contact_params begin k = Koala::Facebook::API.new(@inbox.channel.page_access_token) if @inbox.facebook? @@ -155,14 +163,15 @@ class Messages::Facebook::MessageBuilder rescue Koala::Facebook::AuthenticationError @inbox.channel.authorization_error! raise + rescue Koala::Facebook::ClientError => e + result = {} + # OAuthException, code: 100, error_subcode: 2018218, message: (#100) No profile available for this user + # We don't need to capture this error as we don't care about contact params in case of echo messages + Sentry.capture_exception(e) unless @outgoing_echo rescue StandardError => e result = {} Sentry.capture_exception(e) end - { - name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}", - account_id: @inbox.account_id, - remote_avatar_url: result['profile_pic'] || '' - } + process_contact_params_result(result) end end diff --git a/app/builders/v2/report_builder.rb b/app/builders/v2/report_builder.rb index 30804b8e8..33b2db820 100644 --- a/app/builders/v2/report_builder.rb +++ b/app/builders/v2/report_builder.rb @@ -41,19 +41,25 @@ class V2::ReportBuilder user when :label label + when :team + team end end def inbox - @inbox ||= account.inboxes.where(id: params[:id]).first + @inbox ||= account.inboxes.find(params[:id]) end def user - @user ||= account.users.where(id: params[:id]).first + @user ||= account.users.find(params[:id]) end def label - @label ||= account.labels.where(id: params[:id]).first + @label ||= account.labels.find(params[:id]) + end + + def team + @team ||= account.teams.find(params[:id]) end def conversations_count diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 444f0c918..561b224c3 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -10,7 +10,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController before_action :check_authorization before_action :set_current_page, only: [:index, :active, :search] - before_action :fetch_contact, only: [:show, :update, :contactable_inboxes] + before_action :fetch_contact, only: [:show, :update, :destroy, :contactable_inboxes] before_action :set_include_contact_inboxes, only: [:index, :search] def index @@ -30,10 +30,13 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController end def import + render json: { error: I18n.t('errors.contacts.import.failed') }, status: :unprocessable_entity and return if params[:import_file].blank? + ActiveRecord::Base.transaction do import = Current.account.data_imports.create!(data_type: 'contacts') import.import_file.attach(params[:import_file]) end + head :ok end @@ -70,6 +73,18 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController }, status: :unprocessable_entity end + def destroy + if ::OnlineStatusTracker.get_presence( + @contact.account.id, 'Contact', @contact.id + ) + return render_error({ message: I18n.t('contacts.online.delete', contact_name: @contact.name.capitalize) }, + :unprocessable_entity) + end + + @contact.destroy! + head :ok + end + private # TODO: Move this to a finder class @@ -134,4 +149,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def fetch_contact @contact = Current.account.contacts.includes(contact_inboxes: [:inbox]).find(params[:id]) end + + def render_error(error, error_status) + render json: error, status: error_status + end end diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index d360723a6..5e7c7d433 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -69,6 +69,12 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro def update_last_seen @conversation.agent_last_seen_at = DateTime.now.utc + @conversation.assignee_last_seen_at = DateTime.now.utc if assignee? + @conversation.save! + end + + def custom_attributes + @conversation.custom_attributes = params.permit(custom_attributes: {})[:custom_attributes] @conversation.save! end @@ -112,6 +118,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro def conversation_params additional_attributes = params[:additional_attributes]&.permit! || {} + custom_attributes = params[:custom_attributes]&.permit! || {} status = params[:status].present? ? { status: params[:status] } : {} # TODO: temporary fallback for the old bot status in conversation, we will remove after couple of releases @@ -122,6 +129,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro contact_id: @contact_inbox.contact_id, contact_inbox_id: @contact_inbox.id, additional_attributes: additional_attributes, + custom_attributes: custom_attributes, snoozed_until: params[:snoozed_until] }.merge(status) end @@ -129,4 +137,8 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro def conversation_finder @conversation_finder ||= ConversationFinder.new(current_user, params) end + + def assignee? + @conversation.assignee_id? && current_user == @conversation.assignee + end end diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index cb01fc380..df055923c 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -100,6 +100,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController end def update_channel_feature_flags + return unless @inbox.web_widget? return unless permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].key? :selected_feature_flags @inbox.channel.selected_feature_flags = permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel][:selected_feature_flags] diff --git a/app/controllers/api/v2/accounts/reports_controller.rb b/app/controllers/api/v2/accounts/reports_controller.rb index af28fe544..4fabd587e 100644 --- a/app/controllers/api/v2/accounts/reports_controller.rb +++ b/app/controllers/api/v2/accounts/reports_controller.rb @@ -29,6 +29,12 @@ class Api::V2::Accounts::ReportsController < Api::V1::Accounts::BaseController render layout: false, template: 'api/v2/accounts/reports/labels.csv.erb', format: 'csv' end + def teams + response.headers['Content-Type'] = 'text/csv' + response.headers['Content-Disposition'] = 'attachment; filename=teams_report.csv' + render layout: false, template: 'api/v2/accounts/reports/teams.csv.erb', format: 'csv' + end + private def check_authorization diff --git a/app/controllers/super_admin/dashboard_controller.rb b/app/controllers/super_admin/dashboard_controller.rb index b5f3d34eb..56d19d563 100644 --- a/app/controllers/super_admin/dashboard_controller.rb +++ b/app/controllers/super_admin/dashboard_controller.rb @@ -3,10 +3,9 @@ class SuperAdmin::DashboardController < SuperAdmin::ApplicationController def index @data = Conversation.unscoped.group_by_day(:created_at, range: 30.days.ago..2.seconds.ago).count.to_a - @accounts_count = number_with_delimiter(Account.all.length) - @users_count = number_with_delimiter(User.all.length) - @inboxes_count = number_with_delimiter(Inbox.all.length) - @conversations_count = number_with_delimiter(Conversation.all.length) - @messages_count = number_with_delimiter(Message.all.length) + @accounts_count = number_with_delimiter(Account.count) + @users_count = number_with_delimiter(User.count) + @inboxes_count = number_with_delimiter(Inbox.count) + @conversations_count = number_with_delimiter(Conversation.count) end end diff --git a/app/javascript/dashboard/api/contacts.js b/app/javascript/dashboard/api/contacts.js index 0ed9bb101..a6415cb37 100644 --- a/app/javascript/dashboard/api/contacts.js +++ b/app/javascript/dashboard/api/contacts.js @@ -52,6 +52,14 @@ class ContactAPI extends ApiClient { )}`; return axios.get(requestURL); } + + importContacts(file) { + const formData = new FormData(); + formData.append('import_file', file); + return axios.post(`${this.url}/import`, formData, { + headers: { 'Content-Type': 'multipart/form-data' }, + }); + } } export default new ContactAPI(); diff --git a/app/javascript/dashboard/api/specs/contacts.spec.js b/app/javascript/dashboard/api/specs/contacts.spec.js index 0c0a21125..03a71ca11 100644 --- a/app/javascript/dashboard/api/specs/contacts.spec.js +++ b/app/javascript/dashboard/api/specs/contacts.spec.js @@ -59,6 +59,18 @@ describe('#ContactsAPI', () => { '/api/v1/contacts/search?include_contact_inboxes=false&page=1&sort=date&q=leads&labels[]=customer-support' ); }); + + it('#importContacts', () => { + const file = 'file'; + contactAPI.importContacts(file); + expect(context.axiosMock.post).toHaveBeenCalledWith( + '/api/v1/contacts/import', + expect.any(FormData), + { + headers: { 'Content-Type': 'multipart/form-data' }, + } + ); + }); }); }); diff --git a/app/javascript/dashboard/assets/images/twitter-chat-badge.png b/app/javascript/dashboard/assets/images/twitter-chat-badge.png new file mode 100644 index 000000000..987ed3d07 Binary files /dev/null and b/app/javascript/dashboard/assets/images/twitter-chat-badge.png differ diff --git a/app/javascript/dashboard/assets/scss/_utility-helpers.scss b/app/javascript/dashboard/assets/scss/_utility-helpers.scss new file mode 100644 index 000000000..60fecb994 --- /dev/null +++ b/app/javascript/dashboard/assets/scss/_utility-helpers.scss @@ -0,0 +1,3 @@ +.margin-right-small { + margin-right: var(--space-small); +} diff --git a/app/javascript/dashboard/assets/scss/widgets/_modal.scss b/app/javascript/dashboard/assets/scss/widgets/_modal.scss index 8c4e656c4..a017f776a 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_modal.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_modal.scss @@ -71,7 +71,8 @@ @include padding($space-large); } - form { + form, + .modal-content { @include padding($space-large); align-self: center; diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 6d65ba2dd..5ca64d215 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -194,7 +194,7 @@ export default { }); }, methods: { - handleKeyEvents(e) { + getKeyboardListenerParams() { const allConversations = this.$refs.activeConversation.querySelectorAll( 'div.conversations-list div.conversation' ); @@ -205,7 +205,19 @@ export default { activeConversation ); const lastConversationIndex = allConversations.length - 1; + return { + allConversations, + activeConversation, + activeConversationIndex, + lastConversationIndex, + }; + }, + handleKeyEvents(e) { if (hasPressedAltAndJKey(e)) { + const { + allConversations, + activeConversationIndex, + } = this.getKeyboardListenerParams(); if (activeConversationIndex === -1) { allConversations[0].click(); } @@ -214,6 +226,11 @@ export default { } } if (hasPressedAltAndKKey(e)) { + const { + allConversations, + activeConversationIndex, + lastConversationIndex, + } = this.getKeyboardListenerParams(); if (activeConversationIndex === -1) { allConversations[lastConversationIndex].click(); } else if (activeConversationIndex < lastConversationIndex) { diff --git a/app/javascript/dashboard/components/buttons/ResolveAction.vue b/app/javascript/dashboard/components/buttons/ResolveAction.vue index 76090b89f..637424815 100644 --- a/app/javascript/dashboard/components/buttons/ResolveAction.vue +++ b/app/javascript/dashboard/components/buttons/ResolveAction.vue @@ -176,7 +176,9 @@ export default { '.conversations-list .conversation' ); if (hasPressedAltAndMKey(e)) { - this.$refs.arrowDownButton.$el.click(); + if (this.$refs.arrowDownButton) { + this.$refs.arrowDownButton.$el.click(); + } } if (hasPressedAltAndEKey(e)) { const activeConversation = document.querySelector( diff --git a/app/javascript/dashboard/components/layout/Sidebar.vue b/app/javascript/dashboard/components/layout/Sidebar.vue index e8c0e21f8..07314e9c0 100644 --- a/app/javascript/dashboard/components/layout/Sidebar.vue +++ b/app/javascript/dashboard/components/layout/Sidebar.vue @@ -95,10 +95,15 @@ import AddAccountModal from './sidebarComponents/AddAccountModal.vue'; import AddLabelModal from '../../routes/dashboard/settings/labels/AddLabel'; import WootKeyShortcutModal from 'components/widgets/modal/WootKeyShortcutModal'; import { + hasPressedAltAndCKey, + hasPressedAltAndRKey, + hasPressedAltAndSKey, + hasPressedAltAndVKey, hasPressedCommandAndForwardSlash, isEscape, } from 'shared/helpers/KeyboardHelpers'; import eventListenerMixins from 'shared/mixins/eventListenerMixins'; +import router from '../../routes'; export default { components: { @@ -276,6 +281,27 @@ export default { if (isEscape(e)) { this.closeKeyShortcutModal(); } + + if (hasPressedAltAndCKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('home')) { + router.push({ name: 'home' }); + } + } else if (hasPressedAltAndVKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('contacts_dashboard')) { + router.push({ name: 'contacts_dashboard' }); + } + } else if (hasPressedAltAndRKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('settings_account_reports')) { + router.push({ name: 'settings_account_reports' }); + } + } else if (hasPressedAltAndSKey(e)) { + if (!this.isCurrentRouteSameAsNavigation('agent_list')) { + router.push({ name: 'agent_list' }); + } + } + }, + isCurrentRouteSameAsNavigation(routeName) { + return router.currentRoute && router.currentRoute.name === routeName; }, toggleSupportChatWindow() { window.$chatwoot.toggle(); diff --git a/app/javascript/dashboard/components/layout/SidebarItem.vue b/app/javascript/dashboard/components/layout/SidebarItem.vue index 1799a829a..462853e6a 100644 --- a/app/javascript/dashboard/components/layout/SidebarItem.vue +++ b/app/javascript/dashboard/components/layout/SidebarItem.vue @@ -33,7 +33,7 @@
@@ -59,17 +59,10 @@ import { mapGetters } from 'vuex'; import router from '../../routes'; -import { - hasPressedAltAndCKey, - hasPressedAltAndVKey, - hasPressedAltAndRKey, - hasPressedAltAndSKey, -} from 'shared/helpers/KeyboardHelpers'; import adminMixin from '../../mixins/isAdmin'; -import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import { getInboxClassByType } from 'dashboard/helper/inbox'; export default { - mixins: [adminMixin, eventListenerMixins], + mixins: [adminMixin], props: { menuItem: { type: Object, @@ -124,20 +117,6 @@ export default { } } }, - handleKeyEvents(e) { - if (hasPressedAltAndCKey(e)) { - router.push({ name: 'home' }); - } - if (hasPressedAltAndVKey(e)) { - router.push({ name: 'contacts_dashboard' }); - } - if (hasPressedAltAndRKey(e)) { - router.push({ name: 'settings_account_reports' }); - } - if (hasPressedAltAndSKey(e)) { - router.push({ name: 'settings_home' }); - } - }, showItem(item) { return this.isAdmin && item.newLink !== undefined; }, diff --git a/app/javascript/dashboard/components/widgets/Thumbnail.vue b/app/javascript/dashboard/components/widgets/Thumbnail.vue index 6fe83720b..517950ea0 100644 --- a/app/javascript/dashboard/components/widgets/Thumbnail.vue +++ b/app/javascript/dashboard/components/widgets/Thumbnail.vue @@ -22,19 +22,33 @@ src="~dashboard/assets/images/fb-badge.png" /> + + @@ -42,6 +42,7 @@ import MoreActions from './MoreActions'; import Thumbnail from '../Thumbnail'; import agentMixin from '../../../mixins/agentMixin.js'; import eventListenerMixins from 'shared/mixins/eventListenerMixins'; +import inboxMixin from 'shared/mixins/inboxMixin'; import { hasPressedAltAndOKey } from 'shared/helpers/KeyboardHelpers'; export default { @@ -49,7 +50,7 @@ export default { MoreActions, Thumbnail, }, - mixins: [agentMixin, eventListenerMixins], + mixins: [inboxMixin, agentMixin, eventListenerMixins], props: { chat: { type: Object, @@ -78,6 +79,12 @@ export default { return this.chat.meta; }, + inbox() { + const { inbox_id: inboxId } = this.chat; + const stateInbox = this.$store.getters['inboxes/getInbox'](inboxId); + return stateInbox; + }, + currentContact() { return this.$store.getters['contacts/getContact']( this.chat.meta.sender.id diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index b9c9688fd..ff831281b 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -76,7 +76,6 @@ import { mapGetters } from 'vuex'; import { mixin as clickaway } from 'vue-clickaway'; import alertMixin from 'shared/mixins/alertMixin'; -import eventListenerMixins from 'shared/mixins/eventListenerMixins'; import EmojiInput from 'shared/components/emoji/EmojiInput'; import CannedResponse from './CannedResponse'; @@ -108,13 +107,7 @@ export default { ReplyBottomPanel, WootMessageEditor, }, - mixins: [ - clickaway, - inboxMixin, - uiSettingsMixin, - alertMixin, - eventListenerMixins, - ], + mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin], props: { selectedTweet: { type: [Object, String], @@ -304,6 +297,15 @@ export default { } }, }, + + mounted() { + // Donot use the keyboard listener mixin here as the events here are supposed to be + // working even if input/textarea is focussed. + document.addEventListener('keydown', this.handleKeyEvents); + }, + destroyed() { + document.removeEventListener('keydown', this.handleKeyEvents); + }, methods: { toggleUserMention(currentMentionState) { this.hasUserMention = currentMentionState; @@ -345,7 +347,10 @@ export default { await this.$store.dispatch('sendMessage', messagePayload); this.$emit('scrollToMessage'); } catch (error) { - // Error + const errorMessage = + error?.response?.data?.error || + this.$t('CONVERSATION.MESSAGE_ERROR'); + this.showAlert(errorMessage); } this.hideEmojiPicker(); } diff --git a/app/javascript/dashboard/helper/actionCable.js b/app/javascript/dashboard/helper/actionCable.js index afddb1e88..3a86ad3ea 100644 --- a/app/javascript/dashboard/helper/actionCable.js +++ b/app/javascript/dashboard/helper/actionCable.js @@ -19,6 +19,7 @@ class ActionCableConnector extends BaseActionCableConnector { 'conversation.typing_off': this.onTypingOff, 'conversation.contact_changed': this.onConversationContactChange, 'presence.update': this.onPresenceUpdate, + 'contact.deleted': this.onContactDelete, }; } @@ -115,6 +116,14 @@ class ActionCableConnector extends BaseActionCableConnector { fetchConversationStats = () => { bus.$emit('fetch_conversation_stats'); }; + + onContactDelete = data => { + this.app.$store.dispatch( + 'contacts/deleteContactThroughConversations', + data.id + ); + this.fetchConversationStats(); + }; } export default { diff --git a/app/javascript/dashboard/helper/inbox.js b/app/javascript/dashboard/helper/inbox.js index af8917dab..3b91f1bc9 100644 --- a/app/javascript/dashboard/helper/inbox.js +++ b/app/javascript/dashboard/helper/inbox.js @@ -22,7 +22,10 @@ export const getInboxClassByType = (type, phoneNumber) => { case INBOX_TYPES.EMAIL: return 'ion-ios-email'; + case INBOX_TYPES.TELEGRAM: + return 'ion-ios-navigate'; + default: - return ''; + return 'ion-ios-chatbubble'; } }; diff --git a/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json index f5e8da922..5c331a401 100644 --- a/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json index 28e42b91c..b092c7eb9 100644 --- a/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Vyberte časové pásmo", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json index 3db06c047..45da10bd7 100644 --- a/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "Vi er ikke tilgængelige i øjeblikket. Skriv en besked og vi svarer, når vi er tilbage.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/en/contact.json b/app/javascript/dashboard/i18n/locale/en/contact.json index e00e01647..44f241e79 100644 --- a/app/javascript/dashboard/i18n/locale/en/contact.json +++ b/app/javascript/dashboard/i18n/locale/en/contact.json @@ -54,6 +54,35 @@ "TITLE": "Create new contact", "DESC": "Add basic information details about the contact." }, + "IMPORT_CONTACTS": { + "BUTTON_LABEL": "Import", + "TITLE": "Import Contacts", + "DESC": "Import contacts through a CSV file.", + "DOWNLOAD_LABEL": "Download a sample csv.", + "FORM": { + "LABEL": "CSV File", + "SUBMIT": "Import", + "CANCEL": "Cancel" + }, + "SUCCESS_MESSAGE": "Contacts saved successfully", + "ERROR_MESSAGE": "There was an error, please try again" + }, + "DELETE_CONTACT": { + "BUTTON_LABEL": "Delete Contact", + "TITLE": "Delete contact", + "DESC": "Delete contact details", + "CONFIRM": { + "TITLE": "Confirm Deletion", + "MESSAGE": "Are you sure to delete ", + "PLACE_HOLDER": "Please type {contactName} to confirm", + "YES": "Yes, Delete ", + "NO": "No, Keep " + }, + "API": { + "SUCCESS_MESSAGE": "Contact deleted successfully", + "ERROR_MESSAGE": "Could not delete contact. Please try again later." + } + }, "CONTACT_FORM": { "FORM": { "SUBMIT": "Submit", @@ -239,4 +268,4 @@ "ERROR_MESSAGE": "Could not merge contcts, try again!" } } -} +} \ No newline at end of file diff --git a/app/javascript/dashboard/i18n/locale/en/conversation.json b/app/javascript/dashboard/i18n/locale/en/conversation.json index 42a25e897..d9f4eeba4 100644 --- a/app/javascript/dashboard/i18n/locale/en/conversation.json +++ b/app/javascript/dashboard/i18n/locale/en/conversation.json @@ -84,6 +84,7 @@ "CHANGE_AGENT": "Conversation Assignee changed", "CHANGE_TEAM": "Conversation team changed", "FILE_SIZE_LIMIT": "File exceeds the {MAXIMUM_FILE_UPLOAD_SIZE} attachment limit", + "MESSAGE_ERROR": "Unable to send this message, please try again later", "SENT_BY": "Sent by:", "ASSIGNMENT": { "SELECT_AGENT": "Select Agent", diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index 329c48d31..b585eda4d 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -56,6 +56,11 @@ "CHANNEL_AVATAR": { "LABEL": "Channel Avatar" }, + "CHANNEL_WEBHOOK_URL": { + "LABEL": "Webhook URL", + "PLACEHOLDER": "Enter your Webhook URL", + "ERROR": "Please enter a valid URL" + }, "CHANNEL_DOMAIN": { "LABEL": "Website Domain", "PLACEHOLDER": "Enter your website domain (eg: acme.com)" @@ -127,11 +132,11 @@ "ERROR_MESSAGE": "We were not able to authenticate Twilio credentials, please try again" } }, - "SMS": { + "SMS": { "TITLE": "SMS Channel via Twilio", "DESC": "Start supporting your customers via SMS with Twilio integration." }, - "WHATSAPP": { + "WHATSAPP": { "TITLE": "Whatsapp Channel via Twilio", "DESC": "Start supporting your customers via Whatsapp with Twilio integration." }, @@ -195,6 +200,10 @@ "SUBMIT_BUTTON": "Create LINE Channel", "API": { "ERROR_MESSAGE": "We were not able to save the LINE channel" + }, + "API_CALLBACK": { + "TITLE": "Callback URL", + "SUBTITLE": "You have to configure the webhook URL in LINE application with the URL mentioned here." } }, "TELEGRAM_CHANNEL": { @@ -350,7 +359,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json index 923988f64..5a1c15383 100644 --- a/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json index 89efc3de8..f5010b0d8 100644 --- a/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json index 0327ada74..d22e53b84 100644 --- a/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/it/chatlist.json b/app/javascript/dashboard/i18n/locale/it/chatlist.json index e419e2e00..0f7988618 100644 --- a/app/javascript/dashboard/i18n/locale/it/chatlist.json +++ b/app/javascript/dashboard/i18n/locale/it/chatlist.json @@ -13,18 +13,18 @@ "STATUS_TABS": [ { "NAME": "Apri", - "KEY": "contaaperture" + "KEY": "openCount" }, { "NAME": "Risolti", - "KEY": "Conteggio" + "KEY": "allConvCount" } ], "ASSIGNEE_TYPE_TABS": [ { "NAME": "Miniera", "KEY": "Io", - "COUNT_KEY": "contaMinore" + "COUNT_KEY": "mineCount" }, { "NAME": "Non assegnato", @@ -40,11 +40,11 @@ "CHAT_STATUS_ITEMS": [ { "TEXT": "Apri", - "VALUE": "Aperto" + "VALUE": "open" }, { "TEXT": "Risolti", - "VALUE": "risolto" + "VALUE": "resolved" }, { "TEXT": "Pending", diff --git a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json index 6ca9fa681..e7cc9dbd6 100644 --- a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json index a4cf934ac..19544deed 100644 --- a/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json index 0a026316b..459bbad26 100644 --- a/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json index 0327ada74..d22e53b84 100644 --- a/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json index d347896e5..e18993ee7 100644 --- a/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json index b0d6b2989..6671fa668 100644 --- a/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json index e17f9fb77..89863acc5 100644 --- a/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json index 0327ada74..d22e53b84 100644 --- a/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json index 386160da8..245ffe707 100644 --- a/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json index b89dcc554..f5a87ffe8 100644 --- a/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json index 041ec75dd..836af5d28 100644 --- a/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json index 6001c0eaa..865bf0db7 100644 --- a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json index 4db996bc1..2596ea8a3 100644 --- a/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json index 1313f8385..84fb6cebd 100644 --- a/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json index 93b285669..5c53f19d9 100644 --- a/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json @@ -350,7 +350,7 @@ "TIMEZONE_LABEL": "Select timezone", "UPDATE": "Update business hours settings", "TOGGLE_AVAILABILITY": "Enable business availability for this inbox", - "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for vistors", + "UNAVAILABLE_MESSAGE_LABEL": "Unavailable message for visitors", "UNAVAILABLE_MESSAGE_DEFAULT": "We are unavailable at the moment. Leave a message we will respond once we are back.", "TOGGLE_HELP": "Enabling business availability will show the available hours on live chat widget even if all the agents are offline. Outside available hours vistors can be warned with a message and a pre-chat form.", "DAY": { diff --git a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue index be79067e2..27f2f14c2 100644 --- a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue +++ b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactInfoPanel.vue @@ -3,7 +3,7 @@ - + + availableContactLabels.includes(title) ); - return result.map(value => { - return this.allLabels.find(label => label.title === value); - }); }, ...mapGetters({ diff --git a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsView.vue b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsView.vue index ada19502e..4ac5c0fc7 100644 --- a/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsView.vue +++ b/app/javascript/dashboard/routes/dashboard/contacts/components/ContactsView.vue @@ -7,6 +7,7 @@ this-selected-contact-id="" :on-input-search="onInputSearch" :on-toggle-create="onToggleCreate" + :on-toggle-import="onToggleImport" :header-title="label" /> + + +
@@ -41,6 +45,7 @@ import ContactsTable from './ContactsTable'; import ContactInfoPanel from './ContactInfoPanel'; import CreateContact from 'dashboard/routes/dashboard/conversation/contact/CreateContact'; import TableFooter from 'dashboard/components/widgets/TableFooter'; +import ImportContacts from './ImportContacts.vue'; const DEFAULT_PAGE = 1; @@ -51,6 +56,7 @@ export default { TableFooter, ContactInfoPanel, CreateContact, + ImportContacts, }, props: { label: { type: String, default: '' }, @@ -59,6 +65,7 @@ export default { return { searchQuery: '', showCreateModal: false, + showImportModal: false, selectedContactId: '', sortConfig: { name: 'asc' }, }; @@ -168,6 +175,9 @@ export default { onToggleCreate() { this.showCreateModal = !this.showCreateModal; }, + onToggleImport() { + this.showImportModal = !this.showImportModal; + }, onSortChange(params) { this.sortConfig = params; this.fetchContacts(this.meta.currentPage); diff --git a/app/javascript/dashboard/routes/dashboard/contacts/components/Header.vue b/app/javascript/dashboard/routes/dashboard/contacts/components/Header.vue index 93e471a76..008bf2c34 100644 --- a/app/javascript/dashboard/routes/dashboard/contacts/components/Header.vue +++ b/app/javascript/dashboard/routes/dashboard/contacts/components/Header.vue @@ -29,11 +29,20 @@ {{ $t('CREATE_CONTACT.BUTTON_LABEL') }} + + + {{ $t('IMPORT_CONTACTS.BUTTON_LABEL') }} + @@ -41,7 +50,6 @@ diff --git a/app/javascript/dashboard/routes/dashboard/settings/campaigns/AddCampaign.vue b/app/javascript/dashboard/routes/dashboard/settings/campaigns/AddCampaign.vue index cf56f66e9..267188592 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/campaigns/AddCampaign.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/campaigns/AddCampaign.vue @@ -237,7 +237,7 @@ export default { if (this.isOngoingType) { return this.$store.getters['inboxes/getWebsiteInboxes']; } - return this.$store.getters['inboxes/getTwilioInboxes']; + return this.$store.getters['inboxes/getTwilioSMSInboxes']; }, sendersAndBotList() { return [ diff --git a/app/javascript/dashboard/routes/dashboard/settings/campaigns/EditCampaign.vue b/app/javascript/dashboard/routes/dashboard/settings/campaigns/EditCampaign.vue index 592a09fe7..deb3b56b6 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/campaigns/EditCampaign.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/campaigns/EditCampaign.vue @@ -161,7 +161,7 @@ export default { if (this.isOngoingType) { return this.$store.getters['inboxes/getWebsiteInboxes']; } - return this.$store.getters['inboxes/getTwilioInboxes']; + return this.$store.getters['inboxes/getTwilioSMSInboxes']; }, pageTitle() { return `${this.$t('CAMPAIGN.EDIT.TITLE')} - ${ diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/AddAgents.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/AddAgents.vue index 3a8c93350..b42e5e9c3 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/AddAgents.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/AddAgents.vue @@ -88,7 +88,7 @@ export default { const selectedAgents = this.selectedAgents.map(x => x.id); try { - await InboxMembersAPI.create({ inboxId, agentList: selectedAgents }); + await InboxMembersAPI.update({ inboxId, agentList: selectedAgents }); router.replace({ name: 'settings_inbox_finish', params: { diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue index ad2bab48d..95cbd7646 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue @@ -17,7 +17,7 @@ @@ -25,7 +25,7 @@ @@ -93,6 +93,12 @@ export default { )}`; } + if (this.isALineInbox) { + return `${this.$t('INBOX_MGMT.FINISH.MESSAGE')}. ${this.$t( + 'INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.SUBTITLE' + )}`; + } + if (this.isAEmailInbox) { return this.$t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE'); } diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue index dc5ec797a..a708f8064 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue @@ -51,6 +51,9 @@ Telegram + + Line + {{ globalConfig.apiChannelName || 'API' }} diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue index 686497baa..fd7204fe7 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue @@ -22,7 +22,7 @@ @@ -32,6 +32,24 @@ :label="inboxNameLabel" :placeholder="inboxNamePlaceHolder" /> + + - + + + +
+ +
@@ -310,6 +352,8 @@