feat: Adds new inbox selector with more info for new message modal [cw-1358] (#6823)

This commit is contained in:
Nithin David Thomas
2023-04-19 23:02:50 +05:30
committed by GitHub
parent 76d4c22c2d
commit bd1e69e4b4
6 changed files with 282 additions and 32 deletions

View File

@@ -21,7 +21,7 @@
.multiselect--active {
>.multiselect__tags {
border-color: $color-woot;
border-color: var(--w-500);
}
}
@@ -75,16 +75,13 @@
}
&.multiselect__option--selected {
background: var(--w-400);
color: var(--white);
background: var(--w-75);
&.multiselect__option--highlight:hover {
background: var(--w-600);
color: var(--white);
background: var(--w-75);
&::after {
background: transparent;
color: var(--white);
}
&::after:hover {
@@ -196,6 +193,7 @@
display: flex;
font-size: var(--font-size-small);
margin: 0;
max-height: 3.8rem;
padding: var(--space-smaller) var(--space-micro);
}

View File

@@ -0,0 +1,37 @@
import InboxDropdownItem from './InboxDropdownItem';
export default {
title: 'Components/DropDowns/InboxDropdownItem',
component: InboxDropdownItem,
argTypes: {
name: {
defaultValue: 'My new inbox',
control: {
type: 'text',
},
},
inboxIdentifier: {
defaultValue: 'nithin@mail.com',
control: {
type: 'text',
},
},
channelType: {
defaultValue: 'email',
control: {
type: 'text',
},
},
},
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: { InboxDropdownItem },
template: '<inbox-dropdown-item v-bind="$props" ></inbox-dropdown-item>',
});
export const Banner = Template.bind({});
Banner.args = {};

View File

@@ -0,0 +1,102 @@
<template>
<div class="option-item--inbox">
<span class="badge--icon">
<fluent-icon :icon="computedInboxIcon" size="14" />
</span>
<div class="option__user-data">
<h5 class="option__title">
{{ name }}
</h5>
<p class="option__body text-truncate" :title="inboxIdentifier">
{{ inboxIdentifier || computedInboxType }}
</p>
</div>
</div>
</template>
<script>
import {
getInboxClassByType,
getReadableInboxByType,
} from 'dashboard/helper/inbox';
export default {
components: {},
props: {
name: {
type: String,
default: '',
},
inboxIdentifier: {
type: String,
default: '',
},
channelType: {
type: String,
default: '',
},
},
computed: {
computedInboxIcon() {
if (!this.channelType) return 'chat';
const classByType = getInboxClassByType(
this.channelType,
this.inboxIdentifier
);
return classByType;
},
computedInboxType() {
if (!this.channelType) return 'chat';
const classByType = getReadableInboxByType(
this.channelType,
this.inboxIdentifier
);
return classByType;
},
},
};
</script>
<style lang="scss" scoped>
.option-item--inbox {
display: flex;
align-items: center;
height: 3.8rem;
min-width: 0;
padding: 0 var(--space-smaller);
}
.badge--icon {
display: inline-flex;
border-radius: var(--border-radius-small);
margin-right: var(--space-smaller);
background: var(--s-25);
padding: var(--space-micro);
align-items: center;
flex-shrink: 0;
justify-content: center;
width: var(--space-medium);
height: var(--space-medium);
}
.option__user-data {
display: flex;
flex-direction: column;
width: 100%;
min-width: 0;
margin-left: var(--space-smaller);
margin-right: var(--space-smaller);
}
.option__body {
display: inline-block;
color: var(--s-600);
font-size: var(--font-size-small);
line-height: 1.3;
min-width: 0;
margin: 0;
}
.option__title {
line-height: 1.1;
font-size: var(--font-size-mini);
margin: 0;
}
</style>

View File

@@ -1,5 +1,55 @@
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
export const getInboxSource = (type, phoneNumber, inbox) => {
switch (type) {
case INBOX_TYPES.WEB:
return inbox.website_url || '';
case INBOX_TYPES.TWILIO:
case INBOX_TYPES.WHATSAPP:
return phoneNumber || '';
case INBOX_TYPES.EMAIL:
return inbox.email || '';
default:
return '';
}
};
export const getReadableInboxByType = (type, phoneNumber) => {
switch (type) {
case INBOX_TYPES.WEB:
return 'livechat';
case INBOX_TYPES.FB:
return 'facebook';
case INBOX_TYPES.TWITTER:
return 'twitter';
case INBOX_TYPES.TWILIO:
return phoneNumber?.startsWith('whatsapp') ? 'whatsapp' : 'sms';
case INBOX_TYPES.WHATSAPP:
return 'whatsapp';
case INBOX_TYPES.API:
return 'api';
case INBOX_TYPES.EMAIL:
return 'email';
case INBOX_TYPES.TELEGRAM:
return 'telegram';
case INBOX_TYPES.LINE:
return 'line';
default:
return 'chat';
}
};
export const getInboxClassByType = (type, phoneNumber) => {
switch (type) {
case INBOX_TYPES.WEB:

View File

@@ -182,7 +182,8 @@
"LABEL": "To"
},
"INBOX": {
"LABEL": "Inbox",
"LABEL": "Via Inbox",
"PLACEHOLDER": "Choose source inbox",
"ERROR": "Select an inbox"
},
"SUBJECT": {

View File

@@ -8,17 +8,43 @@
<div v-else>
<div class="row gutter-small">
<div class="columns">
<label :class="{ error: $v.targetInbox.$error }">
<label>
{{ $t('NEW_CONVERSATION.FORM.INBOX.LABEL') }}
<select v-model="targetInbox">
<option
v-for="contactableInbox in inboxes"
:key="contactableInbox.inbox.id"
:value="contactableInbox"
>
{{ contactableInbox.inbox.name }}
</option>
</select>
</label>
<div class="multiselect-wrap--small">
<multiselect
v-model="targetInbox"
track-by="id"
label="name"
:placeholder="$t('FORMS.MULTISELECT.SELECT')"
selected-label=""
select-label=""
deselect-label=""
:max-height="160"
:close-on-select="true"
:options="[...inboxes, ...inboxes]"
>
<template slot="singleLabel" slot-scope="{ option }">
<inbox-dropdown-item
v-if="option.name"
:name="option.name"
:inbox-identifier="computedInboxSource(option)"
:channel-type="option.channel_type"
/>
<span v-else>
{{ $t('NEW_CONVERSATION.FORM.INBOX.PLACEHOLDER') }}
</span>
</template>
<template slot="option" slot-scope="{ option }">
<inbox-dropdown-item
:name="option.name"
:inbox-identifier="computedInboxSource(option)"
:channel-type="option.channel_type"
/>
</template>
</multiselect>
</div>
<label :class="{ error: $v.targetInbox.$error }">
<span v-if="$v.targetInbox.$error" class="message">
{{ $t('NEW_CONVERSATION.FORM.INBOX.ERROR') }}
</span>
@@ -129,10 +155,12 @@ import Thumbnail from 'dashboard/components/widgets/Thumbnail';
import WootMessageEditor from 'dashboard/components/widgets/WootWriter/Editor';
import ReplyEmailHead from 'dashboard/components/widgets/conversation/ReplyEmailHead';
import CannedResponse from 'dashboard/components/widgets/conversation/CannedResponse.vue';
import InboxDropdownItem from 'dashboard/components/widgets/InboxDropdownItem.vue';
import WhatsappTemplates from './WhatsappTemplates.vue';
import alertMixin from 'shared/mixins/alertMixin';
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
import { getInboxSource } from 'dashboard/helper/inbox';
import { required, requiredIf } from 'vuelidate/lib/validators';
export default {
@@ -142,6 +170,7 @@ export default {
ReplyEmailHead,
CannedResponse,
WhatsappTemplates,
InboxDropdownItem,
},
mixins: [alertMixin],
props: {
@@ -161,9 +190,9 @@ export default {
message: '',
showCannedResponseMenu: false,
cannedResponseSearchKey: '',
selectedInbox: '',
bccEmails: '',
ccEmails: '',
targetInbox: {},
whatsappTemplateSelected: false,
};
},
@@ -186,8 +215,8 @@ export default {
}),
emailMessagePayload() {
const payload = {
inboxId: this.targetInbox.inbox.id,
sourceId: this.targetInbox.source_id,
inboxId: this.targetInbox.id,
sourceId: this.targetInbox.sourceId,
contactId: this.contact.id,
message: { content: this.message },
mailSubject: this.subject,
@@ -202,12 +231,17 @@ export default {
}
return payload;
},
targetInbox: {
selectedInbox: {
get() {
return this.selectedInbox || {};
const inboxList = this.contact.contactableInboxes || [];
return (
inboxList.find(inbox => inbox.inbox.id === this.targetInbox.id) || {
inbox: {},
}
);
},
set(value) {
this.selectedInbox = value;
this.targetInbox = value.inbox;
},
},
showNoInboxAlert() {
@@ -217,7 +251,11 @@ export default {
return this.inboxes.length === 0 && !this.uiFlags.isFetchingInboxes;
},
inboxes() {
return this.contact.contactableInboxes || [];
const inboxList = this.contact.contactableInboxes || [];
return inboxList.map(inbox => ({
...inbox.inbox,
sourceId: inbox.source_id,
}));
},
isAnEmailInbox() {
return (
@@ -267,8 +305,8 @@ export default {
},
prepareWhatsAppMessagePayload({ message: content, templateParams }) {
const payload = {
inboxId: this.targetInbox.inbox.id,
sourceId: this.targetInbox.source_id,
inboxId: this.targetInbox.id,
sourceId: this.targetInbox.sourceId,
contactId: this.contact.id,
message: { content, template_params: templateParams },
assigneeId: this.currentUser.id,
@@ -311,6 +349,18 @@ export default {
const payload = this.prepareWhatsAppMessagePayload(messagePayload);
await this.createConversation(payload);
},
inboxReadableIdentifier(inbox) {
return `${inbox.name} (${inbox.channel_type})`;
},
computedInboxSource(inbox) {
if (!inbox.channel_type) return '';
const classByType = getInboxSource(
inbox.channel_type,
inbox.phone_number,
inbox
);
return classByType;
},
},
};
</script>
@@ -352,11 +402,23 @@ export default {
gap: var(--space-small);
}
::v-deep .mention--box {
left: 0;
margin: auto;
right: 0;
top: unset;
height: fit-content;
::v-deep {
.mention--box {
left: 0;
margin: auto;
right: 0;
top: unset;
height: fit-content;
}
/* TODO: Remove when have standardized a component out of multiselect */
.multiselect .multiselect__content .multiselect__option span {
display: inline-flex;
width: var(--space-medium);
color: var(--s-600);
}
.multiselect .multiselect__content .multiselect__option {
padding: var(--space-micro) var(--space-smaller);
}
}
</style>