feat: Shows an alert while replying if chats are not assigned to them (#3867)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
parent
a737f89c47
commit
1a3d39a7f3
4 changed files with 233 additions and 75 deletions
129
app/javascript/dashboard/components/ui/Banner.vue
Normal file
129
app/javascript/dashboard/components/ui/Banner.vue
Normal file
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<div class="banner" :class="bannerClasses">
|
||||
<span>
|
||||
{{ bannerMessage }}
|
||||
<a
|
||||
v-if="hrefLink"
|
||||
:href="hrefLink"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
{{ hrefLinkText }}
|
||||
</a>
|
||||
</span>
|
||||
<woot-button
|
||||
v-if="hasActionButton"
|
||||
size="small"
|
||||
variant="link"
|
||||
icon="arrow-right"
|
||||
color-scheme="primary"
|
||||
class-names="banner-action__button"
|
||||
@click="onClick"
|
||||
>
|
||||
{{ actionButtonLabel }}
|
||||
</woot-button>
|
||||
<woot-button
|
||||
v-if="hasCloseButton"
|
||||
size="small"
|
||||
variant="link"
|
||||
color-scheme="warning"
|
||||
icon="dismiss-circle"
|
||||
class-names="banner-action__button"
|
||||
@click="onClickClose"
|
||||
>
|
||||
</woot-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
bannerMessage: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hrefLink: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hrefLinkText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hasActionButton: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
actionButtonLabel: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
colorScheme: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
hasCloseButton: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
bannerClasses() {
|
||||
return [this.colorScheme];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onClick(e) {
|
||||
this.$emit('click', e);
|
||||
},
|
||||
onClickClose(e) {
|
||||
this.$emit('close', e);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.banner {
|
||||
display: flex;
|
||||
color: var(--white);
|
||||
font-size: var(--font-size-mini);
|
||||
padding: var(--space-slab) var(--space-normal);
|
||||
justify-content: center;
|
||||
position: sticky;
|
||||
|
||||
&.secondary {
|
||||
background: var(--s-300);
|
||||
}
|
||||
|
||||
&.alert {
|
||||
background: var(--r-400);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: var(--y-800);
|
||||
color: var(--s-600);
|
||||
a {
|
||||
color: var(--s-600);
|
||||
}
|
||||
}
|
||||
|
||||
&.gray {
|
||||
background: var(--b-500);
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: var(--white);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
.banner-action__button {
|
||||
margin: 0 var(--space-smaller);
|
||||
|
||||
::v-deep .button__content {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,56 +1,29 @@
|
|||
<template>
|
||||
<div class="view-box fill-height">
|
||||
<div
|
||||
<banner
|
||||
v-if="!currentChat.can_reply && !isAWhatsappChannel"
|
||||
class="banner messenger-policy--banner"
|
||||
>
|
||||
<span>
|
||||
{{ $t('CONVERSATION.CANNOT_REPLY') }}
|
||||
<a
|
||||
:href="facebookReplyPolicy"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('CONVERSATION.24_HOURS_WINDOW') }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="!currentChat.can_reply && isAWhatsappChannel"
|
||||
class="banner messenger-policy--banner"
|
||||
>
|
||||
<span>
|
||||
{{ $t('CONVERSATION.TWILIO_WHATSAPP_CAN_REPLY') }}
|
||||
<a
|
||||
:href="twilioWhatsAppReplyPolicy"
|
||||
rel="noopener noreferrer nofollow"
|
||||
target="_blank"
|
||||
>
|
||||
{{ $t('CONVERSATION.TWILIO_WHATSAPP_24_HOURS_WINDOW') }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
color-scheme="alert"
|
||||
:banner-message="$t('CONVERSATION.CANNOT_REPLY')"
|
||||
:href-link="facebookReplyPolicy"
|
||||
:href-link-text="$t('CONVERSATION.24_HOURS_WINDOW')"
|
||||
/>
|
||||
|
||||
<banner
|
||||
v-if="!currentChat.can_reply && isAWhatsappChannel"
|
||||
color-scheme="alert"
|
||||
:banner-message="$t('CONVERSATION.TWILIO_WHATSAPP_CAN_REPLY')"
|
||||
:href-link="twilioWhatsAppReplyPolicy"
|
||||
:href-link-text="$t('CONVERSATION.TWILIO_WHATSAPP_24_HOURS_WINDOW')"
|
||||
/>
|
||||
|
||||
<banner
|
||||
v-if="isATweet"
|
||||
color-scheme="gray"
|
||||
:banner-message="tweetBannerText"
|
||||
:has-close-button="hasSelectedTweetId"
|
||||
@close="removeTweetSelection"
|
||||
/>
|
||||
|
||||
<div v-if="isATweet" class="banner">
|
||||
<span v-if="!selectedTweetId">
|
||||
{{ $t('CONVERSATION.SELECT_A_TWEET_TO_REPLY') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ $t('CONVERSATION.REPLYING_TO') }}
|
||||
{{ selectedTweet.content || '' }}
|
||||
</span>
|
||||
<button
|
||||
v-if="selectedTweetId"
|
||||
class="banner-close-button"
|
||||
@click="removeTweetSelection"
|
||||
>
|
||||
<fluent-icon
|
||||
v-tooltip="$t('CONVERSATION.REMOVE_SELECTION')"
|
||||
size="16"
|
||||
icon="dismiss"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="sidebar-toggle__wrap">
|
||||
<woot-button
|
||||
variant="smooth"
|
||||
|
@ -126,6 +99,7 @@ import { mapGetters } from 'vuex';
|
|||
import ReplyBox from './ReplyBox';
|
||||
import Message from './Message';
|
||||
import conversationMixin from '../../../mixins/conversations';
|
||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||
import { getTypingUsersText } from '../../../helper/commons';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { REPLY_POLICY } from 'shared/constants/links';
|
||||
|
@ -139,6 +113,7 @@ export default {
|
|||
components: {
|
||||
Message,
|
||||
ReplyBox,
|
||||
Banner,
|
||||
},
|
||||
mixins: [conversationMixin, inboxMixin, eventListenerMixins, clickaway],
|
||||
props: {
|
||||
|
@ -173,7 +148,17 @@ export default {
|
|||
inbox() {
|
||||
return this.$store.getters['inboxes/getInbox'](this.inboxId);
|
||||
},
|
||||
hasSelectedTweetId() {
|
||||
return !!this.selectedTweetId;
|
||||
},
|
||||
|
||||
tweetBannerText() {
|
||||
return !this.selectedTweetId
|
||||
? this.$t('CONVERSATION.SELECT_A_TWEET_TO_REPLY')
|
||||
: `
|
||||
${this.$t('CONVERSATION.REPLYING_TO')}
|
||||
${this.selectedTweet.content}` || '';
|
||||
},
|
||||
typingUsersList() {
|
||||
const userList = this.$store.getters[
|
||||
'conversationTypingStatus/getUserList'
|
||||
|
@ -375,31 +360,6 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.banner {
|
||||
background: var(--b-500);
|
||||
color: var(--white);
|
||||
font-size: var(--font-size-mini);
|
||||
padding: var(--space-slab) var(--space-normal);
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: var(--white);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
&.messenger-policy--banner {
|
||||
background: var(--r-400);
|
||||
}
|
||||
|
||||
.banner-close-button {
|
||||
cursor: pointer;
|
||||
margin-left: var(--space--two);
|
||||
color: var(--white);
|
||||
}
|
||||
}
|
||||
|
||||
.spinner--container {
|
||||
min-height: var(--space-jumbo);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<template>
|
||||
<div class="reply-box" :class="replyBoxClass">
|
||||
<banner
|
||||
v-if="showSelfAssignBanner"
|
||||
color-scheme="secondary"
|
||||
:banner-message="$t('CONVERSATION.NOT_ASSIGNED_TO_YOU')"
|
||||
:has-action-button="true"
|
||||
:action-button-label="$t('CONVERSATION.ASSIGN_TO_ME')"
|
||||
@click="onClickSelfAssign"
|
||||
/>
|
||||
<reply-top-panel
|
||||
:mode="replyType"
|
||||
:set-reply-mode="setReplyMode"
|
||||
|
@ -90,6 +98,7 @@ import AttachmentPreview from 'dashboard/components/widgets/AttachmentsPreview';
|
|||
import ReplyTopPanel from 'dashboard/components/widgets/WootWriter/ReplyTopPanel';
|
||||
import ReplyEmailHead from './ReplyEmailHead';
|
||||
import ReplyBottomPanel from 'dashboard/components/widgets/WootWriter/ReplyBottomPanel';
|
||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||
import { REPLY_EDITOR_MODES } from 'dashboard/components/widgets/WootWriter/constants';
|
||||
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor';
|
||||
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
|
||||
|
@ -117,6 +126,7 @@ export default {
|
|||
ReplyEmailHead,
|
||||
ReplyBottomPanel,
|
||||
WootMessageEditor,
|
||||
Banner,
|
||||
},
|
||||
mixins: [clickaway, inboxMixin, uiSettingsMixin, alertMixin],
|
||||
props: {
|
||||
|
@ -150,6 +160,11 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentChat: 'getSelectedChat',
|
||||
currentUser: 'getCurrentUser',
|
||||
}),
|
||||
|
||||
showRichContentEditor() {
|
||||
if (this.isOnPrivateNote) {
|
||||
return true;
|
||||
|
@ -164,7 +179,36 @@ export default {
|
|||
}
|
||||
return false;
|
||||
},
|
||||
...mapGetters({ currentChat: 'getSelectedChat' }),
|
||||
assignedAgent: {
|
||||
get() {
|
||||
return this.currentChat.meta.assignee;
|
||||
},
|
||||
set(agent) {
|
||||
const agentId = agent ? agent.id : 0;
|
||||
this.$store.dispatch('setCurrentChatAssignee', agent);
|
||||
this.$store
|
||||
.dispatch('assignAgent', {
|
||||
conversationId: this.currentChat.id,
|
||||
agentId,
|
||||
})
|
||||
.then(() => {
|
||||
this.showAlert(this.$t('CONVERSATION.CHANGE_AGENT'));
|
||||
});
|
||||
},
|
||||
},
|
||||
showSelfAssignBanner() {
|
||||
if (this.message !== '' && !this.isOnPrivateNote) {
|
||||
if (!this.assignedAgent) {
|
||||
return true;
|
||||
}
|
||||
if (this.assignedAgent.id !== this.currentUser.id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
enterToSendEnabled() {
|
||||
return !!this.uiSettings.enter_to_send_enabled;
|
||||
},
|
||||
|
@ -372,6 +416,29 @@ export default {
|
|||
toggleEnterToSend(enterToSendEnabled) {
|
||||
this.updateUISettings({ enter_to_send_enabled: enterToSendEnabled });
|
||||
},
|
||||
onClickSelfAssign() {
|
||||
const {
|
||||
account_id,
|
||||
availability_status,
|
||||
available_name,
|
||||
email,
|
||||
id,
|
||||
name,
|
||||
role,
|
||||
avatar_url,
|
||||
} = this.currentUser;
|
||||
const selfAssign = {
|
||||
account_id,
|
||||
availability_status,
|
||||
available_name,
|
||||
email,
|
||||
id,
|
||||
name,
|
||||
role,
|
||||
thumbnail: avatar_url,
|
||||
};
|
||||
this.assignedAgent = selfAssign;
|
||||
},
|
||||
async sendMessage() {
|
||||
if (this.isReplyButtonDisabled) {
|
||||
return;
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
"LOADING_CONVERSATIONS": "Loading Conversations",
|
||||
"CANNOT_REPLY": "You cannot reply due to",
|
||||
"24_HOURS_WINDOW": "24 hour message window restriction",
|
||||
"NOT_ASSIGNED_TO_YOU": "This conversation is not assigned to you. Would you like to assign this conversation to yourself?",
|
||||
"ASSIGN_TO_ME": "Assign to me",
|
||||
"TWILIO_WHATSAPP_CAN_REPLY": "You can only reply to this conversation using a template message due to",
|
||||
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24 hour message window restriction",
|
||||
"SELECT_A_TWEET_TO_REPLY": "Please select a tweet to reply to.",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue