Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,17 @@ export const ShownWithFooter: Story = {
children: <VisualMock text={"Foo Footer"} />,
},
};

export const WithClickableLinks: Story = {
args: {
message:
"Here are some opportunities that match you:\n\n" +
"1. Junior Baker\n" +
" Employer: Sunrise Bakery\n" +
" Apply here: https://jobs.example.com/junior-baker\n\n" +
"2. Pastry Assistant\n" +
" Employer: City Cafe\n" +
" Apply here: www.citycafe.co.ke/careers/pastry-assistant",
sender: ConversationMessageSender.COMPASS,
},
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import React from "react";
import { ConversationMessageSender } from "src/chat/ChatService/ChatService.types";
import { Box, Typography, styled } from "@mui/material";
import { Box, Link, Typography, styled } from "@mui/material";

// Matches http(s) URLs and www. URLs, stopping at whitespace or common trailing punctuation.
const URL_REGEX = /((?:https?:\/\/|www\.)[^\s<]+[^\s<.,;:!?)\]}'"])/gi;

// Splits a plain-text message into text and clickable link segments, preserving the original text.
const renderTextWithLinks = (text: string): React.ReactNode => {
const parts = text.split(URL_REGEX);
return parts.map((part, index) => {
if (index % 2 === 1) {
const href = part.startsWith("www.") ? `https://${part}` : part;
return (
<Link key={index} href={href} target="_blank" rel="noopener noreferrer">
{part}
</Link>
);
}
return part;
});
};

export interface ChatBubbleProps {
message: string | React.ReactNode;
Expand Down Expand Up @@ -39,7 +58,7 @@ const ChatBubble: React.FC<ChatBubbleProps> = ({ message, sender, children }) =>
return (
<MessageBubble origin={sender} data-testid={DATA_TEST_ID.CHAT_MESSAGE_BUBBLE_CONTAINER}>
<Typography whiteSpace="pre-line" data-testid={DATA_TEST_ID.CHAT_MESSAGE_BUBBLE_MESSAGE_TEXT}>
{message}
{typeof message === "string" ? renderTextWithLinks(message) : message}
</Typography>
<Box data-testid={DATA_TEST_ID.CHAT_MESSAGE_BUBBLE_MESSAGE_FOOTER_CONTAINER}>{children}</Box>
</MessageBubble>
Expand Down
Loading