feat(frontend): add compact anonymous conversation labels
Build and publish Docker images / Build and publish images (push) Successful in 2m48s
Build and publish Docker images / Build and publish images (push) Successful in 2m48s
This commit is contained in:
@@ -69,6 +69,81 @@ export const getLastMessage = m => {
|
||||
);
|
||||
};
|
||||
|
||||
const anonymousContactNames = new Set([
|
||||
'',
|
||||
'匿名',
|
||||
'匿名客户',
|
||||
'Anonymous Visitor',
|
||||
'商务通访客',
|
||||
]);
|
||||
|
||||
const firstAttribute = (attributes, ...keys) => {
|
||||
const value = keys
|
||||
.map(key => attributes?.[key])
|
||||
.find(item => typeof item === 'string' && item.trim());
|
||||
return value?.trim() || '';
|
||||
};
|
||||
|
||||
const contactAttributes = contact => ({
|
||||
...(contact?.additional_attributes || {}),
|
||||
...(contact?.additionalAttributes || {}),
|
||||
...(contact?.custom_attributes || {}),
|
||||
...(contact?.customAttributes || {}),
|
||||
});
|
||||
|
||||
const visitorLocation = attributes => {
|
||||
const province = firstAttribute(attributes, 'visitor_province');
|
||||
const city = firstAttribute(attributes, 'visitor_city');
|
||||
if (province || city) {
|
||||
if (!city || !province || city === province || city.startsWith(province)) {
|
||||
return city || province;
|
||||
}
|
||||
return `${province}${city}`;
|
||||
}
|
||||
return firstAttribute(attributes, 'swt_ip_location');
|
||||
};
|
||||
|
||||
const shortConversationCode = conversationId => {
|
||||
const value = String(conversationId ?? '').trim();
|
||||
if (!/^[1-9]\d*$/.test(value)) {
|
||||
return '';
|
||||
}
|
||||
const numericValue = Number(value);
|
||||
return Number.isSafeInteger(numericValue)
|
||||
? numericValue.toString(36).toUpperCase()
|
||||
: '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a stable, compact session code only to generated anonymous names.
|
||||
* The stored contact name remains unchanged.
|
||||
*/
|
||||
export const getConversationContactDisplayName = (contact, conversationId) => {
|
||||
const name = String(contact?.name || '').trim();
|
||||
const attributes = contactAttributes(contact);
|
||||
const source = firstAttribute(attributes, 'visitor_name_source');
|
||||
const isGeneratedName =
|
||||
anonymousContactNames.has(name) ||
|
||||
source === 'ip_geolocation' ||
|
||||
source === 'anonymous_fallback';
|
||||
|
||||
if (!isGeneratedName) {
|
||||
return name;
|
||||
}
|
||||
|
||||
const code = shortConversationCode(conversationId);
|
||||
if (!code) {
|
||||
return name || '匿名';
|
||||
}
|
||||
|
||||
const location =
|
||||
visitorLocation(attributes) ||
|
||||
(source === 'ip_geolocation' && name.endsWith('客户')
|
||||
? name.slice(0, -2)
|
||||
: '');
|
||||
return location ? `${location}·${code}` : `匿名${code}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Filters messages that have been read by the agent.
|
||||
* @param {Array} messages - The array of messages to filter.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {
|
||||
filterDuplicateSourceMessages,
|
||||
getConversationContactDisplayName,
|
||||
getLastMessage,
|
||||
getReadMessages,
|
||||
getUnreadMessages,
|
||||
@@ -37,6 +38,36 @@ describe('conversationHelper', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getConversationContactDisplayName', () => {
|
||||
it('formats a geolocated anonymous visitor with a base36 session code', () => {
|
||||
expect(
|
||||
getConversationContactDisplayName(
|
||||
{
|
||||
name: '河北邯郸客户',
|
||||
additional_attributes: {
|
||||
visitor_name_source: 'ip_geolocation',
|
||||
visitor_province: '河北',
|
||||
visitor_city: '邯郸',
|
||||
},
|
||||
},
|
||||
1296
|
||||
)
|
||||
).toBe('河北邯郸·100');
|
||||
});
|
||||
|
||||
it('uses the anonymous label when location is unavailable', () => {
|
||||
expect(
|
||||
getConversationContactDisplayName({ name: '商务通访客' }, 36)
|
||||
).toBe('匿名10');
|
||||
});
|
||||
|
||||
it('keeps a real contact name unchanged', () => {
|
||||
expect(getConversationContactDisplayName({ name: '张三' }, 1296)).toBe(
|
||||
'张三'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#readMessages', () => {
|
||||
it('should return read messages if conversation is passed', () => {
|
||||
expect(
|
||||
|
||||
Reference in New Issue
Block a user