fix: Remove duplicate contactable inbox in the conversation form (#10554)
--------- Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
parent
1b430ffae2
commit
d902bb1d6f
@ -14,7 +14,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
|||||||
before_action :check_authorization
|
before_action :check_authorization
|
||||||
before_action :set_current_page, only: [:index, :active, :search, :filter]
|
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 :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
|
def index
|
||||||
@contacts_count = resolved_contacts.count
|
@contacts_count = resolved_contacts.count
|
||||||
|
|||||||
@ -27,6 +27,14 @@ class ContactAPI extends ApiClient {
|
|||||||
return axios.get(requestURL);
|
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) {
|
getConversations(contactId) {
|
||||||
return axios.get(`${this.url}/${contactId}/conversations`);
|
return axios.get(`${this.url}/${contactId}/conversations`);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,6 +70,10 @@ const updateContact = async () => {
|
|||||||
try {
|
try {
|
||||||
const { customAttributes, ...basicContactData } = contactData.value;
|
const { customAttributes, ...basicContactData } = contactData.value;
|
||||||
await store.dispatch('contacts/update', basicContactData);
|
await store.dispatch('contacts/update', basicContactData);
|
||||||
|
await store.dispatch(
|
||||||
|
'contacts/fetchContactableInbox',
|
||||||
|
props.selectedContact.id
|
||||||
|
);
|
||||||
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.SUCCESS_MESSAGE'));
|
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.SUCCESS_MESSAGE'));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.ERROR_MESSAGE'));
|
useAlert(t('CONTACTS_LAYOUT.CARD.EDIT_DETAILS_FORM.ERROR_MESSAGE'));
|
||||||
|
|||||||
@ -153,7 +153,6 @@ watch(
|
|||||||
activeContact,
|
activeContact,
|
||||||
() => {
|
() => {
|
||||||
if (activeContact.value && props.contactId) {
|
if (activeContact.value && props.contactId) {
|
||||||
// Add null check for contactInboxes
|
|
||||||
const contactInboxes = activeContact.value?.contactInboxes || [];
|
const contactInboxes = activeContact.value?.contactInboxes || [];
|
||||||
selectedContact.value = {
|
selectedContact.value = {
|
||||||
...activeContact.value,
|
...activeContact.value,
|
||||||
|
|||||||
@ -3,6 +3,15 @@ import { getInboxIconByType } from 'dashboard/helper/inbox';
|
|||||||
import camelcaseKeys from 'camelcase-keys';
|
import camelcaseKeys from 'camelcase-keys';
|
||||||
import ContactAPI from 'dashboard/api/contacts';
|
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 = ({
|
export const generateLabelForContactableInboxesList = ({
|
||||||
name,
|
name,
|
||||||
email,
|
email,
|
||||||
@ -21,10 +30,14 @@ export const generateLabelForContactableInboxesList = ({
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buildContactableInboxesList = contactInboxes => {
|
const transformInbox = ({
|
||||||
if (!contactInboxes) return [];
|
name,
|
||||||
return contactInboxes.map(
|
id,
|
||||||
({ name, id, email, channelType, phoneNumber, ...rest }) => ({
|
email,
|
||||||
|
channelType,
|
||||||
|
phoneNumber,
|
||||||
|
...rest
|
||||||
|
}) => ({
|
||||||
id,
|
id,
|
||||||
icon: getInboxIconByType(channelType, phoneNumber, 'line'),
|
icon: getInboxIconByType(channelType, phoneNumber, 'line'),
|
||||||
label: generateLabelForContactableInboxesList({
|
label: generateLabelForContactableInboxesList({
|
||||||
@ -40,8 +53,26 @@ export const buildContactableInboxesList = contactInboxes => {
|
|||||||
phoneNumber,
|
phoneNumber,
|
||||||
channelType,
|
channelType,
|
||||||
...rest,
|
...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(transformInbox).sort(compareInboxes);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getCapitalizedNameFromEmail = email => {
|
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 () => {
|
const fetchActiveContact = async () => {
|
||||||
if (route.params.contactId) {
|
if (route.params.contactId) {
|
||||||
store.dispatch('contacts/show', { id: route.params.contactId });
|
await store.dispatch('contacts/show', { id: route.params.contactId });
|
||||||
await store.dispatch(
|
await store.dispatch(
|
||||||
'contacts/fetchContactableInbox',
|
'contacts/fetchContactableInbox',
|
||||||
route.params.contactId
|
route.params.contactId
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
json.payload do
|
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
|
end
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
json.payload do
|
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
|
end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user