fix: Properly decode HTML entities in chat messages
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
Some checks failed
Dev Deployment (Zero Downtime) / deploy-dev (push) Has been cancelled
- Fix ' not being decoded to apostrophe - Decode HTML entities when loading messages from localStorage - Improve server-side HTML entity decoding to handle all variations - Replace hardcoded ' in static text with regular apostrophes - Add support for more HTML entity variations (rsquo, lsquo, etc.)
This commit is contained in:
@@ -51,6 +51,14 @@ export default function ChatWidget() {
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
// Helper function to decode HTML entities
|
||||
const decodeHtmlEntities = (text: string): string => {
|
||||
if (!text || typeof text !== 'string') return text;
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.innerHTML = text;
|
||||
return textarea.value;
|
||||
};
|
||||
|
||||
// Load messages from localStorage
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -61,6 +69,7 @@ export default function ChatWidget() {
|
||||
setMessages(
|
||||
parsed.map((m: Message) => ({
|
||||
...m,
|
||||
text: decodeHtmlEntities(m.text), // Decode HTML entities when loading
|
||||
timestamp: new Date(m.timestamp),
|
||||
})),
|
||||
);
|
||||
@@ -72,7 +81,7 @@ export default function ChatWidget() {
|
||||
setMessages([
|
||||
{
|
||||
id: "welcome",
|
||||
text: "Hi! I'm Dennis's AI assistant. Ask me anything about his skills, projects, or experience! 🚀",
|
||||
text: "Hi! I'm Dennis's AI assistant. Ask me anything about his skills, projects, or experience! 🚀",
|
||||
sender: "bot",
|
||||
timestamp: new Date(),
|
||||
},
|
||||
@@ -128,12 +137,8 @@ export default function ChatWidget() {
|
||||
// Decode HTML entities in the reply
|
||||
let replyText = data.reply || "Sorry, I couldn't process that. Please try again.";
|
||||
|
||||
// Decode HTML entities client-side as well (double safety)
|
||||
if (typeof window !== 'undefined') {
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.innerHTML = replyText;
|
||||
replyText = textarea.value;
|
||||
}
|
||||
// Decode HTML entities client-side (double safety)
|
||||
replyText = decodeHtmlEntities(replyText);
|
||||
|
||||
const botMessage: Message = {
|
||||
id: (Date.now() + 1).toString(),
|
||||
@@ -237,7 +242,7 @@ export default function ChatWidget() {
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-bold text-sm">
|
||||
Dennis's AI Assistant
|
||||
Dennis{'\''}s AI Assistant
|
||||
</h3>
|
||||
<p className="text-xs text-white/80">Always online</p>
|
||||
</div>
|
||||
@@ -370,7 +375,7 @@ export default function ChatWidget() {
|
||||
{/* Quick Actions */}
|
||||
<div className="flex gap-2 mt-2 overflow-x-auto pb-1 scrollbar-hide">
|
||||
{[
|
||||
"What are Dennis's skills?",
|
||||
"What are Dennis's skills?",
|
||||
"Tell me about his projects",
|
||||
"How can I contact him?",
|
||||
].map((suggestion, index) => (
|
||||
|
||||
@@ -21,7 +21,7 @@ export function decodeHtmlEntitiesServer(text: string): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
// Map of common HTML entities
|
||||
// Map of common HTML entities (including all variations of apostrophe)
|
||||
const entityMap: Record<string, string> = {
|
||||
''': "'",
|
||||
'"': '"',
|
||||
@@ -33,9 +33,26 @@ export function decodeHtmlEntitiesServer(text: string): string {
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '=',
|
||||
'’': "'",
|
||||
'‘': "'",
|
||||
'”': '"',
|
||||
'“': '"',
|
||||
};
|
||||
|
||||
return text.replace(/&[#\w]+;/g, (entity) => {
|
||||
return entityMap[entity] || entity;
|
||||
// First replace known entities
|
||||
let decoded = text;
|
||||
for (const [entity, replacement] of Object.entries(entityMap)) {
|
||||
decoded = decoded.replace(new RegExp(entity, 'gi'), replacement);
|
||||
}
|
||||
|
||||
// Then handle numeric entities (' ' etc.)
|
||||
decoded = decoded.replace(/&#(\d+);/g, (match, num) => {
|
||||
return String.fromCharCode(parseInt(num, 10));
|
||||
});
|
||||
|
||||
decoded = decoded.replace(/&#x([0-9a-f]+);/gi, (match, hex) => {
|
||||
return String.fromCharCode(parseInt(hex, 16));
|
||||
});
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user