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:
Sivin Varghese 2022-02-07 12:27:20 +05:30 committed by GitHub
parent a737f89c47
commit 1a3d39a7f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 233 additions and 75 deletions

View 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>

View file

@ -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);
}

View file

@ -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;

View file

@ -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.",