Files
chatwoot/app/javascript/shared/composables/useMessageFormatter.js
Sivin Varghese b429ce0ad5 fix: Prevent template variables from becoming links (#10725)
# Pull Request Template

## Description

**Issue**
This PR fixes template variables in messages (e.g., {{customer.name}})
that were being incorrectly converted to clickable links by the
`MessageFormatter's linkify` functionality. This caused formatting
issues and broken links.

**Solution**
Added a `linkify` parameter to `MessageFormatter` to optionally disable
link conversion

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

**Screenshots**

**Before**
<img width="1012" alt="image"
src="https://github.com/user-attachments/assets/70abb238-b4d9-439d-9e51-c7513cf482fb"
/>


**After**
<img width="1012" alt="image"
src="https://github.com/user-attachments/assets/387acb74-674e-4b26-85cc-2d7190d256b1"
/>




## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
2025-01-23 18:18:14 +05:30

85 lines
2.6 KiB
JavaScript

import MessageFormatter from '../helpers/MessageFormatter';
/**
* A composable providing utility functions for message formatting.
*
* @returns {Object} A set of functions for message formatting.
*/
export const useMessageFormatter = () => {
/**
* Formats a message based on specified conditions.
*
* @param {string} message - The message to be formatted.
* @param {boolean} isATweet - Whether the message is a tweet.
* @param {boolean} isAPrivateNote - Whether the message is a private note.
* @returns {string} - The formatted message.
*/
// TODO: ref:https://github.com/chatwoot/chatwoot/pull/10725#discussion_r1925300874
const formatMessage = (message, isATweet, isAPrivateNote, linkify) => {
const messageFormatter = new MessageFormatter(
message,
isATweet,
isAPrivateNote,
linkify
);
return messageFormatter.formattedMessage;
};
/**
* Converts a message to plain text.
*
* @param {string} message - The message to be converted.
* @param {boolean} isATweet - Whether the message is a tweet.
* @returns {string} - The plain text message.
*/
const getPlainText = (message, isATweet) => {
const messageFormatter = new MessageFormatter(message, isATweet);
return messageFormatter.plainText;
};
/**
* Truncates a description to a maximum length of 100 characters.
*
* @param {string} [description=''] - The description to be truncated.
* @returns {string} - The truncated description.
*/
const truncateMessage = (description = '') => {
if (description.length < 100) {
return description;
}
return `${description.slice(0, 97)}...`;
};
/**
* Highlights occurrences of a search term within given content.
*
* @param {string} [content=''] - The content in which to search.
* @param {string} [searchTerm=''] - The term to search for.
* @param {string} [highlightClass=''] - The CSS class to apply to the highlighted term.
* @returns {string} - The content with highlighted terms.
*/
const highlightContent = (
content = '',
searchTerm = '',
highlightClass = ''
) => {
const plainTextContent = getPlainText(content);
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#escaping
const escapedSearchTerm = searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
return plainTextContent.replace(
new RegExp(`(${escapedSearchTerm})`, 'ig'),
`<span class="${highlightClass}">$1</span>`
);
};
return {
formatMessage,
getPlainText,
truncateMessage,
highlightContent,
};
};