From c0dbdc404f36904870a927bf0fd0c86cfef45a5a Mon Sep 17 00:00:00 2001 From: dodaa08 Date: Mon, 5 Jan 2026 14:34:25 +0530 Subject: [PATCH 1/3] fix: add URL detection and linking in user bio fields - Add parseUrls utility function to detect URLs in bio text - Convert detected URLs to clickable links with proper styling - Match email link styling for consistency - Support both http/https URLs and URLs without protocol --- .../views/UserInformation/UserInformation.js | 5 +- .../src/views/UserInformation/parseUrls.js | 65 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 packages/react/src/views/UserInformation/parseUrls.js diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js index de79395c5..ee623582e 100644 --- a/packages/react/src/views/UserInformation/UserInformation.js +++ b/packages/react/src/views/UserInformation/UserInformation.js @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { css } from '@emotion/react'; import { Box, @@ -18,6 +18,7 @@ import formatTimestampGetDate from '../../lib/formatTimestampGetDate'; import UserInfoField from './UserInfoField'; import getUserInformationStyles from './UserInformation.styles'; import useSetExclusiveState from '../../hooks/useSetExclusiveState'; +import { parseUrls } from './parseUrls'; const UserInformation = () => { const { variantOverrides } = useComponentOverrides('UserInformation'); @@ -176,7 +177,7 @@ const UserInformation = () => { {currentUserInfo?.bio && ( "']+)/gi; + +export const parseUrls = (text, theme, mode) => { + if (!text || typeof text !== 'string') { + return null; + } + + const parts = []; + let lastIndex = 0; + let match; + + URL_REGEX.lastIndex = 0; + + while ((match = URL_REGEX.exec(text)) !== null) { + if (match.index > lastIndex) { + parts.push(text.substring(lastIndex, match.index)); + } + + const url = match[0]; + + parts.push( + + {url} + + ); + + lastIndex = match.index + match[0].length; + } + + if (lastIndex < text.length) { + parts.push(text.substring(lastIndex)); + } + + if (parts.length === 0) { + return text; + } + + return ( + + {parts} + + ); +}; \ No newline at end of file From d14943f4e1bbae5d4dc478762849dc3607defac2 Mon Sep 17 00:00:00 2001 From: dodaa08 Date: Mon, 5 Jan 2026 15:59:39 +0530 Subject: [PATCH 2/3] fix: add React import back to UserInformation component --- packages/react/src/views/UserInformation/UserInformation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js index ee623582e..7bd699ce7 100644 --- a/packages/react/src/views/UserInformation/UserInformation.js +++ b/packages/react/src/views/UserInformation/UserInformation.js @@ -1,4 +1,4 @@ -import { useContext, useEffect, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { css } from '@emotion/react'; import { Box, From c5b6e7a132515a9ea38865363d0db793f94c0c5a Mon Sep 17 00:00:00 2001 From: dodaa08 Date: Thu, 15 Jan 2026 15:29:28 +0530 Subject: [PATCH 3/3] refactor: use @rocket.chat/message-parser instead of custom URL regex --- .../views/UserInformation/UserInformation.js | 10 ++- .../src/views/UserInformation/parseUrls.js | 65 ------------------- 2 files changed, 8 insertions(+), 67 deletions(-) delete mode 100644 packages/react/src/views/UserInformation/parseUrls.js diff --git a/packages/react/src/views/UserInformation/UserInformation.js b/packages/react/src/views/UserInformation/UserInformation.js index 7bd699ce7..a544bd334 100644 --- a/packages/react/src/views/UserInformation/UserInformation.js +++ b/packages/react/src/views/UserInformation/UserInformation.js @@ -1,5 +1,6 @@ import React, { useContext, useEffect, useState } from 'react'; import { css } from '@emotion/react'; +import { parse } from '@rocket.chat/message-parser'; import { Box, Sidebar, @@ -18,7 +19,7 @@ import formatTimestampGetDate from '../../lib/formatTimestampGetDate'; import UserInfoField from './UserInfoField'; import getUserInformationStyles from './UserInformation.styles'; import useSetExclusiveState from '../../hooks/useSetExclusiveState'; -import { parseUrls } from './parseUrls'; +import { Markdown } from '../Markdown'; const UserInformation = () => { const { variantOverrides } = useComponentOverrides('UserInformation'); @@ -177,7 +178,12 @@ const UserInformation = () => { {currentUserInfo?.bio && ( + } isAdmin={isAllowedToViewFullInfo} authenticatedUserId={authenticatedUserId} currentUserInfo={currentUserInfo} diff --git a/packages/react/src/views/UserInformation/parseUrls.js b/packages/react/src/views/UserInformation/parseUrls.js deleted file mode 100644 index f520aa47f..000000000 --- a/packages/react/src/views/UserInformation/parseUrls.js +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; -import { css } from '@emotion/react'; -import { Box } from '@embeddedchat/ui-elements'; - -const URL_REGEX = /(https?:\/\/[^\s<>"']+)/gi; - -export const parseUrls = (text, theme, mode) => { - if (!text || typeof text !== 'string') { - return null; - } - - const parts = []; - let lastIndex = 0; - let match; - - URL_REGEX.lastIndex = 0; - - while ((match = URL_REGEX.exec(text)) !== null) { - if (match.index > lastIndex) { - parts.push(text.substring(lastIndex, match.index)); - } - - const url = match[0]; - - parts.push( - - {url} - - ); - - lastIndex = match.index + match[0].length; - } - - if (lastIndex < text.length) { - parts.push(text.substring(lastIndex)); - } - - if (parts.length === 0) { - return text; - } - - return ( - - {parts} - - ); -}; \ No newline at end of file