fix: Use search API instead of filter in the filter in the endpoints (#13651)
- Replace `POST /contacts/filter` with `GET /contacts/search` for contact lookup in compose new conversation - Remove client-side input-type detection logic (`generateContactQuery`, key filtering by email/phone/name) — the search API handles matching across name, email, phone_number, and identifier server-side via a single `ILIKE` query - Filter the contacts with emails in cc and bcc fields. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
@@ -176,32 +176,14 @@ export const prepareWhatsAppMessagePayload = ({
|
||||
};
|
||||
};
|
||||
|
||||
export const generateContactQuery = ({ keys = ['email'], query }) => {
|
||||
return {
|
||||
payload: keys.map(key => {
|
||||
const filterPayload = {
|
||||
attribute_key: key,
|
||||
filter_operator: 'contains',
|
||||
values: [query],
|
||||
attribute_model: 'standard',
|
||||
};
|
||||
if (keys.findIndex(k => k === key) !== keys.length - 1) {
|
||||
filterPayload.query_operator = 'or';
|
||||
}
|
||||
return filterPayload;
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
// API Calls
|
||||
export const searchContacts = async ({ keys, query }) => {
|
||||
export const searchContacts = async query => {
|
||||
const trimmed = typeof query === 'string' ? query.trim() : '';
|
||||
if (!trimmed) return [];
|
||||
|
||||
const {
|
||||
data: { payload },
|
||||
} = await ContactAPI.filter(
|
||||
undefined,
|
||||
'name',
|
||||
generateContactQuery({ keys, query })
|
||||
);
|
||||
} = await ContactAPI.search(trimmed);
|
||||
const camelCasedPayload = camelcaseKeys(payload, { deep: true });
|
||||
// Filter contacts that have either phone_number or email
|
||||
const filteredPayload = camelCasedPayload?.filter(
|
||||
|
||||
@@ -336,70 +336,6 @@ describe('composeConversationHelper', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateContactQuery', () => {
|
||||
it('generates correct query structure for contact search', () => {
|
||||
const query = 'test@example.com';
|
||||
const expected = {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'email',
|
||||
filter_operator: 'contains',
|
||||
values: [query],
|
||||
attribute_model: 'standard',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(helpers.generateContactQuery({ keys: ['email'], query })).toEqual(
|
||||
expected
|
||||
);
|
||||
});
|
||||
|
||||
it('handles empty query', () => {
|
||||
const expected = {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'email',
|
||||
filter_operator: 'contains',
|
||||
values: [''],
|
||||
attribute_model: 'standard',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(
|
||||
helpers.generateContactQuery({ keys: ['email'], query: '' })
|
||||
).toEqual(expected);
|
||||
});
|
||||
|
||||
it('handles mutliple keys', () => {
|
||||
const expected = {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'email',
|
||||
filter_operator: 'contains',
|
||||
values: ['john'],
|
||||
attribute_model: 'standard',
|
||||
query_operator: 'or',
|
||||
},
|
||||
{
|
||||
attribute_key: 'phone_number',
|
||||
filter_operator: 'contains',
|
||||
values: ['john'],
|
||||
attribute_model: 'standard',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
expect(
|
||||
helpers.generateContactQuery({
|
||||
keys: ['email', 'phone_number'],
|
||||
query: 'john',
|
||||
})
|
||||
).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('API calls', () => {
|
||||
describe('searchContacts', () => {
|
||||
it('searches contacts and returns camelCase results', async () => {
|
||||
@@ -413,14 +349,11 @@ describe('composeConversationHelper', () => {
|
||||
},
|
||||
];
|
||||
|
||||
ContactAPI.filter.mockResolvedValue({
|
||||
ContactAPI.search.mockResolvedValue({
|
||||
data: { payload: mockPayload },
|
||||
});
|
||||
|
||||
const result = await helpers.searchContacts({
|
||||
keys: ['email'],
|
||||
query: 'john',
|
||||
});
|
||||
const result = await helpers.searchContacts('john');
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
@@ -432,16 +365,7 @@ describe('composeConversationHelper', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(ContactAPI.filter).toHaveBeenCalledWith(undefined, 'name', {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'email',
|
||||
filter_operator: 'contains',
|
||||
values: ['john'],
|
||||
attribute_model: 'standard',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(ContactAPI.search).toHaveBeenCalledWith('john');
|
||||
});
|
||||
|
||||
it('searches contacts and returns only contacts with email or phone number', async () => {
|
||||
@@ -469,14 +393,11 @@ describe('composeConversationHelper', () => {
|
||||
},
|
||||
];
|
||||
|
||||
ContactAPI.filter.mockResolvedValue({
|
||||
ContactAPI.search.mockResolvedValue({
|
||||
data: { payload: mockPayload },
|
||||
});
|
||||
|
||||
const result = await helpers.searchContacts({
|
||||
keys: ['email'],
|
||||
query: 'john',
|
||||
});
|
||||
const result = await helpers.searchContacts('john');
|
||||
|
||||
// Should only return contacts with either email or phone number
|
||||
expect(result).toEqual([
|
||||
@@ -496,20 +417,11 @@ describe('composeConversationHelper', () => {
|
||||
},
|
||||
]);
|
||||
|
||||
expect(ContactAPI.filter).toHaveBeenCalledWith(undefined, 'name', {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'email',
|
||||
filter_operator: 'contains',
|
||||
values: ['john'],
|
||||
attribute_model: 'standard',
|
||||
},
|
||||
],
|
||||
});
|
||||
expect(ContactAPI.search).toHaveBeenCalledWith('john');
|
||||
});
|
||||
|
||||
it('handles empty search results', async () => {
|
||||
ContactAPI.filter.mockResolvedValue({
|
||||
ContactAPI.search.mockResolvedValue({
|
||||
data: { payload: [] },
|
||||
});
|
||||
|
||||
@@ -536,7 +448,7 @@ describe('composeConversationHelper', () => {
|
||||
},
|
||||
];
|
||||
|
||||
ContactAPI.filter.mockResolvedValue({
|
||||
ContactAPI.search.mockResolvedValue({
|
||||
data: { payload: mockPayload },
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user