fix: Remove duplicate contactable inbox in the conversation form (#10554)
--------- Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
@@ -14,7 +14,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
before_action :check_authorization
|
||||
before_action :set_current_page, only: [:index, :active, :search, :filter]
|
||||
before_action :fetch_contact, only: [:show, :update, :destroy, :avatar, :contactable_inboxes, :destroy_custom_attributes]
|
||||
before_action :set_include_contact_inboxes, only: [:index, :search, :filter]
|
||||
before_action :set_include_contact_inboxes, only: [:index, :search, :filter, :show, :update]
|
||||
|
||||
def index
|
||||
@contacts_count = resolved_contacts.count
|
||||
|
||||
@@ -27,6 +27,14 @@ class ContactAPI extends ApiClient {
|
||||
return axios.get(requestURL);
|
||||
}
|
||||
|
||||
show(id) {
|
||||
return axios.get(`${this.url}/${id}?include_contact_inboxes=false`);
|
||||
}
|
||||
|
||||
update(id, data) {
|
||||
return axios.patch(`${this.url}/${id}?include_contact_inboxes=false`, data);
|
||||
}
|
||||
|
||||
getConversations(contactId) {
|
||||
return axios.get(`${this.url}/${contactId}/conversations`);
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@ const updateContact = async () => {
|
||||
try {
|
||||
const { customAttributes, ...basicContactData } = contactData.value;
|
||||
await store.dispatch('contacts/update', basicContactData);
|
||||
await store.dispatch(
|
||||
'contacts/fetchContactableInbox',
|
||||
props.selectedContact.id
|
||||
);
|
||||
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.ERROR_MESSAGE'));
|
||||
|
||||
@@ -153,7 +153,6 @@ watch(
|
||||
activeContact,
|
||||
() => {
|
||||
if (activeContact.value && props.contactId) {
|
||||
// Add null check for contactInboxes
|
||||
const contactInboxes = activeContact.value?.contactInboxes || [];
|
||||
selectedContact.value = {
|
||||
...activeContact.value,
|
||||
|
||||
@@ -3,6 +3,15 @@ import { getInboxIconByType } from 'dashboard/helper/inbox';
|
||||
import camelcaseKeys from 'camelcase-keys';
|
||||
import ContactAPI from 'dashboard/api/contacts';
|
||||
|
||||
const CHANNEL_PRIORITY = {
|
||||
'Channel::Email': 1,
|
||||
'Channel::Whatsapp': 2,
|
||||
'Channel::Sms': 3,
|
||||
'Channel::TwilioSms': 4,
|
||||
'Channel::WebWidget': 5,
|
||||
'Channel::Api': 6,
|
||||
};
|
||||
|
||||
export const generateLabelForContactableInboxesList = ({
|
||||
name,
|
||||
email,
|
||||
@@ -21,27 +30,49 @@ export const generateLabelForContactableInboxesList = ({
|
||||
return name;
|
||||
};
|
||||
|
||||
const transformInbox = ({
|
||||
name,
|
||||
id,
|
||||
email,
|
||||
channelType,
|
||||
phoneNumber,
|
||||
...rest
|
||||
}) => ({
|
||||
id,
|
||||
icon: getInboxIconByType(channelType, phoneNumber, 'line'),
|
||||
label: generateLabelForContactableInboxesList({
|
||||
name,
|
||||
email,
|
||||
channelType,
|
||||
phoneNumber,
|
||||
}),
|
||||
action: 'inbox',
|
||||
value: id,
|
||||
name,
|
||||
email,
|
||||
phoneNumber,
|
||||
channelType,
|
||||
...rest,
|
||||
});
|
||||
|
||||
export const compareInboxes = (a, b) => {
|
||||
// Channels that have no priority defined should come at the end.
|
||||
const priorityA = CHANNEL_PRIORITY[a.channelType] || 999;
|
||||
const priorityB = CHANNEL_PRIORITY[b.channelType] || 999;
|
||||
|
||||
if (priorityA !== priorityB) {
|
||||
return priorityA - priorityB;
|
||||
}
|
||||
|
||||
const nameA = a.name || '';
|
||||
const nameB = b.name || '';
|
||||
return nameA.localeCompare(nameB);
|
||||
};
|
||||
|
||||
export const buildContactableInboxesList = contactInboxes => {
|
||||
if (!contactInboxes) return [];
|
||||
return contactInboxes.map(
|
||||
({ name, id, email, channelType, phoneNumber, ...rest }) => ({
|
||||
id,
|
||||
icon: getInboxIconByType(channelType, phoneNumber, 'line'),
|
||||
label: generateLabelForContactableInboxesList({
|
||||
name,
|
||||
email,
|
||||
channelType,
|
||||
phoneNumber,
|
||||
}),
|
||||
action: 'inbox',
|
||||
value: id,
|
||||
name,
|
||||
email,
|
||||
phoneNumber,
|
||||
channelType,
|
||||
...rest,
|
||||
})
|
||||
);
|
||||
|
||||
return contactInboxes.map(transformInbox).sort(compareInboxes);
|
||||
};
|
||||
|
||||
export const getCapitalizedNameFromEmail = email => {
|
||||
|
||||
@@ -463,3 +463,74 @@ describe('composeConversationHelper', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('compareInboxes', () => {
|
||||
it('should sort inboxes by channel priority', () => {
|
||||
const inboxes = [
|
||||
{ channelType: 'Channel::Api', name: 'API Inbox' },
|
||||
{ channelType: 'Channel::Email', name: 'Email Inbox' },
|
||||
{ channelType: 'Channel::WebWidget', name: 'Widget' },
|
||||
{ channelType: 'Channel::Whatsapp', name: 'WhatsApp' },
|
||||
];
|
||||
|
||||
const sorted = [...inboxes].sort(helpers.compareInboxes);
|
||||
|
||||
expect(sorted[0].channelType).toBe('Channel::Email');
|
||||
expect(sorted[1].channelType).toBe('Channel::Whatsapp');
|
||||
expect(sorted[2].channelType).toBe('Channel::WebWidget');
|
||||
expect(sorted[3].channelType).toBe('Channel::Api');
|
||||
});
|
||||
|
||||
it('should sort SMS channels correctly', () => {
|
||||
const inboxes = [
|
||||
{ channelType: 'Channel::TwilioSms', name: 'Twilio' },
|
||||
{ channelType: 'Channel::Sms', name: 'Regular SMS' },
|
||||
];
|
||||
|
||||
const sorted = [...inboxes].sort(helpers.compareInboxes);
|
||||
|
||||
expect(sorted[0].channelType).toBe('Channel::Sms');
|
||||
expect(sorted[1].channelType).toBe('Channel::TwilioSms');
|
||||
});
|
||||
|
||||
it('should sort by name when channel types are same', () => {
|
||||
const inboxes = [
|
||||
{ channelType: 'Channel::Email', name: 'Support' },
|
||||
{ channelType: 'Channel::Email', name: 'Marketing' },
|
||||
{ channelType: 'Channel::Email', name: 'Billing' },
|
||||
];
|
||||
|
||||
const sorted = [...inboxes].sort(helpers.compareInboxes);
|
||||
|
||||
expect(sorted.map(inbox => inbox.name)).toEqual([
|
||||
'Billing',
|
||||
'Marketing',
|
||||
'Support',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should put channels without priority at the end', () => {
|
||||
const inboxes = [
|
||||
{ channelType: 'Channel::Unknown', name: 'Unknown' },
|
||||
{ channelType: 'Channel::Email', name: 'Email' },
|
||||
{ channelType: 'Channel::LineChannel', name: 'Line' },
|
||||
{ channelType: 'Channel::Whatsapp', name: 'WhatsApp' },
|
||||
];
|
||||
|
||||
const sorted = [...inboxes].sort(helpers.compareInboxes);
|
||||
|
||||
expect(sorted.map(i => i.channelType)).toEqual([
|
||||
'Channel::Email',
|
||||
'Channel::Whatsapp',
|
||||
|
||||
'Channel::LineChannel',
|
||||
'Channel::Unknown',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle empty array', () => {
|
||||
const inboxes = [];
|
||||
const sorted = [...inboxes].sort(helpers.compareInboxes);
|
||||
expect(sorted).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -62,7 +62,7 @@ const goToContactsList = () => {
|
||||
|
||||
const fetchActiveContact = async () => {
|
||||
if (route.params.contactId) {
|
||||
store.dispatch('contacts/show', { id: route.params.contactId });
|
||||
await store.dispatch('contacts/show', { id: route.params.contactId });
|
||||
await store.dispatch(
|
||||
'contacts/fetchContactableInbox',
|
||||
route.params.contactId
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
json.payload do
|
||||
json.partial! 'api/v1/models/contact', formats: [:json], resource: @contact, with_contact_inboxes: true
|
||||
json.partial! 'api/v1/models/contact', formats: [:json], resource: @contact, with_contact_inboxes: @include_contact_inboxes
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
json.payload do
|
||||
json.partial! 'api/v1/models/contact', formats: [:json], resource: @contact, with_contact_inboxes: true
|
||||
json.partial! 'api/v1/models/contact', formats: [:json], resource: @contact, with_contact_inboxes: @include_contact_inboxes
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user