feat: Create a new conversation from the contact panel (#2019)
* Chore: Improve button component styles
This commit is contained in:
parent
c287ad08fb
commit
864471a21e
16 changed files with 469 additions and 9 deletions
|
@ -14,6 +14,10 @@ class ContactAPI extends ApiClient {
|
|||
return axios.get(`${this.url}/${contactId}/conversations`);
|
||||
}
|
||||
|
||||
getContactableInboxes(contactId) {
|
||||
return axios.get(`${this.url}/${contactId}/contactable_inboxes`);
|
||||
}
|
||||
|
||||
search(search = '', page = 1) {
|
||||
return axios.get(`${this.url}/search?q=${search}&page=${page}`);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
>
|
||||
<spinner v-if="isLoading" size="small" />
|
||||
<i v-else-if="icon" class="icon" :class="icon"></i>
|
||||
<span v-if="$slots.default" class="content"><slot></slot></span>
|
||||
<span v-if="$slots.default" class="button__content"><slot></slot></span>
|
||||
</button>
|
||||
</template>
|
||||
<script>
|
||||
|
@ -63,11 +63,16 @@ export default {
|
|||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&.link {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.spinner {
|
||||
padding: 0 var(--space-small);
|
||||
}
|
||||
.icon + .content {
|
||||
.icon + .button__content {
|
||||
padding-left: var(--space-small);
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"INITIATED_FROM": "Initiated from",
|
||||
"INITIATED_AT": "Initiated at",
|
||||
"IP_ADDRESS": "IP Address",
|
||||
"NEW_MESSAGE": "New message",
|
||||
"CONVERSATIONS": {
|
||||
"NO_RECORDS_FOUND": "There are no previous conversations associated to this contact.",
|
||||
"TITLE": "Previous Conversations"
|
||||
|
@ -106,6 +107,30 @@
|
|||
"CONTACT_ALREADY_EXIST": "This email address is in use for another contact.",
|
||||
"ERROR_MESSAGE": "There was an error, please try again"
|
||||
},
|
||||
"NEW_CONVERSATION": {
|
||||
"BUTTON_LABEL": "Start conversation",
|
||||
"TITLE": "New conversation",
|
||||
"DESC": "Start a new conversation by sending a new message.",
|
||||
"NO_INBOX": "Couldn't find an inbox to initiate a new conversation with this contact.",
|
||||
"FORM": {
|
||||
"TO": {
|
||||
"LABEL": "To"
|
||||
},
|
||||
"INBOX": {
|
||||
"LABEL": "Inbox",
|
||||
"ERROR": "Select an inbox"
|
||||
},
|
||||
"MESSAGE": {
|
||||
"LABEL": "Message",
|
||||
"PLACEHOLDER": "Write your message here",
|
||||
"ERROR": "Message can't be empty"
|
||||
},
|
||||
"SUBMIT": "Send message",
|
||||
"CANCEL": "Cancel",
|
||||
"SUCCESS_MESSAGE": "Message sent!",
|
||||
"ERROR_MESSAGE": "Couldn't send! try again"
|
||||
}
|
||||
},
|
||||
"CONTACTS_PAGE": {
|
||||
"HEADER": "Contacts",
|
||||
"SEARCH_BUTTON": "Search",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<span class="close-button" @click="onClose">
|
||||
<i class="ion-android-close close-icon" />
|
||||
</span>
|
||||
<contact-info :contact="contact" />
|
||||
<contact-info show-new-message :contact="contact" />
|
||||
<contact-custom-attributes
|
||||
v-if="hasContactAttributes"
|
||||
:custom-attributes="contact.custom_attributes"
|
||||
|
|
|
@ -50,19 +50,41 @@
|
|||
</div>
|
||||
</div>
|
||||
<woot-button
|
||||
v-if="!showNewMessage"
|
||||
class="edit-contact"
|
||||
variant="clear"
|
||||
variant="clear link"
|
||||
size="small"
|
||||
@click="toggleEditModal"
|
||||
>
|
||||
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
<div v-else class="contact-actions">
|
||||
<woot-button
|
||||
class="new-message"
|
||||
size="small expanded"
|
||||
@click="toggleConversationModal"
|
||||
>
|
||||
{{ $t('CONTACT_PANEL.NEW_MESSAGE') }}
|
||||
</woot-button>
|
||||
<woot-button
|
||||
variant="hollow"
|
||||
size="small expanded"
|
||||
@click="toggleEditModal"
|
||||
>
|
||||
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
<edit-contact
|
||||
v-if="showEditModal"
|
||||
:show="showEditModal"
|
||||
:contact="contact"
|
||||
@cancel="toggleEditModal"
|
||||
/>
|
||||
<new-conversation
|
||||
:show="showConversationModal"
|
||||
:contact="contact"
|
||||
@cancel="toggleConversationModal"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -71,6 +93,7 @@ import ContactInfoRow from './ContactInfoRow';
|
|||
import Thumbnail from 'dashboard/components/widgets/Thumbnail.vue';
|
||||
import SocialIcons from './SocialIcons';
|
||||
import EditContact from './EditContact';
|
||||
import NewConversation from './NewConversation';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -78,6 +101,7 @@ export default {
|
|||
EditContact,
|
||||
Thumbnail,
|
||||
SocialIcons,
|
||||
NewConversation,
|
||||
},
|
||||
props: {
|
||||
contact: {
|
||||
|
@ -88,10 +112,15 @@ export default {
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
showNewMessage: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showEditModal: false,
|
||||
showConversationModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -111,6 +140,9 @@ export default {
|
|||
toggleEditModal() {
|
||||
this.showEditModal = !this.showEditModal;
|
||||
},
|
||||
toggleConversationModal() {
|
||||
this.showConversationModal = !this.showConversationModal;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -120,7 +152,7 @@ export default {
|
|||
@import '~dashboard/assets/scss/mixins';
|
||||
.contact--profile {
|
||||
align-items: flex-start;
|
||||
padding: var(--space-normal) var(--space-normal) var(--space-large);
|
||||
padding: var(--space-normal) var(--space-normal);
|
||||
|
||||
.user-thumbnail-box {
|
||||
margin-right: $space-normal;
|
||||
|
@ -164,8 +196,21 @@ export default {
|
|||
font-size: $font-weight-normal;
|
||||
}
|
||||
}
|
||||
.contact-actions {
|
||||
margin: var(--space-small) 0;
|
||||
}
|
||||
.button.edit-contact {
|
||||
margin-left: var(--space-two);
|
||||
padding-left: var(--space-micro);
|
||||
}
|
||||
|
||||
.edit-contact {
|
||||
margin-left: var(--space-slab);
|
||||
.button.new-message {
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
|
||||
.contact-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
<template>
|
||||
<form class="conversation--form" @submit.prevent="handleSubmit">
|
||||
<div v-if="showNoInboxAlert" class="callout warning">
|
||||
<p>
|
||||
{{ $t('NEW_CONVERSATION.NO_INBOX') }}
|
||||
</p>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<label :class="{ error: $v.targetInbox.$error }">
|
||||
{{ $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>
|
||||
<span v-if="$v.targetInbox.$error" class="message">
|
||||
{{ $t('NEW_CONVERSATION.FORM.INBOX.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<label>
|
||||
{{ $t('NEW_CONVERSATION.FORM.TO.LABEL') }}
|
||||
<div class="contact-input">
|
||||
<thumbnail
|
||||
:src="contact.thumbnail"
|
||||
size="24px"
|
||||
:username="contact.name"
|
||||
:status="contact.availability_status"
|
||||
/>
|
||||
<h4 class="text-block-title contact-name">
|
||||
{{ contact.name }}
|
||||
</h4>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="columns">
|
||||
<label :class="{ error: $v.message.$error }">
|
||||
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.LABEL') }}
|
||||
<textarea
|
||||
v-model="message"
|
||||
class="message-input"
|
||||
type="text"
|
||||
:placeholder="$t('NEW_CONVERSATION.FORM.MESSAGE.PLACEHOLDER')"
|
||||
@input="$v.message.$touch"
|
||||
/>
|
||||
<span v-if="$v.message.$error" class="message">
|
||||
{{ $t('NEW_CONVERSATION.FORM.MESSAGE.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="button clear" @click.prevent="onCancel">
|
||||
{{ $t('NEW_CONVERSATION.FORM.CANCEL') }}
|
||||
</button>
|
||||
<woot-button type="submit" :is-loading="conversationsUiFlags.isCreating">
|
||||
{{ $t('NEW_CONVERSATION.FORM.SUBMIT') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import Thumbnail from 'dashboard/components/widgets/Thumbnail';
|
||||
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { ExceptionWithMessage } from 'shared/helpers/CustomErrors';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Thumbnail,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
contact: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
onSubmit: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
message: '',
|
||||
selectedInbox: '',
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
message: {
|
||||
required,
|
||||
},
|
||||
targetInbox: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
uiFlags: 'contacts/getUIFlags',
|
||||
conversationsUiFlags: 'contactConversations/getUIFlags',
|
||||
}),
|
||||
getNewConversation() {
|
||||
return {
|
||||
inboxId: this.targetInbox.inbox.id,
|
||||
sourceId: this.targetInbox.source_id,
|
||||
contactId: this.contact.id,
|
||||
message: { content: this.message },
|
||||
};
|
||||
},
|
||||
targetInbox: {
|
||||
get() {
|
||||
return this.selectedInbox || '';
|
||||
},
|
||||
set(value) {
|
||||
this.selectedInbox = value;
|
||||
},
|
||||
},
|
||||
showNoInboxAlert() {
|
||||
if (!this.contact.contactableInboxes) {
|
||||
return false;
|
||||
}
|
||||
return this.inboxes.length === 0 && !this.uiFlags.isFetchingInboxes;
|
||||
},
|
||||
inboxes() {
|
||||
return this.contact.contactableInboxes || [];
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onSuccess() {
|
||||
this.$emit('success');
|
||||
},
|
||||
|
||||
async handleSubmit() {
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const payload = this.getNewConversation;
|
||||
|
||||
await this.onSubmit(payload);
|
||||
this.onSuccess();
|
||||
this.showAlert(this.$t('NEW_CONVERSATION.FORM.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
if (error instanceof ExceptionWithMessage) {
|
||||
this.showAlert(error.data);
|
||||
} else {
|
||||
this.showAlert(this.$t('NEW_CONVERSATION.FORM.ERROR_MESSAGE'));
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.conversation--form {
|
||||
padding: var(--space-normal) var(--space-large) var(--space-large);
|
||||
|
||||
.columns {
|
||||
padding: 0 var(--space-smaller);
|
||||
}
|
||||
}
|
||||
|
||||
.input-group-label {
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
|
||||
.contact-input {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.9rem;
|
||||
background: var(--color-background-light);
|
||||
|
||||
border: 1px solid var(--color-border);
|
||||
padding: var(--space-smaller) var(--space-small);
|
||||
border-radius: var(--border-radius-small);
|
||||
|
||||
.contact-name {
|
||||
margin: 0;
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
.message-input {
|
||||
min-height: 8rem;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<woot-modal :show.sync="show" :on-close="onCancel">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('NEW_CONVERSATION.TITLE')"
|
||||
:header-content="$t('NEW_CONVERSATION.DESC')"
|
||||
/>
|
||||
<conversation-form
|
||||
:contact="contact"
|
||||
:on-submit="onSubmit"
|
||||
@success="onSuccess"
|
||||
@cancel="onCancel"
|
||||
/>
|
||||
</div>
|
||||
</woot-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ConversationForm from './ConversationForm';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ConversationForm,
|
||||
},
|
||||
props: {
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
contact: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
const { id } = this.contact;
|
||||
this.$store.dispatch('contacts/fetchContactableInbox', id);
|
||||
},
|
||||
methods: {
|
||||
onCancel() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
onSuccess() {
|
||||
this.$emit('cancel');
|
||||
},
|
||||
async onSubmit(contactItem) {
|
||||
await this.$store.dispatch('contactConversations/create', contactItem);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -1,6 +1,7 @@
|
|||
import Vue from 'vue';
|
||||
import * as types from '../mutation-types';
|
||||
import ContactAPI from '../../api/contacts';
|
||||
import ConversationApi from '../../api/conversations';
|
||||
|
||||
const state = {
|
||||
records: {},
|
||||
|
@ -19,6 +20,30 @@ export const getters = {
|
|||
};
|
||||
|
||||
export const actions = {
|
||||
create: async ({ commit }, params) => {
|
||||
commit(types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, {
|
||||
isCreating: true,
|
||||
});
|
||||
const { inboxId, message, contactId, sourceId } = params;
|
||||
try {
|
||||
const { data } = await ConversationApi.create({
|
||||
inbox_id: inboxId,
|
||||
contact_id: contactId,
|
||||
source_id: sourceId,
|
||||
message,
|
||||
});
|
||||
commit(types.default.ADD_CONTACT_CONVERSATION, {
|
||||
id: contactId,
|
||||
data,
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
commit(types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, {
|
||||
isCreating: false,
|
||||
});
|
||||
}
|
||||
},
|
||||
get: async ({ commit }, contactId) => {
|
||||
commit(types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, {
|
||||
isFetching: true,
|
||||
|
@ -53,6 +78,10 @@ export const mutations = {
|
|||
[types.default.SET_CONTACT_CONVERSATIONS]: ($state, { id, data }) => {
|
||||
Vue.set($state.records, id, data);
|
||||
},
|
||||
[types.default.ADD_CONTACT_CONVERSATION]: ($state, { id, data }) => {
|
||||
const conversations = $state.records[id] || [];
|
||||
Vue.set($state.records, id, [...conversations, data]);
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -83,6 +83,26 @@ export const actions = {
|
|||
}
|
||||
},
|
||||
|
||||
fetchContactableInbox: async ({ commit }, id) => {
|
||||
commit(types.SET_CONTACT_UI_FLAG, { isFetchingInboxes: true });
|
||||
try {
|
||||
const response = await ContactAPI.getContactableInboxes(id);
|
||||
const contact = {
|
||||
id,
|
||||
contactableInboxes: response.data.payload,
|
||||
};
|
||||
commit(types.SET_CONTACT_ITEM, contact);
|
||||
} catch (error) {
|
||||
if (error.response?.data?.message) {
|
||||
throw new ExceptionWithMessage(error.response.data.message);
|
||||
} else {
|
||||
throw new Error(error);
|
||||
}
|
||||
} finally {
|
||||
commit(types.SET_CONTACT_UI_FLAG, { isFetchingInboxes: false });
|
||||
}
|
||||
},
|
||||
|
||||
updatePresence: ({ commit }, data) => {
|
||||
commit(types.UPDATE_CONTACTS_PRESENCE, data);
|
||||
},
|
||||
|
|
|
@ -11,6 +11,7 @@ const state = {
|
|||
uiFlags: {
|
||||
isFetching: false,
|
||||
isFetchingItem: false,
|
||||
isFetchingInboxes: false,
|
||||
isUpdating: false,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import * as MutationHelpers from 'shared/helpers/vuex/mutationHelpers';
|
||||
import * as types from '../mutation-types';
|
||||
import { INBOX_TYPES } from 'shared/mixins/inboxMixin';
|
||||
import InboxesAPI from '../../api/inboxes';
|
||||
import WebChannel from '../../api/channel/webChannel';
|
||||
import FBChannel from '../../api/channel/fbChannel';
|
||||
|
@ -41,6 +42,20 @@ export const getters = {
|
|||
getInboxes($state) {
|
||||
return $state.records;
|
||||
},
|
||||
getNewConversationInboxes($state) {
|
||||
return $state.records.filter(inbox => {
|
||||
const {
|
||||
channel_type: channelType,
|
||||
phone_number: phoneNumber = '',
|
||||
} = inbox;
|
||||
|
||||
const isEmailChannel = channelType === INBOX_TYPES.EMAIL;
|
||||
const isSmsChannel =
|
||||
channelType === INBOX_TYPES.TWILIO &&
|
||||
phoneNumber.startsWith('whatsapp');
|
||||
return isEmailChannel || isSmsChannel;
|
||||
});
|
||||
},
|
||||
getInbox: $state => inboxId => {
|
||||
const [inbox] = $state.records.filter(
|
||||
record => record.id === Number(inboxId)
|
||||
|
|
|
@ -38,4 +38,43 @@ describe('#actions', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#create', () => {
|
||||
it('sends correct actions if API is success', async () => {
|
||||
axios.post.mockResolvedValue({ data: conversationList[0] });
|
||||
await actions.create(
|
||||
{ commit },
|
||||
{ inboxId: 1, message: { content: 'hi' }, contactId: 4, sourceId: 5 }
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, { isCreating: true }],
|
||||
|
||||
[
|
||||
types.default.ADD_CONTACT_CONVERSATION,
|
||||
{ id: 4, data: conversationList[0] },
|
||||
],
|
||||
[
|
||||
types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG,
|
||||
{ isCreating: false },
|
||||
],
|
||||
]);
|
||||
});
|
||||
it('sends correct actions if API is error', async () => {
|
||||
axios.post.mockRejectedValue({ message: 'Incorrect header' });
|
||||
|
||||
await expect(
|
||||
actions.create(
|
||||
{ commit },
|
||||
{ inboxId: 1, message: { content: 'hi' }, contactId: 4, sourceId: 5 }
|
||||
)
|
||||
).rejects.toThrow(Error);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG, { isCreating: true }],
|
||||
[
|
||||
types.default.SET_CONTACT_CONVERSATIONS_UI_FLAG,
|
||||
{ isCreating: false },
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,4 +26,17 @@ describe('#mutations', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#ADD_CONTACT_CONVERSATION', () => {
|
||||
it('Adds new contact conversation to records', () => {
|
||||
const state = { records: {} };
|
||||
mutations[types.default.ADD_CONTACT_CONVERSATION](state, {
|
||||
id: 1,
|
||||
data: { id: 1, contact_id: 1, message: 'hello' },
|
||||
});
|
||||
expect(state.records).toEqual({
|
||||
1: [{ id: 1, contact_id: 1, message: 'hello' }],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -114,6 +114,7 @@ export default {
|
|||
// Contact Conversation
|
||||
SET_CONTACT_CONVERSATIONS_UI_FLAG: 'SET_CONTACT_CONVERSATIONS_UI_FLAG',
|
||||
SET_CONTACT_CONVERSATIONS: 'SET_CONTACT_CONVERSATIONS',
|
||||
ADD_CONTACT_CONVERSATION: 'ADD_CONTACT_CONVERSATION',
|
||||
|
||||
// Conversation Label
|
||||
SET_CONVERSATION_LABELS_UI_FLAG: 'SET_CONVERSATION_LABELS_UI_FLAG',
|
||||
|
|
|
@ -40,7 +40,7 @@ class Contacts::ContactableInboxesService
|
|||
end
|
||||
|
||||
def twilio_contactable_inbox(inbox)
|
||||
return unless @contact.phone_number
|
||||
return if @contact.phone_number.blank?
|
||||
|
||||
case inbox.channel.medium
|
||||
when 'sms'
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
json.source_id resource.source_id
|
||||
json.inbox resource.inbox
|
||||
json.inbox do
|
||||
json.partial! 'api/v1/models/inbox.json.jbuilder', resource: resource.inbox
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue