From d692eac260b06bf41c2788d100141e4230207033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=A4=AA=E0=A5=8D=E0=A4=B0=E0=A4=A5=E0=A4=AE=E0=A5=87?= =?UTF-8?q?=E0=A4=B6=20Sonpatki?= Date: Sun, 7 Mar 2021 20:42:45 +0530 Subject: [PATCH 01/27] chore: Add name to the sender email id (#1485) --- app/mailers/application_mailer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 9513056fe..12341e30c 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,7 +1,7 @@ class ApplicationMailer < ActionMailer::Base include ActionView::Helpers::SanitizeHelper - default from: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com') + default from: ENV.fetch('MAILER_SENDER_EMAIL', 'Chatwoot ') before_action { ensure_current_account(params.try(:[], :account)) } around_action :switch_locale layout 'mailer/base' From d70208a0a83847271735959e1944682e57de400b Mon Sep 17 00:00:00 2001 From: Nithin David Thomas Date: Mon, 8 Mar 2021 13:13:13 +0530 Subject: [PATCH 02/27] Fix: apply alert conditions while document is hidden (#1859) --- .../shared/helpers/AudioNotificationHelper.js | 43 ++++--- .../specs/AudioNotificationHelper.spec.js | 109 ++++++++++++++++++ 2 files changed, 135 insertions(+), 17 deletions(-) create mode 100644 app/javascript/shared/helpers/specs/AudioNotificationHelper.spec.js diff --git a/app/javascript/shared/helpers/AudioNotificationHelper.js b/app/javascript/shared/helpers/AudioNotificationHelper.js index 3f8f77c4c..90d3bcdaa 100644 --- a/app/javascript/shared/helpers/AudioNotificationHelper.js +++ b/app/javascript/shared/helpers/AudioNotificationHelper.js @@ -34,36 +34,45 @@ export const getAlertAudio = async () => { } }; -const shouldPlayAudio = data => { - const { conversation_id: currentConvId } = window.WOOT.$route.params; - const currentUserId = window.WOOT.$store.getters.getCurrentUserID; +export const shouldPlayAudio = ( + message, + conversationId, + userId, + isDocHiddden +) => { const { conversation_id: incomingConvId, sender_id: senderId, message_type: messageType, - } = data; - const isFromCurrentUser = currentUserId === senderId; + private: isPrivate, + } = message; + const isFromCurrentUser = userId === senderId; const playAudio = - currentConvId !== incomingConvId && - !isFromCurrentUser && - messageType === MESSAGE_TYPE.INCOMING; - return playAudio; + !isFromCurrentUser && (messageType === MESSAGE_TYPE.INCOMING || isPrivate); + + if (isDocHiddden) return playAudio; + if (conversationId !== incomingConvId) return playAudio; + return false; }; export const newMessageNotification = data => { + const { conversation_id: currentConvId } = window.WOOT.$route.params; + const currentUserId = window.WOOT.$store.getters.getCurrentUserID; + const isDocHiddden = document.hidden; + const { enable_audio_alerts: enableAudioAlerts = false, } = window.WOOT.$store.getters.getUISettings; - if (!enableAudioAlerts) return false; - if (document.hidden) { + const playAudio = shouldPlayAudio( + data, + currentConvId, + currentUserId, + isDocHiddden + ); + + if (enableAudioAlerts && playAudio) { window.playAudioAlert(); - } else { - const playAudio = shouldPlayAudio(data); - if (playAudio) { - window.playAudioAlert(); - } } - return false; }; diff --git a/app/javascript/shared/helpers/specs/AudioNotificationHelper.spec.js b/app/javascript/shared/helpers/specs/AudioNotificationHelper.spec.js new file mode 100644 index 000000000..8d2b0f2fe --- /dev/null +++ b/app/javascript/shared/helpers/specs/AudioNotificationHelper.spec.js @@ -0,0 +1,109 @@ +/** + * @jest-environment jsdom + */ + +import { shouldPlayAudio } from '../AudioNotificationHelper'; + +describe('shouldPlayAudio', () => { + describe('Document active', () => { + it('Retuns true if incoming message', () => { + const message = { + conversation_id: 10, + sender_id: 5, + message_type: 0, + private: false, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, false]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(true); + }); + it('Retuns false if outgoing message', () => { + const message = { + conversation_id: 10, + sender_id: 5, + message_type: 1, + private: false, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, false]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(false); + }); + + it('Retuns false if from Same sender', () => { + const message = { + conversation_id: 1, + sender_id: 2, + message_type: 0, + private: false, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, true]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(false); + }); + it('Retuns true if private message from another agent', () => { + const message = { + conversation_id: 1, + sender_id: 5, + message_type: 1, + private: true, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, true]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(true); + }); + }); + describe('Document inactive', () => { + it('Retuns true if incoming message', () => { + const message = { + conversation_id: 1, + sender_id: 5, + message_type: 0, + private: false, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, true]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(true); + }); + it('Retuns false if outgoing message', () => { + const message = { + conversation_id: 1, + sender_id: 5, + message_type: 1, + private: false, + }; + const [conversationId, userId, isDocHiddden] = [1, 2, true]; + const result = shouldPlayAudio( + message, + conversationId, + userId, + isDocHiddden + ); + expect(result).toBe(false); + }); + }); +}); From 759ed43745b69ec04478191d0a69efa9081ee9c8 Mon Sep 17 00:00:00 2001 From: Nithin David Thomas Date: Mon, 8 Mar 2021 13:30:33 +0530 Subject: [PATCH 03/27] Chore: Responsive fixes for common screen widths (#1856) --- .../dashboard/assets/scss/_foundation-settings.scss | 4 +++- app/javascript/dashboard/components/ChatList.vue | 7 +++++-- .../widgets/conversation/ConversationBox.vue | 13 ++++++++----- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/javascript/dashboard/assets/scss/_foundation-settings.scss b/app/javascript/dashboard/assets/scss/_foundation-settings.scss index 79bc1ae29..e8862b5bf 100644 --- a/app/javascript/dashboard/assets/scss/_foundation-settings.scss +++ b/app/javascript/dashboard/assets/scss/_foundation-settings.scss @@ -89,7 +89,9 @@ $breakpoints: (small: 0, medium: 640px, large: 1024px, xlarge: 1200px, - xxlarge: 1440px); + xxlarge: 1400px, + xxxlarge: 1600px, +); $print-breakpoint: large; $breakpoint-classes: (small medium large); diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 09e55e8c3..6603a25c6 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -232,10 +232,13 @@ export default { width: 36rem; } @include breakpoint(xlarge up) { - width: 33rem; + width: 35rem; } @include breakpoint(xxlarge up) { - width: 42rem; + width: 38rem; + } + @include breakpoint(xxxlarge up) { + flex-basis: 46rem; } } diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue index 2a29df541..32471638c 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue @@ -87,23 +87,26 @@ export default { .conversation-sidebar-wrap { height: auto; - flex: 0 1; + flex: 0 0; overflow: hidden; overflow: auto; background: white; - flex-shrink: 0; flex-basis: 28rem; @include breakpoint(large up) { - flex-basis: 31em; + flex-basis: 30em; } @include breakpoint(xlarge up) { - flex-basis: 32em; + flex-basis: 31em; } @include breakpoint(xxlarge up) { - flex-basis: 36rem; + flex-basis: 33rem; + } + + @include breakpoint(xxxlarge up) { + flex-basis: 40rem; } &::v-deep .contact--panel { From 0e40f8a10fbd1e3de06d82b9a86ca77989f0ab48 Mon Sep 17 00:00:00 2001 From: Nithin David Thomas Date: Tue, 9 Mar 2021 15:26:03 +0530 Subject: [PATCH 04/27] Fix: emoji box not showing up (#1873) --- .../components/widgets/conversation/ConversationBox.vue | 4 +--- .../components/widgets/conversation/ConversationHeader.vue | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue index 32471638c..587f78304 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationBox.vue @@ -80,9 +80,7 @@ export default { display: flex; background: var(--color-background-light); margin: 0; - height: auto; - flex: 1 1; - overflow: hidden; + height: calc(100vh - var(--space-jumbo)); } .conversation-sidebar-wrap { diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue index d12d26657..e8f032a36 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationHeader.vue @@ -133,4 +133,8 @@ export default { overflow: hidden; text-overflow: ellipsis; } + +.conv-header { + flex: 0 0 var(--space-jumbo); +} From 94159ca9dfe117b497e0ddbbcf69686a7176c989 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+sivin-git@users.noreply.github.com> Date: Tue, 9 Mar 2021 18:37:18 +0530 Subject: [PATCH 05/27] Fix: Canned responses table column width breakage (#1881) --- .../routes/dashboard/settings/canned/Index.vue | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/javascript/dashboard/routes/dashboard/settings/canned/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/canned/Index.vue index 95065f547..c3f192c3b 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/canned/Index.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/canned/Index.vue @@ -40,7 +40,9 @@ :key="cannedItem.short_code" > - {{ cannedItem.short_code }} + + {{ cannedItem.short_code }} + {{ cannedItem.content }} @@ -99,9 +101,7 @@ + From 1c7e5df91aa085741ea7c1b94db87a7017675b66 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+sivin-git@users.noreply.github.com> Date: Tue, 9 Mar 2021 19:52:14 +0530 Subject: [PATCH 06/27] Enhancement: Conversation item redesign (#1857) * Rearrange the inboxes label in conversations. --- .../scss/widgets/_conversation-card.scss | 1 - .../assets/scss/widgets/_sidemenu.scss | 2 - .../components/layout/SidebarItem.vue | 42 ++--------- .../widgets/conversation/ConversationCard.vue | 74 +++++++++++++++---- app/javascript/dashboard/helper/inbox.js | 28 +++++++ .../dashboard/helper/specs/inbox.spec.js | 35 +++++++++ 6 files changed, 131 insertions(+), 51 deletions(-) create mode 100644 app/javascript/dashboard/helper/inbox.js create mode 100644 app/javascript/dashboard/helper/specs/inbox.spec.js diff --git a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss index 06749c99d..11394f032 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_conversation-card.scss @@ -14,7 +14,6 @@ @include flex; @include flex-shrink; @include padding(0 0 0 $space-normal); - align-items: center; border-bottom: 1px solid transparent; border-left: $space-micro solid transparent; border-top: 1px solid transparent; diff --git a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss index 344317735..65abd09c7 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_sidemenu.scss @@ -49,10 +49,8 @@ margin-top: $space-micro; .inbox-icon { - $icon-top-space: -1px; display: inline-block; margin-right: $space-micro; - margin-top: $icon-top-space; min-width: $space-normal; text-align: center; } diff --git a/app/javascript/dashboard/components/layout/SidebarItem.vue b/app/javascript/dashboard/components/layout/SidebarItem.vue index 3210d2292..981fbef3c 100644 --- a/app/javascript/dashboard/components/layout/SidebarItem.vue +++ b/app/javascript/dashboard/components/layout/SidebarItem.vue @@ -60,35 +60,7 @@ import { mapGetters } from 'vuex'; import router from '../../routes'; import adminMixin from '../../mixins/isAdmin'; -import { INBOX_TYPES } from 'shared/mixins/inboxMixin'; - -const getInboxClassByType = (type, phoneNumber) => { - switch (type) { - case INBOX_TYPES.WEB: - return 'ion-earth'; - - case INBOX_TYPES.FB: - return 'ion-social-facebook'; - - case INBOX_TYPES.TWITTER: - return 'ion-social-twitter'; - - case INBOX_TYPES.TWILIO: - return phoneNumber.startsWith('whatsapp') - ? 'ion-social-whatsapp-outline' - : 'ion-android-textsms'; - - case INBOX_TYPES.API: - return 'ion-cloud'; - - case INBOX_TYPES.EMAIL: - return 'ion-email'; - - default: - return ''; - } -}; - +import { getInboxClassByType } from 'dashboard/helper/inbox'; export default { mixins: [adminMixin], props: { @@ -166,26 +138,26 @@ export default { } .inbox-icon.ion-social-facebook { - color: var(--color-facebook-brand); + color: var(--color-facebook-brand); } .inbox-icon.ion-social-whatsapp-outline { - color: var(--color-twitter-brand); + color: var(--color-whatsapp-brand); } .inbox-icon.ion-social-twitter { - color: var(--color-twitter-brand); + color: var(--color-twitter-brand); } .inbox-icon.ion-android-textsms { - color: var(--color-sms-twilio); + color: var(--color-sms-twilio); } .inbox-icon.ion-earth { - color: var(--color-woot); + color: var(--color-woot); } .inbox-icon.ion-cloud { - color: var(--color-cloud-generic); + color: var(--color-cloud-generic); } diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue index 0b39013bf..e9fdc62df 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationCard.vue @@ -1,7 +1,11 @@ @@ -266,12 +269,14 @@ import SettingsSection from '../../../../components/SettingsSection'; import inboxMixin from 'shared/mixins/inboxMixin'; import FacebookReauthorize from './facebook/Reauthorize'; import PreChatFormSettings from './PreChatForm/Settings'; +import WeeklyAvailability from './components/WeeklyAvailability'; export default { components: { SettingsSection, FacebookReauthorize, PreChatFormSettings, + WeeklyAvailability, }, mixins: [alertMixin, configMixin, inboxMixin], data() { @@ -329,6 +334,10 @@ export default { key: 'preChatForm', name: this.$t('INBOX_MGMT.TABS.PRE_CHAT_FORM'), }, + { + key: 'businesshours', + name: this.$t('INBOX_MGMT.TABS.BUSINESS_HOURS'), + }, { key: 'configuration', name: this.$t('INBOX_MGMT.TABS.CONFIGURATION'), diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue index 6e2cbb151..9e6338605 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/BusinessDay.vue @@ -92,11 +92,13 @@ export default { ...this.timeSlot, from: timeSlots[0], to: timeSlots[16], + valid: true, } : { ...this.timeSlot, from: '', to: '', + valid: false, }; this.$emit('update', newSlot); }, @@ -106,9 +108,12 @@ export default { return this.timeSlot.from; }, set(value) { + const fromDate = parse(value, 'hh:mm a', new Date()); + const valid = differenceInMinutes(this.toDate, fromDate) / 60 > 0; this.$emit('update', { ...this.timeSlot, from: value, + valid, }); }, }, @@ -117,10 +122,21 @@ export default { return this.timeSlot.to; }, set(value) { - this.$emit('update', { - ...this.timeSlot, - to: value, - }); + const toDate = parse(value, 'hh:mm a', new Date()); + if (value === '12:00 AM') { + this.$emit('update', { + ...this.timeSlot, + to: value, + valid: true, + }); + } else { + const valid = differenceInMinutes(toDate, this.fromDate) / 60 > 0; + this.$emit('update', { + ...this.timeSlot, + to: value, + valid, + }); + } }, }, fromDate() { @@ -130,10 +146,14 @@ export default { return parse(this.toTime, 'hh:mm a', new Date()); }, totalHours() { - return differenceInMinutes(this.toDate, this.fromDate) / 60; + const totalHours = differenceInMinutes(this.toDate, this.fromDate) / 60; + if (this.toTime === '12:00 AM') { + return 24 + totalHours; + } + return totalHours; }, hasError() { - return this.totalHours < 0; + return !this.timeSlot.valid; }, }, }; @@ -157,8 +177,8 @@ export default { display: flex; align-items: center; justify-content: space-between; - padding: var(--space-normal); - height: var(--space-larger); + padding: var(--space-small) 0; + min-height: var(--space-larger); box-sizing: content-box; border-bottom: 1px solid var(--color-border-light); } @@ -213,7 +233,7 @@ export default { } .date-error { - padding: var(--space-small) 0; + padding-top: var(--space-smaller); } .error { diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/components/WeeklyAvailability.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/WeeklyAvailability.vue new file mode 100644 index 000000000..4107c5151 --- /dev/null +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/components/WeeklyAvailability.vue @@ -0,0 +1,193 @@ +