From 242de0b3f973e1ae8205b4c2ba18236c283b7aa5 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 12 Oct 2022 23:32:24 +0530 Subject: [PATCH 01/16] chore: `Vscode` extension recommendations (#5607) * Added vscode extension recommendations * Revert the change * Revert .gitignore * Change `volar` to `vetur` --- .gitignore | 5 +---- .vscode/extensions.json | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 .vscode/extensions.json diff --git a/.gitignore b/.gitignore index e4b14d2f5..11a8c50e3 100644 --- a/.gitignore +++ b/.gitignore @@ -39,9 +39,6 @@ public/packs* *.un~ .jest-cache -#VS Code files -.vscode - # ignore jetbrains IDE files .idea @@ -62,4 +59,4 @@ package-lock.json test/cypress/videos/* /config/master.key -/config/*.enc \ No newline at end of file +/config/*.enc diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..254e696a4 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,32 @@ +{ + "recommendations": [ + // Spell check + "streetsidesoftware.code-spell-checker", + // Better Comments + "aaron-bond.better-comments", + // Rails Test Runner + "davidpallinder.rails-test-runner", + // Eslint + "dbaeumer.vscode-eslint", + // Auto Close Tag + "formulahendry.auto-close-tag", + // Auto Rename Tag + "formulahendry.auto-rename-tag", + // Hight light colors + "naumovs.color-highlight", + // GitLens + "eamodio.gitlens", + // Ruby + "rebornix.ruby", + // Vue + "octref.vetur", + // Prettier + "esbenp.prettier-vscode", + // Dot Env + "mikestead.dotenv", + // HTML CSS Support + "ecmel.vscode-html-css", + // Tailwind CSS Intellisense + "bradlc.vscode-tailwindcss", + ] +} From 1b5a335f93564885f2ab179fa712f798bc5dda65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kube=C5=A1?= <46596180+KubesDavid@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:00:42 +0200 Subject: [PATCH 02/16] fix: Update .editorconfig to fix spaces and indent_style (#5612) --- .editorconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7203adb09..2a5fe28cf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,8 +7,8 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -indent_style = spaces +indent_style = space tab_width = 2 -[{*.{rb,erb,js,coffee,json,yml,css,scss,sh,markdown,md,html}] +[*.{rb,erb,js,coffee,json,yml,css,scss,sh,markdown,md,html}] indent_size = 2 From fca629a32afdc98afdaac526f9b240d12560143d Mon Sep 17 00:00:00 2001 From: Tejaswini Chile Date: Thu, 13 Oct 2022 03:02:54 +0530 Subject: [PATCH 03/16] fix: Update timezone to get `wday` from working_hours (#5605) Co-authored-by: Pranav Raj S --- app/models/working_hour.rb | 5 ++++- spec/models/working_hour_spec.rb | 14 ++++++++++++++ spec/services/contacts/filter_service_spec.rb | 1 + spec/services/conversations/filter_service_spec.rb | 1 + 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/models/working_hour.rb b/app/models/working_hour.rb index 885165da2..5ad4d0446 100644 --- a/app/models/working_hour.rb +++ b/app/models/working_hour.rb @@ -40,7 +40,10 @@ class WorkingHour < ApplicationRecord validate :open_all_day_and_closed_all_day def self.today - find_by(day_of_week: Date.current.wday) + # While getting the day of the week, consider the timezone as well. `first` would + # return the first working hour from the list of working hours available per week. + inbox = first.inbox + find_by(day_of_week: Time.zone.now.in_time_zone(inbox.timezone).to_date.wday) end def open_at?(time) diff --git a/spec/models/working_hour_spec.rb b/spec/models/working_hour_spec.rb index c126f6f87..a5018a28e 100644 --- a/spec/models/working_hour_spec.rb +++ b/spec/models/working_hour_spec.rb @@ -88,4 +88,18 @@ RSpec.describe WorkingHour do 'Validation failed: open_all_day and closed_all_day cannot be true at the same time') end end + + context 'when on monday 9am in Sydney timezone' do + let(:inbox) { create(:inbox) } + + before do + Time.zone = 'Australia/Sydney' + inbox.update(timezone: 'Australia/Sydney') + travel_to '10.10.2022 9:00 AEDT' + end + + it 'is considered working hour' do + expect(described_class.today.open_now?).to be true + end + end end diff --git a/spec/services/contacts/filter_service_spec.rb b/spec/services/contacts/filter_service_spec.rb index 5f52a1a3c..7e6661aed 100644 --- a/spec/services/contacts/filter_service_spec.rb +++ b/spec/services/contacts/filter_service_spec.rb @@ -167,6 +167,7 @@ describe ::Contacts::FilterService do context 'with x_days_before filter' do before do + Time.zone = 'UTC' el_contact.update(last_activity_at: (Time.zone.today - 4.days)) cs_contact.update(last_activity_at: (Time.zone.today - 5.days)) en_contact.update(last_activity_at: (Time.zone.today - 2.days)) diff --git a/spec/services/conversations/filter_service_spec.rb b/spec/services/conversations/filter_service_spec.rb index ed489bd30..a17351ec3 100644 --- a/spec/services/conversations/filter_service_spec.rb +++ b/spec/services/conversations/filter_service_spec.rb @@ -309,6 +309,7 @@ describe ::Conversations::FilterService do context 'with x_days_before filter' do before do + Time.zone = 'UTC' en_conversation_1.update!(last_activity_at: (Time.zone.today - 4.days)) en_conversation_2.update!(last_activity_at: (Time.zone.today - 5.days)) user_2_assigned_conversation.update!(last_activity_at: (Time.zone.today - 2.days)) From 0c8f744c33b5d2fc691cab43755285fd671fb1d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kube=C5=A1?= <46596180+KubesDavid@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:42:06 +0200 Subject: [PATCH 04/16] chore: Remove unnecessary methods and polyfills (#5614) --- app/javascript/packs/sdk.js | 10 ++--- app/javascript/sdk/DOMHelpers.js | 58 +++-------------------------- app/javascript/sdk/IFrameHelper.js | 15 ++++---- app/javascript/sdk/bubbleHelpers.js | 14 +++---- 4 files changed, 24 insertions(+), 73 deletions(-) diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 064033841..2fdd6c57b 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -10,7 +10,7 @@ import { getUserCookieName, hasUserKeys, } from '../sdk/cookieHelpers'; -import { addClass, removeClass } from '../sdk/DOMHelpers'; +import { addClasses, removeClasses } from '../sdk/DOMHelpers'; import { SDK_SET_BUBBLE_VISIBILITY } from 'shared/constants/sharedFrameEvents'; const runSDK = ({ baseUrl, websiteToken }) => { if (window.$chatwoot) { @@ -41,12 +41,12 @@ const runSDK = ({ baseUrl, websiteToken }) => { let widgetElm = document.querySelector('.woot--bubble-holder'); let widgetHolder = document.querySelector('.woot-widget-holder'); if (visibility === 'hide') { - addClass(widgetHolder, 'woot-widget--without-bubble'); - addClass(widgetElm, 'woot-hidden'); + addClasses(widgetHolder, 'woot-widget--without-bubble'); + addClasses(widgetElm, 'woot-hidden'); window.$chatwoot.hideMessageBubble = true; } else if (visibility === 'show') { - removeClass(widgetElm, 'woot-hidden'); - removeClass(widgetHolder, 'woot-widget--without-bubble'); + removeClasses(widgetElm, 'woot-hidden'); + removeClasses(widgetHolder, 'woot-widget--without-bubble'); window.$chatwoot.hideMessageBubble = false; } IFrameHelper.sendMessage(SDK_SET_BUBBLE_VISIBILITY, { diff --git a/app/javascript/sdk/DOMHelpers.js b/app/javascript/sdk/DOMHelpers.js index 2ac6188e6..47a45cc78 100644 --- a/app/javascript/sdk/DOMHelpers.js +++ b/app/javascript/sdk/DOMHelpers.js @@ -3,68 +3,20 @@ import { IFrameHelper } from './IFrameHelper'; export const loadCSS = () => { const css = document.createElement('style'); - css.type = 'text/css'; css.innerHTML = `${SDK_CSS}`; document.body.appendChild(css); }; -export const wootOn = (elm, event, fn) => { - if (document.addEventListener) { - elm.addEventListener(event, fn, false); - } else if (document.attachEvent) { - // <= IE 8 loses scope so need to apply, we add this to object so we - // can detach later (can't detach anonymous functions) - // eslint-disable-next-line - elm[event + fn] = function() { - // eslint-disable-next-line - return fn.apply(elm, arguments); - }; - elm.attachEvent(`on${event}`, elm[event + fn]); - } -}; - -export const classHelper = (classes, action, elm) => { - let search; - let replace; - let i; - let has = false; - if (classes) { - // Trim any whitespace - const classarray = classes.split(/\s+/); - for (i = 0; i < classarray.length; i += 1) { - search = new RegExp(`\\b${classarray[i]}\\b`, 'g'); - replace = new RegExp(` *${classarray[i]}\\b`, 'g'); - if (action === 'remove') { - // eslint-disable-next-line - elm.className = elm.className.replace(replace, ''); - } else if (action === 'toggle') { - // eslint-disable-next-line - elm.className = elm.className.match(search) - ? elm.className.replace(replace, '') - : `${elm.className} ${classarray[i]}`; - } else if (action === 'has') { - if (elm.className.match(search)) { - has = true; - break; - } - } - } - } - return has; -}; - -export const addClass = (elm, classes) => { - if (classes) { - elm.className += ` ${classes}`; - } +export const addClasses = (elm, classes) => { + elm.classList.add(...classes.split(' ')); }; export const toggleClass = (elm, classes) => { - classHelper(classes, 'toggle', elm); + elm.classList.toggle(classes); }; -export const removeClass = (elm, classes) => { - classHelper(classes, 'remove', elm); +export const removeClasses = (elm, classes) => { + elm.classList.remove(...classes.split(' ')); }; export const onLocationChange = ({ referrerURL, referrerHost }) => { diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 47596bce3..bbc2cfafd 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -1,9 +1,8 @@ import Cookies from 'js-cookie'; import { - wootOn, - addClass, + addClasses, loadCSS, - removeClass, + removeClasses, onLocationChangeListener, } from './DOMHelpers'; import { @@ -68,7 +67,7 @@ export const IFrameHelper = { holderClassName += ` woot-widget-holder--flat`; } - addClass(widgetHolder, holderClassName); + addClasses(widgetHolder, holderClassName); widgetHolder.appendChild(iframe); body.appendChild(widgetHolder); IFrameHelper.initPostMessageCommunication(); @@ -99,7 +98,7 @@ export const IFrameHelper = { }; }, initWindowSizeListener: () => { - wootOn(window, 'resize', () => IFrameHelper.toggleCloseButton()); + window.addEventListener('resize', () => IFrameHelper.toggleCloseButton()); }, preventDefaultScroll: () => { widgetHolder.addEventListener('wheel', event => { @@ -241,9 +240,9 @@ export const IFrameHelper = { event.unreadMessageCount > 0 && !bubbleElement.classList.contains('unread-notification') ) { - addClass(bubbleElement, 'unread-notification'); + addClasses(bubbleElement, 'unread-notification'); } else if (event.unreadMessageCount === 0) { - removeClass(bubbleElement, 'unread-notification'); + removeClasses(bubbleElement, 'unread-notification'); } }, @@ -284,7 +283,7 @@ export const IFrameHelper = { target: chatBubble, }); - addClass(closeBubble, closeBtnClassName); + addClasses(closeBubble, closeBtnClassName); chatIcon.style.background = widgetColor; closeBubble.style.background = widgetColor; diff --git a/app/javascript/sdk/bubbleHelpers.js b/app/javascript/sdk/bubbleHelpers.js index b1ef9110f..5eab20f5d 100644 --- a/app/javascript/sdk/bubbleHelpers.js +++ b/app/javascript/sdk/bubbleHelpers.js @@ -1,4 +1,4 @@ -import { addClass, removeClass, toggleClass, wootOn } from './DOMHelpers'; +import { addClasses, removeClasses, toggleClass } from './DOMHelpers'; import { IFrameHelper } from './IFrameHelper'; import { isExpandedView } from './settingsHelper'; @@ -41,14 +41,14 @@ export const createBubbleIcon = ({ className, src, target }) => { export const createBubbleHolder = hideMessageBubble => { if (hideMessageBubble) { - addClass(bubbleHolder, 'woot-hidden'); + addClasses(bubbleHolder, 'woot-hidden'); } - addClass(bubbleHolder, 'woot--bubble-holder'); + addClasses(bubbleHolder, 'woot--bubble-holder'); body.appendChild(bubbleHolder); }; export const createNotificationBubble = () => { - addClass(notificationBubble, 'woot--notification'); + addClasses(notificationBubble, 'woot--notification'); return notificationBubble; }; @@ -71,15 +71,15 @@ export const onBubbleClick = (props = {}) => { }; export const onClickChatBubble = () => { - wootOn(bubbleHolder, 'click', onBubbleClick); + bubbleHolder.addEventListener('click', onBubbleClick); }; export const addUnreadClass = () => { const holderEl = document.querySelector('.woot-widget-holder'); - addClass(holderEl, 'has-unread-view'); + addClasses(holderEl, 'has-unread-view'); }; export const removeUnreadClass = () => { const holderEl = document.querySelector('.woot-widget-holder'); - removeClass(holderEl, 'has-unread-view'); + removeClasses(holderEl, 'has-unread-view'); }; From 6c048626d0a8b8fc38e7e9244d2ac7de399a26bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kube=C5=A1?= <46596180+KubesDavid@users.noreply.github.com> Date: Wed, 12 Oct 2022 23:55:59 +0200 Subject: [PATCH 05/16] chore: Replace deprecated functions (#5611) Co-authored-by: Pranav Raj S --- app/javascript/dashboard/components/widgets/Avatar.vue | 2 +- .../dashboard/components/widgets/conversation/ReplyBox.vue | 2 +- .../dashboard/conversation/contact/ConversationForm.vue | 2 +- .../routes/dashboard/settings/inbox/WidgetBuilder.vue | 2 +- app/javascript/shared/mixins/campaignMixin.js | 4 ++-- app/javascript/survey/views/Response.vue | 2 +- app/models/working_hour.rb | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/Avatar.vue b/app/javascript/dashboard/components/widgets/Avatar.vue index daf044288..df654ee7e 100644 --- a/app/javascript/dashboard/components/widgets/Avatar.vue +++ b/app/javascript/dashboard/components/widgets/Avatar.vue @@ -78,7 +78,7 @@ export default { if (initials.length > 2 && initials.search(/[A-Z]/) !== -1) { initials = initials.replace(/[a-z]+/g, ''); } - initials = initials.substr(0, 2).toUpperCase(); + initials = initials.substring(0, 2).toUpperCase(); return initials; }, }, diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index 1b0b9ca36..bbc2f017e 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -477,7 +477,7 @@ export default { const hasNextWord = updatedMessage.includes(' '); const isShortCodeActive = this.hasSlashCommand && !hasNextWord; if (isShortCodeActive) { - this.mentionSearchKey = updatedMessage.substr(1, updatedMessage.length); + this.mentionSearchKey = updatedMessage.substring(1); this.showMentions = true; } else { this.mentionSearchKey = ''; diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue index 9dda5c02c..c9294aa2a 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ConversationForm.vue @@ -239,7 +239,7 @@ export default { const hasNextWord = value.includes(' '); const isShortCodeActive = this.hasSlashCommand && !hasNextWord; if (isShortCodeActive) { - this.cannedResponseSearchKey = value.substr(1, value.length); + this.cannedResponseSearchKey = value.substring(1); this.showCannedResponseMenu = true; } else { this.cannedResponseSearchKey = ''; diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/WidgetBuilder.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/WidgetBuilder.vue index 8da5183d7..bdc20e14e 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/WidgetBuilder.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/WidgetBuilder.vue @@ -243,7 +243,7 @@ export default { this.$t('INBOX_MGMT.WIDGET_BUILDER.SCRIPT_SETTINGS', { options: JSON.stringify(options), }) + - script.substring(13, script.length) + script.substring(13) ); }, getWidgetViewOptions() { diff --git a/app/javascript/shared/mixins/campaignMixin.js b/app/javascript/shared/mixins/campaignMixin.js index b9353ff29..ebf98aa37 100644 --- a/app/javascript/shared/mixins/campaignMixin.js +++ b/app/javascript/shared/mixins/campaignMixin.js @@ -1,10 +1,10 @@ import { CAMPAIGN_TYPES } from '../constants/campaign'; + export default { computed: { campaignType() { const pageURL = window.location.href; - const type = pageURL.substr(pageURL.lastIndexOf('/') + 1); - return type; + return pageURL.substring(pageURL.lastIndexOf('/') + 1); }, isOngoingType() { return this.campaignType === CAMPAIGN_TYPES.ONGOING; diff --git a/app/javascript/survey/views/Response.vue b/app/javascript/survey/views/Response.vue index 6ec4ec100..828a9cbee 100644 --- a/app/javascript/survey/views/Response.vue +++ b/app/javascript/survey/views/Response.vue @@ -93,7 +93,7 @@ export default { computed: { surveyId() { const pageURL = window.location.href; - return pageURL.substr(pageURL.lastIndexOf('/') + 1); + return pageURL.substring(pageURL.lastIndexOf('/') + 1); }, isRatingSubmitted() { return this.surveyDetails && this.surveyDetails.rating; diff --git a/app/models/working_hour.rb b/app/models/working_hour.rb index 5ad4d0446..01b972bd4 100644 --- a/app/models/working_hour.rb +++ b/app/models/working_hour.rb @@ -40,7 +40,7 @@ class WorkingHour < ApplicationRecord validate :open_all_day_and_closed_all_day def self.today - # While getting the day of the week, consider the timezone as well. `first` would + # While getting the day of the week, consider the timezone as well. `first` would # return the first working hour from the list of working hours available per week. inbox = first.inbox find_by(day_of_week: Time.zone.now.in_time_zone(inbox.timezone).to_date.wday) From ee520bdf982186eec0c74f32741a61363b50cdf4 Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Thu, 13 Oct 2022 04:52:44 +0530 Subject: [PATCH 06/16] feat: Show last active portal articles when sidebar portal icon is clicked (#5616) --- .../layout/config/sidebarItems/primaryMenu.js | 2 +- .../components/HelpCenterLayout.vue | 11 +++++-- .../helpcenter/components/PortalListItem.vue | 8 ++++- .../dashboard/helpcenter/helpcenter.routes.js | 8 +++++ .../pages/articles/DefaultPortalArticles.vue | 31 +++++++++++++++++++ 5 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 app/javascript/dashboard/routes/dashboard/helpcenter/pages/articles/DefaultPortalArticles.vue diff --git a/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js b/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js index cc4287503..fa4633ec1 100644 --- a/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js +++ b/app/javascript/dashboard/components/layout/config/sidebarItems/primaryMenu.js @@ -39,7 +39,7 @@ const primaryMenuItems = accountId => [ label: 'HELP_CENTER.TITLE', featureFlag: 'help_center', toState: frontendURL(`accounts/${accountId}/portals`), - toStateName: 'list_all_portals', + toStateName: 'default_portal_articles', roles: ['administrator'], }, { diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue index 528b55575..562d6bd07 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/HelpCenterLayout.vue @@ -59,6 +59,7 @@ import HelpCenterSidebar from '../components/Sidebar/Sidebar.vue'; import CommandBar from 'dashboard/routes/dashboard/commands/commandbar.vue'; import WootKeyShortcutModal from 'dashboard/components/widgets/modal/WootKeyShortcutModal'; import NotificationPanel from 'dashboard/routes/dashboard/notifications/components/NotificationPanel'; +import uiSettingsMixin from 'dashboard/mixins/uiSettings'; import portalMixin from '../mixins/portalMixin'; import AddCategory from '../pages/categories/AddCategory'; @@ -72,7 +73,7 @@ export default { PortalPopover, AddCategory, }, - mixins: [portalMixin], + mixins: [portalMixin, uiSettingsMixin], data() { return { isSidebarOpen: false, @@ -231,7 +232,13 @@ export default { }, updated() { const slug = this.$route.params.portalSlug; - if (slug) this.lastActivePortalSlug = slug; + if (slug) { + this.lastActivePortalSlug = slug; + this.updateUISettings({ + last_active_portal_slug: slug, + last_active_locale_code: this.selectedLocaleInPortal, + }); + } }, methods: { handleResize() { diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalListItem.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalListItem.vue index e0e002002..0354ad22b 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalListItem.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/PortalListItem.vue @@ -188,13 +188,15 @@ From d2fd05ee4e18701fcc10ba95e1404d4af364abef Mon Sep 17 00:00:00 2001 From: Pranav Raj S Date: Wed, 12 Oct 2022 21:45:28 -0700 Subject: [PATCH 07/16] fix: Show webhook url only on WhatsApp inbox (#5618) --- .../routes/dashboard/settings/inbox/FinishSetup.vue | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue index 01c46f5dc..7931016e4 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue @@ -19,15 +19,11 @@ :script="currentInbox.callback_webhook_url" /> -
+

{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_CALLBACK.WEBHOOK_URL') }}

- +

{{ $t( @@ -36,7 +32,6 @@ }}

From 8f4944fda065e4e6282930ff76bdfc18798b0984 Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Thu, 13 Oct 2022 13:46:28 +0530 Subject: [PATCH 08/16] chore: revert arm64 docker build in gh action (#5619) ref: https://github.com/chatwoot/chatwoot/pull/5575 https://github.com/chatwoot/chatwoot/pull/5575#issuecomment-1277208625 --- .github/workflows/publish_foss_docker.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish_foss_docker.yml b/.github/workflows/publish_foss_docker.yml index aa1b15df2..2ddaba7e5 100644 --- a/.github/workflows/publish_foss_docker.yml +++ b/.github/workflows/publish_foss_docker.yml @@ -58,6 +58,6 @@ jobs: with: context: . file: docker/Dockerfile - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64 push: true tags: ${{ env.DOCKER_TAG }} From a533f43fbf5ed6273ad3e0026d87d2d2a934c83e Mon Sep 17 00:00:00 2001 From: Tejaswini Chile Date: Fri, 14 Oct 2022 02:01:49 +0530 Subject: [PATCH 09/16] fix: Stop raising errors for unsupported Whatsapp messages (#5541) - Handle unsupported Whatsapp messages --- .../whatsapp/incoming_message_base_service.rb | 6 ++- .../jobs/webhooks/whatsapp_events_job_spec.rb | 53 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/app/services/whatsapp/incoming_message_base_service.rb b/app/services/whatsapp/incoming_message_base_service.rb index e55d5fd26..40dafaced 100644 --- a/app/services/whatsapp/incoming_message_base_service.rb +++ b/app/services/whatsapp/incoming_message_base_service.rb @@ -12,7 +12,7 @@ class Whatsapp::IncomingMessageBaseService set_conversation - return if @processed_params[:messages].blank? + return if @processed_params[:messages].blank? || unprocessable_message_type? @message = @conversation.messages.build( content: message_content(@processed_params[:messages].first), @@ -86,6 +86,10 @@ class Whatsapp::IncomingMessageBaseService @processed_params[:messages].first[:type] end + def unprocessable_message_type? + %w[reaction contacts].include?(message_type) + end + def attach_files return if %w[text button interactive].include?(message_type) diff --git a/spec/jobs/webhooks/whatsapp_events_job_spec.rb b/spec/jobs/webhooks/whatsapp_events_job_spec.rb index 2a28fe41f..00fde3d41 100644 --- a/spec/jobs/webhooks/whatsapp_events_job_spec.rb +++ b/spec/jobs/webhooks/whatsapp_events_job_spec.rb @@ -62,6 +62,59 @@ RSpec.describe Webhooks::WhatsappEventsJob, type: :job do job.perform_now(wb_params) end + it 'Ignore reaction type message and stop raising error' do + other_channel = create(:channel_whatsapp, phone_number: '+1987654', provider: 'whatsapp_cloud', sync_templates: false, + validate_provider_config: false) + wb_params = { + phone_number: channel.phone_number, + object: 'whatsapp_business_account', + entry: [{ + changes: [{ + value: { + contacts: [{ profile: { name: 'Test Test' }, wa_id: '1111981136571' }], + messages: [{ + from: '1111981136571', reaction: { emoji: '👍' }, timestamp: '1664799904', type: 'reaction' + }], + metadata: { + phone_number_id: other_channel.provider_config['phone_number_id'], + display_phone_number: other_channel.phone_number.delete('+') + } + } + }] + }] + }.with_indifferent_access + expect do + Whatsapp::IncomingMessageWhatsappCloudService.new(inbox: other_channel.inbox, params: wb_params).perform + end.not_to change(Message, :count) + end + + it 'Ignore contacts type message and stop raising error' do + other_channel = create(:channel_whatsapp, phone_number: '+1987654', provider: 'whatsapp_cloud', sync_templates: false, + validate_provider_config: false) + wb_params = { + phone_number: channel.phone_number, + object: 'whatsapp_business_account', + entry: [{ + changes: [{ + value: { + contacts: [{ profile: { name: 'Test Test' }, wa_id: '1111981136571' }], + messages: [{ from: '1111981136571', + contacts: [{ phones: [{ phone: '+1987654' }], name: { first_name: 'contact name' } }], + timestamp: '1664799904', + type: 'contacts' }], + metadata: { + phone_number_id: other_channel.provider_config['phone_number_id'], + display_phone_number: other_channel.phone_number.delete('+') + } + } + }] + }] + }.with_indifferent_access + expect do + Whatsapp::IncomingMessageWhatsappCloudService.new(inbox: other_channel.inbox, params: wb_params).perform + end.not_to change(Message, :count) + end + it 'will not enque Whatsapp::IncomingMessageWhatsappCloudService when invalid phone number id' do other_channel = create(:channel_whatsapp, phone_number: '+1987654', provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false) From bf4338ef9e3fc7637f0d8d3549afc7a002873e47 Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Fri, 14 Oct 2022 02:05:11 +0530 Subject: [PATCH 10/16] feat: Make category name in article table clickable (#5626) Co-authored-by: Pranav Raj S --- .../helpcenter/components/ArticleItem.vue | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleItem.vue b/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleItem.vue index cecf1f39e..b602baaa8 100644 --- a/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleItem.vue +++ b/app/javascript/dashboard/routes/dashboard/helpcenter/components/ArticleItem.vue @@ -16,7 +16,12 @@
- {{ category.name }} + + {{ category.name }} + @@ -43,6 +48,8 @@ From 1f271356ca065e6a9a0169503cababad240cd3bc Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Fri, 14 Oct 2022 02:06:42 +0530 Subject: [PATCH 11/16] feat: Update the design for dropdown buttons (#5625) --- .../assets/scss/widgets/_buttons.scss | 17 +++++++++++- .../dashboard/assets/scss/widgets/_modal.scss | 10 ++----- app/javascript/dashboard/components/Modal.vue | 10 ++++--- .../components/ui/MultiselectDropdown.vue | 26 ++++++++++++++++--- .../ui/MultiselectDropdownItems.vue | 13 +++++----- .../components/ui/dropdown/DropdownItem.vue | 8 ++---- 6 files changed, 57 insertions(+), 27 deletions(-) diff --git a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss index 9d3f84b25..478045000 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_buttons.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_buttons.scss @@ -113,9 +113,22 @@ $default-button-height: 4.0rem; } &.clear { + color: var(--w-700); + + &.secondary { + color: var(--s-700) + } + + &.success { + color: var(--g-700) + } + + &.alert { + color: var(--r-700) + } &.warning { - color: var(--y-600); + color: var(--y-700) } &:hover { @@ -146,6 +159,8 @@ $default-button-height: 4.0rem; &.small { height: var(--space-large); + padding-bottom: var(--space-smaller); + padding-top: var(--space-smaller); } &.large { diff --git a/app/javascript/dashboard/assets/scss/widgets/_modal.scss b/app/javascript/dashboard/assets/scss/widgets/_modal.scss index fc497f069..543a60797 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_modal.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_modal.scss @@ -14,15 +14,9 @@ } .modal--close { - border-radius: 50%; - color: $color-heading; - cursor: pointer; - font-size: $font-size-big; - line-height: $space-normal; - padding: $space-normal; position: absolute; - right: $space-micro; - top: $space-micro; + right: $space-small; + top: $space-small; &:hover { background: $color-background; diff --git a/app/javascript/dashboard/components/Modal.vue b/app/javascript/dashboard/components/Modal.vue index f4cad844a..d5dd55ffa 100644 --- a/app/javascript/dashboard/components/Modal.vue +++ b/app/javascript/dashboard/components/Modal.vue @@ -7,9 +7,13 @@ @click="onBackDropClick" >
- +
diff --git a/app/javascript/shared/components/ui/MultiselectDropdown.vue b/app/javascript/shared/components/ui/MultiselectDropdown.vue index 76908c380..1636ca252 100644 --- a/app/javascript/shared/components/ui/MultiselectDropdown.vue +++ b/app/javascript/shared/components/ui/MultiselectDropdown.vue @@ -41,9 +41,18 @@ :class="{ 'dropdown-pane--open': showSearchDropdown }" class="dropdown-pane" > -

- {{ multiselectorTitle }} -

+ diff --git a/app/javascript/shared/components/ui/MultiselectDropdownItems.vue b/app/javascript/shared/components/ui/MultiselectDropdownItems.vue index 8aadcb7cb..96aa99323 100644 --- a/app/javascript/shared/components/ui/MultiselectDropdownItems.vue +++ b/app/javascript/shared/components/ui/MultiselectDropdownItems.vue @@ -20,6 +20,7 @@ .dropdown-menu__item { list-style: none; + margin-bottom: var(--space-micro); ::v-deep { a, .button { + display: inline-flex; width: 100%; text-align: left; color: var(--s-700); - white-space: nowrap; - display: inline-flex; - padding: var(--space-small); - padding-top: var(--space-small); - padding-bottom: var(--space-small); - border-radius: var(--border-radius-normal); &:hover { background: var(--color-background); From e310230f624df59f99c4c602129d29652bb26c5a Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Thu, 13 Oct 2022 15:12:04 -0700 Subject: [PATCH 12/16] chore: Refactor Contact Inbox Builders (#5617) - Remove duplicate code and move everything to builders - fixes: #4680 --- .rubocop.yml | 1 + app/builders/contact_inbox_builder.rb | 43 ++-- ... => contact_inbox_with_contact_builder.rb} | 56 +++-- .../messages/facebook/message_builder.rb | 32 +-- .../contacts/contact_inboxes_controller.rb | 7 +- .../api/v1/accounts/contacts_controller.rb | 7 +- .../v1/accounts/conversations_controller.rb | 27 ++- .../concerns/request_exception_handler.rb | 2 + .../api/v1/inboxes/contacts_controller.rb | 2 +- app/mailboxes/mailbox_helper.rb | 2 +- app/models/channel/facebook_page.rb | 15 +- app/models/channel/twitter_profile.rb | 15 +- app/models/channel/web_widget.rb | 18 +- app/services/line/incoming_message_service.rb | 2 +- app/services/sms/incoming_message_service.rb | 2 +- .../telegram/incoming_message_service.rb | 2 +- .../twilio/incoming_message_service.rb | 2 +- .../whatsapp/incoming_message_base_service.rb | 2 +- db/seeds.rb | 9 +- spec/builders/contact_inbox_builder_spec.rb | 196 +++++++++--------- ...ontact_inbox_with_contact_builder_spec.rb} | 2 +- 21 files changed, 234 insertions(+), 210 deletions(-) rename app/builders/{contact_builder.rb => contact_inbox_with_contact_builder.rb} (51%) rename spec/builders/{contact_builder_spec.rb => contact_inbox_with_contact_builder_spec.rb} (98%) diff --git a/.rubocop.yml b/.rubocop.yml index dafd9a620..3665ad2e3 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -16,6 +16,7 @@ Metrics/ClassLength: - 'app/models/message.rb' - 'app/builders/messages/facebook/message_builder.rb' - 'app/controllers/api/v1/accounts/contacts_controller.rb' + - 'app/controllers/api/v1/accounts/conversations_controller.rb' - 'app/listeners/action_cable_listener.rb' - 'app/models/conversation.rb' RSpec/ExampleLength: diff --git a/app/builders/contact_inbox_builder.rb b/app/builders/contact_inbox_builder.rb index 1b8782c51..8fcd2b158 100644 --- a/app/builders/contact_inbox_builder.rb +++ b/app/builders/contact_inbox_builder.rb @@ -1,13 +1,12 @@ +# This Builder will create a contact inbox with specified attributes. If the contact inbox already exists, it will be returned. +# For Specific Channels like whatsapp, email etc . it smartly generated appropriate the source id when none is provided. + class ContactInboxBuilder - pattr_initialize [:contact_id!, :inbox_id!, :source_id] + pattr_initialize [:contact, :inbox, :source_id, { hmac_verified: false }] def perform - @contact = Contact.find(contact_id) - @inbox = @contact.account.inboxes.find(inbox_id) - return unless ['Channel::TwilioSms', 'Channel::Sms', 'Channel::Email', 'Channel::Api', 'Channel::Whatsapp'].include? @inbox.channel_type - - source_id = @source_id || generate_source_id - create_contact_inbox(source_id) if source_id.present? + @source_id ||= generate_source_id + create_contact_inbox if source_id.present? end private @@ -19,23 +18,37 @@ class ContactInboxBuilder when 'Channel::Whatsapp' wa_source_id when 'Channel::Email' - @contact.email + email_source_id when 'Channel::Sms' - @contact.phone_number - when 'Channel::Api' + phone_source_id + when 'Channel::Api', 'Channel::WebWidget' SecureRandom.uuid + else + raise "Unsupported operation for this channel: #{@inbox.channel_type}" end end + def email_source_id + raise ActionController::ParameterMissing, 'contact email' unless @contact.email + + @contact.email + end + + def phone_source_id + raise ActionController::ParameterMissing, 'contact phone number' unless @contact.phone_number + + @contact.phone_number + end + def wa_source_id - return unless @contact.phone_number + raise ActionController::ParameterMissing, 'contact phone number' unless @contact.phone_number # whatsapp doesn't want the + in e164 format @contact.phone_number.delete('+').to_s end def twilio_source_id - return unless @contact.phone_number + raise ActionController::ParameterMissing, 'contact phone number' unless @contact.phone_number case @inbox.channel.medium when 'sms' @@ -45,11 +58,11 @@ class ContactInboxBuilder end end - def create_contact_inbox(source_id) - ::ContactInbox.find_or_create_by!( + def create_contact_inbox + ::ContactInbox.create_with(hmac_verified: hmac_verified || false).find_or_create_by!( contact_id: @contact.id, inbox_id: @inbox.id, - source_id: source_id + source_id: @source_id ) end end diff --git a/app/builders/contact_builder.rb b/app/builders/contact_inbox_with_contact_builder.rb similarity index 51% rename from app/builders/contact_builder.rb rename to app/builders/contact_inbox_with_contact_builder.rb index 938072643..d97f64cfe 100644 --- a/app/builders/contact_builder.rb +++ b/app/builders/contact_inbox_with_contact_builder.rb @@ -1,25 +1,47 @@ -class ContactBuilder - pattr_initialize [:source_id!, :inbox!, :contact_attributes!, :hmac_verified] +# This Builder will create a contact and contact inbox with specified attributes. +# If an existing identified contact exisits, it will be returned. +# for contact inbox logic it uses the contact inbox builder + +class ContactInboxWithContactBuilder + pattr_initialize [:inbox!, :contact_attributes!, :source_id, :hmac_verified] def perform - contact_inbox = inbox.contact_inboxes.find_by(source_id: source_id) - return contact_inbox if contact_inbox + find_or_create_contact_and_contact_inbox + # in case of race conditions where contact is created by another thread + # we will try to find the contact and create a contact inbox + rescue ActiveRecord::RecordNotUnique + find_or_create_contact_and_contact_inbox + end - build_contact_inbox + def find_or_create_contact_and_contact_inbox + @contact_inbox = inbox.contact_inboxes.find_by(source_id: source_id) if source_id.present? + return @contact_inbox if @contact_inbox + + ActiveRecord::Base.transaction(requires_new: true) do + build_contact_with_contact_inbox + update_contact_avatar(@contact) unless @contact.avatar.attached? + @contact_inbox + end end private + def build_contact_with_contact_inbox + @contact = find_contact || create_contact + @contact_inbox = create_contact_inbox + end + def account @account ||= inbox.account end - def create_contact_inbox(contact) - ::ContactInbox.create_with(hmac_verified: hmac_verified || false).find_or_create_by!( - contact_id: contact.id, - inbox_id: inbox.id, - source_id: source_id - ) + def create_contact_inbox + ContactInboxBuilder.new( + contact: @contact, + inbox: @inbox, + source_id: @source_id, + hmac_verified: hmac_verified + ).perform end def update_contact_avatar(contact) @@ -61,16 +83,4 @@ class ContactBuilder account.contacts.find_by(phone_number: phone_number) end - - def build_contact_inbox - ActiveRecord::Base.transaction do - contact = find_contact || create_contact - contact_inbox = create_contact_inbox(contact) - update_contact_avatar(contact) - contact_inbox - rescue StandardError => e - Rails.logger.error e - raise e - end - end end diff --git a/app/builders/messages/facebook/message_builder.rb b/app/builders/messages/facebook/message_builder.rb index 9f670602a..42d567e54 100644 --- a/app/builders/messages/facebook/message_builder.rb +++ b/app/builders/messages/facebook/message_builder.rb @@ -22,10 +22,9 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder return if @inbox.channel.reauthorization_required? ActiveRecord::Base.transaction do - build_contact + build_contact_inbox build_message end - ensure_contact_avatar rescue Koala::Facebook::AuthenticationError @inbox.channel.authorization_error! rescue StandardError => e @@ -35,15 +34,12 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder private - def contact - @contact ||= @inbox.contact_inboxes.find_by(source_id: @sender_id)&.contact - end - - def build_contact - return if contact.present? - - @contact = Contact.create!(contact_params.except(:remote_avatar_url)) - @contact_inbox = ContactInbox.find_or_create_by!(contact: contact, inbox: @inbox, source_id: @sender_id) + def build_contact_inbox + @contact_inbox = ::ContactInboxWithContactBuilder.new( + source_id: @sender_id, + inbox: @inbox, + contact_attributes: contact_params + ).perform end def build_message @@ -54,19 +50,11 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder end end - def ensure_contact_avatar - return if contact_params[:remote_avatar_url].blank? - return if @contact.avatar.attached? - - Avatar::AvatarFromUrlJob.perform_later(@contact, contact_params[:remote_avatar_url]) - end - def conversation @conversation ||= Conversation.find_by(conversation_params) || build_conversation end def build_conversation - @contact_inbox ||= contact.contact_inboxes.find_by!(source_id: @sender_id) Conversation.create!(conversation_params.merge( contact_inbox_id: @contact_inbox.id )) @@ -94,7 +82,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder { account_id: @inbox.account_id, inbox_id: @inbox.id, - contact_id: contact.id + contact_id: @contact_inbox.contact_id } end @@ -105,7 +93,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder message_type: @message_type, content: response.content, source_id: response.identifier, - sender: @outgoing_echo ? nil : contact + sender: @outgoing_echo ? nil : @contact_inbox.contact } end @@ -113,7 +101,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder { name: "#{result['first_name'] || 'John'} #{result['last_name'] || 'Doe'}", account_id: @inbox.account_id, - remote_avatar_url: result['profile_pic'] || '' + avatar_url: result['profile_pic'] } end diff --git a/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb b/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb index fdcdcaf9e..b4287ae08 100644 --- a/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/contacts/contact_inboxes_controller.rb @@ -2,8 +2,11 @@ class Api::V1::Accounts::Contacts::ContactInboxesController < Api::V1::Accounts: before_action :ensure_inbox, only: [:create] def create - source_id = params[:source_id] || SecureRandom.uuid - @contact_inbox = ContactInbox.create!(contact: @contact, inbox: @inbox, source_id: source_id) + @contact_inbox = ContactInboxBuilder.new( + contact: @contact, + inbox: @inbox, + source_id: params[:source_id] + ).perform end private diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 1c56e9c04..b86b973df 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -134,8 +134,11 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController return if params[:inbox_id].blank? inbox = Current.account.inboxes.find(params[:inbox_id]) - source_id = params[:source_id] || SecureRandom.uuid - ContactInbox.create!(contact: @contact, inbox: inbox, source_id: source_id) + ContactInboxBuilder.new( + contact: @contact, + inbox: inbox, + source_id: params[:source_id] + ).perform end def permitted_params diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index 0515eabca..8734a3dd4 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro include DateRangeHelper before_action :conversation, except: [:index, :meta, :search, :create, :filter] - before_action :contact_inbox, only: [:create] + before_action :inbox, :contact, :contact_inbox, only: [:create] def index result = conversation_finder.perform @@ -109,22 +109,35 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro authorize @conversation.inbox, :show? end + def inbox + return if params[:inbox_id].blank? + + @inbox = Current.account.inboxes.find(params[:inbox_id]) + authorize @inbox, :show? + end + + def contact + return if params[:contact_id].blank? + + @contact = Current.account.contacts.find(params[:contact_id]) + end + def contact_inbox @contact_inbox = build_contact_inbox + # fallback for the old case where we do look up only using source id + # In future we need to change this and make sure we do look up on combination of inbox_id and source_id + # and deprecate the support of passing only source_id as the param @contact_inbox ||= ::ContactInbox.find_by!(source_id: params[:source_id]) authorize @contact_inbox.inbox, :show? end def build_contact_inbox - return if params[:contact_id].blank? || params[:inbox_id].blank? - - inbox = Current.account.inboxes.find(params[:inbox_id]) - authorize inbox, :show? + return if @inbox.blank? || @contact.blank? ContactInboxBuilder.new( - contact_id: params[:contact_id], - inbox_id: inbox.id, + contact: @contact, + inbox: @inbox, source_id: params[:source_id] ).perform end diff --git a/app/controllers/concerns/request_exception_handler.rb b/app/controllers/concerns/request_exception_handler.rb index 6e9ed04cc..2f53fdc2b 100644 --- a/app/controllers/concerns/request_exception_handler.rb +++ b/app/controllers/concerns/request_exception_handler.rb @@ -13,6 +13,8 @@ module RequestExceptionHandler render_not_found_error('Resource could not be found') rescue Pundit::NotAuthorizedError render_unauthorized('You are not authorized to do this action') + rescue ActionController::ParameterMissing => e + render_could_not_create_error(e.message) ensure # to address the thread variable leak issues in Puma/Thin webserver Current.reset diff --git a/app/controllers/public/api/v1/inboxes/contacts_controller.rb b/app/controllers/public/api/v1/inboxes/contacts_controller.rb index eb794f2a0..1fde3051e 100644 --- a/app/controllers/public/api/v1/inboxes/contacts_controller.rb +++ b/app/controllers/public/api/v1/inboxes/contacts_controller.rb @@ -4,7 +4,7 @@ class Public::Api::V1::Inboxes::ContactsController < Public::Api::V1::InboxesCon def create source_id = params[:source_id] || SecureRandom.uuid - @contact_inbox = ::ContactBuilder.new( + @contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: source_id, inbox: @inbox_channel.inbox, contact_attributes: permitted_params.except(:identifier, :identifier_hash) diff --git a/app/mailboxes/mailbox_helper.rb b/app/mailboxes/mailbox_helper.rb index 1519343ca..216d5c2c3 100644 --- a/app/mailboxes/mailbox_helper.rb +++ b/app/mailboxes/mailbox_helper.rb @@ -34,7 +34,7 @@ module MailboxHelper end def create_contact - @contact_inbox = ::ContactBuilder.new( + @contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: processed_mail.original_sender, inbox: @inbox, contact_attributes: { diff --git a/app/models/channel/facebook_page.rb b/app/models/channel/facebook_page.rb index 2153708e2..bba45f326 100644 --- a/app/models/channel/facebook_page.rb +++ b/app/models/channel/facebook_page.rb @@ -37,16 +37,11 @@ class Channel::FacebookPage < ApplicationRecord end def create_contact_inbox(instagram_id, name) - ActiveRecord::Base.transaction do - contact = inbox.account.contacts.create!(name: name) - ::ContactInbox.create!( - contact_id: contact.id, - inbox_id: inbox.id, - source_id: instagram_id - ) - rescue StandardError => e - Rails.logger.error e - end + @contact_inbox = ::ContactInboxWithContactBuilder.new({ + source_id: instagram_id, + inbox: inbox, + contact_attributes: { name: name } + }).perform end def subscribe diff --git a/app/models/channel/twitter_profile.rb b/app/models/channel/twitter_profile.rb index 4f6fa7ba1..d0f765e9f 100644 --- a/app/models/channel/twitter_profile.rb +++ b/app/models/channel/twitter_profile.rb @@ -32,16 +32,11 @@ class Channel::TwitterProfile < ApplicationRecord end def create_contact_inbox(profile_id, name, additional_attributes) - ActiveRecord::Base.transaction do - contact = inbox.account.contacts.create!(additional_attributes: additional_attributes, name: name) - ::ContactInbox.create!( - contact_id: contact.id, - inbox_id: inbox.id, - source_id: profile_id - ) - rescue StandardError => e - Rails.logger.error e - end + ::ContactInboxWithContactBuilder.new({ + source_id: profile_id, + inbox: inbox, + contact_attributes: { name: name, additional_attributes: additional_attributes } + }).perform end def twitter_client diff --git a/app/models/channel/web_widget.rb b/app/models/channel/web_widget.rb index b85443633..59d392892 100644 --- a/app/models/channel/web_widget.rb +++ b/app/models/channel/web_widget.rb @@ -98,19 +98,9 @@ class Channel::WebWidget < ApplicationRecord end def create_contact_inbox(additional_attributes = {}) - ActiveRecord::Base.transaction do - contact = inbox.account.contacts.create!( - name: ::Haikunator.haikunate(1000), - additional_attributes: additional_attributes - ) - contact_inbox = ::ContactInbox.create!( - contact_id: contact.id, - inbox_id: inbox.id, - source_id: SecureRandom.uuid - ) - contact_inbox - rescue StandardError => e - Rails.logger.error e - end + ::ContactInboxWithContactBuilder.new({ + inbox: inbox, + contact_attributes: { additional_attributes: additional_attributes } + }).perform end end diff --git a/app/services/line/incoming_message_service.rb b/app/services/line/incoming_message_service.rb index 535c03dc7..48a52eb8f 100644 --- a/app/services/line/incoming_message_service.rb +++ b/app/services/line/incoming_message_service.rb @@ -81,7 +81,7 @@ class Line::IncomingMessageService end def set_contact - contact_inbox = ::ContactBuilder.new( + contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: line_contact_info['userId'], inbox: inbox, contact_attributes: contact_attributes diff --git a/app/services/sms/incoming_message_service.rb b/app/services/sms/incoming_message_service.rb index 7ee6e3e63..7aa22b19e 100644 --- a/app/services/sms/incoming_message_service.rb +++ b/app/services/sms/incoming_message_service.rb @@ -37,7 +37,7 @@ class Sms::IncomingMessageService end def set_contact - contact_inbox = ::ContactBuilder.new( + contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: params[:from], inbox: @inbox, contact_attributes: contact_attributes diff --git a/app/services/telegram/incoming_message_service.rb b/app/services/telegram/incoming_message_service.rb index a26bda14e..e8ab8a72c 100644 --- a/app/services/telegram/incoming_message_service.rb +++ b/app/services/telegram/incoming_message_service.rb @@ -31,7 +31,7 @@ class Telegram::IncomingMessageService end def set_contact - contact_inbox = ::ContactBuilder.new( + contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: params[:message][:from][:id], inbox: inbox, contact_attributes: contact_attributes diff --git a/app/services/twilio/incoming_message_service.rb b/app/services/twilio/incoming_message_service.rb index 50c77111c..4473131df 100644 --- a/app/services/twilio/incoming_message_service.rb +++ b/app/services/twilio/incoming_message_service.rb @@ -47,7 +47,7 @@ class Twilio::IncomingMessageService end def set_contact - contact_inbox = ::ContactBuilder.new( + contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: params[:From], inbox: inbox, contact_attributes: contact_attributes diff --git a/app/services/whatsapp/incoming_message_base_service.rb b/app/services/whatsapp/incoming_message_base_service.rb index 40dafaced..da08e02d6 100644 --- a/app/services/whatsapp/incoming_message_base_service.rb +++ b/app/services/whatsapp/incoming_message_base_service.rb @@ -48,7 +48,7 @@ class Whatsapp::IncomingMessageBaseService contact_params = @processed_params[:contacts]&.first return if contact_params.blank? - contact_inbox = ::ContactBuilder.new( + contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: contact_params[:wa_id], inbox: inbox, contact_attributes: { name: contact_params.dig(:profile, :name), phone_number: "+#{@processed_params[:messages].first[:from]}" } diff --git a/db/seeds.rb b/db/seeds.rb index c4c7eda71..ead862669 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -46,8 +46,13 @@ unless Rails.env.production? inbox = Inbox.create!(channel: web_widget, account: account, name: 'Acme Support') InboxMember.create!(user: user, inbox: inbox) - contact = Contact.create!(name: 'jane', email: 'jane@example.com', phone_number: '+2320000', account: account) - contact_inbox = ContactInbox.create!(inbox: inbox, contact: contact, source_id: user.id, hmac_verified: true) + contact = ::ContactInboxWithContactBuilder.new( + source_id: user.id, + inbox: inbox, + hmac_verified: true, + contact_attributes: { name: 'jane', email: 'jane@example.com', phone_number: '+2320000' } + ).perform&.contact + conversation = Conversation.create!( account: account, inbox: inbox, diff --git a/spec/builders/contact_inbox_builder_spec.rb b/spec/builders/contact_inbox_builder_spec.rb index 47210f6ca..46b0d749c 100644 --- a/spec/builders/contact_inbox_builder_spec.rb +++ b/spec/builders/contact_inbox_builder_spec.rb @@ -12,8 +12,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id, + contact: contact, + inbox: twilio_inbox, source_id: contact.phone_number ).perform @@ -23,8 +23,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with phone number and source id is not provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id + contact: contact, + inbox: twilio_inbox ).perform expect(contact_inbox.id).to eq(existing_contact_inbox.id) @@ -33,8 +33,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id, + contact: contact, + inbox: twilio_inbox, source_id: '+224213223422' ).perform @@ -44,12 +44,23 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with contact phone number when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id + contact: contact, + inbox: twilio_inbox ).perform expect(contact_inbox.source_id).to eq(contact.phone_number) end + + it 'raises error when contact phone number is not present and no source id is provided' do + contact.update!(phone_number: nil) + + expect do + described_class.new( + contact: contact, + inbox: twilio_inbox + ).perform + end.to raise_error(ActionController::ParameterMissing, 'param is missing or the value is empty: contact phone number') + end end describe 'twilio whatsapp inbox' do @@ -59,8 +70,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: "whatsapp:#{contact.phone_number}") contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id, + contact: contact, + inbox: twilio_inbox, source_id: "whatsapp:#{contact.phone_number}" ).perform @@ -70,8 +81,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with phone number and source id is not provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: "whatsapp:#{contact.phone_number}") contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id + contact: contact, + inbox: twilio_inbox ).perform expect(contact_inbox.id).to eq(existing_contact_inbox.id) @@ -80,8 +91,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: twilio_inbox, source_id: "whatsapp:#{contact.phone_number}") contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id, + contact: contact, + inbox: twilio_inbox, source_id: 'whatsapp:+555555' ).perform @@ -91,12 +102,23 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with contact phone number when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twilio_inbox.id + contact: contact, + inbox: twilio_inbox ).perform expect(contact_inbox.source_id).to eq("whatsapp:#{contact.phone_number}") end + + it 'raises error when contact phone number is not present and no source id is provided' do + contact.update!(phone_number: nil) + + expect do + described_class.new( + contact: contact, + inbox: twilio_inbox + ).perform + end.to raise_error(ActionController::ParameterMissing, 'param is missing or the value is empty: contact phone number') + end end describe 'whatsapp inbox' do @@ -105,8 +127,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: whatsapp_inbox, source_id: contact.phone_number&.delete('+')) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: whatsapp_inbox.id, + contact: contact, + inbox: whatsapp_inbox, source_id: contact.phone_number&.delete('+') ).perform @@ -116,8 +138,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with phone number and source id is not provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: whatsapp_inbox, source_id: contact.phone_number&.delete('+')) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: whatsapp_inbox.id + contact: contact, + inbox: whatsapp_inbox ).perform expect(contact_inbox.id).to be(existing_contact_inbox.id) @@ -126,8 +148,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: whatsapp_inbox, source_id: contact.phone_number&.delete('+')) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: whatsapp_inbox.id, + contact: contact, + inbox: whatsapp_inbox, source_id: '555555' ).perform @@ -137,12 +159,23 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with contact phone number when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: whatsapp_inbox.id + contact: contact, + inbox: whatsapp_inbox ).perform expect(contact_inbox.source_id).to eq(contact.phone_number&.delete('+')) end + + it 'raises error when contact phone number is not present and no source id is provided' do + contact.update!(phone_number: nil) + + expect do + described_class.new( + contact: contact, + inbox: whatsapp_inbox + ).perform + end.to raise_error(ActionController::ParameterMissing, 'param is missing or the value is empty: contact phone number') + end end describe 'sms inbox' do @@ -152,8 +185,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: sms_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: sms_inbox.id, + contact: contact, + inbox: sms_inbox, source_id: contact.phone_number ).perform @@ -163,8 +196,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with phone number and source id is not provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: sms_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: sms_inbox.id + contact: contact, + inbox: sms_inbox ).perform expect(contact_inbox.id).to eq(existing_contact_inbox.id) @@ -173,8 +206,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: sms_inbox, source_id: contact.phone_number) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: sms_inbox.id, + contact: contact, + inbox: sms_inbox, source_id: '+224213223422' ).perform @@ -184,12 +217,23 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with contact phone number when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: sms_inbox.id + contact: contact, + inbox: sms_inbox ).perform expect(contact_inbox.source_id).to eq(contact.phone_number) end + + it 'raises error when contact phone number is not present and no source id is provided' do + contact.update!(phone_number: nil) + + expect do + described_class.new( + contact: contact, + inbox: sms_inbox + ).perform + end.to raise_error(ActionController::ParameterMissing, 'param is missing or the value is empty: contact phone number') + end end describe 'email inbox' do @@ -199,8 +243,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: email_inbox, source_id: contact.email) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: email_inbox.id, + contact: contact, + inbox: email_inbox, source_id: contact.email ).perform @@ -210,8 +254,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with email and source id is not provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: email_inbox, source_id: contact.email) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: email_inbox.id + contact: contact, + inbox: email_inbox ).perform expect(contact_inbox.id).to eq(existing_contact_inbox.id) @@ -220,8 +264,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: email_inbox, source_id: contact.email) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: email_inbox.id, + contact: contact, + inbox: email_inbox, source_id: 'xyc@xyc.com' ).perform @@ -231,12 +275,23 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with contact email when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: email_inbox.id + contact: contact, + inbox: email_inbox ).perform expect(contact_inbox.source_id).to eq(contact.email) end + + it 'raises error when contact email is not present and no source id is provided' do + contact.update!(email: nil) + + expect do + described_class.new( + contact: contact, + inbox: email_inbox + ).perform + end.to raise_error(ActionController::ParameterMissing, 'param is missing or the value is empty: contact email') + end end describe 'api inbox' do @@ -246,8 +301,8 @@ describe ::ContactInboxBuilder do it 'does not create contact inbox when contact inbox already exists with the source id provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: api_inbox, source_id: 'test') contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: api_inbox.id, + contact: contact, + inbox: api_inbox, source_id: 'test' ).perform @@ -257,8 +312,8 @@ describe ::ContactInboxBuilder do it 'creates a new contact inbox when different source id is provided' do existing_contact_inbox = create(:contact_inbox, contact: contact, inbox: api_inbox, source_id: SecureRandom.uuid) contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: api_inbox.id, + contact: contact, + inbox: api_inbox, source_id: 'test' ).perform @@ -268,61 +323,12 @@ describe ::ContactInboxBuilder do it 'creates a contact inbox with SecureRandom.uuid when source id not provided and no contact inbox exists' do contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: api_inbox.id + contact: contact, + inbox: api_inbox ).perform expect(contact_inbox.source_id).not_to be_nil end end - - describe 'web widget' do - let!(:website_channel) { create(:channel_widget, account: account) } - let!(:website_inbox) { create(:inbox, channel: website_channel, account: account) } - - it 'does not create contact inbox' do - contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: website_inbox.id, - source_id: 'test' - ).perform - - expect(contact_inbox).to be_nil - end - end - - describe 'facebook inbox' do - before do - stub_request(:post, /graph.facebook.com/) - end - - let!(:facebook_channel) { create(:channel_facebook_page, account: account) } - let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } - - it 'does not create contact inbox' do - contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: facebook_inbox.id, - source_id: 'test' - ).perform - - expect(contact_inbox).to be_nil - end - end - - describe 'twitter inbox' do - let!(:twitter_channel) { create(:channel_twitter_profile, account: account) } - let!(:twitter_inbox) { create(:inbox, channel: twitter_channel, account: account) } - - it 'does not create contact inbox' do - contact_inbox = described_class.new( - contact_id: contact.id, - inbox_id: twitter_inbox.id, - source_id: 'test' - ).perform - - expect(contact_inbox).to be_nil - end - end end end diff --git a/spec/builders/contact_builder_spec.rb b/spec/builders/contact_inbox_with_contact_builder_spec.rb similarity index 98% rename from spec/builders/contact_builder_spec.rb rename to spec/builders/contact_inbox_with_contact_builder_spec.rb index 29df0da22..e76d199d4 100644 --- a/spec/builders/contact_builder_spec.rb +++ b/spec/builders/contact_inbox_with_contact_builder_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -describe ::ContactBuilder do +describe ::ContactInboxWithContactBuilder do let(:account) { create(:account) } let(:inbox) { create(:inbox, account: account) } let(:contact) { create(:contact, email: 'xyc@example.com', phone_number: '+23423424123', account: account, identifier: '123') } From a6960dc2d38f64f02eb17af88c59ca3f50a24c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Kube=C5=A1?= <46596180+KubesDavid@users.noreply.github.com> Date: Fri, 14 Oct 2022 05:43:11 +0200 Subject: [PATCH 13/16] chore: Refactor widget (#5621) --- app/javascript/widget/api/agent.js | 3 +-- app/javascript/widget/api/campaign.js | 3 +-- app/javascript/widget/api/conversation.js | 12 ++++-------- app/javascript/widget/assets/scss/woot.scss | 5 +---- app/javascript/widget/components/AgentMessage.vue | 3 +-- app/javascript/widget/components/ChatAttachment.vue | 4 ++-- .../widget/components/ChatHeaderExpanded.vue | 7 ++++++- app/javascript/widget/components/ChatInputWrap.vue | 4 +--- app/javascript/widget/components/FileBubble.vue | 3 +-- app/javascript/widget/components/PreChat/Form.vue | 7 ++----- .../widget/components/TeamAvailability.vue | 4 ++-- .../widget/components/UnreadMessageList.vue | 3 +-- app/javascript/widget/helpers/IframeEventHelper.js | 2 +- app/javascript/widget/helpers/utils.js | 11 +---------- .../widget/store/modules/conversation/getters.js | 6 ++---- .../widget/store/modules/conversation/helpers.js | 2 +- .../widget/store/modules/conversation/mutations.js | 3 +-- .../widget/store/modules/conversationLabels.js | 4 ++-- 18 files changed, 31 insertions(+), 55 deletions(-) diff --git a/app/javascript/widget/api/agent.js b/app/javascript/widget/api/agent.js index 0debeccaf..5dceecad7 100644 --- a/app/javascript/widget/api/agent.js +++ b/app/javascript/widget/api/agent.js @@ -3,6 +3,5 @@ import { API } from 'widget/helpers/axios'; export const getAvailableAgents = async websiteToken => { const urlData = endPoints.getAvailableAgents(websiteToken); - const result = await API.get(urlData.url, { params: urlData.params }); - return result; + return API.get(urlData.url, { params: urlData.params }); }; diff --git a/app/javascript/widget/api/campaign.js b/app/javascript/widget/api/campaign.js index 57d81e084..efa154f41 100644 --- a/app/javascript/widget/api/campaign.js +++ b/app/javascript/widget/api/campaign.js @@ -3,8 +3,7 @@ import { API } from 'widget/helpers/axios'; const getCampaigns = async websiteToken => { const urlData = endPoints.getCampaigns(websiteToken); - const result = await API.get(urlData.url, { params: urlData.params }); - return result; + return API.get(urlData.url, { params: urlData.params }); }; const triggerCampaign = async ({ diff --git a/app/javascript/widget/api/conversation.js b/app/javascript/widget/api/conversation.js index fdb3842fd..4cf4de25e 100755 --- a/app/javascript/widget/api/conversation.js +++ b/app/javascript/widget/api/conversation.js @@ -3,26 +3,22 @@ import { API } from 'widget/helpers/axios'; const createConversationAPI = async content => { const urlData = endPoints.createConversation(content); - const result = await API.post(urlData.url, urlData.params); - return result; + return API.post(urlData.url, urlData.params); }; const sendMessageAPI = async content => { const urlData = endPoints.sendMessage(content); - const result = await API.post(urlData.url, urlData.params); - return result; + return API.post(urlData.url, urlData.params); }; const sendAttachmentAPI = async attachment => { const urlData = endPoints.sendAttachment(attachment); - const result = await API.post(urlData.url, urlData.params); - return result; + return API.post(urlData.url, urlData.params); }; const getMessagesAPI = async ({ before }) => { const urlData = endPoints.getConversation({ before }); - const result = await API.get(urlData.url, { params: urlData.params }); - return result; + return API.get(urlData.url, { params: urlData.params }); }; const getConversationAPI = async () => { diff --git a/app/javascript/widget/assets/scss/woot.scss b/app/javascript/widget/assets/scss/woot.scss index 9a2a6a8e6..3f882eb38 100755 --- a/app/javascript/widget/assets/scss/woot.scss +++ b/app/javascript/widget/assets/scss/woot.scss @@ -61,10 +61,7 @@ body { .is-flat-design { .chat-bubble { - border-bottom-left-radius: 0 !important; - border-bottom-right-radius: 0 !important; - border-top-left-radius: 0 !important; - border-top-right-radius: 0 !important; + border-radius: 0 !important; box-shadow: none; } diff --git a/app/javascript/widget/components/AgentMessage.vue b/app/javascript/widget/components/AgentMessage.vue index c338dce83..6b1fb782b 100755 --- a/app/javascript/widget/components/AgentMessage.vue +++ b/app/javascript/widget/components/AgentMessage.vue @@ -104,8 +104,7 @@ export default { ) { return false; } - if (!this.message.content) return false; - return true; + return this.message.content; }, readableTime() { const { created_at: createdAt = '' } = this.message; diff --git a/app/javascript/widget/components/ChatAttachment.vue b/app/javascript/widget/components/ChatAttachment.vue index 87da3f5df..0412ca5fb 100755 --- a/app/javascript/widget/components/ChatAttachment.vue +++ b/app/javascript/widget/components/ChatAttachment.vue @@ -54,9 +54,9 @@ export default { }, async onFileUpload(file) { if (this.globalConfig.directUploadsEnabled) { - this.onDirectFileUpload(file); + await this.onDirectFileUpload(file); } else { - this.onIndirectFileUpload(file); + await this.onIndirectFileUpload(file); } }, async onDirectFileUpload(file) { diff --git a/app/javascript/widget/components/ChatHeaderExpanded.vue b/app/javascript/widget/components/ChatHeaderExpanded.vue index c1823f504..f82f66c46 100755 --- a/app/javascript/widget/components/ChatHeaderExpanded.vue +++ b/app/javascript/widget/components/ChatHeaderExpanded.vue @@ -7,7 +7,12 @@ class="flex items-start" :class="[avatarUrl ? 'justify-between' : 'justify-end']" > - + Avatar

{ - if ( + return !( (isUserEmailAvailable && field.name === 'emailAddress') || (isUserPhoneNumberAvailable && field.name === 'phoneNumber') - ) { - return false; - } - return true; + ); }); }, enabledPreChatFields() { diff --git a/app/javascript/widget/components/TeamAvailability.vue b/app/javascript/widget/components/TeamAvailability.vue index 1f4c5d046..a3a6b0c02 100644 --- a/app/javascript/widget/components/TeamAvailability.vue +++ b/app/javascript/widget/components/TeamAvailability.vue @@ -13,7 +13,7 @@ }}
- {{ replyWaitMeessage }} + {{ replyWaitMessage }}
@@ -75,7 +75,7 @@ export default { } return anyAgentOnline; }, - replyWaitMeessage() { + replyWaitMessage() { const { workingHoursEnabled } = this.channelConfig; if (this.isOnline) { diff --git a/app/javascript/widget/components/UnreadMessageList.vue b/app/javascript/widget/components/UnreadMessageList.vue index 19afe49d1..6683c585e 100644 --- a/app/javascript/widget/components/UnreadMessageList.vue +++ b/app/javascript/widget/components/UnreadMessageList.vue @@ -107,13 +107,12 @@ export default { .clear-button { background: transparent; color: $color-woot; - padding: 0; border: 0; font-weight: $font-weight-bold; font-size: $font-size-medium; transition: all 0.3s var(--ease-in-cubic); margin-left: $space-smaller; - padding-right: $space-one; + padding: 0 $space-one 0 0; &:hover { transform: translateX($space-smaller); diff --git a/app/javascript/widget/helpers/IframeEventHelper.js b/app/javascript/widget/helpers/IframeEventHelper.js index 953802df8..40c0e1f1c 100644 --- a/app/javascript/widget/helpers/IframeEventHelper.js +++ b/app/javascript/widget/helpers/IframeEventHelper.js @@ -10,7 +10,7 @@ export const loadedEventConfig = () => { export const getExtraSpaceToScroll = () => { // This function calculates the extra space needed for the view to - // accomodate the height of close button + height of + // accommodate the height of close button + height of // read messages button. So that scrollbar won't appear const unreadMessageWrap = document.querySelector('.unread-messages'); const unreadCloseWrap = document.querySelector('.close-unread-wrap'); diff --git a/app/javascript/widget/helpers/utils.js b/app/javascript/widget/helpers/utils.js index 1a4b2c1d6..a4d5dafa3 100755 --- a/app/javascript/widget/helpers/utils.js +++ b/app/javascript/widget/helpers/utils.js @@ -3,13 +3,6 @@ import { WOOT_PREFIX } from './constants'; export const isEmptyObject = obj => Object.keys(obj).length === 0 && obj.constructor === Object; -export const arrayToHashById = array => - array.reduce((map, obj) => { - const newMap = map; - newMap[obj.id] = obj; - return newMap; - }, {}); - export const sendMessage = msg => { window.parent.postMessage( `chatwoot-widget:${JSON.stringify({ ...msg })}`, @@ -22,9 +15,7 @@ export const IFrameHelper = { sendMessage, isAValidEvent: e => { const isDataAString = typeof e.data === 'string'; - const isAValidWootEvent = - isDataAString && e.data.indexOf(WOOT_PREFIX) === 0; - return isAValidWootEvent; + return isDataAString && e.data.indexOf(WOOT_PREFIX) === 0; }, getMessage: e => JSON.parse(e.data.replace(WOOT_PREFIX, '')), }; diff --git a/app/javascript/widget/store/modules/conversation/getters.js b/app/javascript/widget/store/modules/conversation/getters.js index 9d1c067f4..74e582348 100644 --- a/app/javascript/widget/store/modules/conversation/getters.js +++ b/app/javascript/widget/store/modules/conversation/getters.js @@ -32,7 +32,7 @@ export const getters = { }, getUnreadMessageCount: _state => { const { userLastSeenAt } = _state.meta; - const count = Object.values(_state.conversations).filter(chat => { + return Object.values(_state.conversations).filter(chat => { const { created_at: createdAt, message_type: messageType } = chat; const isOutGoing = messageType === MESSAGE_TYPE.OUTGOING; const hasNotSeen = userLastSeenAt @@ -40,7 +40,6 @@ export const getters = { : true; return hasNotSeen && isOutGoing; }).length; - return count; }, getUnreadTextMessages: (_state, _getters) => { const unreadCount = _getters.getUnreadMessageCount; @@ -50,7 +49,6 @@ export const getters = { return messageType === MESSAGE_TYPE.OUTGOING; }); const maxUnreadCount = Math.min(unreadCount, 3); - const allUnreadMessages = unreadAgentMessages.splice(-maxUnreadCount); - return allUnreadMessages; + return unreadAgentMessages.splice(-maxUnreadCount); }, }; diff --git a/app/javascript/widget/store/modules/conversation/helpers.js b/app/javascript/widget/store/modules/conversation/helpers.js index 44e2a6729..2ebac5242 100644 --- a/app/javascript/widget/store/modules/conversation/helpers.js +++ b/app/javascript/widget/store/modules/conversation/helpers.js @@ -29,7 +29,7 @@ const shouldShowAvatar = (message, nextMessage) => { export const groupConversationBySender = conversationsForADate => conversationsForADate.map((message, index) => { - let showAvatar = false; + let showAvatar; const isLastMessage = index === conversationsForADate.length - 1; if (isASubmittedFormMessage(message)) { showAvatar = false; diff --git a/app/javascript/widget/store/modules/conversation/mutations.js b/app/javascript/widget/store/modules/conversation/mutations.js index f47971f07..ca6dafada 100644 --- a/app/javascript/widget/store/modules/conversation/mutations.js +++ b/app/javascript/widget/store/modules/conversation/mutations.js @@ -88,8 +88,7 @@ export const mutations = { }, toggleAgentTypingStatus($state, { status }) { - const isTyping = status === 'on'; - $state.uiFlags.isAgentTyping = isTyping; + $state.uiFlags.isAgentTyping = status === 'on'; }, setMetaUserLastSeenAt($state, lastSeen) { diff --git a/app/javascript/widget/store/modules/conversationLabels.js b/app/javascript/widget/store/modules/conversationLabels.js index 3fbcd230d..3ae600082 100644 --- a/app/javascript/widget/store/modules/conversationLabels.js +++ b/app/javascript/widget/store/modules/conversationLabels.js @@ -9,14 +9,14 @@ export const actions = { try { await conversationLabels.create(label); } catch (error) { - // Ingore error + // Ignore error } }, destroy: async (_, label) => { try { await conversationLabels.destroy(label); } catch (error) { - // Ingore error + // Ignore error } }, }; From db53af91e740f9a0efecf855d9da63250d1be4d2 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Fri, 14 Oct 2022 12:46:41 -0700 Subject: [PATCH 14/16] chore (#5636) * New translations conversation.json (Latvian) * New translations bulkActions.json (Portuguese, Brazilian) * New translations agentMgmt.json (Latvian) * New translations teamsSettings.json (Latvian) * New translations contactFilters.json (Latvian) * New translations automation.json (Latvian) * New translations attributesMgmt.json (Latvian) * New translations labelsMgmt.json (Latvian) * New translations settings.json (Latvian) * New translations integrations.json (Latvian) * New translations inboxMgmt.json (Latvian) * New translations generalSettings.json (Latvian) * New translations contact.json (Latvian) * New translations helpCenter.json (Latvian) --- app/javascript/dashboard/i18n/locale/lv/agentMgmt.json | 6 +++--- .../dashboard/i18n/locale/lv/attributesMgmt.json | 2 +- .../dashboard/i18n/locale/lv/automation.json | 2 +- app/javascript/dashboard/i18n/locale/lv/contact.json | 2 +- .../dashboard/i18n/locale/lv/contactFilters.json | 2 +- .../dashboard/i18n/locale/lv/conversation.json | 2 +- .../dashboard/i18n/locale/lv/generalSettings.json | 2 +- .../dashboard/i18n/locale/lv/helpCenter.json | 10 +++++----- app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json | 6 ++++-- .../dashboard/i18n/locale/lv/integrations.json | 4 ++-- .../dashboard/i18n/locale/lv/labelsMgmt.json | 2 +- app/javascript/dashboard/i18n/locale/lv/settings.json | 2 ++ .../dashboard/i18n/locale/lv/teamsSettings.json | 2 +- .../dashboard/i18n/locale/pt_BR/bulkActions.json | 4 +++- 14 files changed, 27 insertions(+), 21 deletions(-) diff --git a/app/javascript/dashboard/i18n/locale/lv/agentMgmt.json b/app/javascript/dashboard/i18n/locale/lv/agentMgmt.json index 5b4319962..933a88bab 100644 --- a/app/javascript/dashboard/i18n/locale/lv/agentMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lv/agentMgmt.json @@ -12,12 +12,12 @@ "404": "Šim kontam nav piesaistīts neviens aģents", "TITLE": "Pārvaldīt Jūsu komandas aģentus", "DESC": "Jūs varat pievienot/noņemt aģentus pie/no savas komandas.", - "NAME": "Vārds", - "EMAIL": "e-pasts", + "NAME": "Nosaukums", + "EMAIL": "Epasts", "STATUS": "Statuss", "ACTIONS": "Darbības", "VERIFIED": "Pārbaudīts", - "VERIFICATION_PENDING": "Gaida apstiprinājumu" + "VERIFICATION_PENDING": "Tiek gaidīta verifikācija" }, "ADD": { "TITLE": "Pievienot aģentu Jūsu komandai", diff --git a/app/javascript/dashboard/i18n/locale/lv/attributesMgmt.json b/app/javascript/dashboard/i18n/locale/lv/attributesMgmt.json index 716f98705..ef12fa631 100644 --- a/app/javascript/dashboard/i18n/locale/lv/attributesMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lv/attributesMgmt.json @@ -81,7 +81,7 @@ }, "LIST": { "TABLE_HEADER": [ - "Vārds", + "Nosaukums", "Apraksts", "Tips", "Atslēga" diff --git a/app/javascript/dashboard/i18n/locale/lv/automation.json b/app/javascript/dashboard/i18n/locale/lv/automation.json index a7edf9c25..84d8beedb 100644 --- a/app/javascript/dashboard/i18n/locale/lv/automation.json +++ b/app/javascript/dashboard/i18n/locale/lv/automation.json @@ -40,7 +40,7 @@ }, "LIST": { "TABLE_HEADER": [ - "Vārds", + "Nosaukums", "Apraksts", "Aktīvs", "Izveidots" diff --git a/app/javascript/dashboard/i18n/locale/lv/contact.json b/app/javascript/dashboard/i18n/locale/lv/contact.json index 2e167ae2c..ffe81f9af 100644 --- a/app/javascript/dashboard/i18n/locale/lv/contact.json +++ b/app/javascript/dashboard/i18n/locale/lv/contact.json @@ -202,7 +202,7 @@ "404": "Neviena kontaktpersona neatbilst jūsu meklēšanas vaicājumam 🔍", "NO_CONTACTS": "Nav pieejamu kontaktpersonu", "TABLE_HEADER": { - "NAME": "Vārds", + "NAME": "Nosaukums", "PHONE_NUMBER": "Telefona Numurs", "CONVERSATIONS": "Sarunas", "LAST_ACTIVITY": "Pēdējās Darbības", diff --git a/app/javascript/dashboard/i18n/locale/lv/contactFilters.json b/app/javascript/dashboard/i18n/locale/lv/contactFilters.json index e86ac2152..5ec1c3f4b 100644 --- a/app/javascript/dashboard/i18n/locale/lv/contactFilters.json +++ b/app/javascript/dashboard/i18n/locale/lv/contactFilters.json @@ -26,7 +26,7 @@ "days_before": "Ir x dienas pirms" }, "ATTRIBUTES": { - "NAME": "Vārds", + "NAME": "Nosaukums", "EMAIL": "E-pasts", "PHONE_NUMBER": "Tālruņa numurs", "IDENTIFIER": "Identifikators", diff --git a/app/javascript/dashboard/i18n/locale/lv/conversation.json b/app/javascript/dashboard/i18n/locale/lv/conversation.json index bb6274007..088a5e8bb 100644 --- a/app/javascript/dashboard/i18n/locale/lv/conversation.json +++ b/app/javascript/dashboard/i18n/locale/lv/conversation.json @@ -151,7 +151,7 @@ "CONTEXT_MENU": { "COPY": "Kopēt", "DELETE": "Dzēst", - "CREATE_A_CANNED_RESPONSE": "Add to canned responses" + "CREATE_A_CANNED_RESPONSE": "Pievienot sagatavotajām atbildēm" } }, "EMAIL_TRANSCRIPT": { diff --git a/app/javascript/dashboard/i18n/locale/lv/generalSettings.json b/app/javascript/dashboard/i18n/locale/lv/generalSettings.json index f2a3c3b6f..5e5e39a98 100644 --- a/app/javascript/dashboard/i18n/locale/lv/generalSettings.json +++ b/app/javascript/dashboard/i18n/locale/lv/generalSettings.json @@ -71,7 +71,7 @@ "LOADING_MESSAGE": "Notiek paziņojumu ielāde...", "404": "Nav paziņojumu", "TABLE_HEADER": [ - "Vārds", + "Nosaukums", "Telefona numurs", "Sarunas", "Pēdējā Sazināšanās" diff --git a/app/javascript/dashboard/i18n/locale/lv/helpCenter.json b/app/javascript/dashboard/i18n/locale/lv/helpCenter.json index c877bdb20..39705cf26 100644 --- a/app/javascript/dashboard/i18n/locale/lv/helpCenter.json +++ b/app/javascript/dashboard/i18n/locale/lv/helpCenter.json @@ -92,7 +92,7 @@ "PORTAL_CONFIG": { "TITLE": "Portāla Konfigurācijas", "ITEMS": { - "NAME": "Vārds", + "NAME": "Nosaukums", "DOMAIN": "Pielāgots domēns", "SLUG": "Slug", "TITLE": "Portāla nosaukums", @@ -144,7 +144,7 @@ "TITLE": "Kategorijas iekš", "NEW_CATEGORY": "Jauna kategorija", "TABLE": { - "NAME": "Vārds", + "NAME": "Nosaukums", "DESCRIPTION": "Apraksts", "LOCALE": "Lokalizācija", "ARTICLE_COUNT": "Rakstu skaits", @@ -204,7 +204,7 @@ "HELP_TEXT": "Šis logotips tiks attēlots portāla galvenē." }, "NAME": { - "LABEL": "Vārds", + "LABEL": "Nosaukums", "PLACEHOLDER": "Portāla nosaukums", "HELP_TEXT": "Nosaukums tiks izmantots publiskajā portālā iekšēji.", "ERROR": "Nepieciešams nosaukums" @@ -344,7 +344,7 @@ "PORTAL": "Portāls", "LOCALE": "Lokalizācija", "NAME": { - "LABEL": "Vārds", + "LABEL": "Nosaukums", "PLACEHOLDER": "Kategorijas nosaukums", "HELP_TEXT": "Kategorijas nosaukums tiks izmantots publiskajā portālā, lai klasificētu rakstus.", "ERROR": "Nepieciešams nosaukums" @@ -375,7 +375,7 @@ "PORTAL": "Portāls", "LOCALE": "Lokalizācija", "NAME": { - "LABEL": "Vārds", + "LABEL": "Nosaukums", "PLACEHOLDER": "Kategorijas nosaukums", "HELP_TEXT": "Kategorijas nosaukums tiks izmantots publiskajā portālā, lai klasificētu rakstus.", "ERROR": "Nepieciešams nosaukums" diff --git a/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json index 12f32f6f0..f62035e3c 100644 --- a/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json @@ -239,7 +239,9 @@ }, "API_CALLBACK": { "TITLE": "Atzvanīšanas URL", - "SUBTITLE": "Jums ir facebook izstrādātāju portālā jānokonfigurē webhook URL, izmantojot šeit minēto URL." + "SUBTITLE": "Jums Facebook izstrādātāju portālā ir jānokonfigurē webhoot URL un verifikācijas token ar tālāk norādītajām vērtībām.", + "WEBHOOK_URL": "Webhook URL", + "WEBHOOK_VERIFICATION_TOKEN": "Webhook Verifikācijas Token" }, "SUBMIT_BUTTON": "Izveidot WhatsApp kanālu", "API": { @@ -357,7 +359,7 @@ }, "FINISH": { "TITLE": "Jūsu Iesūtne ir gatava!", - "MESSAGE": "Tagad Jūs varat izmantot savu jauno Kanālu lai sazinātos ar saviem klientiem. Priecīgu atbalstīšanu ", + "MESSAGE": "Tagad Jūs varat izmantot savu jauno Kanālu lai sazinātos ar saviem klientiem. Priecīgu atbalstīšanu", "BUTTON_TEXT": "Iet uz", "MORE_SETTINGS": "Papildu iestatījumi", "WEBSITE_SUCCESS": "Jūs esat veiksmīgi pabeidzis tīmekļa vietnes kanāla izveidi. Nokopējiet tālāk redzamo kodu un ievietojiet to savā tīmekļa vietnē. Nākamreiz, kad klients izmantos tiešsaistes tērzēšanu, saruna automātiski tiks parādīta Jūsu iesūtnē." diff --git a/app/javascript/dashboard/i18n/locale/lv/integrations.json b/app/javascript/dashboard/i18n/locale/lv/integrations.json index 372061132..48752ccce 100644 --- a/app/javascript/dashboard/i18n/locale/lv/integrations.json +++ b/app/javascript/dashboard/i18n/locale/lv/integrations.json @@ -94,14 +94,14 @@ "404": "Šajā kontā vēl nav nokonfigurēta neviena informācijas paneļa lietotne", "LOADING": "Notiek informācijas paneļa lietotņu iegūšana...", "TABLE_HEADER": [ - "Vārds", + "Nosaukums", "Endpoint" ], "EDIT_TOOLTIP": "Rediģēt lietotni", "DELETE_TOOLTIP": "Dzēst lietotni" }, "FORM": { - "TITLE_LABEL": "Vārds", + "TITLE_LABEL": "Nosaukums", "TITLE_PLACEHOLDER": "Ievadiet informācijas paneļa lietotnes nosaukumu", "TITLE_ERROR": "Informācijas paneļa lietotnei ir jānorāda nosaukums", "URL_LABEL": "Endpoint", diff --git a/app/javascript/dashboard/i18n/locale/lv/labelsMgmt.json b/app/javascript/dashboard/i18n/locale/lv/labelsMgmt.json index 81b975bbc..011b780c1 100644 --- a/app/javascript/dashboard/i18n/locale/lv/labelsMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lv/labelsMgmt.json @@ -10,7 +10,7 @@ "TITLE": "Pārvaldīt Etiķetes", "DESC": "Etiķetes ļauj grupēt sarunas kopā.", "TABLE_HEADER": [ - "Vārds", + "Nosaukums", "Apraksts", "Krāsa" ] diff --git a/app/javascript/dashboard/i18n/locale/lv/settings.json b/app/javascript/dashboard/i18n/locale/lv/settings.json index effdabc47..e2b82e781 100644 --- a/app/javascript/dashboard/i18n/locale/lv/settings.json +++ b/app/javascript/dashboard/i18n/locale/lv/settings.json @@ -179,6 +179,7 @@ "CONTACTS": "Kontaktpersonas", "HOME": "Sākums", "AGENTS": "Aģenti", + "AGENT_BOTS": "Bots", "INBOXES": "Iesūtnes", "NOTIFICATIONS": "Paziņojumi", "CANNED_RESPONSES": "Sagatavotās Atbildes", @@ -189,6 +190,7 @@ "LABELS": "Etiķetes", "CUSTOM_ATTRIBUTES": "Pielāgotas Īpašības", "AUTOMATION": "Automatizācija", + "MACROS": "Macros", "TEAMS": "Komandas", "BILLING": "Norēķini", "CUSTOM_VIEWS_FOLDER": "Mapes", diff --git a/app/javascript/dashboard/i18n/locale/lv/teamsSettings.json b/app/javascript/dashboard/i18n/locale/lv/teamsSettings.json index 960b5b26d..8d6f4b4da 100644 --- a/app/javascript/dashboard/i18n/locale/lv/teamsSettings.json +++ b/app/javascript/dashboard/i18n/locale/lv/teamsSettings.json @@ -69,7 +69,7 @@ }, "AGENTS": { "AGENT": "AĢENTS", - "EMAIL": "e-pasts", + "EMAIL": "Epasts", "BUTTON_TEXT": "Pievienot aģentus", "ADD_AGENTS": "Notiek aģentu pievienošana Jūsu komandai...", "SELECT": "izvēlēties", diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/bulkActions.json b/app/javascript/dashboard/i18n/locale/pt_BR/bulkActions.json index f3f54ea9f..caf0ed3df 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/bulkActions.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/bulkActions.json @@ -2,9 +2,11 @@ "BULK_ACTION": { "CONVERSATIONS_SELECTED": "%{conversationCount} conversas selecionadas", "AGENT_SELECT_LABEL": "Selecione Agente", - "ASSIGN_CONFIRMATION_LABEL": "Você tem certeza que deseja atribuir %{conversationCount} %{conversationLabel} para", + "ASSIGN_CONFIRMATION_LABEL": "Você tem certeza que quer atribuir %{conversationCount} %{conversationLabel} para", + "UNASSIGN_CONFIRMATION_LABEL": "Você tem certeza que quer remover a atribuição de %{conversationCount} %{conversationLabel}?", "GO_BACK_LABEL": "Voltar atrás", "ASSIGN_LABEL": "Atribua", + "YES": "Sim", "ASSIGN_AGENT_TOOLTIP": "Atribuir Agente", "ASSIGN_SUCCESFUL": "Conversas atribuídas com sucesso", "ASSIGN_FAILED": "Falha ao atribuir conversas, por favor, tente novamente", From ce3730d64078da7546a22db0a2749e0a84875b89 Mon Sep 17 00:00:00 2001 From: Simon Pankovski <46830637+simonpankovski@users.noreply.github.com> Date: Fri, 14 Oct 2022 22:38:08 +0200 Subject: [PATCH 15/16] fix: Avoid email icon getting distorted (#5633) Co-authored-by: Pranav Raj S --- .../routes/dashboard/conversation/contact/ContactInfoRow.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfoRow.vue b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfoRow.vue index 33559e123..4e33bc7fa 100644 --- a/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfoRow.vue +++ b/app/javascript/dashboard/routes/dashboard/conversation/contact/ContactInfoRow.vue @@ -10,10 +10,11 @@ From 252eda14c6e62cb8f91a8f7337d2dc05dc550bdf Mon Sep 17 00:00:00 2001 From: Nithin David Thomas <1277421+nithindavid@users.noreply.github.com> Date: Mon, 17 Oct 2022 05:18:32 +0530 Subject: [PATCH 16/16] chore: Add woot button to message context menu (#5638) --- .../components/widgets/conversation/Message.vue | 2 ++ .../conversations/components/MessageContextMenu.vue | 12 +++++++----- .../shared/components/ui/dropdown/DropdownItem.vue | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/conversation/Message.vue b/app/javascript/dashboard/components/widgets/conversation/Message.vue index 3481125ca..7fb24301b 100644 --- a/app/javascript/dashboard/components/widgets/conversation/Message.vue +++ b/app/javascript/dashboard/components/widgets/conversation/Message.vue @@ -420,6 +420,8 @@ export default { diff --git a/app/javascript/shared/components/ui/dropdown/DropdownItem.vue b/app/javascript/shared/components/ui/dropdown/DropdownItem.vue index c4da84234..893026451 100644 --- a/app/javascript/shared/components/ui/dropdown/DropdownItem.vue +++ b/app/javascript/shared/components/ui/dropdown/DropdownItem.vue @@ -35,6 +35,7 @@ export default { a, .button { display: inline-flex; + white-space: nowrap; width: 100%; text-align: left; color: var(--s-700);