From b9d2722e41067f218fd3adf26a2dd46d412e11a5 Mon Sep 17 00:00:00 2001
From: Devansh
Date: Mon, 16 Sep 2024 18:04:11 +0530
Subject: [PATCH 01/76] Fix: emoji parsing issue in file description
---
.../react/src/views/AttachmentPreview/AttachmentPreview.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
index 236c3ec1ba..209c9e33e8 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js
@@ -6,6 +6,7 @@ import CheckPreviewType from './CheckPreviewType';
import RCContext from '../../context/RCInstance';
import { useMessageStore } from '../../store';
import getAttachmentPreviewStyles from './AttachmentPreview.styles';
+import { parseEmoji } from '../../lib/emoji';
const AttachmentPreview = () => {
const { RCInstance, ECOptions } = useContext(RCContext);
@@ -25,7 +26,7 @@ const AttachmentPreview = () => {
};
const handleFileDescription = (e) => {
- setFileDescription(e.target.value);
+ setFileDescription(parseEmoji(e.target.value));
};
const submit = async () => {
From 5cdba75ff9fb58f967e896a38f0c843142d10b45 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 18 Sep 2024 22:28:39 +0530
Subject: [PATCH 02/76] fix
---
packages/react/src/views/ChatHeader/ChatHeader.js | 7 ++++++-
.../src/views/ReportMessage/MessageReportWindow.js | 10 +++++++---
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index d9b6b8461b..0e46b9ccdd 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -93,8 +93,13 @@ const ChatHeader = ({
const headerTitle = useMessageStore((state) => state.headerTitle);
const filtered = useMessageStore((state) => state.filtered);
const setFilter = useMessageStore((state) => state.setFilter);
- const threadTitle = useMessageStore((state) => state.threadMainMessage?.msg);
+
const isThreadOpen = useMessageStore((state) => state.isThreadOpen);
+ const threadMainMessage = useMessageStore((state) => state.threadMainMessage);
+ const threadTitle =
+ threadMainMessage?.msg ||
+ (threadMainMessage?.file ? threadMainMessage.file.name : '');
+
const closeThread = useMessageStore((state) => state.closeThread);
const setShowMembers = useMemberStore((state) => state.setShowMembers);
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 96bf234353..0f5e9644e9 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -7,9 +7,13 @@ import styles from './ReportMessage.styles';
const MessageReportWindow = ({ messageId }) => {
const [reportDescription, setDescription] = useState('');
- const messages = useMessageStore((state) => state.messages);
- const messageText = messages.filter((message) => message._id === messageId)[0]
- ?.msg;
+ const messages = useMessageStore((state) => state.messages) || [];
+ const threadMessages = useMessageStore((state) => state.threadMessages) || [];
+ const allMessages = [...messages, ...threadMessages];
+ const messageText = allMessages.filter(
+ (message) => message._id === messageId
+ )[0]?.msg;
+ console.log('messagetext', messageText);
return (
Date: Sat, 21 Sep 2024 22:19:48 +0530
Subject: [PATCH 03/76] Starred Model fix
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index a49f547e18..81a277084e 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -26,9 +26,11 @@ export const MessageAggregator = ({
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
+ const threadMessages=useMessageStore((state)=>state.threadMessages)|| [];
+ const allMessages=[...messages,...threadMessages];
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
- searchFiltered || messages,
+ searchFiltered || allMessages,
shouldRender
);
From 5c78a16e76ce40f76b9f68da06375e04d267997b Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Thu, 26 Sep 2024 00:50:59 +0530
Subject: [PATCH 04/76] removed console.log
---
packages/react/src/views/ReportMessage/MessageReportWindow.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 0f5e9644e9..74bc1fb814 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -13,7 +13,6 @@ const MessageReportWindow = ({ messageId }) => {
const messageText = allMessages.filter(
(message) => message._id === messageId
)[0]?.msg;
- console.log('messagetext', messageText);
return (
Date: Fri, 27 Sep 2024 21:53:31 +0530
Subject: [PATCH 05/76] prettier
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 81a277084e..9b9c573066 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -26,8 +26,8 @@ export const MessageAggregator = ({
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
- const threadMessages=useMessageStore((state)=>state.threadMessages)|| [];
- const allMessages=[...messages,...threadMessages];
+ const threadMessages = useMessageStore((state) => state.threadMessages) || [];
+ const allMessages = [...messages, ...threadMessages];
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
searchFiltered || allMessages,
From 13d807e7f781e298c3839179f3e16ec55c9747e4 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sat, 5 Oct 2024 18:25:48 +0530
Subject: [PATCH 06/76] Combine build steps for react, ui-elements, and
layout_editor packages (#637)
* Combine build steps for react, ui-elements, and layout_editor packages
* Small change in build-lint
---
.github/workflows/build-and-lint.yml | 2 +-
.github/workflows/deploy.yml | 15 +++------------
2 files changed, 4 insertions(+), 13 deletions(-)
diff --git a/.github/workflows/build-and-lint.yml b/.github/workflows/build-and-lint.yml
index d92c4001a5..375ec8c3af 100644
--- a/.github/workflows/build-and-lint.yml
+++ b/.github/workflows/build-and-lint.yml
@@ -34,7 +34,7 @@ jobs:
${{ runner.os }}-yarn-
- name: Install dependencies
- run: yarn
+ run: yarn install
- name: Format check
run: yarn format:check
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 3099455b0c..b3b61cc78c 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -30,19 +30,10 @@ jobs:
node-version: "16.19.0"
- name: Install Dependencies
- run: yarn
-
- - name: Build Storybook
- run: yarn build:storybook
- working-directory: packages/react
-
- - name: Build UI-Elements
- run: yarn build:storybook
- working-directory: packages/ui-elements
+ run: yarn install
- - name: Build Layout Editor
- run: npm run build
- working-directory: packages/layout_editor
+ - name: Build packages
+ run: yarn build && yarn build:storybook
- name: Setup Node.js for Docs
uses: actions/setup-node@v4
From 3657c15f23917c11d4508694e9e7433fca06a136 Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sat, 5 Oct 2024 18:28:18 +0530
Subject: [PATCH 07/76] Changed workflow name
---
.github/workflows/deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index b3b61cc78c..4055f20ca6 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -1,4 +1,4 @@
-name: Build and Publish Storybook to GitHub Pages
+name: Build and Publish
on:
push:
From ebca321b2fa034376c8100cf381637fa88df8538 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sun, 6 Oct 2024 12:32:46 +0530
Subject: [PATCH 08/76] Added Feature to deploy previews of pull requests
(#638)
* Added Feature to deploy previews of pull requests
* Removed environment variables from build-lint workflow
* Modified the changes mentioned in the code-review
---
.github/workflows/build-pr.yml | 65 +++++++++++++++++++++++++++
.github/workflows/deploy-pr.yml | 36 +++++++++++++++
.github/workflows/pr-cleanup.yml | 34 ++++++++++++++
packages/docs/docusaurus.config.js | 2 +-
packages/layout_editor/vite.config.ts | 2 +-
5 files changed, 137 insertions(+), 2 deletions(-)
create mode 100644 .github/workflows/build-pr.yml
create mode 100644 .github/workflows/deploy-pr.yml
create mode 100644 .github/workflows/pr-cleanup.yml
diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
new file mode 100644
index 0000000000..66c97af32c
--- /dev/null
+++ b/.github/workflows/build-pr.yml
@@ -0,0 +1,65 @@
+name: Build PR-Preview
+
+on:
+ pull_request_review:
+ types: submitted
+
+concurrency:
+ group: ${{github.workflow}}-${{github.ref}}
+ cancel-in-progress: true
+
+env:
+ LAYOUT_EDITOR_BASE_URL: "/EmbeddedChat/pulls/pr-${{github.event.pull_request.number}}/layout_editor"
+ DOCS_BASE_URL: "/EmbeddedChat/pulls/pr-${{github.event.pull_request.number}}/docs"
+ STORYBOOK_RC_HOST: "https://demo.qa.rocket.chat"
+
+jobs:
+ build:
+ if: github.event.review.state == 'approved' && (github.event.review.author_association == 'COLLABORATOR' || github.event.review.author_association == 'OWNER')
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "16.19.0"
+
+ - name: Install Dependencies
+ run: yarn install
+
+ - name: Build packages
+ run: yarn build && yarn build:storybook
+
+ - name: Setup Node.js for Docs
+ uses: actions/setup-node@v4
+ with:
+ node-version: "18.x"
+
+ - name: "Install dependencies for docs"
+ run: yarn install
+ working-directory: packages/docs/
+
+ - name: Build Docs
+ run: yarn build
+ working-directory: packages/docs/
+
+ - name: Prepare Build Folder
+ run: |
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/ui-elements
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/layout_editor
+ mkdir -p build/pulls/pr-${{github.event.pull_request.number}}/docs
+
+ mv -v packages/react/storybook-static/* build/pulls/pr-${{github.event.pull_request.number}}/
+ mv -v packages/ui-elements/storybook-static/* build/pulls/pr-${{github.event.pull_request.number}}/ui-elements/
+ mv -v packages/layout_editor/dist/* build/pulls/pr-${{github.event.pull_request.number}}/layout_editor/
+ mv -v packages/docs/build/* build/pulls/pr-${{github.event.pull_request.number}}/docs/
+
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@v4
+ with:
+ name: github-pages
+ path: build/
diff --git a/.github/workflows/deploy-pr.yml b/.github/workflows/deploy-pr.yml
new file mode 100644
index 0000000000..4f687507d3
--- /dev/null
+++ b/.github/workflows/deploy-pr.yml
@@ -0,0 +1,36 @@
+name: Deploy PR-Preview
+
+on:
+ workflow_run:
+ workflows: ["Build PR-Preview"]
+ types:
+ - completed
+
+permissions:
+ contents: write
+ pages: write
+
+jobs:
+ deploy:
+ if: github.event.workflow_run.conclusion == 'success'
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: github-pages
+ path: build/
+ github-token: ${{github.token}}
+ repository: ${{github.repository}}
+ run-id: ${{github.event.workflow_run.id}}
+
+ - name: Deploy to GitHub Pages
+ uses: crazy-max/ghaction-github-pages@v2
+ with:
+ target_branch: gh-deploy
+ build_dir: build/
+ commit_message: "Deploy to Github Pages"
+ jekyll: false
+ keep_history: true
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/pr-cleanup.yml b/.github/workflows/pr-cleanup.yml
new file mode 100644
index 0000000000..c5b878373c
--- /dev/null
+++ b/.github/workflows/pr-cleanup.yml
@@ -0,0 +1,34 @@
+name: Pull Request Cleanup
+on:
+ pull_request_target:
+ types: [closed]
+
+jobs:
+ cleanup:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+ with:
+ ref: gh-deploy
+
+ - name: Check if Deployment Exists
+ id: check_deployment
+ run: |
+ if [ -d "pulls/pr-${{ github.event.pull_request.number }}" ]; then
+ echo "deployment_exists=true" >> $GITHUB_ENV
+ else
+ echo "deployment_exists=false" >> $GITHUB_ENV
+ fi
+
+ - name: Remove Deployment
+ if: env.deployment_exists == 'true'
+ run: |
+ git config --global user.email "github-actions[bot]@users.noreply.github.com"
+ git config --global user.name "github-actions[bot]"
+ git fetch origin gh-deploy
+ git checkout gh-deploy
+ git rm -r pulls/pr-${{github.event.pull_request.number}}
+ git commit -m "Remove deployment for PR #${{github.event.pull_request.number}}"
+ git push origin gh-deploy
diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js
index f9073bfa8e..1201dae919 100644
--- a/packages/docs/docusaurus.config.js
+++ b/packages/docs/docusaurus.config.js
@@ -17,7 +17,7 @@ const config = {
url: "https://rocketchat.github.io/",
// Set the // pathname under which your site is served
// For GitHub pages deployment, it is often '//'
- baseUrl: "/EmbeddedChat/docs/",
+ baseUrl: process.env.DOCS_BASE_URL || "/EmbeddedChat/docs/",
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
diff --git a/packages/layout_editor/vite.config.ts b/packages/layout_editor/vite.config.ts
index 2b9daff2d3..b6ab8acd24 100644
--- a/packages/layout_editor/vite.config.ts
+++ b/packages/layout_editor/vite.config.ts
@@ -11,5 +11,5 @@ export default defineConfig({
},
}),
],
- base: "/EmbeddedChat/layout_editor"
+ base: process.env.LAYOUT_EDITOR_BASE_URL || '/EmbeddedChat/layout_editor',
});
From 9187d953545ad04199682a44080a9d9b205470da Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sun, 6 Oct 2024 12:54:20 +0530
Subject: [PATCH 09/76] added pr test info in pr template
---
.github/pull_request_template.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 337559b404..8a4d4f38d1 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -9,3 +9,9 @@
Fixes # (issue)
## Video/Screenshots
+
+## PR Test Details
+
+**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval.
+
+
From d21255c9e1d88e0ddae73c052396cfbda7b306bf Mon Sep 17 00:00:00 2001
From: Rahul Singh Thakur <65606499+Barrylimarti@users.noreply.github.com>
Date: Sat, 2 Nov 2024 21:44:15 +0530
Subject: [PATCH 10/76] [fix] Re-rendering fixed while opening pinned and
starred messages. (#644)
* added memoization to stop rerenders
* added memoization for allmessage and shouldrender
* fixed linting errors and imports
---
packages/react/src/hooks/useSetMessageList.js | 14 ++++++--------
.../views/MessageAggregators/StarredMessages.js | 13 ++++++++-----
.../MessageAggregators/common/MessageAggregator.js | 7 +++++--
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/packages/react/src/hooks/useSetMessageList.js b/packages/react/src/hooks/useSetMessageList.js
index a2b3917d59..69b4bef7cf 100644
--- a/packages/react/src/hooks/useSetMessageList.js
+++ b/packages/react/src/hooks/useSetMessageList.js
@@ -1,16 +1,14 @@
-import { useState, useEffect } from 'react';
+import { useState, useEffect, useMemo } from 'react';
export const useSetMessageList = (messages, shouldRender) => {
const [loading, setLoading] = useState(true);
- const [messageList, setMessageList] = useState([]);
- useEffect(() => {
- setLoading(true);
- const filteredMessages = messages.filter((message) =>
- shouldRender(message)
- );
+ const messageList = useMemo(
+ () => messages.filter(shouldRender),
+ [messages, shouldRender]
+ );
- setMessageList(filteredMessages);
+ useEffect(() => {
setLoading(false);
}, [messages, shouldRender]);
diff --git a/packages/react/src/views/MessageAggregators/StarredMessages.js b/packages/react/src/views/MessageAggregators/StarredMessages.js
index 9a79fa0ebe..b7d77b864e 100644
--- a/packages/react/src/views/MessageAggregators/StarredMessages.js
+++ b/packages/react/src/views/MessageAggregators/StarredMessages.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useCallback } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import { useUserStore } from '../../store';
import { MessageAggregator } from './common/MessageAggregator';
@@ -7,15 +7,18 @@ const StarredMessages = () => {
const authenticatedUserId = useUserStore((state) => state.userId);
const { variantOverrides } = useComponentOverrides('StarredMessages');
const viewType = variantOverrides.viewType || 'Sidebar';
+ const shouldRender = useCallback(
+ (msg) =>
+ msg.starred &&
+ msg.starred.some((star) => star._id === authenticatedUserId),
+ [authenticatedUserId]
+ );
return (
- msg.starred &&
- msg.starred.some((star) => star._id === authenticatedUserId)
- }
+ shouldRender={shouldRender}
viewType={viewType}
/>
);
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 9b9c573066..079582e86a 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useMemo } from 'react';
import { isSameDay, format } from 'date-fns';
import { Box, Sidebar, Popup, useTheme } from '@embeddedchat/ui-elements';
import { MessageDivider } from '../../Message/MessageDivider';
@@ -27,7 +27,10 @@ export const MessageAggregator = ({
const setExclusiveState = useSetExclusiveState();
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
- const allMessages = [...messages, ...threadMessages];
+ const allMessages = useMemo(
+ () => [...messages, ...threadMessages],
+ [messages, threadMessages]
+ );
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
searchFiltered || allMessages,
From faf9fb76b35bc19bf1f75e56b28b7b24a8a7d30a Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sat, 2 Nov 2024 21:49:44 +0530
Subject: [PATCH 11/76] fixed markdown rendering in report message (#611)
* fix
* formatting fix
* fix
* Fiexed lint issues
---
.../react/src/views/ReportMessage/MessageReportWindow.js | 8 --------
1 file changed, 8 deletions(-)
diff --git a/packages/react/src/views/ReportMessage/MessageReportWindow.js b/packages/react/src/views/ReportMessage/MessageReportWindow.js
index 74bc1fb814..33957e72ea 100644
--- a/packages/react/src/views/ReportMessage/MessageReportWindow.js
+++ b/packages/react/src/views/ReportMessage/MessageReportWindow.js
@@ -2,17 +2,10 @@ import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Box, Input } from '@embeddedchat/ui-elements';
import ReportWindowButtons from './ReportWindowButtons';
-import { useMessageStore } from '../../store';
import styles from './ReportMessage.styles';
const MessageReportWindow = ({ messageId }) => {
const [reportDescription, setDescription] = useState('');
- const messages = useMessageStore((state) => state.messages) || [];
- const threadMessages = useMessageStore((state) => state.threadMessages) || [];
- const allMessages = [...messages, ...threadMessages];
- const messageText = allMessages.filter(
- (message) => message._id === messageId
- )[0]?.msg;
return (
{
reportDescription={reportDescription}
messageId={messageId}
>
- {JSON.stringify(messageText)}
Date: Mon, 4 Nov 2024 22:20:27 +0530
Subject: [PATCH 12/76] added instruction to replace pr num
---
.github/pull_request_template.md | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 8a4d4f38d1..ccf362d516 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -12,6 +12,4 @@ Fixes # (issue)
## PR Test Details
-**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval.
-
-
+**Note**: The PR will be ready for live testing at https://rocketchat.github.io/EmbeddedChat/pulls/pr- after approval. Contributors are requested to replace `` with the actual PR number.
From 36534fc3fd7e5f7824a1c316878a3c7e54828eed Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:36:32 +0530
Subject: [PATCH 13/76] Prevent Quote Message Overflow (#659)
* prevent quote message overflow
* Removed sidebar open checking and added styling to Quote Message Box
---
packages/react/src/views/ChatInput/ChatInput.js | 6 +++++-
.../react/src/views/QuoteMessage/QuoteMessage.styles.js | 6 ++++++
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 99c1c8b4f7..ba9f569b2f 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -423,7 +423,11 @@ const ChatInput = ({ scrollToBottom }) => {
return (
-
+
{(quoteMessage.msg || quoteMessage.attachments) && (
)}
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
index 5ffe32dd2e..1b6619ea95 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.styles.js
@@ -12,6 +12,8 @@ const getQuoteMessageStyles = (theme) => {
z-index: 1200;
border: 1px solid ${theme.colors.border};
border-radius: ${theme.radius};
+ max-width: 100%;
+ box-sizing: border-box;
`,
avatarContainer: css`
@@ -22,6 +24,10 @@ const getQuoteMessageStyles = (theme) => {
message: css`
padding: 0.25rem;
+ overflow-wrap: break-word;
+ word-break: break-word;
+ white-space: normal;
+ width: 100%;
`,
actionBtn: css`
From e898504343afd7c87dd60afcdb9aaffc033a53ac Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 10 Nov 2024 15:39:38 +0530
Subject: [PATCH 14/76] Trim Whitespaces in Username/Email Fields in
EmbeddedChat Login Form (#657)
* trim whitespaces in username/email fields to prevent login issues
* Remove extra .trim()
---
packages/api/src/EmbeddedChatApi.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 574370a5b1..021a82c4db 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -121,12 +121,12 @@ export default class EmbeddedChatApi {
let credentials;
if (!code) {
credentials = credentials = {
- user: userOrEmail,
+ user: userOrEmail.trim(),
password,
};
} else {
credentials = {
- user: userOrEmail,
+ user: userOrEmail.trim(),
password,
code,
};
From afa6b81bafb150fa960a561b9a28fdb819aa8019 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 10 Nov 2024 21:30:55 +0530
Subject: [PATCH 15/76] Fix: Display emoji in visual format and enable send
icon on emoji selection (#663)
* Fix: Display emoji in visual format and enable send icon on emoji selection
* Revised code
---
packages/react/src/views/ChatInput/ChatInput.js | 15 +++++++++------
.../views/ChatInput/ChatInputFormattingToolbar.js | 7 ++++++-
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index ba9f569b2f..eae9573aed 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -25,7 +25,6 @@ import useAttachmentWindowStore from '../../store/attachmentwindow';
import MembersList from '../Mentions/MembersList';
import { TypingUsers } from '../TypingUsers';
import createPendingMessage from '../../lib/createPendingMessage';
-import { parseEmoji } from '../../lib/emoji';
import { CommandsList } from '../CommandList';
import useSettingsStore from '../../store/settingsStore';
import ChannelState from '../ChannelState/ChannelState';
@@ -34,6 +33,7 @@ import { getChatInputStyles } from './ChatInput.styles';
import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
+import { parseEmoji } from '../../lib/emoji';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -362,14 +362,16 @@ const ChatInput = ({ scrollToBottom }) => {
setData(event.target.files[0]);
};
- const onTextChange = (e) => {
+ const onTextChange = (e, val) => {
sendTypingStart();
- const message = e.target.value;
+ const message = val || e.target.value;
messageRef.current.value = parseEmoji(message);
setDisableButton(!messageRef.current.value.length);
- handleNewLine(e, false);
- searchMentionUser(message);
- showCommands(e);
+ if (e !== null) {
+ handleNewLine(e, false);
+ searchMentionUser(message);
+ showCommands(e);
+ }
};
const handleFocus = () => {
@@ -532,6 +534,7 @@ const ChatInput = ({ scrollToBottom }) => {
)}
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 634b2255af..fd96f50363 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -19,6 +19,7 @@ import formatSelection from '../../lib/formatSelection';
const ChatInputFormattingToolbar = ({
messageRef,
inputRef,
+ triggerButton,
optionConfig = {
surfaceItems: ['emoji', 'formatter', 'audio', 'video', 'file'],
formatters: ['bold', 'italic', 'strike', 'code', 'multiline'],
@@ -46,7 +47,11 @@ const ChatInputFormattingToolbar = ({
const handleEmojiClick = (emojiEvent) => {
const [emoji] = emojiEvent.names;
- messageRef.current.value += ` :${emoji.replace(/[\s-]+/g, '_')}: `;
+ const message = `${messageRef.current.value} :${emoji.replace(
+ /[\s-]+/g,
+ '_'
+ )}: `;
+ triggerButton?.(null, message);
};
const chatToolMap = {
From 75f7760cd0671714250e2002dd5367df60e1f75a Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Mon, 11 Nov 2024 21:11:39 +0530
Subject: [PATCH 16/76] Fix logout issue (#666)
* set messages and avatar url to null on logout
* Fixed linting issues
* Remove unnecessary import
---
packages/react/src/views/ChatHeader/ChatHeader.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 0e46b9ccdd..7c43056a65 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -88,8 +88,9 @@ const ChatHeader = ({
const dispatchToastMessage = useToastBarDispatch();
const getMessagesAndRoles = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
-
+ const setMessages = useMessageStore((state) => state.setMessages);
const avatarUrl = useUserStore((state) => state.avatarUrl);
+ const setUserAvatarUrl = useUserStore((state) => state.setUserAvatarUrl);
const headerTitle = useMessageStore((state) => state.headerTitle);
const filtered = useMessageStore((state) => state.filtered);
const setFilter = useMessageStore((state) => state.setFilter);
@@ -128,6 +129,9 @@ const ChatHeader = ({
const handleLogout = useCallback(async () => {
try {
await RCInstance.logout();
+ setMessages([]);
+ setUserAvatarUrl(null);
+ useMessageStore.setState({ isMessageLoaded: false });
} catch (e) {
console.error(e);
} finally {
From 8ba15a5f8cc32a6c5887df8aa08374ba4599c0ba Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Fri, 29 Nov 2024 01:00:17 +0530
Subject: [PATCH 17/76] Fix: Prevent repeated API calls in searchMessages after
typing stops (#655)
* Fix: Prevent repeated API calls in searchMessages after typing stops
* Implement Rate Limiter
* Revised debounce
---
.../views/MessageAggregators/SearchMessages.js | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/SearchMessages.js b/packages/react/src/views/MessageAggregators/SearchMessages.js
index e627921c80..b4248461c6 100644
--- a/packages/react/src/views/MessageAggregators/SearchMessages.js
+++ b/packages/react/src/views/MessageAggregators/SearchMessages.js
@@ -1,4 +1,4 @@
-import React, { useState, useContext, useEffect } from 'react';
+import React, { useState, useContext, useEffect, useCallback } from 'react';
import debounce from 'lodash/debounce';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
@@ -15,14 +15,17 @@ const SearchMessages = () => {
setText(e.target.value);
};
- const searchMessages = async () => {
+ const searchMessages = useCallback(async () => {
const { messages } = await RCInstance.getSearchMessages(text);
setMessageList(messages);
- };
+ }, [text, RCInstance]);
- const debouncedSearch = debounce(async () => {
- await searchMessages();
- }, 500);
+ const debouncedSearch = useCallback(
+ debounce(async () => {
+ await searchMessages();
+ }, 500),
+ [searchMessages]
+ );
useEffect(() => {
if (!text.trim()) {
From 38f52a1119e4b2a0b12f60dd59f724b891d0697a Mon Sep 17 00:00:00 2001
From: Zishan Ahmad
Date: Sun, 15 Dec 2024 15:28:28 +0530
Subject: [PATCH 18/76] Fix code scanning alert no. 13: Incomplete string
escaping or encoding (#684)
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
---
packages/ui-elements/tools/icons-generator.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 7dc17fc93b..538d42f406 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -64,7 +64,7 @@ const camelCase = (name) =>
const codeModifier = (code) => {
let newCode = code.replace(/class=/g, 'className=');
const openingTag = newCode.match(//g)[0];
- const newOpeningTag = openingTag.replace('>', ' {...props}>');
+ const newOpeningTag = openingTag.replace(/>/g, ' {...props}>');
newCode = newCode.replace(openingTag, newOpeningTag);
return newCode;
};
From 8284ffa38dca7cfe00430cc89b25f30bd7e7eece Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:31:51 +0530
Subject: [PATCH 19/76] Fix: Restrict Pin Icon Visibility Based on User
Permissions (#674)
* Fix:Fix: Restrict pin icon visibility based on user permissions
* Restrict pin icon visibility
---
packages/react/src/hooks/useRCAuth.js | 5 +++++
packages/react/src/store/userStore.js | 5 ++++-
packages/react/src/views/Message/Message.js | 7 +++++++
packages/react/src/views/Message/MessageToolbox.js | 5 ++++-
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 83b013353b..6a997cb569 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -20,11 +20,15 @@ export const useRCAuth = () => {
);
const setPassword = useUserStore((state) => state.setPassword);
const setEmailorUser = useUserStore((state) => state.setEmailorUser);
+ const setUserPinPermissions = useUserStore(
+ (state) => state.setUserPinPermissions
+ );
const dispatchToastMessage = useToastBarDispatch();
const handleLogin = async (userOrEmail, password, code) => {
try {
const res = await RCInstance.login(userOrEmail, password, code);
+ const permissions = await RCInstance.permissionInfo();
if (res.error === 'Unauthorized' || res.error === 403) {
dispatchToastMessage({
type: 'error',
@@ -56,6 +60,7 @@ export const useRCAuth = () => {
setIsTotpModalOpen(false);
setEmailorUser(null);
setPassword(null);
+ setUserPinPermissions(permissions.update[150]);
dispatchToastMessage({
type: 'success',
message: 'Successfully logged in',
diff --git a/packages/react/src/store/userStore.js b/packages/react/src/store/userStore.js
index c4128cf468..d3c3aa24c3 100644
--- a/packages/react/src/store/userStore.js
+++ b/packages/react/src/store/userStore.js
@@ -27,8 +27,11 @@ const useUserStore = create((set) => ({
setPassword: (password) => set(() => ({ password })),
emailoruser: null,
setEmailorUser: (emailoruser) => set(() => ({ emailoruser })),
- roles: {},
+ roles: [],
setRoles: (roles) => set((state) => ({ ...state, roles })),
+ userPinPermissions: {},
+ setUserPinPermissions: (userPinPermissions) =>
+ set((state) => ({ ...state, userPinPermissions })),
showCurrentUserInfo: false,
setShowCurrentUserInfo: (showCurrentUserInfo) =>
set(() => ({ showCurrentUserInfo })),
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 8ce3d8bf5c..64d2050f09 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -51,6 +51,10 @@ const Message = ({
const authenticatedUserId = useUserStore((state) => state.userId);
const authenticatedUserUsername = useUserStore((state) => state.username);
+ const userRoles = useUserStore((state) => state.roles);
+ const pinPermissions = useUserStore(
+ (state) => state.userPinPermissions.roles
+ );
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
@@ -67,6 +71,7 @@ const Message = ({
const theme = useTheme();
const styles = getMessageStyles(theme);
const bubbleStyles = useBubbleStyles(isMe);
+ const pinRoles = new Set(pinPermissions);
const variantStyles =
!isInSidebar && variantOverrides === 'bubble' ? bubbleStyles : {};
@@ -200,6 +205,8 @@ const Message = ({
message={message}
isEditing={editMessage._id === message._id}
authenticatedUserId={authenticatedUserId}
+ userRoles={userRoles}
+ pinRoles={pinRoles}
handleOpenThread={handleOpenThread}
handleDeleteMessage={handleDeleteMessage}
handleStarMessage={handleStarMessage}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 248dd35586..55af7f64d5 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -21,6 +21,8 @@ export const MessageToolbox = ({
style = {},
isThreadMessage = false,
authenticatedUserId,
+ userRoles,
+ pinRoles,
handleOpenThread,
handleEmojiClick,
handlePinMessage,
@@ -67,6 +69,7 @@ export const MessageToolbox = ({
setShowDeleteModal(false);
};
+ const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
const options = useMemo(
() => ({
reply: {
@@ -110,7 +113,7 @@ export const MessageToolbox = ({
id: 'pin',
onClick: () => handlePinMessage(message),
iconName: message.pinned ? 'pin-filled' : 'pin',
- visible: !isThreadMessage,
+ visible: !isThreadMessage && isAllowedToPin,
},
edit: {
label: 'Edit',
From 32e14bca76e10bbbf40899d6cb594eb3fccb0af2 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:38:17 +0530
Subject: [PATCH 20/76] Made message box responsive and fixed alignment (#664)
---
.../react/src/views/ChatBody/ChatBody.styles.js | 2 +-
.../react/src/views/ChatInput/ChatInput.styles.js | 13 +++++++++++--
.../react/src/views/ChatLayout/ChatLayout.styles.js | 1 +
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js
index 36fc549b5f..06be313a16 100644
--- a/packages/react/src/views/ChatBody/ChatBody.styles.js
+++ b/packages/react/src/views/ChatBody/ChatBody.styles.js
@@ -9,7 +9,7 @@ export const getChatbodyStyles = () => {
overflow-x: hidden;
display: flex;
flex-direction: column-reverse;
- max-height: 600px;
+ max-height: 100%;
position: relative;
padding-top: 70px;
margin-top: 0.25rem;
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index 73e91eb971..a1474877f9 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -22,6 +22,9 @@ export const getChatInputStyles = (theme) => {
justify-content: center;
flex-direction: row;
padding: 0.5rem;
+ @media (max-width: 383px) {
+ min-height: 100px;
+ }
`,
iconCursor: css`
@@ -51,6 +54,9 @@ export const getChatInputStyles = (theme) => {
&::placeholder {
padding-left: 5px;
}
+ @media (max-width: 383px) {
+ font-size: 18px;
+ }
`,
};
@@ -68,9 +74,12 @@ export const getChatInputFormattingToolbarStyles = ({ theme, mode }) => {
: lighten(theme.colors.background, 1)};
display: flex;
position: relative;
- flex-direction: row;
- gap: 0.375rem;
+ gap: 0.1rem;
border-radius: 0 0 ${theme.radius} ${theme.radius};
+ @media (max-width: 383px) {
+ display: grid;
+ grid-template-columns: repeat(5, 0.2fr);
+ }
`,
};
return styles;
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.styles.js b/packages/react/src/views/ChatLayout/ChatLayout.styles.js
index 3afa726498..56dd748cbe 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.styles.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.styles.js
@@ -12,6 +12,7 @@ const styles = {
flex: 1;
flex-direction: column;
position: relative;
+ min-width: 0;
`,
sidebar: css`
From a6ea2bcbd4295cafe6046bd8be457aa3f1a10868 Mon Sep 17 00:00:00 2001
From: Devansh Kansagra <125076549+devanshkansagra@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:39:38 +0530
Subject: [PATCH 21/76] Fix: Quoting issues (#641)
* fixed recursive quoting issue
* fixed multiple quoting issue
* Removed unwanted comment
* added checks which causing error in deployment
* Resolved the commits
* Fix the issue of not able to send the quoted thread messages
---
packages/react/src/store/messageStore.js | 10 +-
.../src/views/AttachmentHandler/Attachment.js | 53 ++++++
.../AttachmentHandler/AttachmentMetadata.js | 2 +-
.../AttachmentHandler/AudioAttachment.js | 135 ++++++++++++--
.../AttachmentHandler/ImageAttachment.js | 146 +++++++++++++--
.../views/AttachmentHandler/TextAttachment.js | 77 +++++++-
.../AttachmentHandler/VideoAttachment.js | 174 +++++++++++++++---
.../react/src/views/ChatInput/ChatInput.js | 56 ++++--
.../src/views/ChatInput/ChatInput.styles.js | 4 +
.../Message/BubbleVariant/Bubble.styles.js | 6 +-
packages/react/src/views/Message/Message.js | 4 +-
.../src/views/QuoteMessage/QuoteMessage.js | 75 +++++++-
12 files changed, 647 insertions(+), 95 deletions(-)
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 012a97e1ed..507ba3d141 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -8,7 +8,7 @@ const useMessageStore = create((set, get) => ({
threadMessages: [],
filtered: false,
editMessage: {},
- quoteMessage: {},
+ quoteMessage: [],
messageToReport: NaN,
showReportMessage: false,
isRecordingMessage: false,
@@ -71,7 +71,13 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
- setQuoteMessage: (quoteMessage) => set(() => ({ quoteMessage })),
+ addQuoteMessage: (quoteMessage) =>
+ set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
+ removeQuoteMessage: (quoteMessage) =>
+ set((state) => ({
+ quoteMessage: state.quoteMessage.filter((i) => i !== quoteMessage),
+ })),
+ clearQuoteMessages: () => set({ quoteMessage: [] }),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
toggleShowReportMessage: () => {
diff --git a/packages/react/src/views/AttachmentHandler/Attachment.js b/packages/react/src/views/AttachmentHandler/Attachment.js
index bc07a740c1..594bfa7d70 100644
--- a/packages/react/src/views/AttachmentHandler/Attachment.js
+++ b/packages/react/src/views/AttachmentHandler/Attachment.js
@@ -8,11 +8,16 @@ import VideoAttachment from './VideoAttachment';
import TextAttachment from './TextAttachment';
const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
+ const author = {
+ authorIcon: attachment?.author_icon,
+ authorName: attachment?.author_name,
+ };
if (attachment && attachment.audio_url) {
return (
);
@@ -22,6 +27,7 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
@@ -31,6 +37,7 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
@@ -40,10 +47,56 @@ const Attachment = ({ attachment, host, type, variantStyles = {} }) => {
);
}
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.image_url
+ ) {
+ return (
+
+ );
+ }
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.audio_url
+ ) {
+ return (
+
+ );
+ }
+ if (
+ attachment.attachments &&
+ Array.isArray(attachment.attachments) &&
+ attachment.attachments[0]?.video_url
+ ) {
+ return (
+
+ );
+ }
return (
{
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index ce84815828..0f5824aa0f 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -1,18 +1,129 @@
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { css } from '@emotion/react';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
+import RCContext from '../../context/RCInstance';
-const AudioAttachment = ({ attachment, host, variantStyles }) => (
-
-
-
-
-);
+const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
+ const { RCInstance } = useContext(RCContext);
+ const { theme } = useTheme();
+ const getUserAvatarUrl = (icon) => {
+ const instanceHost = RCInstance.getHost();
+ const URL = `${instanceHost}${icon}`;
+ return URL;
+ };
+ const { authorIcon, authorName } = author;
+ return (
+
+
+ {type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{nestedAttachment.author_name}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+
+ ))}
+
+
+ );
+};
export default AudioAttachment;
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index 8937782569..b9e6533ad4 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -1,32 +1,81 @@
-import React, { useState } from 'react';
+import React, { useState, useContext } from 'react';
import { css } from '@emotion/react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
import ImageGallery from '../ImageGallery/ImageGallery';
+import RCContext from '../../context/RCInstance';
-const ImageAttachment = ({ attachment, host, variantStyles = {} }) => {
+const ImageAttachment = ({
+ attachment,
+ host,
+ type,
+ author,
+ variantStyles = {},
+}) => {
+ const { RCInstance } = useContext(RCContext);
const [showGallery, setShowGallery] = useState(false);
+ const getUserAvatarUrl = (icon) => {
+ const instanceHost = RCInstance.getHost();
+ const URL = `${instanceHost}${icon}`;
+ return URL;
+ };
const extractIdFromUrl = (url) => {
const match = url.match(/\/file-upload\/(.*?)\//);
return match ? match[1] : null;
};
+ const { theme } = useTheme();
+
+ const { authorIcon, authorName } = author;
+
return (
-
setShowGallery(true)}
- css={css`
- cursor: pointer;
- border-radius: inherit;
- line-height: 0;
- `}
+ css={[
+ css`
+ cursor: pointer;
+ border-radius: inherit;
+ line-height: 0;
+ padding: 0.5rem;
+ `,
+ (type ? variantStyles.pinnedContainer : '') ||
+ css`
+ ${type === 'file'
+ ? `border: 2px solid ${theme.colors.border};`
+ : ''}
+ `,
+ ]}
>
+ {type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
{
borderBottomRightRadius: 'inherit',
}}
/>
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+ setShowGallery(true)}
+ css={[
+ css`
+ cursor: pointer;
+ border-radius: inherit;
+ line-height: 0;
+ padding: 0.5rem;
+ `,
+ (nestedAttachment.attachments[0].type
+ ? variantStyles.pinnedContainer
+ : variantStyles.quoteContainer) ||
+ css`
+ ${nestedAttachment.attachments[0].type === 'file'
+ ? `border: 2px solid ${theme.colors.border};`
+ : ''}
+ `,
+ ]}
+ >
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{nestedAttachment.author_name}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+ {showGallery && (
+
+ )}
+
+ ))}
{showGallery && (
{
return URL;
};
- let attachmentText = attachment?.text;
- if (attachmentText.includes(')')) {
- attachmentText = attachmentText.split(')')[1] || '';
- }
-
const { theme } = useTheme();
return (
@@ -67,7 +62,77 @@ const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
white-space: pre-line;
`}
>
- {attachmentText}
+ {attachment?.text
+ ? attachment.text[0] === '['
+ ? attachment.text.match(/\n(.*)/)?.[1] || ''
+ : attachment.text
+ : ''}
+ {attachment?.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment?.author_name && (
+ <>
+
+ @{nestedAttachment?.author_name}
+ >
+ )}
+
+
+ {nestedAttachment?.text
+ ? nestedAttachment.text[0] === '['
+ ? nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
+ : nestedAttachment.text
+ : ''}
+
+
+ ))}
);
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 0472d34c21..06e3453167 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -1,8 +1,9 @@
-import React from 'react';
+import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
+import RCContext from '../../context/RCInstance';
const userAgentMIMETypeFallback = (type) => {
const userAgent = navigator.userAgent.toLocaleLowerCase();
@@ -14,35 +15,152 @@ const userAgentMIMETypeFallback = (type) => {
return type;
};
-const VideoAttachment = ({ attachment, host, variantStyles = {} }) => (
-
-
-
-
+
+ {attachment.attachments &&
+ attachment.attachments.map((nestedAttachment, index) => (
+
+
+ {nestedAttachment.type === 'file' ? (
+ <>
+
+
+ @{authorName}
+
+ >
+ ) : (
+ ''
+ )}
+
+
+
+
+ ))}
+
-
-);
+ );
+};
export default VideoAttachment;
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index eae9573aed..581cbf0d26 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -90,20 +90,20 @@ const ChatInput = ({ scrollToBottom }) => {
editMessage,
setEditMessage,
quoteMessage,
- setQuoteMessage,
isRecordingMessage,
upsertMessage,
replaceMessage,
+ clearQuoteMessages,
threadId,
} = useMessageStore((state) => ({
editMessage: state.editMessage,
setEditMessage: state.setEditMessage,
quoteMessage: state.quoteMessage,
- setQuoteMessage: state.setQuoteMessage,
isRecordingMessage: state.isRecordingMessage,
upsertMessage: state.upsertMessage,
replaceMessage: state.replaceMessage,
threadId: state.threadMainMessage?._id,
+ clearQuoteMessages: state.clearQuoteMessages,
}));
const setIsLoginModalOpen = useLoginStore(
@@ -255,14 +255,31 @@ const ChatInput = ({ scrollToBottom }) => {
messageRef.current.value = '';
setDisableButton(true);
- const { msg, attachments, _id } = quoteMessage;
let pendingMessage = '';
-
- if (msg || attachments) {
- setQuoteMessage({});
- const msgLink = await getMessageLink(_id);
+ let quotedMessages = '';
+
+ if (quoteMessage.length > 0) {
+ // for (const quote of quoteMessage) {
+ // const { msg, attachments, _id } = quote;
+ // if (msg || attachments) {
+ // const msgLink = await getMessageLink(_id);
+ // quotedMessages += `[ ](${msgLink})`;
+ // }
+ // }
+
+ const quoteArray = await Promise.all(
+ quoteMessage.map(async (quote) => {
+ const { msg, attachments, _id } = quote;
+ if (msg || attachments) {
+ const msgLink = await getMessageLink(_id);
+ quotedMessages += `[ ](${msgLink})`;
+ }
+ return quotedMessages;
+ })
+ );
+ quotedMessages = quoteArray.join('');
pendingMessage = createPendingMessage(
- `[ ](${msgLink})\n ${message}`,
+ `${quotedMessages}\n${message}`,
userInfo
);
} else {
@@ -283,10 +300,9 @@ const ChatInput = ({ scrollToBottom }) => {
ECOptions.enableThreads ? threadId : undefined
);
- if (!res.success) {
- handleSendError('Error sending message, login again');
- } else {
- replaceMessage(pendingMessage._id, res.message);
+ if (res.success) {
+ clearQuoteMessages();
+ replaceMessage(pendingMessage, res.message);
}
};
@@ -425,14 +441,14 @@ const ChatInput = ({ scrollToBottom }) => {
return (
-
- {(quoteMessage.msg || quoteMessage.attachments) && (
-
- )}
+
+
+ {quoteMessage &&
+ quoteMessage.length > 0 &&
+ quoteMessage.map((message, index) => (
+
+ ))}
+
{editMessage.msg || editMessage.attachments || isChannelReadOnly ? (
{
font-size: 18px;
}
`,
+ quoteContainer: css`
+ max-height: 300px;
+ overflow: scroll;
+ `,
};
return styles;
diff --git a/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js b/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
index 42f978f9eb..5f87c0b5e4 100644
--- a/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
+++ b/packages/react/src/views/Message/BubbleVariant/Bubble.styles.js
@@ -94,7 +94,7 @@ export const getBubbleStyles = (theme) => {
overflow: hidden;
`,
pinnedContainer: css`
- max-width: 80%;
+ max-width: 100%;
`,
quoteContainer: css`
@@ -112,7 +112,7 @@ export const getBubbleStyles = (theme) => {
`,
attachmentMetaContainer: css`
- padding: 2.5% 2.5% 0;
+ padding: 2.5% 0 0;
`,
emojiPickerStyles: css`
@@ -172,7 +172,7 @@ export const getBubbleStylesMe = (theme) => {
pinnedContainerMe: css`
border-inline-start: none;
- border-inline-end: 3px solid ${theme.colors.border};
+ border-inline-end: none;
`,
textUserInfoMe: css`
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 64d2050f09..7f7fde3752 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -58,7 +58,7 @@ const Message = ({
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
- const setQuoteMessage = useMessageStore((state) => state.setQuoteMessage);
+ const addQuoteMessage = useMessageStore((state) => state.addQuoteMessage);
const openThread = useMessageStore((state) => state.openThread);
const dispatchToastMessage = useToastBarDispatch();
@@ -218,7 +218,7 @@ const Message = ({
setEditMessage(message);
}
}}
- handleQuoteMessage={() => setQuoteMessage(message)}
+ handleQuoteMessage={() => addQuoteMessage(message)}
handleEmojiClick={handleEmojiClick}
handlerReportMessage={() => {
setMessageToReport(message._id);
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.js b/packages/react/src/views/QuoteMessage/QuoteMessage.js
index fab425ebaa..be715cf0ed 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.js
@@ -11,17 +11,21 @@ import {
import RCContext from '../../context/RCInstance';
import { useMessageStore } from '../../store';
import getQuoteMessageStyles from './QuoteMessage.styles';
+import Attachment from '../AttachmentHandler/Attachment';
const QuoteMessage = ({ className = '', style = {}, message }) => {
const { RCInstance } = useContext(RCContext);
+ const instanceHost = RCInstance.getHost();
const getUserAvatarUrl = (username) => {
- const host = RCInstance.getHost();
+ const host = instanceHost;
const URL = `${host}/avatar/${username}`;
return URL;
};
const { theme } = useTheme();
const styles = getQuoteMessageStyles(theme);
- const setQuoteMessage = useMessageStore((state) => state.setQuoteMessage);
+ const removeQuoteMessage = useMessageStore(
+ (state) => state.removeQuoteMessage
+ );
const { classNames, styleOverrides } = useComponentOverrides('QuoteMessage');
return (
@@ -31,7 +35,11 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
css={styles.messageContainer}
>
- setQuoteMessage({})} size="small">
+ removeQuoteMessage(message)}
+ size="small"
+ >
@@ -45,11 +53,62 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
{format(new Date(message.ts), 'h:mm a')}
- {message.msg
- ? message.msg
- : `${message.file?.name} (${
- message.file?.size ? (message.file.size / 1024).toFixed(2) : 0
- } kB)`}
+ {message.file ? (
+ message.file.type.startsWith('image/') ? (
+
+

+
{`${message.file.name} (${(message.file.size / 1024).toFixed(
+ 2
+ )} kB)`}
+
+ ) : message.file.type.startsWith('video/') ? (
+
+ ) : message.file.type.startsWith('audio/') ? (
+
+ ) : (
+
+ {message.msg
+ ? message.msg
+ : `${message.file?.name} (${
+ message.file?.size
+ ? (message.file.size / 1024).toFixed(2)
+ : 0
+ } kB)`}
+
+ )
+ ) : message?.msg[0] === '[' ? (
+ message?.msg.match(/\n(.*)/)[1]
+ ) : (
+ message?.msg
+ )}
+ {message.attachments &&
+ message.attachments.length > 0 &&
+ message.msg &&
+ message.msg[0] === '[' &&
+ message.attachments.map((attachment, index) => (
+
+ ))}
);
From 28a82023953ea9316b1687574dcbe97647a992ed Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:45:08 +0530
Subject: [PATCH 22/76] Feat: Added Scroll-to-Message Functionality (#667)
* Added go to Message Feature
* fix linting issues
* Implement jump to message functionality
* Fix linting
* Append msg to URL
* Remove appending in URL
* Fix popup mode issue
---
.../common/MessageAggregator.js | 64 +++++++++++++++----
1 file changed, 50 insertions(+), 14 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 079582e86a..58fccff3c4 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,10 +1,17 @@
import React, { useState, useMemo } from 'react';
import { isSameDay, format } from 'date-fns';
-import { Box, Sidebar, Popup, useTheme } from '@embeddedchat/ui-elements';
+import {
+ Box,
+ Sidebar,
+ Popup,
+ useTheme,
+ ActionButton,
+ Icon,
+} from '@embeddedchat/ui-elements';
import { MessageDivider } from '../../Message/MessageDivider';
import Message from '../../Message/Message';
import getMessageAggregatorStyles from './MessageAggregator.styles';
-import { useMessageStore } from '../../../store';
+import { useMessageStore, useSidebarStore } from '../../../store';
import { useSetMessageList } from '../../../hooks/useSetMessageList';
import LoadingIndicator from './LoadingIndicator';
import NoMessagesIndicator from './NoMessageIndicator';
@@ -37,6 +44,17 @@ export const MessageAggregator = ({
shouldRender
);
+ const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
+ const setJumpToMessage = (msgId) => {
+ if (msgId) {
+ const element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ setShowSidebar(false);
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ }
+ }
+ };
+
const isMessageNewDay = (current, previous) =>
!previous ||
!shouldRender(previous) ||
@@ -90,20 +108,38 @@ export const MessageAggregator = ({
fileMessage={msg}
/>
) : (
-
+ >
+
+
+ setJumpToMessage(msg._id)}
+ css={{
+ position: 'relative',
+ zIndex: 10,
+ }}
+ >
+
+
+
)}
);
From f64a3a6525436636abf75d1cffc4463096d36ac6 Mon Sep 17 00:00:00 2001
From: Rahul Singh Thakur <65606499+Barrylimarti@users.noreply.github.com>
Date: Sun, 15 Dec 2024 16:48:45 +0530
Subject: [PATCH 23/76] Fix: Sidebar starred messages fetched by api to include
thread messages. (#669)
* fetch starred message api called
* starred messages fetching from api
* ran prettier
* fixed linting errors
---
packages/react/src/hooks/useFetchChatData.js | 23 +++++++++++++-
.../react/src/store/starredMessageStore.js | 2 ++
packages/react/src/views/ChatBody/ChatBody.js | 2 +-
.../react/src/views/ChatHeader/ChatHeader.js | 2 +-
.../react/src/views/ChatLayout/ChatLayout.js | 30 +++++++++++++++++--
packages/react/src/views/Message/Message.js | 4 ++-
.../MessageAggregators/StarredMessages.js | 8 +++--
.../common/MessageAggregator.js | 5 ++--
8 files changed, 65 insertions(+), 11 deletions(-)
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 1d08f0eaf4..99c48aa1e4 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -5,6 +5,7 @@ import {
useChannelStore,
useMemberStore,
useMessageStore,
+ useStarredMessageStore,
} from '../store';
const useFetchChatData = (showRoles) => {
@@ -13,6 +14,9 @@ const useFetchChatData = (showRoles) => {
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const setMessages = useMessageStore((state) => state.setMessages);
const setAdmins = useMemberStore((state) => state.setAdmins);
+ const setStarredMessages = useStarredMessageStore(
+ (state) => state.setStarredMessages
+ );
const isUserAuthenticated = useUserStore(
(state) => state.isUserAuthenticated
);
@@ -80,7 +84,24 @@ const useFetchChatData = (showRoles) => {
]
);
- return getMessagesAndRoles;
+ const getStarredMessages = useCallback(
+ async (anonymousMode) => {
+ if (isUserAuthenticated) {
+ try {
+ if (!isUserAuthenticated && !anonymousMode) {
+ return;
+ }
+ const { messages } = await RCInstance.getStarredMessages();
+ setStarredMessages(messages);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ },
+ [isUserAuthenticated, RCInstance, setStarredMessages]
+ );
+
+ return { getMessagesAndRoles, getStarredMessages };
};
export default useFetchChatData;
diff --git a/packages/react/src/store/starredMessageStore.js b/packages/react/src/store/starredMessageStore.js
index a564df3c41..989ec8b6fb 100644
--- a/packages/react/src/store/starredMessageStore.js
+++ b/packages/react/src/store/starredMessageStore.js
@@ -3,6 +3,8 @@ import { create } from 'zustand';
const useStarredMessageStore = create((set) => ({
showStarred: false,
setShowStarred: (showStarred) => set(() => ({ showStarred })),
+ starredMessages: [],
+ setStarredMessages: (messages) => set(() => ({ starredMessages: messages })),
}));
export default useStarredMessageStore;
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index e5a6bd1a33..a582244d0f 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -69,7 +69,7 @@ const ChatBody = ({
const username = useUserStore((state) => state.username);
- const getMessagesAndRoles = useFetchChatData(showRoles);
+ const { getMessagesAndRoles } = useFetchChatData(showRoles);
const getThreadMessages = useCallback(async () => {
if (isUserAuthenticated && threadMainMessage?._id) {
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 7c43056a65..99babdc51a 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -86,7 +86,7 @@ const ChatHeader = ({
);
const dispatchToastMessage = useToastBarDispatch();
- const getMessagesAndRoles = useFetchChatData(showRoles);
+ const { getMessagesAndRoles } = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
const setMessages = useMessageStore((state) => state.setMessages);
const avatarUrl = useUserStore((state) => state.avatarUrl);
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.js b/packages/react/src/views/ChatLayout/ChatLayout.js
index 6243dc0cc8..ee6b0c1b94 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.js
@@ -1,4 +1,4 @@
-import React, { useRef } from 'react';
+import React, { useEffect, useRef, useCallback, useState } from 'react';
import { Box, useComponentOverrides } from '@embeddedchat/ui-elements';
import styles from './ChatLayout.styles';
import {
@@ -36,9 +36,15 @@ import useUiKitStore from '../../store/uiKitStore';
const ChatLayout = () => {
const messageListRef = useRef(null);
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
- const { ECOptions } = useRCContext();
+ const { RCInstance, ECOptions } = useRCContext();
const anonymousMode = ECOptions?.anonymousMode;
const showRoles = ECOptions?.anonymousMode;
+ const setStarredMessages = useStarredMessageStore(
+ (state) => state.setStarredMessages
+ );
+ const starredMessages = useStarredMessageStore(
+ (state) => state.starredMessages
+ );
const showSidebar = useSidebarStore((state) => state.showSidebar);
const showMentions = useMentionsStore((state) => state.showMentions);
const showAllFiles = useFileStore((state) => state.showAllFiles);
@@ -57,6 +63,9 @@ const ChatLayout = () => {
const attachmentWindowOpen = useAttachmentWindowStore(
(state) => state.attachmentWindowOpen
);
+ const isUserAuthenticated = useUserStore(
+ (state) => state.isUserAuthenticated
+ );
const { data, handleDrag, handleDragDrop } = useDropBox();
const { uiKitContextualBarOpen, uiKitContextualBarData } = useUiKitStore(
(state) => ({
@@ -72,7 +81,22 @@ const ChatLayout = () => {
});
}
};
-
+ const getStarredMessages = useCallback(async () => {
+ if (isUserAuthenticated) {
+ try {
+ if (!isUserAuthenticated && !anonymousMode) {
+ return;
+ }
+ const { messages } = await RCInstance.getStarredMessages();
+ setStarredMessages(messages);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }, [isUserAuthenticated, anonymousMode, RCInstance]);
+ useEffect(() => {
+ getStarredMessages();
+ }, [showSidebar]);
return (
state.addQuoteMessage);
const openThread = useMessageStore((state) => state.openThread);
-
+ const { getStarredMessages } = useFetchChatData();
const dispatchToastMessage = useToastBarDispatch();
const { editMessage, setEditMessage } = useMessageStore((state) => ({
editMessage: state.editMessage,
@@ -92,6 +93,7 @@ const Message = ({
message: 'Message unstarred',
});
}
+ getStarredMessages();
};
const handlePinMessage = async (msg) => {
diff --git a/packages/react/src/views/MessageAggregators/StarredMessages.js b/packages/react/src/views/MessageAggregators/StarredMessages.js
index b7d77b864e..5ced944f06 100644
--- a/packages/react/src/views/MessageAggregators/StarredMessages.js
+++ b/packages/react/src/views/MessageAggregators/StarredMessages.js
@@ -1,12 +1,15 @@
-import React, { useCallback } from 'react';
+import React, { useCallback, useEffect } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
-import { useUserStore } from '../../store';
+import { useStarredMessageStore, useUserStore } from '../../store';
import { MessageAggregator } from './common/MessageAggregator';
const StarredMessages = () => {
const authenticatedUserId = useUserStore((state) => state.userId);
const { variantOverrides } = useComponentOverrides('StarredMessages');
const viewType = variantOverrides.viewType || 'Sidebar';
+ const starredMessages = useStarredMessageStore(
+ (state) => state.starredMessages
+ );
const shouldRender = useCallback(
(msg) =>
msg.starred &&
@@ -18,6 +21,7 @@ const StarredMessages = () => {
title="Starred Messages"
iconName="star"
noMessageInfo="No Starred Messages"
+ fetchedMessageList={starredMessages}
shouldRender={shouldRender}
viewType={viewType}
/>
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 58fccff3c4..3f4f62e730 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -23,6 +23,7 @@ export const MessageAggregator = ({
iconName,
noMessageInfo,
shouldRender,
+ fetchedMessageList,
searchProps,
searchFiltered,
fetching,
@@ -40,7 +41,7 @@ export const MessageAggregator = ({
);
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
- searchFiltered || allMessages,
+ fetchedMessageList || searchFiltered || allMessages,
shouldRender
);
@@ -57,7 +58,7 @@ export const MessageAggregator = ({
const isMessageNewDay = (current, previous) =>
!previous ||
- !shouldRender(previous) ||
+ shouldRender(previous) ||
!isSameDay(new Date(current.ts), new Date(previous.ts));
const noMessages = messageList?.length === 0 || !messageRendered;
From 10584052690572433dfae0103229189379e8b7af Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Tue, 17 Dec 2024 09:27:43 +0530
Subject: [PATCH 24/76] fix: ensure pin permission changes reflect without
requiring user logout (#688)
---
packages/react/src/views/EmbeddedChat.js | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index 2dc8379879..a7e258b442 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -83,6 +83,9 @@ const EmbeddedChat = (props) => {
}));
const setIsLoginIn = useLoginStore((state) => state.setIsLoginIn);
+ const setUserPinPermissions = useUserStore(
+ (state) => state.setUserPinPermissions
+ );
if (isClosable && !setClosableState) {
throw Error(
@@ -125,6 +128,8 @@ const EmbeddedChat = (props) => {
setIsLoginIn(true);
try {
await RCInstance.autoLogin(auth);
+ const permissions = await RCInstance.permissionInfo();
+ setUserPinPermissions(permissions.update[150]);
} catch (error) {
console.error(error);
} finally {
From 9a3b7ac93c3a2233ab7ceb2d49d205317cde8b16 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 22 Dec 2024 13:57:01 +0530
Subject: [PATCH 25/76] Fixed UI issues for Sidebar (#634)
* Fixed UI issues for Sidebar
* Fixed sidebar height issue
* Removed unnecessary spacing
* Fixed reply in thread issue
* Adjusted dynamic header visibility
* Revert zIndex changes
* Linting fix
* Run prettier
* Remove zIndex
* Adjusted zIndex for ViewComponent
* Fix sidebar width
* Remove global css for sidebar
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/views/ChatHeader/ChatHeader.js | 4 +++-
packages/react/src/views/GlobalStyles.js | 12 +++++++++++-
packages/react/src/views/Message/Message.js | 5 +++--
packages/react/src/views/Message/Message.styles.js | 3 +++
.../MessageAggregators/common/MessageAggregator.js | 9 ++++++++-
.../src/views/RoomInformation/RoomInformation.js | 1 +
packages/react/src/views/RoomMembers/RoomMember.js | 1 +
7 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 99babdc51a..0107399771 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -21,6 +21,7 @@ import {
usePinnedMessageStore,
useStarredMessageStore,
useFileStore,
+ useSidebarStore,
} from '../../store';
import { DynamicHeader } from '../DynamicHeader';
import useFetchChatData from '../../hooks/useFetchChatData';
@@ -84,7 +85,7 @@ const ChatHeader = ({
const setIsUserAuthenticated = useUserStore(
(state) => state.setIsUserAuthenticated
);
-
+ const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
const dispatchToastMessage = useToastBarDispatch();
const { getMessagesAndRoles } = useFetchChatData(showRoles);
const setMessageLimit = useSettingsStore((state) => state.setMessageLimit);
@@ -130,6 +131,7 @@ const ChatHeader = ({
try {
await RCInstance.logout();
setMessages([]);
+ setShowSidebar(false);
setUserAvatarUrl(null);
useMessageStore.setState({ isMessageLoaded: false });
} catch (e) {
diff --git a/packages/react/src/views/GlobalStyles.js b/packages/react/src/views/GlobalStyles.js
index b26977e635..c9c821feff 100644
--- a/packages/react/src/views/GlobalStyles.js
+++ b/packages/react/src/views/GlobalStyles.js
@@ -8,7 +8,6 @@ const getGlobalStyles = (theme) => css`
margin: 0;
padding: 0;
}
-
.ec-embedded-chat body {
font-family: ${theme.typography.default.fontFamily};
font-size: ${theme.typography.default.fontSize}px;
@@ -36,6 +35,17 @@ const getGlobalStyles = (theme) => css`
.ec-embedded-chat ::-webkit-scrollbar-button {
display: none;
}
+ @media (max-width: 780px) {
+ .ec-sidebar {
+ position: absolute;
+ width: 100% !important;
+ height: calc(100% - 56.39px) !important;
+ min-width: 250px !important;
+ left: 0;
+ bottom: 0;
+ background: ${theme.colors.background}!important;
+ }
+ }
`;
const GlobalStyles = () => {
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index e460adad0d..b587d09e11 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -11,7 +11,7 @@ import {
import { Attachments } from '../AttachmentHandler';
import { Markdown } from '../Markdown';
import MessageHeader from './MessageHeader';
-import { useMessageStore, useUserStore } from '../../store';
+import { useMessageStore, useUserStore, useSidebarStore } from '../../store';
import RCContext from '../../context/RCInstance';
import { MessageBody } from './MessageBody';
import { MessageReactions } from './MessageReactions';
@@ -49,7 +49,7 @@ const Message = ({
const { RCInstance, ECOptions } = useContext(RCContext);
showAvatar = ECOptions?.showAvatar && showAvatar;
-
+ const { showSidebar, setShowSidebar } = useSidebarStore();
const authenticatedUserId = useUserStore((state) => state.userId);
const authenticatedUserUsername = useUserStore((state) => state.username);
const userRoles = useUserStore((state) => state.roles);
@@ -137,6 +137,7 @@ const Message = ({
const handleOpenThread = (msg) => async () => {
openThread(msg);
+ setShowSidebar(false);
};
const isStarred = message.starred?.find((u) => u._id === authenticatedUserId);
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index b6b978fb4c..9f9358fd92 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -81,6 +81,9 @@ export const getMessageDividerStyles = (theme) => {
margin-bottom: 0.75rem;
padding-left: 1.25rem;
padding-right: 1.25rem;
+ @media (max-width: 780px) {
+ z-index: 1;
+ }
`,
dividerContent: css`
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 3f4f62e730..6e1786a339 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -70,7 +70,11 @@ export const MessageAggregator = ({
iconName={iconName}
searchProps={searchProps}
onClose={() => setExclusiveState(null)}
- style={{ padding: 0 }}
+ style={{
+ width: '400px',
+ padding: 0,
+ zIndex: window.innerWidth <= 780 ? 1 : null,
+ }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
@@ -126,6 +130,9 @@ export const MessageAggregator = ({
isInSidebar
style={{
flex: 1,
+ paddingLeft: 3,
+ paddingRight: 2,
+ minWidth: 0,
}}
/>
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index 504b0f4ba8..3cfdefad08 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -30,6 +30,7 @@ const Roominfo = () => {
title="Room Information"
iconName="info"
onClose={() => setExclusiveState(null)}
+ style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
diff --git a/packages/react/src/views/RoomMembers/RoomMember.js b/packages/react/src/views/RoomMembers/RoomMember.js
index c52f48c9dd..85b268b07a 100644
--- a/packages/react/src/views/RoomMembers/RoomMember.js
+++ b/packages/react/src/views/RoomMembers/RoomMember.js
@@ -55,6 +55,7 @@ const RoomMembers = ({ members }) => {
title="Members"
iconName="members"
onClose={() => setExclusiveState(null)}
+ style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
{...(viewType === 'Popup'
? {
isPopupHeader: true,
From 3d6700c2f93cc9bb9eb4bd54fdfec4009befca6b Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sun, 22 Dec 2024 14:21:20 +0530
Subject: [PATCH 26/76] fix(permissions): ensure admin-granted edit message
permissions apply in EmbeddedChat (#702)
---
packages/react/src/hooks/useRCAuth.js | 11 ++++++++++-
packages/react/src/store/messageStore.js | 3 +++
packages/react/src/views/EmbeddedChat.js | 6 +++++-
packages/react/src/views/Message/Message.js | 5 +++++
packages/react/src/views/Message/MessageToolbox.js | 8 +++++++-
5 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/hooks/useRCAuth.js b/packages/react/src/hooks/useRCAuth.js
index 6a997cb569..c0b1d3a3b4 100644
--- a/packages/react/src/hooks/useRCAuth.js
+++ b/packages/react/src/hooks/useRCAuth.js
@@ -1,7 +1,12 @@
import { useContext } from 'react';
import { useToastBarDispatch } from '@embeddedchat/ui-elements';
import RCContext from '../context/RCInstance';
-import { useUserStore, totpModalStore, useLoginStore } from '../store';
+import {
+ useUserStore,
+ totpModalStore,
+ useLoginStore,
+ useMessageStore,
+} from '../store';
export const useRCAuth = () => {
const { RCInstance } = useContext(RCContext);
@@ -23,6 +28,9 @@ export const useRCAuth = () => {
const setUserPinPermissions = useUserStore(
(state) => state.setUserPinPermissions
);
+ const setEditMessagePermissions = useMessageStore(
+ (state) => state.setEditMessagePermissions
+ );
const dispatchToastMessage = useToastBarDispatch();
const handleLogin = async (userOrEmail, password, code) => {
@@ -61,6 +69,7 @@ export const useRCAuth = () => {
setEmailorUser(null);
setPassword(null);
setUserPinPermissions(permissions.update[150]);
+ setEditMessagePermissions(permissions.update[28]);
dispatchToastMessage({
type: 'success',
message: 'Successfully logged in',
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 507ba3d141..676258c1c4 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -71,6 +71,9 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
+ editMessagePermissions: {},
+ setEditMessagePermissions: (editMessagePermissions) =>
+ set((state) => ({ ...state, editMessagePermissions })),
addQuoteMessage: (quoteMessage) =>
set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
removeQuoteMessage: (quoteMessage) =>
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index a7e258b442..00557f289c 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -18,7 +18,7 @@ import {
import { ChatLayout } from './ChatLayout';
import { ChatHeader } from './ChatHeader';
import { RCInstanceProvider } from '../context/RCInstance';
-import { useUserStore, useLoginStore } from '../store';
+import { useUserStore, useLoginStore, useMessageStore } from '../store';
import DefaultTheme from '../theme/DefaultTheme';
import { getTokenStorage } from '../lib/auth';
import { styles } from './EmbeddedChat.styles';
@@ -87,6 +87,9 @@ const EmbeddedChat = (props) => {
(state) => state.setUserPinPermissions
);
+ const setEditMessagePermissions = useMessageStore(
+ (state) => state.setEditMessagePermissions
+ );
if (isClosable && !setClosableState) {
throw Error(
'Please provide a setClosableState to props when isClosable = true'
@@ -130,6 +133,7 @@ const EmbeddedChat = (props) => {
await RCInstance.autoLogin(auth);
const permissions = await RCInstance.permissionInfo();
setUserPinPermissions(permissions.update[150]);
+ setEditMessagePermissions(permissions.update[28]);
} catch (error) {
console.error(error);
} finally {
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index b587d09e11..aafb5642b5 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -56,6 +56,9 @@ const Message = ({
const pinPermissions = useUserStore(
(state) => state.userPinPermissions.roles
);
+ const editMessagePermissions = useMessageStore(
+ (state) => state.editMessagePermissions.roles
+ );
const [setMessageToReport, toggleShowReportMessage] = useMessageStore(
(state) => [state.setMessageToReport, state.toggleShowReportMessage]
);
@@ -73,6 +76,7 @@ const Message = ({
const styles = getMessageStyles(theme);
const bubbleStyles = useBubbleStyles(isMe);
const pinRoles = new Set(pinPermissions);
+ const editMessageRoles = new Set(editMessagePermissions);
const variantStyles =
!isInSidebar && variantOverrides === 'bubble' ? bubbleStyles : {};
@@ -210,6 +214,7 @@ const Message = ({
authenticatedUserId={authenticatedUserId}
userRoles={userRoles}
pinRoles={pinRoles}
+ editMessageRoles={editMessageRoles}
handleOpenThread={handleOpenThread}
handleDeleteMessage={handleDeleteMessage}
handleStarMessage={handleStarMessage}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 55af7f64d5..61765c8dd9 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -23,6 +23,7 @@ export const MessageToolbox = ({
authenticatedUserId,
userRoles,
pinRoles,
+ editMessageRoles,
handleOpenThread,
handleEmojiClick,
handlePinMessage,
@@ -70,6 +71,11 @@ export const MessageToolbox = ({
};
const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
+ const isAllowedToEditMessage = userRoles.some((role) =>
+ editMessageRoles.has(role)
+ )
+ ? true
+ : message.u._id === authenticatedUserId;
const options = useMemo(
() => ({
reply: {
@@ -120,7 +126,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: message.u._id === authenticatedUserId,
+ visible: isAllowedToEditMessage,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From 0d7ff8d496326394a21191127b1f8579b209ec54 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sun, 22 Dec 2024 14:38:04 +0530
Subject: [PATCH 27/76] fixed all markdown issues (#614)
* fix mardown
* fix conflicts
* fix formatting issues
* fixed lint issues
* changes
* prettier
* fix quote
* fixed
* removed markdown from passed prop
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/views/ChatInput/ChatInput.js | 1 +
.../react/src/views/Message/MessageToolbox.js | 4 ++--
.../src/views/QuoteMessage/QuoteMessage.js | 17 +++++++++--------
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 581cbf0d26..86b4b5082a 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,6 +34,7 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
+import { Markdown } from '../Markdown';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 61765c8dd9..0ed468bd7a 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -10,9 +10,9 @@ import {
useTheme,
} from '@embeddedchat/ui-elements';
import { EmojiPicker } from '../EmojiPicker';
-import { parseEmoji } from '../../lib/emoji';
import { getMessageToolboxStyles } from './Message.styles';
import SurfaceMenu from '../SurfaceMenu/SurfaceMenu';
+import { Markdown } from '../Markdown';
export const MessageToolbox = ({
className = '',
@@ -249,7 +249,7 @@ export const MessageToolbox = ({
padding: '0 0.5rem 0.5rem',
}}
>
- {parseEmoji(message.msg)}
+
+ {currentUserInfo?.statusText && (
+
+ {currentUserInfo?.statusText}
+
+ )}
+ {currentUserInfo?.nickname && (
+
+ )}
{currentUserInfo?.roles?.length && (
{
))}
}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
@@ -121,7 +145,7 @@ const UserInformation = () => {
@@ -132,17 +156,26 @@ const UserInformation = () => {
? 'Never'
: formatTimestamp(currentUserInfo.lastLogin)
}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
+ {currentUserInfo?.bio && (
+
+ )}
(
@@ -158,14 +191,14 @@ const UserInformation = () => {
))}
- isAdmin={isAdmin}
+ isAdmin={isAllowedToViewFullInfo}
authenticatedUserId={authenticatedUserId}
currentUserInfo={currentUserInfo}
/>
From f6eaf878afd12d074ec002ef05fd24db2c1e152c Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:47:35 +0530
Subject: [PATCH 35/76] Fix: Editing of Audio, Video and File Message (#697)
* updated handleEditMessage functionality, added valdation for audio, video and file message
* I have hidden the edit option for the audio/video message, and reverted previous approach of showing popup message
* fix: apply Prettier formatting
* Update visibility logic for 'Edit' button
* wrapped logic in the variable 'isVisibleForMessageType' for this check and used it
---
packages/react/src/views/Message/MessageToolbox.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index a3e2c1ec71..710be2b5a2 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -75,11 +75,17 @@ export const MessageToolbox = ({
};
const isAllowedToPin = userRoles.some((role) => pinRoles.has(role));
+
const isAllowedToEditMessage = userRoles.some((role) =>
editMessageRoles.has(role)
)
? true
: message.u._id === authenticatedUserId;
+
+ const isVisibleForMessageType =
+ message.files?.[0].type !== 'audio/mpeg' &&
+ message.files?.[0].type !== 'video/mp4';
+
const options = useMemo(
() => ({
reply: {
@@ -130,7 +136,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: isAllowedToEditMessage,
+ visible: isAllowedToEditMessage && isVisibleForMessageType,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From f3b33bc20c5de1d3b71d92aee11a66a73ce5ffad Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 1 Jan 2025 18:52:10 +0530
Subject: [PATCH 36/76] Fix UI Not Updating Immediately After Pinning/Unpinning
Messages (#654)
* pin
* removed comment
---
packages/react/src/views/Message/Message.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index a17a3c3a3c..6aed12ef0c 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -102,10 +102,12 @@ const Message = ({
const handlePinMessage = async (msg) => {
const isPinned = msg.pinned;
+ msg.pinned = !isPinned;
const pinOrUnpin = isPinned
? await RCInstance.unpinMessage(msg._id)
: await RCInstance.pinMessage(msg._id);
if (pinOrUnpin.error) {
+ msg.pinned = isPinned;
dispatchToastMessage({
type: 'error',
message: 'Error pinning message',
From de1036c181e856f3d1858d69332237099ac2416d Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:59:15 +0530
Subject: [PATCH 37/76] fix: image gallery showing error (#759)
---
packages/api/src/EmbeddedChatApi.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index b9a8cef326..c2fdabb694 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -714,7 +714,7 @@ export default class EmbeddedChatApi {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(
- `${this.host}/api/v1/channels.images?roomId=${this.rid}`,
+ `${this.host}/api/v1/rooms.images?roomId=${this.rid}`,
{
headers: {
"Content-Type": "application/json",
From d920d596f02a0f4d10261d57fad81daa86788e93 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:10:42 +0530
Subject: [PATCH 38/76] Feat: add announcement , display room avatar , make
room name clickable. (#734)
* Added room announcement feature , display avatar and make room name clickable
* remove showChannelAvatar from ECOptions
* Add padding
* Add padding to modal
* Remove text underline in announcement in normal view
* add showAnnouncement dependency to useEffect
* Run prettier
* replace channelInfo.description
---
packages/react/src/views/ChatBody/ChatBody.js | 75 +++++++++++++++++--
.../src/views/ChatBody/ChatBody.styles.js | 20 ++++-
.../react/src/views/ChatHeader/ChatHeader.js | 49 +++++++++---
.../src/views/ChatHeader/ChatHeader.styles.js | 11 ++-
packages/react/src/views/EmbeddedChat.js | 4 +
.../views/RoomInformation/RoomInformation.js | 52 ++++++-------
.../RoomInformation/RoomInformation.styles.js | 25 +++++++
7 files changed, 193 insertions(+), 43 deletions(-)
create mode 100644 packages/react/src/views/RoomInformation/RoomInformation.styles.js
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index a582244d0f..721c2d2dc1 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -1,11 +1,19 @@
/* eslint-disable no-shadow */
-import React, { useCallback, useContext, useEffect, useState } from 'react';
+import React, {
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+ useRef,
+} from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import {
Box,
Throbber,
useComponentOverrides,
+ Modal,
+ useTheme,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import {
@@ -33,21 +41,23 @@ const ChatBody = ({
scrollToBottom,
}) => {
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
-
- const styles = getChatbodyStyles();
+ const { theme, mode } = useTheme();
+ const styles = getChatbodyStyles(theme, mode);
const [scrollPosition, setScrollPosition] = useState(0);
const [popupVisible, setPopupVisible] = useState(false);
const [, setIsUserScrolledUp] = useState(false);
const [otherUserMessage, setOtherUserMessage] = useState(false);
-
+ const [isOverflowing, setIsOverflowing] = useState(false);
const { RCInstance, ECOptions } = useContext(RCContext);
+ const showAnnouncement = ECOptions?.showAnnouncement;
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages);
-
+ const [isModalOpen, setModalOpen] = useState(false);
const setThreadMessages = useMessageStore((state) => state.setThreadMessages);
const upsertMessage = useMessageStore((state) => state.upsertMessage);
const removeMessage = useMessageStore((state) => state.removeMessage);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
+ const channelInfo = useChannelStore((state) => state.channelInfo);
const isLoginIn = useLoginStore((state) => state.isLoginIn);
const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [
@@ -182,7 +192,24 @@ const ChatBody = ({
const showNewMessagesPopup = () => {
setPopupVisible(true);
};
+ const announcementRef = useRef(null);
+
+ const toggleModal = () => {
+ setModalOpen(!isModalOpen);
+ };
+
+ const checkOverflow = () => {
+ if (announcementRef.current) {
+ setIsOverflowing(
+ announcementRef.current.scrollWidth >
+ announcementRef.current.clientWidth
+ );
+ }
+ };
+ useEffect(() => {
+ checkOverflow();
+ }, [channelInfo.announcement, showAnnouncement]);
useEffect(() => {
const currentRef = messageListRef.current;
currentRef.addEventListener('scroll', handleScroll);
@@ -204,6 +231,44 @@ const ChatBody = ({
return (
<>
+ {channelInfo.announcement && showAnnouncement && (
+
+
+ {channelInfo.announcement}
+
+
+ )}
+ {isModalOpen && (
+
+
+ Announcement
+
+
+
+ {channelInfo.announcement}
+
+
+ )}
{
+export const getChatbodyStyles = (theme, mode) => {
const styles = {
chatbodyContainer: css`
flex: 1;
@@ -14,6 +15,23 @@ export const getChatbodyStyles = () => {
padding-top: 70px;
margin-top: 0.25rem;
`,
+ announcementStyles: css`
+ display: flex;
+ justify-content: center;
+ padding: 7px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ background-color: ${mode === 'light'
+ ? lighten(theme.colors.info, 0.78)
+ : darken(theme.colors.primary, 0.7)};
+ `,
+ announcementTextBox: css`
+ max-width: 80%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ `,
};
return styles;
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 0107399771..817ff40975 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useMemo } from 'react';
+import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import {
Box,
@@ -8,6 +9,7 @@ import {
useToastBarDispatch,
useComponentOverrides,
useTheme,
+ Avatar,
} from '@embeddedchat/ui-elements';
import { useRCContext } from '../../context/RCInstance';
import {
@@ -115,7 +117,10 @@ const ChatHeader = ({
);
const setShowAllFiles = useFileStore((state) => state.setShowAllFiles);
const setShowMentions = useMentionsStore((state) => state.setShowMentions);
-
+ const getChannelAvatarURL = (channelname) => {
+ const host = RCInstance.getHost();
+ return `${host}/avatar/${channelname}`;
+ };
const handleGoBack = async () => {
if (isUserAuthenticated) {
getMessagesAndRoles();
@@ -347,7 +352,6 @@ const ChatHeader = ({
>
-
{isUserAuthenticated ? (
<>
@@ -355,17 +359,40 @@ const ChatHeader = ({
level={3}
className="ec-chat-header--channelName"
css={styles.clearSpacing}
+ style={{
+ display: 'flex',
+ alignItems: 'center',
+ gap: '0.2rem',
+ }}
>
- {channelInfo.name || channelName || 'channelName'}
+
+
+ setExclusiveState(setShowChannelinfo)}
+ >
+
+
+ {channelInfo.name || channelName || 'channelName'}
+
+
+ {fullScreen && (
+
+ {channelInfo.topic || ''}
+
+ )}
+
- {fullScreen && (
-
- {channelInfo.description || ''}
-
- )}
>
) : (
{
margin: 0;
padding: 0;
`,
-
chatHeaderChild: css`
${rowCentreAlign}
padding: 0 0.75rem;
@@ -43,6 +42,16 @@ const getChatHeaderStyles = ({ theme, mode }) => {
position:relative;
gap: 0.5rem;
`,
+ channelName: css`
+ display: flex;
+ align-items: center;
+ gap: 0.1rem;
+ cursor: pointer;
+ `,
+ channelTopic: css`
+ opacity: 0.8rem;
+ font-size: 1rem;
+ `,
};
return styles;
};
diff --git a/packages/react/src/views/EmbeddedChat.js b/packages/react/src/views/EmbeddedChat.js
index 00557f289c..17b1ff1a41 100644
--- a/packages/react/src/views/EmbeddedChat.js
+++ b/packages/react/src/views/EmbeddedChat.js
@@ -44,6 +44,7 @@ const EmbeddedChat = (props) => {
toastBarPosition = 'bottom right',
showRoles = false,
showAvatar = true,
+ showAnnouncement = true,
showUsername = false,
showName = true,
enableThreads = false,
@@ -204,6 +205,7 @@ const EmbeddedChat = (props) => {
showName,
showRoles,
showAvatar,
+ showAnnouncement,
showUsername,
hideHeader,
anonymousMode,
@@ -219,6 +221,7 @@ const EmbeddedChat = (props) => {
showName,
showRoles,
showAvatar,
+ showAnnouncement,
showUsername,
hideHeader,
anonymousMode,
@@ -281,6 +284,7 @@ EmbeddedChat.propTypes = {
toastBarPosition: PropTypes.string,
showRoles: PropTypes.bool,
showAvatar: PropTypes.bool,
+ showAnnouncement: PropTypes.bool,
enableThreads: PropTypes.bool,
theme: PropTypes.object,
auth: PropTypes.oneOfType([
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index 3cfdefad08..b4e26764c9 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -9,11 +9,12 @@ import {
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import { useChannelStore } from '../../store';
+import getRoomInformationStyles from './RoomInformation.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
const Roominfo = () => {
const { RCInstance } = useContext(RCContext);
-
+ const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
@@ -44,34 +45,35 @@ const Roominfo = () => {
overflow: auto;
`}
>
-
-
- # {channelInfo.name}
-
-
- Description
-
-
- {channelInfo.description}
-
+
+
+
+ # {channelInfo.name}
+ {channelInfo.description && (
+ <>
+ Description
+ {channelInfo.description}
+ >
+ )}
+ {channelInfo.topic && (
+ <>
+ Topic
+ {channelInfo.topic}
+ >
+ )}
+ {channelInfo.announcement && (
+ <>
+ Announcement
+ {channelInfo.announcement}
+ >
+ )}
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
new file mode 100644
index 0000000000..9ab039b94a
--- /dev/null
+++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
@@ -0,0 +1,25 @@
+import { css } from '@emotion/react';
+
+const getRoomInformationStyles = () => {
+ const styles = {
+ infoContainer: css`
+ margin: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 0.1rem;
+ `,
+ infoHeader: css`
+ margin-block: 5px;
+ font-weight: 900;
+ `,
+ info: css`
+ word-wrap: break-word;
+ overflow-wrap: anywhere;
+ white-space: normal;
+ `,
+ };
+
+ return styles;
+};
+
+export default getRoomInformationStyles;
From 1c01bbdc444f35422422bae2dd3521685fa2095e Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:11:04 +0530
Subject: [PATCH 39/76] fix: user action messages (#746)
* fix: user action messages
* remove showUsername
---
packages/react/src/views/Message/Message.js | 5 ++++-
packages/react/src/views/Message/MessageHeader.js | 12 ++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 6aed12ef0c..140cbdc963 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -207,7 +207,10 @@ const Message = ({
isPinned={isPinned}
/>
)}
-
+
{shouldShowHeader && (
0 ? message.msg : '(none)'
+ }`;
+ case 'room_changed_description':
+ return `changed description to: ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
+ case 'room_changed_topic':
+ return `changed topic to: ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
default:
return '';
}
From 051dfe377bbf12655de0978b5cbf276df7094fa2 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:13:45 +0530
Subject: [PATCH 40/76] Display user roles (Admin, Leader, Moderator, Owner)
next to message headers (#738)
---
packages/react/src/views/ChatLayout/ChatLayout.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/ChatLayout/ChatLayout.js b/packages/react/src/views/ChatLayout/ChatLayout.js
index ee6b0c1b94..60c935a360 100644
--- a/packages/react/src/views/ChatLayout/ChatLayout.js
+++ b/packages/react/src/views/ChatLayout/ChatLayout.js
@@ -38,7 +38,7 @@ const ChatLayout = () => {
const { classNames, styleOverrides } = useComponentOverrides('ChatBody');
const { RCInstance, ECOptions } = useRCContext();
const anonymousMode = ECOptions?.anonymousMode;
- const showRoles = ECOptions?.anonymousMode;
+ const showRoles = ECOptions?.showRoles;
const setStarredMessages = useStarredMessageStore(
(state) => state.setStarredMessages
);
From 470588888738fbb07d1e96cb64f80e7e285aac60 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Wed, 1 Jan 2025 19:24:22 +0530
Subject: [PATCH 41/76] feat: add password visibility toggle feature in API
development portal (#706)
* feat: add password visibility toggle feature in API development portal
* Simplify changes
---------
Co-authored-by: Zishan Ahmad
---
packages/api/playground/index.html | 11 +++++++++++
packages/api/playground/playground.js | 19 +++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/packages/api/playground/index.html b/packages/api/playground/index.html
index 6091350192..d850068e98 100644
--- a/packages/api/playground/index.html
+++ b/packages/api/playground/index.html
@@ -24,6 +24,14 @@
.playground-output #output{
white-space: pre-wrap;
}
+ #togglePassword {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ vertical-align: middle;
+ width: 50px;
+ }
@@ -43,6 +51,9 @@
+
+ Show
+
Sign in
{
`}
>
{attachment.title}
diff --git a/packages/react/src/views/AttachmentHandler/Attachments.js b/packages/react/src/views/AttachmentHandler/Attachments.js
index 35010476a4..f558ad5ec0 100644
--- a/packages/react/src/views/AttachmentHandler/Attachments.js
+++ b/packages/react/src/views/AttachmentHandler/Attachments.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import Attachment from './Attachment';
import RCContext from '../../context/RCInstance';
-const Attachments = ({ attachments, type, variantStyles = {} }) => {
+const Attachments = ({ attachments, type, variantStyles = {}, msg }) => {
const { RCInstance } = useContext(RCContext);
let host = RCInstance.getHost();
host = host.replace(/\/$/, '');
@@ -15,6 +15,7 @@ const Attachments = ({ attachments, type, variantStyles = {} }) => {
host={host}
variantStyles={variantStyles}
type={type}
+ msg={msg}
/>
));
};
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index 0f5824aa0f..b88d0a41da 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -5,7 +5,14 @@ import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import AttachmentMetadata from './AttachmentMetadata';
import RCContext from '../../context/RCInstance';
-const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
+const AudioAttachment = ({
+ attachment,
+ host,
+ type,
+ author,
+ variantStyles,
+ msg,
+}) => {
const { RCInstance } = useContext(RCContext);
const { theme } = useTheme();
const getUserAvatarUrl = (icon) => {
@@ -58,6 +65,7 @@ const AudioAttachment = ({ attachment, host, type, author, variantStyles }) => {
attachment={attachment}
url={host + (attachment.title_url || attachment.audio_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index b9e6533ad4..04a2addc49 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -12,6 +12,7 @@ const ImageAttachment = ({
type,
author,
variantStyles = {},
+ msg,
}) => {
const { RCInstance } = useContext(RCContext);
const [showGallery, setShowGallery] = useState(false);
@@ -75,6 +76,7 @@ const ImageAttachment = ({
attachment={attachment}
url={host + (attachment.title_link || attachment.image_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
{
const { RCInstance } = useContext(RCContext);
const { theme } = useTheme();
@@ -74,6 +75,7 @@ const VideoAttachment = ({
attachment={attachment}
url={host + (attachment.title_url || attachment.video_url)}
variantStyles={variantStyles}
+ msg={msg}
/>
@@ -101,14 +126,32 @@ const AttachmentPreview = () => {
>
File description
- {
- handleFileDescription(e);
- }}
- value={fileDescription}
- css={styles.input}
- placeholder="Description"
- />
+
+
+ {showMembersList && (
+
+ )}
+
+ {
+ handleFileDescription(e);
+ }}
+ css={styles.input}
+ placeholder="Description"
+ ref={messageRef}
+ />
+
diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
index 44729be847..45f8cf455a 100644
--- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
+++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.styles.js
@@ -11,7 +11,7 @@ const getAttachmentPreviewStyles = () => {
`,
input: css`
- width: 95.5%;
+ width: 100%;
`,
modalContent: css`
@@ -19,6 +19,22 @@ const getAttachmentPreviewStyles = () => {
overflow-x: hidden;
max-height: 350px;
`,
+
+ fileDescription: css`
+ width: 100%;
+ position: relative;
+ z-index: 1300;
+ `,
+
+ mentionListContainer: css`
+ position: absolute;
+ top: -100px;
+ width: 100%;
+ max-height: 100px;
+ overflow-y: auto;
+ background: white;
+ z-index: 1400;
+ `,
};
return styles;
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 86b4b5082a..91fc98deca 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -469,18 +469,23 @@ const ChatInput = ({ scrollToBottom }) => {
}
/>
) : null}
-
- {showMembersList && (
-
- )}
+
+ {showMembersList && (
+
+ )}
+
{showCommandList && (
{
+const Markdown = ({ body, md, isReaction = false }) => {
const members = useMemberStore((state) => state.members);
const username = useUserStore((state) => state.username);
const value = useMemo(() => ({ members, username }), [members, username]);
@@ -23,12 +23,12 @@ const Markdown = ({ body, isReaction = false }) => {
);
}
- if (!body || !body.md) return <>>;
+ if (!body || !md) return <>>;
return (
-
+
);
diff --git a/packages/react/src/views/Mentions/MembersList.styles.js b/packages/react/src/views/Mentions/MembersList.styles.js
index e288cae04d..03bc8f4018 100644
--- a/packages/react/src/views/Mentions/MembersList.styles.js
+++ b/packages/react/src/views/Mentions/MembersList.styles.js
@@ -3,7 +3,7 @@ import { css } from '@emotion/react';
const getMemberListStyles = (theme) => {
const styles = {
main: css`
- margin: 0.2rem 2rem;
+ margin: 0.2rem 0rem;
display: block;
overflow: auto;
max-height: 10rem;
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 140cbdc963..2a56b20b76 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -233,14 +233,19 @@ const Message = ({
>
{message.attachments && message.attachments.length > 0 ? (
<>
-
+
>
) : (
-
+
)}
{message.blocks && (
From 3e1360e3302e918a430c053364fda1fe41e155e9 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 11:17:00 +0530
Subject: [PATCH 44/76] Fix: Capitalize the first letter of user roles for
improved UI (#798)
---
packages/react/src/views/Message/MessageHeader.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/Message/MessageHeader.js b/packages/react/src/views/Message/MessageHeader.js
index 594c435113..89206256ea 100644
--- a/packages/react/src/views/Message/MessageHeader.js
+++ b/packages/react/src/views/Message/MessageHeader.js
@@ -127,7 +127,7 @@ const MessageHeader = ({
css={styles.userRole}
className={appendClassNames('ec-message-user-role')}
>
- admin
+ Admin
)}
@@ -138,7 +138,7 @@ const MessageHeader = ({
css={styles.userRole}
className={appendClassNames('ec-message-user-role')}
>
- {role}
+ {role.charAt(0).toUpperCase() + role.slice(1)}
))}
>
From 843adf0836cbb8c6996e805839f4e330e63b7b16 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 11:25:24 +0530
Subject: [PATCH 45/76] Fix bug: Display user roles in MessageAggregator when
showRoles is true (#790)
---
.../src/views/MessageAggregators/common/MessageAggregator.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index c70f3d73a5..241c0aa576 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -17,6 +17,7 @@ import LoadingIndicator from './LoadingIndicator';
import NoMessagesIndicator from './NoMessageIndicator';
import FileDisplay from '../../FileMessage/FileMessage';
import useSetExclusiveState from '../../../hooks/useSetExclusiveState';
+import { useRCContext } from '../../../context/RCInstance';
export const MessageAggregator = ({
title,
@@ -33,6 +34,8 @@ export const MessageAggregator = ({
const { theme } = useTheme();
const styles = getMessageAggregatorStyles(theme);
const setExclusiveState = useSetExclusiveState();
+ const { ECOptions } = useRCContext();
+ const showRoles = ECOptions?.showRoles;
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
const allMessages = useMemo(
@@ -126,7 +129,7 @@ export const MessageAggregator = ({
type="default"
showAvatar
showToolbox={false}
- showRoles={false}
+ showRoles={showRoles}
isInSidebar
style={{
flex: 1,
From 73f8fc08041f9190e541709f178a594f7543dc54 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:42:49 +0530
Subject: [PATCH 46/76] Fix: Disable hover effect for User Action Messages
(#795)
---
packages/react/src/views/Message/Message.js | 18 ++++++++++++++++++
.../react/src/views/Message/Message.styles.js | 9 +--------
2 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 2a56b20b76..03c558c761 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -7,6 +7,8 @@ import {
useComponentOverrides,
appendClassNames,
useTheme,
+ lighten,
+ darken,
} from '@embeddedchat/ui-elements';
import { Attachments } from '../AttachmentHandler';
import { Markdown } from '../Markdown';
@@ -72,8 +74,23 @@ const Message = ({
}));
const isMe = message.u._id === authenticatedUserId;
+
const theme = useTheme();
+ const { mode } = useTheme();
const styles = getMessageStyles(theme);
+ const hasType = Boolean(message.t);
+
+ const hoverStyle = hasType
+ ? {}
+ : {
+ '&:hover': {
+ backgroundColor:
+ mode === 'light'
+ ? darken(theme.theme.colors.background, 0.03)
+ : lighten(theme.theme.colors.background, 1),
+ },
+ };
+
const bubbleStyles = useBubbleStyles(isMe);
const pinRoles = new Set(pinPermissions);
const editMessageRoles = new Set(editMessagePermissions);
@@ -195,6 +212,7 @@ const Message = ({
className={appendClassNames('ec-message', classNames)}
css={[
variantStyles.messageParent || styles.main,
+ hoverStyle,
editMessage._id === message._id && styles.messageEditing,
]}
style={styleOverrides}
diff --git a/packages/react/src/views/Message/Message.styles.js b/packages/react/src/views/Message/Message.styles.js
index 9f9358fd92..8c380d241b 100644
--- a/packages/react/src/views/Message/Message.styles.js
+++ b/packages/react/src/views/Message/Message.styles.js
@@ -1,7 +1,6 @@
import { css } from '@emotion/react';
-import { lighten, darken } from '@embeddedchat/ui-elements';
-export const getMessageStyles = ({ theme, mode }) => {
+export const getMessageStyles = ({ theme }) => {
const styles = {
main: css`
display: flex;
@@ -12,12 +11,6 @@ export const getMessageStyles = ({ theme, mode }) => {
padding-left: 2.25rem;
padding-right: 2.25rem;
color: ${theme.colors.foreground};
-
- &:hover {
- background-color: ${mode === 'light'
- ? darken(theme.colors.background, 0.03)
- : lighten(theme.colors.background, 1)};
- }
`,
messageEditing: css`
background-color: ${theme.colors.secondary};
From dd0657f299412a71c6a9950aeda91240ad1c368c Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:44:55 +0530
Subject: [PATCH 47/76] fix: jump to message highlights the element (#748)
* add highlight color
* lint
* consume theme
---
.../views/MessageAggregators/common/MessageAggregator.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 241c0aa576..3411d54107 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -54,7 +54,11 @@ export const MessageAggregator = ({
const element = document.getElementById(`ec-message-body-${msgId}`);
if (element) {
setShowSidebar(false);
- element.scrollIntoView({ behavior: 'smooth', block: 'center' });
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
}
}
};
From bd6cefb81da9d8b3fb5d1a30453364065fdb29b5 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:45:42 +0530
Subject: [PATCH 48/76] Fix: The 'Copy' option functionality is now working for
File messages (#716)
* Fix: 'Copy' option functionality is not working for File messages
* Updated logic with copy file name in case of description not present
---
packages/react/src/views/Message/Message.js | 30 ++++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index 03c558c761..fa8c864fec 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -138,20 +138,24 @@ const Message = ({
};
const handleCopyMessage = async (msg) => {
- navigator.clipboard
- .writeText(msg.msg)
- .then(() => {
- dispatchToastMessage({
- type: 'success',
- message: 'Message copied successfully',
- });
- })
- .catch(() => {
- dispatchToastMessage({
- type: 'error',
- message: 'Error in copying message',
- });
+ const textToCopy =
+ msg.msg ||
+ (msg.attachments && msg.attachments[0]
+ ? msg.attachments[0].description || msg.attachments[0].title
+ : '');
+
+ try {
+ await navigator.clipboard.writeText(textToCopy);
+ dispatchToastMessage({
+ type: 'success',
+ message: 'Message copied successfully',
});
+ } catch (error) {
+ dispatchToastMessage({
+ type: 'error',
+ message: 'Error in copying message',
+ });
+ }
};
const getMessageLink = async (id) => {
From 12cefd6a031645ac77673484ad5ba70dd90ee586 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sun, 5 Jan 2025 15:56:08 +0530
Subject: [PATCH 49/76] feat: Add Syntax Highlighting to Multiline Code Blocks
using react-syntax-highlighter (#764)
* add code syntax highlighting
* Run prettier
* remove unecessary space in package.json
* Make multiline code occupy full width
* use react-syntax-highlighter
* Remove theme state and useEffect
---
packages/markups/package.json | 3 +-
packages/markups/src/elements/CodeBlock.js | 19 +++++--
packages/markups/src/elements/CodeElement.js | 14 +++--
.../markups/src/elements/elements.styles.js | 57 +++++++++++++------
yarn.lock | 24 ++++++++
5 files changed, 89 insertions(+), 28 deletions(-)
diff --git a/packages/markups/package.json b/packages/markups/package.json
index 3b09bc97fc..2c617f5266 100644
--- a/packages/markups/package.json
+++ b/packages/markups/package.json
@@ -76,6 +76,7 @@
"@emotion/react": "11.7.1",
"@rollup/plugin-json": "^6.0.0",
"emoji-toolkit": "^7.0.1",
- "prop-types": "^15.8.1"
+ "prop-types": "^15.8.1",
+ "react-syntax-highlighter": "^15.6.1"
}
}
diff --git a/packages/markups/src/elements/CodeBlock.js b/packages/markups/src/elements/CodeBlock.js
index b8f5acf133..54bad69fcb 100644
--- a/packages/markups/src/elements/CodeBlock.js
+++ b/packages/markups/src/elements/CodeBlock.js
@@ -1,9 +1,13 @@
-import React, { useMemo } from 'react';
+import React, { useMemo, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
-import { CodeBlockStyles as styles } from './elements.styles';
+import { Box, useTheme } from '@embeddedchat/ui-elements';
+import SyntaxHighlighter from 'react-syntax-highlighter';
+import { vs, monokai } from 'react-syntax-highlighter/dist/esm/styles/hljs';
+import { CodeBlockStyles } from './elements.styles';
const CodeBlock = ({ lines }) => {
+ const { mode } = useTheme();
+ const styles = CodeBlockStyles();
const code = useMemo(
() => lines.map((line) => line.value.value).join('\n'),
[lines]
@@ -14,7 +18,13 @@ const CodeBlock = ({ lines }) => {
```
- {code}
+
+ {code}
+
```
@@ -23,7 +33,6 @@ const CodeBlock = ({ lines }) => {
};
export default CodeBlock;
-
CodeBlock.propTypes = {
lines: PropTypes.any,
};
diff --git a/packages/markups/src/elements/CodeElement.js b/packages/markups/src/elements/CodeElement.js
index 043f5a2a00..8a2483f17f 100644
--- a/packages/markups/src/elements/CodeElement.js
+++ b/packages/markups/src/elements/CodeElement.js
@@ -1,12 +1,16 @@
import React from 'react';
import PropTypes from 'prop-types';
import PlainSpan from './PlainSpan';
+import { InlineElementsStyles } from './elements.styles';
-const CodeElement = ({ contents }) => (
-
-
-
-);
+const CodeElement = ({ contents }) => {
+ const styles = InlineElementsStyles();
+ return (
+
+
+
+ );
+};
export default CodeElement;
diff --git a/packages/markups/src/elements/elements.styles.js b/packages/markups/src/elements/elements.styles.js
index aa44d77dd1..2f1f2fb295 100644
--- a/packages/markups/src/elements/elements.styles.js
+++ b/packages/markups/src/elements/elements.styles.js
@@ -1,23 +1,46 @@
import { css } from '@emotion/react';
-import { useTheme } from '@embeddedchat/ui-elements';
+import { useTheme, darken } from '@embeddedchat/ui-elements';
-export const CodeBlockStyles = {
- copyonly: css`
- display: none;
- width: 100%;
- height: 0;
- user-select: none;
- vertical-align: baseline;
- font-size: 0;
- -moz-box-orient: vertical;
- `,
+export const InlineElementsStyles = () => {
+ const { theme } = useTheme();
+ const styles = {
+ inlineElement: css`
+ font-weight: 600;
+ font-size: 0.75rem;
+ width: fit-content;
+ padding: 3px;
+ background-color: ${theme.colors.border};
+ border-radius: 6px;
+ `,
+ };
+ return styles;
+};
+export const CodeBlockStyles = () => {
+ const { theme } = useTheme();
+ const styles = {
+ copyonly: css`
+ display: none;
+ width: 100%;
+ height: 0;
+ user-select: none;
+ vertical-align: baseline;
+ font-size: 0;
+ -moz-box-orient: vertical;
+ `,
- prestyle: css`
- display: inline-block;
- max-width: 100%;
- overflow-x: auto;
- white-space: pre-wrap;
- `,
+ prestyle: css`
+ display: inline-block;
+ width: 100%;
+ overflow-x: auto;
+ white-space: pre-wrap;
+ `,
+ codeBlock: css`
+ background-color: ${darken(theme.colors.accent, 0.01)} !important;
+ border-radius: ${theme.radius};
+ font-weight: 600;
+ `,
+ };
+ return styles;
};
export const ColorElementStyles = {
diff --git a/yarn.lock b/yarn.lock
index 39464bc873..585c7d5679 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2366,6 +2366,7 @@ __metadata:
prop-types: ^15.8.1
react: ^17.0.2
react-dom: ^17.0.2
+ react-syntax-highlighter: ^15.6.1
rimraf: ^5.0.1
rollup: ^2.70.1
rollup-plugin-analyzer: ^4.0.0
@@ -18694,6 +18695,13 @@ __metadata:
languageName: node
linkType: hard
+"highlightjs-vue@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "highlightjs-vue@npm:1.0.0"
+ checksum: 895f2dd22c93a441aca7df8d21f18c00697537675af18832e50810a071715f79e45eda677e6244855f325234c6a06f7bd76f8f20bd602040fc350c80ac7725e4
+ languageName: node
+ linkType: hard
+
"hmac-drbg@npm:^1.0.1":
version: 1.0.1
resolution: "hmac-drbg@npm:1.0.1"
@@ -27213,6 +27221,22 @@ __metadata:
languageName: node
linkType: hard
+"react-syntax-highlighter@npm:^15.6.1":
+ version: 15.6.1
+ resolution: "react-syntax-highlighter@npm:15.6.1"
+ dependencies:
+ "@babel/runtime": ^7.3.1
+ highlight.js: ^10.4.1
+ highlightjs-vue: ^1.0.0
+ lowlight: ^1.17.0
+ prismjs: ^1.27.0
+ refractor: ^3.6.0
+ peerDependencies:
+ react: ">= 0.14.0"
+ checksum: 417b6f1f2e0c1e00dcc12d34da457b94c7419345306a951d0a8d2d031a0c964179d6b700137870ad1397572cbc3a4454e94de7bbef914a81674edae2098f02dc
+ languageName: node
+ linkType: hard
+
"react@npm:18.2.0, react@npm:^18.2.0":
version: 18.2.0
resolution: "react@npm:18.2.0"
From 9352c030224059a865a7c0da1905e3940824ce86 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 16:17:56 +0530
Subject: [PATCH 50/76] Feat: Added 'Collapse & Uncollapse' Functionality for
Audio, Video Messages & Image attachment (#772)
* BUG: Fix extra top space for audio and video messages to improve UI consistency
* Fix: Add padding for audio and video messages in nested attachments and quotes
* added conditional CSS handling the description present or absent case
* Same logic for conditional CSS but written in better way
* Feat: Add 'Collapse & Uncollapse' functionality for Audio and Video messages
* Feat: Add 'Collapse & Uncollapse' functionality
* Feat: Add 'Collapse & Uncollapse' functionality
* Added Collapse & Uncollapse Functionality for Image Attachment
* Using chevron-down, chevron-left instead of arrow-down, arrow-right
---
.../AttachmentHandler/AttachmentMetadata.js | 19 +++++++++-
.../AttachmentHandler/AudioAttachment.js | 14 ++++++-
.../AttachmentHandler/ImageAttachment.js | 30 ++++++++++-----
.../AttachmentHandler/VideoAttachment.js | 38 ++++++++++++-------
4 files changed, 74 insertions(+), 27 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
index 5bd249ce5e..390cab7b71 100644
--- a/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
+++ b/packages/react/src/views/AttachmentHandler/AttachmentMetadata.js
@@ -3,7 +3,14 @@ import { css } from '@emotion/react';
import { ActionButton, Box } from '@embeddedchat/ui-elements';
import { Markdown } from '../Markdown';
-const AttachmentMetadata = ({ attachment, url, variantStyles = {}, msg }) => {
+const AttachmentMetadata = ({
+ attachment,
+ url,
+ variantStyles = {},
+ msg,
+ onExpandCollapseClick,
+ isExpanded,
+}) => {
const handleDownload = async () => {
try {
const response = await fetch(url);
@@ -78,6 +85,16 @@ const AttachmentMetadata = ({ attachment, url, variantStyles = {}, msg }) => {
>
{attachment.title}
+
{
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
-
+ {isExpanded && (
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
diff --git a/packages/react/src/views/AttachmentHandler/ImageAttachment.js b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
index 04a2addc49..5f95829df0 100644
--- a/packages/react/src/views/AttachmentHandler/ImageAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/ImageAttachment.js
@@ -30,10 +30,14 @@ const ImageAttachment = ({
const { authorIcon, authorName } = author;
+ const [isExpanded, setIsExpanded] = useState(true);
+ const toggleExpanded = () => {
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
setShowGallery(true)}
css={[
css`
cursor: pointer;
@@ -77,16 +81,22 @@ const ImageAttachment = ({
url={host + (attachment.title_link || attachment.image_url)}
variantStyles={variantStyles}
msg={msg}
+ onExpandCollapseClick={toggleExpanded}
+ isExpanded={isExpanded}
/>
-
+ {isExpanded && (
+ setShowGallery(true)}>
+
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 0b364b1a2d..4407481ee4 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -1,4 +1,4 @@
-import React, { useContext } from 'react';
+import React, { useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
@@ -31,6 +31,12 @@ const VideoAttachment = ({
return URL;
};
const { authorIcon, authorName } = author;
+
+ const [isExpanded, setIsExpanded] = useState(true);
+ const toggleExpanded = () => {
+ setIsExpanded((prevState) => !prevState);
+ };
+
return (
-
+ {isExpanded && (
+
+ )}
{attachment.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
From ad7fefd70556d6f7d97dda26d24d45bb733b3a5a Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Sun, 5 Jan 2025 16:25:06 +0530
Subject: [PATCH 51/76] fix (#704)
---
packages/react/src/views/Message/MessageToolbox.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 710be2b5a2..f276ef82cf 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -129,7 +129,7 @@ export const MessageToolbox = ({
id: 'pin',
onClick: () => handlePinMessage(message),
iconName: message.pinned ? 'pin-filled' : 'pin',
- visible: !isThreadMessage && isAllowedToPin,
+ visible: isAllowedToPin,
},
edit: {
label: 'Edit',
From 836a83ee8125c33cf412d0d77d6db0003140e3fb Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 16:38:31 +0530
Subject: [PATCH 52/76] Attachmentwindow for audio & video messages (#770)
---
.../views/ChatInput/AudioMessageRecorder.js | 29 +++++++------------
.../views/ChatInput/VideoMessageRecoder.js | 28 ++++++------------
2 files changed, 19 insertions(+), 38 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index caef86e700..1d3af014fc 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -1,15 +1,9 @@
-import React, {
- useState,
- useEffect,
- useCallback,
- useContext,
- useRef,
-} from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Box, Icon, ActionButton, useTheme } from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
-import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
+import useAttachmentWindowStore from '../../store/attachmentwindow';
const AudioMessageRecorder = () => {
const videoRef = useRef(null);
@@ -19,13 +13,17 @@ const AudioMessageRecorder = () => {
(state) => state.toogleRecordingMessage
);
- const { RCInstance, ECOptions } = useContext(RCContext);
+ const { toggle, setData } = useAttachmentWindowStore((state) => ({
+ toggle: state.toggle,
+ setData: state.setData,
+ }));
+
const [state, setRecordState] = useState('idle');
const [time, setTime] = useState('00:00');
const [recordingInterval, setRecordingInterval] = useState(null);
const [file, setFile] = useState(null);
const [isRecorded, setIsRecorded] = useState(false);
- const threadId = useMessageStore((_state) => _state.threadMainMessage?._id);
+
const onStop = (audioChunks) => {
const audioBlob = new Blob(audioChunks, { type: 'audio/mpeg' });
const fileName = 'Audio record.mp3';
@@ -120,16 +118,9 @@ const AudioMessageRecorder = () => {
}, [handleMount]);
useEffect(() => {
- const sendRecording = async () => {
- await RCInstance.sendAttachment(
- file,
- undefined,
- undefined,
- ECOptions.enableThreads ? threadId : undefined
- );
- };
if (isRecorded && file) {
- sendRecording();
+ toggle();
+ setData(file);
setIsRecorded(false);
}
if (file) {
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 4d5b00810d..2fbe2bb149 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -1,10 +1,4 @@
-import React, {
- useState,
- useEffect,
- useCallback,
- useContext,
- useRef,
-} from 'react';
+import React, { useState, useEffect, useCallback, useRef } from 'react';
import { css } from '@emotion/react';
import {
Box,
@@ -14,9 +8,9 @@ import {
useTheme,
} from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
-import RCContext from '../../context/RCInstance';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
+import useAttachmentWindowStore from '../../store/attachmentwindow';
const VideoMessageRecorder = () => {
const videoRef = useRef(null);
@@ -27,13 +21,16 @@ const VideoMessageRecorder = () => {
(state) => state.toogleRecordingMessage
);
- const { RCInstance, ECOptions } = useContext(RCContext);
+ const { toggle, setData } = useAttachmentWindowStore((state) => ({
+ toggle: state.toggle,
+ setData: state.setData,
+ }));
+
const [state, setRecordState] = useState('idle');
const [time, setTime] = useState('00:00');
const [recordingInterval, setRecordingInterval] = useState(null);
const [file, setFile] = useState(null);
const [isRecorded, setIsRecorded] = useState(false);
- const threadId = useMessageStore((_state) => _state.threadMainMessage?._id);
const onStop = (videoChunks) => {
const videoBlob = new Blob(videoChunks, { type: 'video/mp4' });
@@ -135,16 +132,9 @@ const VideoMessageRecorder = () => {
}, [handleMount]);
useEffect(() => {
- const sendRecording = async () => {
- await RCInstance.sendAttachment(
- file,
- undefined,
- undefined,
- ECOptions.enableThreads ? threadId : undefined
- );
- };
if (isRecorded && file) {
- sendRecording();
+ toggle();
+ setData(file);
setIsRecorded(false);
}
if (file) {
From a8f3226186369d3f9eb435d98e85911737b45738 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sun, 5 Jan 2025 21:28:08 +0530
Subject: [PATCH 53/76] Fix: Prevent click actions when disabled (#736)
---
.../react/src/views/ChatInput/AudioMessageRecorder.js | 10 ++++++++--
.../src/views/ChatInput/ChatInputFormattingToolbar.js | 11 ++++++++---
.../react/src/views/ChatInput/VideoMessageRecoder.js | 10 ++++++++--
3 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 1d3af014fc..8f2287569b 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -5,7 +5,7 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const AudioMessageRecorder = () => {
+const AudioMessageRecorder = ({ disabled }) => {
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -47,6 +47,7 @@ const AudioMessageRecorder = () => {
};
const handleRecordButtonClick = () => {
+ if (disabled) return;
setRecordState('recording');
try {
start();
@@ -130,7 +131,12 @@ const AudioMessageRecorder = () => {
if (state === 'idle') {
return (
-
+
);
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 851034833d..0097471058 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -80,6 +80,7 @@ const ChatInputFormattingToolbar = ({
ghost
disabled={isRecordingMessage}
onClick={() => {
+ if (isRecordingMessage) return;
setEmojiOpen(true);
}}
>
@@ -89,12 +90,12 @@ const ChatInputFormattingToolbar = ({
),
audio: (
-
+
),
video: (
-
+
),
file: (
@@ -103,7 +104,10 @@ const ChatInputFormattingToolbar = ({
square
ghost
disabled={isRecordingMessage}
- onClick={handleClickToOpenFiles}
+ onClick={() => {
+ if (isRecordingMessage) return;
+ handleClickToOpenFiles();
+ }}
>
@@ -132,6 +136,7 @@ const ChatInputFormattingToolbar = ({
disabled={isRecordingMessage}
ghost
onClick={() => {
+ if (isRecordingMessage) return;
formatSelection(messageRef, item.pattern);
}}
>
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 2fbe2bb149..911df74c69 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -12,7 +12,7 @@ import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
import useAttachmentWindowStore from '../../store/attachmentwindow';
-const VideoMessageRecorder = () => {
+const VideoMessageRecorder = ({ disabled }) => {
const videoRef = useRef(null);
const { theme } = useTheme();
const styles = getCommonRecorderStyles(theme);
@@ -55,6 +55,7 @@ const VideoMessageRecorder = () => {
};
const handleRecordButtonClick = () => {
+ if (disabled) return;
setRecordState('recording');
try {
start(videoRef.current);
@@ -145,7 +146,12 @@ const VideoMessageRecorder = () => {
return (
<>
{state === 'idle' && (
-
+
)}
From f0a94a7d155a5087d71dcaed03ffa9425f0ae78d Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Wed, 8 Jan 2025 20:34:50 +0530
Subject: [PATCH 54/76] Feat: Add cursor pointer on scrollbar thumb hover
(#835)
---
packages/react/src/views/GlobalStyles.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/react/src/views/GlobalStyles.js b/packages/react/src/views/GlobalStyles.js
index c9c821feff..ca4d72fa97 100644
--- a/packages/react/src/views/GlobalStyles.js
+++ b/packages/react/src/views/GlobalStyles.js
@@ -30,6 +30,7 @@ const getGlobalStyles = (theme) => css`
.ec-embedded-chat ::-webkit-scrollbar-thumb:hover {
background: ${theme.colors.primary};
+ cursor: pointer;
}
.ec-embedded-chat ::-webkit-scrollbar-button {
From 4d80839c275d921e44ea8e33c757af96dc28e6b7 Mon Sep 17 00:00:00 2001
From: Smriti Doneria
Date: Wed, 8 Jan 2025 21:22:29 +0530
Subject: [PATCH 55/76] Fix arrow redirection for thread messages in starred
message modal (#833)
* fix redirection
* fix
---
.../common/MessageAggregator.js | 56 +++++++++++++++----
1 file changed, 46 insertions(+), 10 deletions(-)
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index 3411d54107..d6ec35541a 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -1,5 +1,5 @@
import React, { useState, useMemo } from 'react';
-import { isSameDay, format } from 'date-fns';
+import { isSameDay, format, set } from 'date-fns';
import {
Box,
Sidebar,
@@ -49,16 +49,52 @@ export const MessageAggregator = ({
);
const setShowSidebar = useSidebarStore((state) => state.setShowSidebar);
- const setJumpToMessage = (msgId) => {
+ const openThread = useMessageStore((state) => state.openThread);
+ const closeThread = useMessageStore((state) => state.closeThread);
+
+ const setJumpToMessage = (msg) => {
+ if (!msg || !msg._id) {
+ console.error('Invalid message object:', msg);
+ return;
+ }
+ const { _id: msgId, tmid: threadId } = msg;
if (msgId) {
- const element = document.getElementById(`ec-message-body-${msgId}`);
- if (element) {
- setShowSidebar(false);
- element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
- element.style.backgroundColor = theme.colors.warning;
+ let element;
+ if (threadId) {
+ const parentMessage = messages.find((m) => m._id === threadId);
+ if (parentMessage) {
+ closeThread();
+ setTimeout(() => {
+ openThread(parentMessage);
+ setShowSidebar(false);
+ setTimeout(() => {
+ element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ element.scrollIntoView({
+ behavior: 'smooth',
+ block: 'nearest',
+ });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
+ }
+ }, 300);
+ }, 300);
+ }
+ } else {
+ closeThread();
setTimeout(() => {
- element.style.backgroundColor = '';
- }, 1000);
+ element = document.getElementById(`ec-message-body-${msgId}`);
+ if (element) {
+ setShowSidebar(false);
+ element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
+ element.style.backgroundColor = theme.colors.warning;
+ setTimeout(() => {
+ element.style.backgroundColor = '';
+ }, 1000);
+ }
+ }, 300);
}
}
};
@@ -146,7 +182,7 @@ export const MessageAggregator = ({
setJumpToMessage(msg._id)}
+ onClick={() => setJumpToMessage(msg)}
css={{
position: 'relative',
zIndex: 10,
From 7ef302e4d9b7a289d36392903eb6314ec9cdb472 Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:39:31 +0530
Subject: [PATCH 56/76] fix: ensure Admin role tag is visible to all users in
channel messages (#784)
---
packages/api/src/EmbeddedChatApi.ts | 35 ++++++++++++++++++++
packages/react/src/hooks/useFetchChatData.js | 8 ++---
2 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index c2fdabb694..408f811c5a 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -605,6 +605,41 @@ export default class EmbeddedChatApi {
}
}
+ async getUserRoles() {
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const response = await fetch(
+ `${this.host}/api/v1/method.call/getUserRoles`,
+ {
+ body: JSON.stringify({
+ message: JSON.stringify({
+ msg: "method",
+ id: null,
+ method: "getUserRoles",
+ params: [],
+ }),
+ }),
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "POST",
+ }
+ );
+
+ const result = await response.json();
+
+ if (result.success && result.message) {
+ const parsedMessage = JSON.parse(result.message);
+ return parsedMessage;
+ }
+ return null;
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
async sendTypingStatus(username: string, typing: boolean) {
try {
this.rcClient.methodCall(
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 9eb04e9bee..583ad431e5 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -55,10 +55,10 @@ const useFetchChatData = (showRoles) => {
if (showRoles) {
const { roles } = await RCInstance.getChannelRoles(isChannelPrivate);
- const fetchedAdmins = await RCInstance.getUsersInRole('admin');
- const adminUsernames = fetchedAdmins?.users?.map(
- (user) => user.username
- );
+ const fetchedRoles = await RCInstance.getUserRoles();
+ const fetchedAdmins = fetchedRoles?.result;
+
+ const adminUsernames = fetchedAdmins?.map((user) => user.username);
setAdmins(adminUsernames);
const rolesObj =
From a593589b906a4b1ef80353cef408d00d9a978546 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:50:24 +0530
Subject: [PATCH 57/76] Fix announcement issue (#851)
---
packages/react/src/views/ChatHeader/ChatHeader.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 817ff40975..7e4864adae 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -136,6 +136,7 @@ const ChatHeader = ({
try {
await RCInstance.logout();
setMessages([]);
+ setChannelInfo({});
setShowSidebar(false);
setUserAvatarUrl(null);
useMessageStore.setState({ isMessageLoaded: false });
From 7e3105a8d70986810a9b795798215bb1eb095617 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:53:40 +0530
Subject: [PATCH 58/76] Fix: Prevent Quoting the Same Message Multiple Times
(#800)
* fix multiple quote messages addition and deletion
* revert removeQuoteMessage
---
packages/react/src/store/messageStore.js | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 676258c1c4..69d1d2b73f 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -75,11 +75,17 @@ const useMessageStore = create((set, get) => ({
setEditMessagePermissions: (editMessagePermissions) =>
set((state) => ({ ...state, editMessagePermissions })),
addQuoteMessage: (quoteMessage) =>
- set((state) => ({ quoteMessage: [...state.quoteMessage, quoteMessage] })),
+ set((state) => {
+ const updatedQuoteMessages = state.quoteMessage.filter(
+ (msg) => msg._id !== quoteMessage._id
+ );
+ return { quoteMessage: [...updatedQuoteMessages, quoteMessage] };
+ }),
removeQuoteMessage: (quoteMessage) =>
set((state) => ({
quoteMessage: state.quoteMessage.filter((i) => i !== quoteMessage),
})),
+
clearQuoteMessages: () => set({ quoteMessage: [] }),
setMessageToReport: (messageId) =>
set(() => ({ messageToReport: messageId })),
From 2f833441a10643b19f12cf1c235b952ba0e654db Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 16:54:12 +0530
Subject: [PATCH 59/76] fix delete modal content and markdown issues (#774)
Co-authored-by: Zishan Ahmad
---
.../views/AttachmentHandler/TextAttachment.js | 37 ++++++++---
.../react/src/views/Message/MessageToolbox.js | 64 +++++++++++++++++--
.../src/views/QuoteMessage/QuoteMessage.js | 4 +-
3 files changed, 87 insertions(+), 18 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/TextAttachment.js b/packages/react/src/views/AttachmentHandler/TextAttachment.js
index bc79b8c5c4..b8477cd8bb 100644
--- a/packages/react/src/views/AttachmentHandler/TextAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/TextAttachment.js
@@ -3,6 +3,7 @@ import { css } from '@emotion/react';
import PropTypes from 'prop-types';
import { Box, Avatar, useTheme } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
+import { Markdown } from '../Markdown';
const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
const { RCInstance } = useContext(RCContext);
@@ -62,11 +63,19 @@ const TextAttachment = ({ attachment, type, variantStyles = {} }) => {
white-space: pre-line;
`}
>
- {attachment?.text
- ? attachment.text[0] === '['
- ? attachment.text.match(/\n(.*)/)?.[1] || ''
- : attachment.text
- : ''}
+ {attachment?.text ? (
+ attachment.text[0] === '[' ? (
+ attachment.text.match(/\n(.*)/)?.[1] || ''
+ ) : (
+
+ )
+ ) : (
+ ''
+ )}
{attachment?.attachments &&
attachment.attachments.map((nestedAttachment, index) => (
{
white-space: pre-line;
`}
>
- {nestedAttachment?.text
- ? nestedAttachment.text[0] === '['
- ? nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
- : nestedAttachment.text
- : ''}
+ {nestedAttachment?.text ? (
+ nestedAttachment.text[0] === '[' ? (
+ nestedAttachment.text.match(/\n(.*)/)?.[1] || ''
+ ) : (
+
+ )
+ ) : (
+ ''
+ )}
))}
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index f276ef82cf..34752872eb 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -1,4 +1,4 @@
-import React, { useState, useMemo } from 'react';
+import React, { useState, useContext, useMemo } from 'react';
import {
Box,
Modal,
@@ -9,10 +9,12 @@ import {
appendClassNames,
useTheme,
} from '@embeddedchat/ui-elements';
+import RCContext from '../../context/RCInstance';
import { EmojiPicker } from '../EmojiPicker';
import { getMessageToolboxStyles } from './Message.styles';
import SurfaceMenu from '../SurfaceMenu/SurfaceMenu';
import { Markdown } from '../Markdown';
+import Attachment from '../AttachmentHandler/Attachment';
export const MessageToolbox = ({
className = '',
@@ -59,6 +61,8 @@ export const MessageToolbox = ({
className,
style
);
+ const { RCInstance } = useContext(RCContext);
+ const instanceHost = RCInstance.getHost();
const { theme } = useTheme();
const styles = getMessageToolboxStyles(theme);
const surfaceItems =
@@ -269,13 +273,61 @@ export const MessageToolbox = ({
-
+ {message.file ? (
+ message.file.type.startsWith('image/') ? (
+
+

+
{`${message.file.name} (${(
+ message.file.size / 1024
+ ).toFixed(2)} kB)`}
+
+ ) : message.file.type.startsWith('video/') ? (
+
+ ) : message.file.type.startsWith('audio/') ? (
+
+ ) : (
+
+ )
+ ) : (
+
+ )}
+ {message.attachments &&
+ message.attachments.length > 0 &&
+ message.msg &&
+ message.msg[0] === '[' &&
+ message.attachments.map((attachment, index) => (
+
+ ))}
diff --git a/packages/react/src/views/QuoteMessage/QuoteMessage.js b/packages/react/src/views/QuoteMessage/QuoteMessage.js
index 2a402da43a..7fd9634e04 100644
--- a/packages/react/src/views/QuoteMessage/QuoteMessage.js
+++ b/packages/react/src/views/QuoteMessage/QuoteMessage.js
@@ -85,7 +85,7 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
) : (
{message.msg ? (
-
+
) : (
`${message.file?.name} (${
message.file?.size ? (message.file.size / 1024).toFixed(2) : 0
@@ -96,7 +96,7 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
) : message?.msg[0] === '[' ? (
message?.msg.match(/\n(.*)/)[1]
) : (
-
+
)}
{message.attachments &&
message.attachments.length > 0 &&
From dc2c2dd58430773fa599a94656980fc30a46ccdf Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:03:10 +0530
Subject: [PATCH 60/76] fix: thread message issue (#860)
* fix thread message issue
* Fix aggregator issue
---
packages/api/src/EmbeddedChatApi.ts | 26 ++--
packages/react/src/views/ChatBody/ChatBody.js | 2 +-
.../common/MessageAggregator.js | 113 +++++++++---------
.../src/views/MessageList/MessageList.js | 6 +-
4 files changed, 80 insertions(+), 67 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 408f811c5a..2f843a1cd8 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -553,15 +553,23 @@ export default class EmbeddedChatApi {
}
async getThreadMessages(tmid: string, isChannelPrivate = false) {
- return this.getMessages(
- false,
- {
- query: {
- tmid,
- },
- },
- isChannelPrivate
- );
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const messages = await fetch(
+ `${this.host}/api/v1/chat.getThreadMessages?roomId=${this.rid}&tmid=${tmid}`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "GET",
+ }
+ );
+ return await messages.json();
+ } catch (err) {
+ console.log(err);
+ }
}
async getChannelRoles(isChannelPrivate = false) {
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index 721c2d2dc1..940b63e9bb 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -91,7 +91,7 @@ const ChatBody = ({
threadMainMessage._id,
isChannelPrivate
);
- setThreadMessages(messages);
+ setThreadMessages(messages.reverse());
} catch (e) {
console.error(e);
}
diff --git a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
index d6ec35541a..56d52a08c3 100644
--- a/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
+++ b/packages/react/src/views/MessageAggregators/common/MessageAggregator.js
@@ -39,9 +39,10 @@ export const MessageAggregator = ({
const messages = useMessageStore((state) => state.messages);
const threadMessages = useMessageStore((state) => state.threadMessages) || [];
const allMessages = useMemo(
- () => [...messages, ...threadMessages],
+ () => [...messages, ...[...threadMessages].reverse()],
[messages, threadMessages]
);
+
const [messageRendered, setMessageRendered] = useState(false);
const { loading, messageList } = useSetMessageList(
fetchedMessageList || searchFiltered || allMessages,
@@ -137,65 +138,67 @@ export const MessageAggregator = ({
)}
- {messageList.map((msg, index, arr) => {
- const newDay = isMessageNewDay(msg, arr[index - 1]);
- if (!messageRendered && shouldRender(msg)) {
- setMessageRendered(true);
- }
+ {[...new Map(messageList.map((msg) => [msg._id, msg])).values()].map(
+ (msg, index, arr) => {
+ const newDay = isMessageNewDay(msg, arr[index - 1]);
+ if (!messageRendered && shouldRender(msg)) {
+ setMessageRendered(true);
+ }
- return (
-
- {type === 'message' && newDay && (
-
- {format(new Date(msg.ts), 'MMMM d, yyyy')}
-
- )}
- {type === 'file' ? (
-
- ) : (
-
-
+ {type === 'message' && newDay && (
+
+ {format(new Date(msg.ts), 'MMMM d, yyyy')}
+
+ )}
+ {type === 'file' ? (
+
-
- setJumpToMessage(msg)}
- css={{
- position: 'relative',
- zIndex: 10,
- marginRight: '5px',
+ ) : (
+
-
-
-
- )}
-
- );
- })}
+
+
+ setJumpToMessage(msg)}
+ css={{
+ position: 'relative',
+ zIndex: 10,
+ marginRight: '5px',
+ }}
+ >
+
+
+
+ )}
+
+ );
+ }
+ )}
)}
diff --git a/packages/react/src/views/MessageList/MessageList.js b/packages/react/src/views/MessageList/MessageList.js
index 14521affd0..29a489be0e 100644
--- a/packages/react/src/views/MessageList/MessageList.js
+++ b/packages/react/src/views/MessageList/MessageList.js
@@ -17,9 +17,11 @@ const MessageList = ({ messages }) => {
const isMessageNewDay = (current, previous) =>
!previous || !isSameDay(new Date(current.ts), new Date(previous.ts));
+ const filteredMessages = messages.filter((msg) => !msg.tmid);
+
return (
<>
- {messages.length === 0 ? (
+ {filteredMessages.length === 0 ? (
{
) : (
<>
- {messages.map((msg, index, arr) => {
+ {filteredMessages.map((msg, index, arr) => {
const prev = arr[index + 1];
const next = arr[index - 1];
From 8b05419c9f880ea316006bf949c303da595f9351 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:06:35 +0530
Subject: [PATCH 61/76] Fix: Add channel-name in msgBox (#857)
* add channel-name in msgBox
* fix
---
packages/react/src/views/ChatInput/ChatInput.js | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index 91fc98deca..aca2de0ac7 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -75,10 +75,13 @@ const ChatInput = ({ scrollToBottom }) => {
name: state.name,
}));
- const { isChannelPrivate, isChannelReadOnly } = useChannelStore((state) => ({
- isChannelPrivate: state.isChannelPrivate,
- isChannelReadOnly: state.isChannelReadOnly,
- }));
+ const { isChannelPrivate, isChannelReadOnly, channelInfo } = useChannelStore(
+ (state) => ({
+ isChannelPrivate: state.isChannelPrivate,
+ isChannelReadOnly: state.isChannelReadOnly,
+ channelInfo: state.channelInfo,
+ })
+ );
const { members, setMembersHandler } = useMemberStore((state) => ({
members: state.members,
@@ -514,7 +517,7 @@ const ChatInput = ({ scrollToBottom }) => {
disabled={!isUserAuthenticated || !canSendMsg || isRecordingMessage}
placeholder={
isUserAuthenticated && canSendMsg
- ? 'Message'
+ ? `Message #${channelInfo.name}`
: isUserAuthenticated
? 'This room is read only'
: 'Sign in to chat'
From 727800ae4b70457d7fee2fe54ba32dd9071901c4 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 17:07:43 +0530
Subject: [PATCH 62/76] Feat: Add icon showing private channel (#867)
* add lock icon
* add icon
* add lock file
* fix size of headerIcon
---
.../react/src/views/ChatHeader/ChatHeader.js | 8 ++++++--
.../src/views/RoomInformation/RoomInformation.js | 15 ++++++++++++++-
.../RoomInformation/RoomInformation.styles.js | 2 ++
.../src/components/Icon/icons/HashLock.js | 16 ++++++++++++++++
.../src/components/Icon/icons/Lock.js | 15 +++++++++++++++
.../src/components/Icon/icons/index.js | 4 ++++
packages/ui-elements/tools/icons-generator.js | 2 ++
7 files changed, 59 insertions(+), 3 deletions(-)
create mode 100644 packages/ui-elements/src/components/Icon/icons/HashLock.js
create mode 100644 packages/ui-elements/src/components/Icon/icons/Lock.js
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 7e4864adae..5f2dbf43ee 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -377,10 +377,14 @@ const ChatHeader = ({
onClick={() => setExclusiveState(setShowChannelinfo)}
>
-
+
{channelInfo.name || channelName || 'channelName'}
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.js b/packages/react/src/views/RoomInformation/RoomInformation.js
index b4e26764c9..ea1d5c7313 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.js
@@ -6,6 +6,7 @@ import {
Sidebar,
Popup,
useComponentOverrides,
+ Icon,
} from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
import { useChannelStore } from '../../store';
@@ -16,6 +17,7 @@ const Roominfo = () => {
const { RCInstance } = useContext(RCContext);
const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
+ const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
const setExclusiveState = useSetExclusiveState();
@@ -55,7 +57,18 @@ const Roominfo = () => {
- # {channelInfo.name}
+
+
+ {channelInfo.name}
+
{channelInfo.description && (
<>
Description
diff --git a/packages/react/src/views/RoomInformation/RoomInformation.styles.js b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
index 9ab039b94a..5925297dcf 100644
--- a/packages/react/src/views/RoomInformation/RoomInformation.styles.js
+++ b/packages/react/src/views/RoomInformation/RoomInformation.styles.js
@@ -16,6 +16,8 @@ const getRoomInformationStyles = () => {
word-wrap: break-word;
overflow-wrap: anywhere;
white-space: normal;
+ opacity: 0.7;
+ font-size: 0.9rem;
`,
};
diff --git a/packages/ui-elements/src/components/Icon/icons/HashLock.js b/packages/ui-elements/src/components/Icon/icons/HashLock.js
new file mode 100644
index 0000000000..d44f815849
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/HashLock.js
@@ -0,0 +1,16 @@
+import React from 'react';
+
+const HashLock = (props) => (
+
+);
+
+export default HashLock;
diff --git a/packages/ui-elements/src/components/Icon/icons/Lock.js b/packages/ui-elements/src/components/Icon/icons/Lock.js
new file mode 100644
index 0000000000..00c234f3a5
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/Lock.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Lock = (props) => (
+
+);
+
+export default Lock;
diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js
index 77cd6a4511..3e23f0667d 100644
--- a/packages/ui-elements/src/components/Icon/icons/index.js
+++ b/packages/ui-elements/src/components/Icon/icons/index.js
@@ -4,6 +4,8 @@ import Star from './Star';
import Pin from './Pin';
import ReplyDirectly from './ReplyDirectly';
import Hash from './Hash';
+import HashLock from './HashLock';
+import Lock from './Lock';
import Computer from './Computer';
import Cross from './Cross';
import Mic from './Mic';
@@ -69,6 +71,8 @@ const icons = {
pin: Pin,
'reply-directly': ReplyDirectly,
hash: Hash,
+ hash_lock: HashLock,
+ lock: Lock,
computer: Computer,
cross: Cross,
copy: Copy,
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 538d42f406..4b2b2e6ca1 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -8,6 +8,8 @@ const iconsList = [
'star',
'reply-directly',
'hash',
+ 'hash_lock',
+ 'lock',
'computer',
'cross',
'mic',
From b8890044cac148b39695864e0981ffe4ec7268a5 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Sat, 11 Jan 2025 21:56:13 +0530
Subject: [PATCH 63/76] fix: video modal responsiveness (#726)
* video modal fix
* Make video modal occupy full space
* make the video modal occupy full size only for smaller screens
* change screen width upper-bound from 500px to 768px
---
packages/react/src/views/ChatInput/ChatInput.styles.js | 8 ++++++++
.../react/src/views/ChatInput/VideoMessageRecoder.js | 9 ++++-----
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.styles.js b/packages/react/src/views/ChatInput/ChatInput.styles.js
index 7aa85e40f1..21e7a24736 100644
--- a/packages/react/src/views/ChatInput/ChatInput.styles.js
+++ b/packages/react/src/views/ChatInput/ChatInput.styles.js
@@ -112,6 +112,14 @@ export const getCommonRecorderStyles = (theme) => {
display: flex;
margin: auto;
`,
+ modal: {
+ '@media(max-width: 768px)': {
+ height: '100%',
+ width: '100%',
+ maxHeight: '100%',
+ maxWidth: '100%',
+ },
+ },
};
return styles;
diff --git a/packages/react/src/views/ChatInput/VideoMessageRecoder.js b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
index 911df74c69..91783d676a 100644
--- a/packages/react/src/views/ChatInput/VideoMessageRecoder.js
+++ b/packages/react/src/views/ChatInput/VideoMessageRecoder.js
@@ -164,10 +164,7 @@ const VideoMessageRecorder = ({ disabled }) => {
);
};
diff --git a/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js b/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
index 3374417f64..e42215564b 100644
--- a/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
+++ b/packages/ui-elements/src/components/StaticSelect/StaticSelect.styles.js
@@ -38,6 +38,15 @@ const getStaticSelectStyles = (theme) => {
cursor: not-allowed !important;
color: ${theme.colors.mutedForeground};
`,
+
+ fileTypeSelect: css`
+ position: absolute;
+ z-index: 10;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ background-color: white;
+ `,
};
return styles;
From bcc7e95e5b9c2f2474fef558652adfec17557565 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Sat, 11 Jan 2025 21:58:25 +0530
Subject: [PATCH 65/76] Feat: Added 'Mentions you' and 'Mentions user' tooltips
for mentioned users & underline on hover (#859)
* Feat: Added Tooltip for Send button & Arrow-back button
* removed tooltip for send button & changed label to Jump to message
* Removed gap between tooltip and tooltipArrow for left position
* Added tooltip styles positioning for left, right positions
* Dynamic Positioning for Tooltip with readable code
* Feat: Add 'Mentions you' and 'Mentions user' tooltips for mentioned users & underline on hover
* Update Tooltip.styles.js
* Update Tooltip.js
* Update MessageAggregator.js
* Added tooltip for all and here mentions
---------
Co-authored-by: Zishan Ahmad
---
packages/markups/src/elements/CodeBlock.js | 2 +-
.../markups/src/elements/elements.styles.js | 7 ++++
packages/markups/src/mentions/UserMention.js | 35 ++++++++++++-------
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/packages/markups/src/elements/CodeBlock.js b/packages/markups/src/elements/CodeBlock.js
index 54bad69fcb..d2d93901ee 100644
--- a/packages/markups/src/elements/CodeBlock.js
+++ b/packages/markups/src/elements/CodeBlock.js
@@ -1,4 +1,4 @@
-import React, { useMemo, useEffect, useState } from 'react';
+import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Box, useTheme } from '@embeddedchat/ui-elements';
import SyntaxHighlighter from 'react-syntax-highlighter';
diff --git a/packages/markups/src/elements/elements.styles.js b/packages/markups/src/elements/elements.styles.js
index 2f1f2fb295..31497a6517 100644
--- a/packages/markups/src/elements/elements.styles.js
+++ b/packages/markups/src/elements/elements.styles.js
@@ -99,6 +99,13 @@ const useMentionStyles = (contents, username) => {
cursor: pointer;
padding: 1.5px;
border-radius: 3px;
+
+ &:hover {
+ text-decoration: underline;
+ text-decoration-color: ${contents.value === username
+ ? theme.colors.destructiveForeground
+ : theme.colors.mutedForeground};
+ }
`,
};
diff --git a/packages/markups/src/mentions/UserMention.js b/packages/markups/src/mentions/UserMention.js
index c860a4d70d..45615e4a1a 100644
--- a/packages/markups/src/mentions/UserMention.js
+++ b/packages/markups/src/mentions/UserMention.js
@@ -1,6 +1,6 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
-import { Box } from '@embeddedchat/ui-elements';
+import { Box, Tooltip } from '@embeddedchat/ui-elements';
import { useUserStore } from '@embeddedchat/react/src/store';
import useSetExclusiveState from '@embeddedchat/react/src/hooks/useSetExclusiveState';
import RCContext from '@embeddedchat/react/src/context/RCInstance';
@@ -27,7 +27,9 @@ const UserMention = ({ contents }) => {
};
const hasMember = (user) => {
- if (user === 'all' || user === 'here') return true;
+ if (user === 'all' || user === 'here') {
+ return true;
+ }
let found = false;
Object.keys(members).forEach((ele) => {
if (members[ele].username === user) {
@@ -39,20 +41,27 @@ const UserMention = ({ contents }) => {
const styles = useMentionStyles(contents, username);
+ const handleClick = () => {
+ if (!['here', 'all'].includes(contents.value)) {
+ handleUserInfo(contents.value);
+ }
+ };
+
+ const tooltipMap = {
+ all: 'Mentions all the room members',
+ here: 'Mentions online room members',
+ [username]: 'Mentions you',
+ };
+ const tooltipText = tooltipMap[contents.value] || 'Mentions user';
+
return (
<>
{hasMember(contents.value) ? (
- handleUserInfo(contents.value)
- }
- >
- {contents.value}
-
+
+
+ {contents.value}
+
+
) : (
`@${contents.value}`
)}
From 8f3bb40f65f4dc46e87839ca56cf9bb8f9bb9415 Mon Sep 17 00:00:00 2001
From: Piyush <157290995+thepiyush-303@users.noreply.github.com>
Date: Sat, 11 Jan 2025 22:10:47 +0530
Subject: [PATCH 66/76] fix: handleNewLine function to properly add new line in
desired location (#838)
* fix shift+enter in messageBox
* lint
---
packages/react/src/views/ChatInput/ChatInput.js | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/ChatInput/ChatInput.js b/packages/react/src/views/ChatInput/ChatInput.js
index aca2de0ac7..33f40d7af3 100644
--- a/packages/react/src/views/ChatInput/ChatInput.js
+++ b/packages/react/src/views/ChatInput/ChatInput.js
@@ -34,7 +34,6 @@ import useShowCommands from '../../hooks/useShowCommands';
import useSearchMentionUser from '../../hooks/useSearchMentionUser';
import formatSelection from '../../lib/formatSelection';
import { parseEmoji } from '../../lib/emoji';
-import { Markdown } from '../Markdown';
const ChatInput = ({ scrollToBottom }) => {
const { styleOverrides, classNames } = useComponentOverrides('ChatInput');
@@ -172,7 +171,15 @@ const ChatInput = ({ scrollToBottom }) => {
};
const handleNewLine = (e, addLine = true) => {
- if (addLine) messageRef.current.value += '\n';
+ if (addLine) {
+ const { selectionStart, selectionEnd, value } = messageRef.current;
+ messageRef.current.value = `${value.substring(
+ 0,
+ selectionStart
+ )}\n${value.substring(selectionEnd)}`;
+ messageRef.current.selectionStart = messageRef.current.selectionEnd;
+ messageRef.current.selectionEnd = selectionStart + 1;
+ }
e.target.style.height = 'auto';
if (e.target.scrollHeight <= 150) {
From 577a1f05cecd900e51e85db20a64c8b65b95bd9b Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 21:41:54 +0530
Subject: [PATCH 67/76] fix:Message notification for avatar change, channel to
team change and team to channel change. (#919)
---
.../react/src/views/Message/MessageHeader.js | 20 ++++++++++++++++---
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/Message/MessageHeader.js b/packages/react/src/views/Message/MessageHeader.js
index 89206256ea..eaaaa54cd0 100644
--- a/packages/react/src/views/Message/MessageHeader.js
+++ b/packages/react/src/views/Message/MessageHeader.js
@@ -68,18 +68,32 @@ const MessageHeader = ({
return 'unarchived room';
case 'room-allowed-reacting':
return 'allowed reactions';
+ case 'room_changed_avatar':
+ return `changed room avatar`;
case 'room_changed_announcement':
- return `changed announcement to: ${
+ return `changed room announcement to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
case 'room_changed_description':
- return `changed description to: ${
+ return `changed room description to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
case 'room_changed_topic':
- return `changed topic to: ${
+ return `changed room topic to: ${
message?.msg && message.msg.length > 0 ? message.msg : '(none)'
}`;
+ case 'r':
+ return `changed room name to ${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ }`;
+ case 'user-converted-to-team':
+ return `converted #${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ } to team`;
+ case 'user-converted-to-channel':
+ return `converted #${
+ message?.msg && message.msg.length > 0 ? message.msg : '(none)'
+ } to channel`;
default:
return '';
}
From db8eb49f40c6eb46cf66f7c5e6947e303036306a Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:16:59 +0530
Subject: [PATCH 68/76] Fix:Formattin toolbar tooltip names according to
rocket.chat (#879)
---
packages/react/src/lib/textFormat.js | 14 +++++++++-----
.../views/ChatInput/ChatInputFormattingToolbar.js | 6 +++++-
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/packages/react/src/lib/textFormat.js b/packages/react/src/lib/textFormat.js
index 10ceb7f33c..a1978c0033 100644
--- a/packages/react/src/lib/textFormat.js
+++ b/packages/react/src/lib/textFormat.js
@@ -1,7 +1,11 @@
export const formatter = [
- { name: 'bold', pattern: '*{{text}}*' },
- { name: 'italic', pattern: '_{{text}}_' },
- { name: 'strike', pattern: '~{{text}}~' },
- { name: 'code', pattern: '`{{text}}`' },
- { name: 'multiline', pattern: '```\n{{text}}\n``` ' },
+ { name: 'bold', pattern: '*{{text}}*', tooltip: 'Bold' },
+ { name: 'italic', pattern: '_{{text}}_', tooltip: 'Italic' },
+ { name: 'strike', pattern: '~{{text}}~', tooltip: 'Strikethrough' },
+ { name: 'code', pattern: '`{{text}}`', tooltip: 'Inline code' },
+ {
+ name: 'multiline',
+ pattern: '```\n{{text}}\n```',
+ tooltip: 'Multi-line code',
+ },
];
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 0097471058..4c72bc4dc6 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -130,7 +130,11 @@ const ChatInputFormattingToolbar = ({
formatter: formatters
.map((name) => formatter.find((item) => item.name === name))
.map((item) => (
-
+
Date: Mon, 27 Jan 2025 22:28:21 +0530
Subject: [PATCH 69/76] Add hover effect to Members section (#847)
---
.../src/views/RoomMembers/RoomMemberItem.js | 7 ++--
.../views/RoomMembers/RoomMembers.styles.js | 36 ++++++++++++-------
2 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/packages/react/src/views/RoomMembers/RoomMemberItem.js b/packages/react/src/views/RoomMembers/RoomMemberItem.js
index 0c38355eb9..f5ff504035 100644
--- a/packages/react/src/views/RoomMembers/RoomMemberItem.js
+++ b/packages/react/src/views/RoomMembers/RoomMemberItem.js
@@ -1,9 +1,9 @@
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
-import { Box, Icon, Avatar } from '@embeddedchat/ui-elements';
+import { Box, Icon, Avatar, useTheme } from '@embeddedchat/ui-elements';
import RCContext from '../../context/RCInstance';
-import { RoomMemberItemStyles as styles } from './RoomMembers.styles';
+import { RoomMemberItemStyles } from './RoomMembers.styles';
import useSetExclusiveState from '../../hooks/useSetExclusiveState';
import { useUserStore } from '../../store';
@@ -11,6 +11,9 @@ const RoomMemberItem = ({ user, host }) => {
const { RCInstance } = useContext(RCContext);
const [userStatus, setUserStatus] = useState('');
const avatarUrl = new URL(`avatar/${user.username}`, host).toString();
+ const { theme } = useTheme();
+ const { mode } = useTheme();
+ const styles = RoomMemberItemStyles(theme, mode);
useEffect(() => {
const getStatus = async () => {
diff --git a/packages/react/src/views/RoomMembers/RoomMembers.styles.js b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
index ac9df00bf0..415940c2f4 100644
--- a/packages/react/src/views/RoomMembers/RoomMembers.styles.js
+++ b/packages/react/src/views/RoomMembers/RoomMembers.styles.js
@@ -1,4 +1,5 @@
import { css } from '@emotion/react';
+import { lighten, darken } from '@embeddedchat/ui-elements';
export const getRoomMemberStyles = (theme) => {
const styles = {
@@ -49,20 +50,29 @@ export const getRoomMemberStyles = (theme) => {
return styles;
};
-export const RoomMemberItemStyles = {
- container: css`
- width: 100%;
- padding-bottom: 8px;
- padding-top: 8px;
- display: flex;
- align-items: center;
- `,
+export const RoomMemberItemStyles = (theme, mode) => {
+ const styles = {
+ container: css`
+ width: 100%;
+ padding-bottom: 8px;
+ padding-top: 8px;
+ display: flex;
+ align-items: center;
- icon: css`
- padding: 0.125em;
- margin-right: 0.5rem;
- align-self: center;
- `,
+ &:hover {
+ background-color: ${mode === 'light'
+ ? darken(theme.colors.background, 0.03)
+ : lighten(theme.colors.background, 1)};
+ }
+ `,
+
+ icon: css`
+ padding: 0.125em;
+ margin-right: 0.5rem;
+ align-self: center;
+ `,
+ };
+ return styles;
};
export const InviteMemberStyles = {
From dd4195ae3a2c80fc22271c540b5f842d17c8e395 Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:40:34 +0530
Subject: [PATCH 70/76] fix : Add Hover Effect to FileMessage Component (#845)
* feat: Enhance FileMessage component with hover effect based on theme
* fixed linting
---
.../src/views/FileMessage/FileMessage.js | 20 +++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/packages/react/src/views/FileMessage/FileMessage.js b/packages/react/src/views/FileMessage/FileMessage.js
index a074e981ef..4944005c0d 100644
--- a/packages/react/src/views/FileMessage/FileMessage.js
+++ b/packages/react/src/views/FileMessage/FileMessage.js
@@ -1,4 +1,4 @@
-import React, { useState, useCallback, memo } from 'react';
+import React, { useState, useCallback, memo, useContext } from 'react';
import PropTypes from 'prop-types';
import {
Box,
@@ -9,6 +9,9 @@ import {
useToastBarDispatch,
useComponentOverrides,
appendClassNames,
+ useTheme,
+ lighten,
+ darken,
} from '@embeddedchat/ui-elements';
import FilePreviewContainer from './FilePreviewContainer';
import FileBodyContainer from '../Message/MessageBodyContainer';
@@ -26,6 +29,19 @@ const FileMessage = ({ fileMessage }) => {
const { RCInstance } = useRCContext();
const messages = useMessageStore((state) => state.messages);
+ const theme = useTheme();
+ const { mode } = theme;
+ const messageStyles = styles.message;
+
+ const hoverStyle = {
+ '&:hover': {
+ backgroundColor:
+ mode === 'light'
+ ? darken(theme.theme.colors.background, 0.03)
+ : lighten(theme.theme.colors.background, 1),
+ },
+ };
+
const [fileToDelete, setFileToDelete] = useState({});
const downloadFile = useCallback((url, title) => {
@@ -69,7 +85,7 @@ const FileMessage = ({ fileMessage }) => {
From eb0854f5e16bd636236bae6a6cfcedeae85cd7d2 Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:46:53 +0530
Subject: [PATCH 71/76] Feat: Show 'Edit Message' Button for all message types
(#826)
* Feat: Conditionally show 'Edit Message' button based on attachment description
* Edit option visible to all message types
---
packages/react/src/views/Message/MessageToolbox.js | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/packages/react/src/views/Message/MessageToolbox.js b/packages/react/src/views/Message/MessageToolbox.js
index 34752872eb..0208ff663d 100644
--- a/packages/react/src/views/Message/MessageToolbox.js
+++ b/packages/react/src/views/Message/MessageToolbox.js
@@ -86,10 +86,6 @@ export const MessageToolbox = ({
? true
: message.u._id === authenticatedUserId;
- const isVisibleForMessageType =
- message.files?.[0].type !== 'audio/mpeg' &&
- message.files?.[0].type !== 'video/mp4';
-
const options = useMemo(
() => ({
reply: {
@@ -140,7 +136,7 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
- visible: isAllowedToEditMessage && isVisibleForMessageType,
+ visible: isAllowedToEditMessage,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
From 93198dc79f9b6bac0483e49252694cd4ce053d79 Mon Sep 17 00:00:00 2001
From: Abir Chakraborty <142606190+abirc8010@users.noreply.github.com>
Date: Mon, 27 Jan 2025 22:48:55 +0530
Subject: [PATCH 72/76] Fix attachment and avatar responsiveness in messages
(#922)
---
.../src/views/AttachmentHandler/AudioAttachment.js | 6 +++++-
.../src/views/AttachmentHandler/VideoAttachment.js | 3 ++-
packages/react/src/views/Message/Message.styles.js | 3 +++
.../react/src/views/Message/MessageAvatarContainer.js | 10 +++++++++-
4 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/packages/react/src/views/AttachmentHandler/AudioAttachment.js b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
index 8e3ce527a4..5caf16e760 100644
--- a/packages/react/src/views/AttachmentHandler/AudioAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/AudioAttachment.js
@@ -76,7 +76,11 @@ const AudioAttachment = ({
isExpanded={isExpanded}
/>
{isExpanded && (
-
+
)}
{attachment.attachments &&
diff --git a/packages/react/src/views/AttachmentHandler/VideoAttachment.js b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
index 4407481ee4..5c29bc507b 100644
--- a/packages/react/src/views/AttachmentHandler/VideoAttachment.js
+++ b/packages/react/src/views/AttachmentHandler/VideoAttachment.js
@@ -87,11 +87,12 @@ const VideoAttachment = ({
/>
{isExpanded && (
))}
From 9d84f49d6783f0210a5c534553e7edfb468da83d Mon Sep 17 00:00:00 2001
From: Dhairyashil Shinde <93669429+dhairyashiil@users.noreply.github.com>
Date: Mon, 27 Jan 2025 23:04:04 +0530
Subject: [PATCH 74/76] feat: Add 'Cancel Recording' and 'Finish Recording'
tooltips for audio/video buttons (#812)
---
.../views/ChatInput/AudioMessageRecorder.js | 42 ++++++++++++-------
.../ChatInput/ChatInputFormattingToolbar.js | 12 +-----
.../views/ChatInput/VideoMessageRecoder.js | 35 +++++++++-------
3 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/packages/react/src/views/ChatInput/AudioMessageRecorder.js b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
index 8f2287569b..9ff497a30f 100644
--- a/packages/react/src/views/ChatInput/AudioMessageRecorder.js
+++ b/packages/react/src/views/ChatInput/AudioMessageRecorder.js
@@ -1,5 +1,11 @@
import React, { useState, useEffect, useCallback, useRef } from 'react';
-import { Box, Icon, ActionButton, useTheme } from '@embeddedchat/ui-elements';
+import {
+ Box,
+ Icon,
+ ActionButton,
+ Tooltip,
+ useTheme,
+} from '@embeddedchat/ui-elements';
import { useMediaRecorder } from '../../hooks/useMediaRecorder';
import useMessageStore from '../../store/messageStore';
import { getCommonRecorderStyles } from './ChatInput.styles';
@@ -131,14 +137,16 @@ const AudioMessageRecorder = ({ disabled }) => {
if (state === 'idle') {
return (
-
-
-
+
+
+
+
+
);
}
@@ -146,18 +154,22 @@ const AudioMessageRecorder = ({ disabled }) => {
{state === 'recording' && (
<>
-
-
-
+
+
+
+
+
{time}
-
-
-
+
+
+
+
+
>
)}
diff --git a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
index 4c72bc4dc6..523b9ef976 100644
--- a/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
+++ b/packages/react/src/views/ChatInput/ChatInputFormattingToolbar.js
@@ -88,16 +88,8 @@ const ChatInputFormattingToolbar = ({
),
- audio: (
-
-
-
- ),
- video: (
-
-
-
- ),
+ audio: ,
+ video: ,
file: (
{
return (
<>
{state === 'idle' && (
-
-
-
+
+
+
+
+
)}
{state === 'recording' && (
@@ -178,16 +181,20 @@ const VideoMessageRecorder = ({ disabled }) => {
`}
/>
-
-
-
+
+
+
+
+
{time}
-
-
-
+
+
+
+
+
>
From bde1a165d67184aff0928ea35dca9e1e470e0c2c Mon Sep 17 00:00:00 2001
From: Anirban Singha <143536290+SinghaAnirban005@users.noreply.github.com>
Date: Thu, 30 Jan 2025 22:59:53 +0530
Subject: [PATCH 75/76] feat: implement loading of older messages functionality
(#810)
* feat: implement loading of older messages functionality
* Fix lint error
* Globalize messages offset
* ensure loader appears far from date header
---
packages/api/src/EmbeddedChatApi.ts | 41 ++++++++++
packages/react/src/hooks/useFetchChatData.js | 4 +-
packages/react/src/store/messageStore.js | 20 +++--
packages/react/src/views/ChatBody/ChatBody.js | 74 ++++++++++++++++-
.../src/views/ChatBody/ChatBody.styles.js | 2 +-
packages/react/src/views/Message/Message.js | 10 +--
.../src/views/MessageList/MessageList.js | 82 ++++++++++++++-----
7 files changed, 197 insertions(+), 36 deletions(-)
diff --git a/packages/api/src/EmbeddedChatApi.ts b/packages/api/src/EmbeddedChatApi.ts
index 3a1c3b5f9e..44cff0eaf4 100644
--- a/packages/api/src/EmbeddedChatApi.ts
+++ b/packages/api/src/EmbeddedChatApi.ts
@@ -552,6 +552,47 @@ export default class EmbeddedChatApi {
}
}
+ async getOlderMessages(
+ anonymousMode = false,
+ options: {
+ query?: object | undefined;
+ field?: object | undefined;
+ offset?: number;
+ } = {
+ query: undefined,
+ field: undefined,
+ offset: 50,
+ },
+ isChannelPrivate = false
+ ) {
+ const roomType = isChannelPrivate ? "groups" : "channels";
+ const endp = anonymousMode ? "anonymousread" : "messages";
+ const query = options?.query
+ ? `&query=${JSON.stringify(options.query)}`
+ : "";
+ const field = options?.field
+ ? `&field=${JSON.stringify(options.field)}`
+ : "";
+ const offset = options?.offset ? options.offset : 0;
+ try {
+ const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
+ const messages = await fetch(
+ `${this.host}/api/v1/${roomType}.${endp}?roomId=${this.rid}${query}${field}&offset=${offset}`,
+ {
+ headers: {
+ "Content-Type": "application/json",
+ "X-Auth-Token": authToken,
+ "X-User-Id": userId,
+ },
+ method: "GET",
+ }
+ );
+ return await messages.json();
+ } catch (err) {
+ console.log(err);
+ }
+ }
+
async getThreadMessages(tmid: string, isChannelPrivate = false) {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
diff --git a/packages/react/src/hooks/useFetchChatData.js b/packages/react/src/hooks/useFetchChatData.js
index 583ad431e5..7f5b491252 100644
--- a/packages/react/src/hooks/useFetchChatData.js
+++ b/packages/react/src/hooks/useFetchChatData.js
@@ -13,6 +13,7 @@ const useFetchChatData = (showRoles) => {
const setMemberRoles = useMemberStore((state) => state.setMemberRoles);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const setMessages = useMessageStore((state) => state.setMessages);
+ const setMessagesOffset = useMessageStore((state) => state.setMessagesOffset);
const setAdmins = useMemberStore((state) => state.setAdmins);
const setStarredMessages = useStarredMessageStore(
(state) => state.setStarredMessages
@@ -31,7 +32,7 @@ const useFetchChatData = (showRoles) => {
return;
}
- const { messages } = await RCInstance.getMessages(
+ const { messages, count } = await RCInstance.getMessages(
anonymousMode,
ECOptions?.enableThreads
? {
@@ -47,6 +48,7 @@ const useFetchChatData = (showRoles) => {
if (messages) {
setMessages(messages.filter((message) => message._hidden !== true));
+ setMessagesOffset(count);
}
if (!isUserAuthenticated) {
diff --git a/packages/react/src/store/messageStore.js b/packages/react/src/store/messageStore.js
index 69d1d2b73f..a9a7265c86 100644
--- a/packages/react/src/store/messageStore.js
+++ b/packages/react/src/store/messageStore.js
@@ -8,6 +8,7 @@ const useMessageStore = create((set, get) => ({
threadMessages: [],
filtered: false,
editMessage: {},
+ messagesOffset: 0,
quoteMessage: [],
messageToReport: NaN,
showReportMessage: false,
@@ -16,11 +17,19 @@ const useMessageStore = create((set, get) => ({
threadMainMessage: null,
headerTitle: null,
setFilter: (filter) => set(() => ({ filtered: filter })),
- setMessages: (messages) =>
- set(() => ({
- messages,
- isMessageLoaded: true,
- })),
+ setMessages: (newMessages, append = false) =>
+ set((state) => {
+ const allMessages = append
+ ? [...state.messages, ...newMessages]
+ : newMessages;
+ const uniqueMessages = Array.from(
+ new Map(allMessages.map((msg) => [msg._id, msg])).values()
+ );
+ return {
+ messages: uniqueMessages,
+ isMessageLoaded: true,
+ };
+ }),
upsertMessage: (message, enableThreads = false) => {
if (message.tmid && enableThreads) {
if (get().threadMainMessage?._id === message.tmid) {
@@ -71,6 +80,7 @@ const useMessageStore = create((set, get) => ({
}
},
setEditMessage: (editMessage) => set(() => ({ editMessage })),
+ setMessagesOffset: (newOffset) => set(() => ({ messagesOffset: newOffset })),
editMessagePermissions: {},
setEditMessagePermissions: (editMessagePermissions) =>
set((state) => ({ ...state, editMessagePermissions })),
diff --git a/packages/react/src/views/ChatBody/ChatBody.js b/packages/react/src/views/ChatBody/ChatBody.js
index 940b63e9bb..8d7c3ac978 100644
--- a/packages/react/src/views/ChatBody/ChatBody.js
+++ b/packages/react/src/views/ChatBody/ChatBody.js
@@ -51,14 +51,19 @@ const ChatBody = ({
const { RCInstance, ECOptions } = useContext(RCContext);
const showAnnouncement = ECOptions?.showAnnouncement;
const messages = useMessageStore((state) => state.messages);
+ const offset = useMessageStore((state) => state.messagesOffset);
+ const setMessagesOffset = useMessageStore((state) => state.setMessagesOffset);
const threadMessages = useMessageStore((state) => state.threadMessages);
const [isModalOpen, setModalOpen] = useState(false);
const setThreadMessages = useMessageStore((state) => state.setThreadMessages);
const upsertMessage = useMessageStore((state) => state.upsertMessage);
+ const [loadingOlderMessages, setLoadingOlderMessages] = useState(false);
+ const [hasMoreMessages, setHasMoreMessages] = useState(true);
const removeMessage = useMessageStore((state) => state.removeMessage);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const channelInfo = useChannelStore((state) => state.channelInfo);
const isLoginIn = useLoginStore((state) => state.isLoginIn);
+ const setMessages = useMessageStore((state) => state.setMessages);
const [isThreadOpen, threadMainMessage] = useMessageStore((state) => [
state.isThreadOpen,
@@ -153,6 +158,7 @@ const ChatBody = ({
RCInstance.auth.onAuthChange((user) => {
if (user) {
getMessagesAndRoles();
+ setHasMoreMessages(true);
} else {
getMessagesAndRoles(anonymousMode);
}
@@ -166,13 +172,57 @@ const ChatBody = ({
setPopupVisible(false);
};
- const handleScroll = useCallback(() => {
+ const handleScroll = useCallback(async () => {
if (messageListRef && messageListRef.current) {
setScrollPosition(messageListRef.current.scrollTop);
setIsUserScrolledUp(
messageListRef.current.scrollTop + messageListRef.current.clientHeight <
messageListRef.current.scrollHeight
);
+
+ if (
+ messageListRef.current.scrollTop === 0 &&
+ !loadingOlderMessages &&
+ hasMoreMessages
+ ) {
+ setLoadingOlderMessages(true);
+
+ try {
+ const olderMessages = await RCInstance.getOlderMessages(
+ anonymousMode,
+ ECOptions?.enableThreads
+ ? {
+ query: {
+ tmid: {
+ $exists: false,
+ },
+ },
+ offset,
+ }
+ : undefined,
+ anonymousMode ? false : isChannelPrivate
+ );
+ const messageList = messageListRef.current;
+ if (olderMessages?.messages?.length) {
+ const previousScrollHeight = messageList.scrollHeight;
+
+ setMessages(olderMessages.messages, true);
+ setMessagesOffset(offset + olderMessages.messages.length);
+
+ requestAnimationFrame(() => {
+ const newScrollHeight = messageList.scrollHeight;
+ messageList.scrollTop = newScrollHeight - previousScrollHeight;
+ });
+ } else {
+ setHasMoreMessages(false);
+ }
+ } catch (error) {
+ console.error('Error fetching older messages:', error);
+ setHasMoreMessages(false);
+ } finally {
+ setLoadingOlderMessages(false);
+ }
+ }
}
const isAtBottom = messageListRef?.current?.scrollTop === 0;
@@ -183,6 +233,15 @@ const ChatBody = ({
}
}, [
messageListRef,
+ offset,
+ setMessagesOffset,
+ setMessages,
+ anonymousMode,
+ hasMoreMessages,
+ RCInstance,
+ isChannelPrivate,
+ ECOptions?.enableThreads,
+ loadingOlderMessages,
setScrollPosition,
setIsUserScrolledUp,
setPopupVisible,
@@ -207,6 +266,12 @@ const ChatBody = ({
}
};
+ useEffect(() => {
+ if (messageListRef.current) {
+ messageListRef.current.scrollTop = messageListRef.current.scrollHeight;
+ }
+ }, [messages]);
+
useEffect(() => {
checkOverflow();
}, [channelInfo.announcement, showAnnouncement]);
@@ -292,7 +357,12 @@ const ChatBody = ({
threadMessages={threadMessages}
/>
) : (
-
+
)}
diff --git a/packages/react/src/views/ChatBody/ChatBody.styles.js b/packages/react/src/views/ChatBody/ChatBody.styles.js
index f7824d924f..20deecd1f5 100644
--- a/packages/react/src/views/ChatBody/ChatBody.styles.js
+++ b/packages/react/src/views/ChatBody/ChatBody.styles.js
@@ -9,7 +9,7 @@ export const getChatbodyStyles = (theme, mode) => {
overflow: auto;
overflow-x: hidden;
display: flex;
- flex-direction: column-reverse;
+ flex-direction: column;
max-height: 100%;
position: relative;
padding-top: 70px;
diff --git a/packages/react/src/views/Message/Message.js b/packages/react/src/views/Message/Message.js
index fa8c864fec..dd8cf8d09d 100644
--- a/packages/react/src/views/Message/Message.js
+++ b/packages/react/src/views/Message/Message.js
@@ -212,6 +212,11 @@ const Message = ({
return (
<>
+ {newDay && (
+
+ {format(new Date(message.ts), 'MMMM d, yyyy')}
+
+ )}
- {newDay && (
-
- {format(new Date(message.ts), 'MMMM d, yyyy')}
-
- )}
>
);
};
diff --git a/packages/react/src/views/MessageList/MessageList.js b/packages/react/src/views/MessageList/MessageList.js
index 29a489be0e..6a13952165 100644
--- a/packages/react/src/views/MessageList/MessageList.js
+++ b/packages/react/src/views/MessageList/MessageList.js
@@ -2,17 +2,24 @@ import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { isSameDay } from 'date-fns';
-import { Box, Icon } from '@embeddedchat/ui-elements';
+import { Box, Icon, Throbber, useTheme } from '@embeddedchat/ui-elements';
import { useMessageStore } from '../../store';
import MessageReportWindow from '../ReportMessage/MessageReportWindow';
import isMessageSequential from '../../lib/isMessageSequential';
import { Message } from '../Message';
import isMessageLastSequential from '../../lib/isMessageLastSequential';
+import { MessageBody } from '../Message/MessageBody';
-const MessageList = ({ messages }) => {
+const MessageList = ({
+ messages,
+ loadingOlderMessages,
+ isUserAuthenticated,
+ hasMoreMessages,
+}) => {
const showReportMessage = useMessageStore((state) => state.showReportMessage);
const messageToReport = useMessageStore((state) => state.messageToReport);
const isMessageLoaded = useMessageStore((state) => state.isMessageLoaded);
+ const { theme } = useTheme();
const isMessageNewDay = (current, previous) =>
!previous || !isSameDay(new Date(current.ts), new Date(previous.ts));
@@ -37,28 +44,59 @@ const MessageList = ({ messages }) => {
) : (
<>
- {filteredMessages.map((msg, index, arr) => {
- const prev = arr[index + 1];
- const next = arr[index - 1];
+ {!hasMoreMessages && isUserAuthenticated && (
+
+ Start of conversation
+
+ )}
+ {loadingOlderMessages && isUserAuthenticated && (
+
+
+
+ )}
+ {messages
+ .slice()
+ .reverse()
+ .map((msg, index, arr) => {
+ const prev = arr[index - 1];
+ const next = arr[index + 1];
- if (!msg) return null;
- const newDay = isMessageNewDay(msg, prev);
- const sequential = isMessageSequential(msg, prev, 300);
- const lastSequential =
- sequential && isMessageLastSequential(msg, next);
+ if (!msg) return null;
+ const newDay = isMessageNewDay(msg, prev);
+ const sequential = isMessageSequential(msg, prev, 300);
+ const lastSequential =
+ sequential && isMessageLastSequential(msg, next);
- return (
-
- );
- })}
+ return (
+
+ );
+ })}
{showReportMessage && (
)}
From 2004d448cde695fa923f3f78cee1bc68ab18612c Mon Sep 17 00:00:00 2001
From: AYUSHKUMAR_21JE0209
<103947228+AyushKumar123456789@users.noreply.github.com>
Date: Thu, 30 Jan 2025 23:36:52 +0530
Subject: [PATCH 76/76] feat : added icon to show Update ChannelHeader and
RoomInfo UI for (Channels Converted to Teams). (#926)
* feat : added icon to show channel is team now
* Fixed prettier
---------
Co-authored-by: Zishan Ahmad
---
packages/react/src/store/channelStore.js | 2 ++
packages/react/src/views/ChatHeader/ChatHeader.js | 11 ++++++++++-
.../src/views/RoomInformation/RoomInformation.js | 8 +++++---
.../ui-elements/src/components/Icon/icons/Team.js | 15 +++++++++++++++
.../src/components/Icon/icons/index.js | 2 ++
packages/ui-elements/tools/icons-generator.js | 1 +
6 files changed, 35 insertions(+), 4 deletions(-)
create mode 100644 packages/ui-elements/src/components/Icon/icons/Team.js
diff --git a/packages/react/src/store/channelStore.js b/packages/react/src/store/channelStore.js
index 2ba08bddb4..f3acbb914f 100644
--- a/packages/react/src/store/channelStore.js
+++ b/packages/react/src/store/channelStore.js
@@ -4,10 +4,12 @@ const useChannelStore = create((set) => ({
showChannelinfo: false,
isChannelPrivate: false,
isChannelReadOnly: false,
+ isRoomTeam: false,
setShowChannelinfo: (showChannelinfo) => set(() => ({ showChannelinfo })),
channelInfo: {},
setChannelInfo: (channelInfo) => set(() => ({ channelInfo })),
setIsChannelPrivate: (isChannelPrivate) => set(() => ({ isChannelPrivate })),
+ setIsRoomTeam: (isRoomTeam) => set(() => ({ isRoomTeam })),
setIsChannelReadOnly: (isChannelReadOnly) =>
set(() => ({ isChannelReadOnly })),
}));
diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js
index 5f2dbf43ee..0971ce7c77 100644
--- a/packages/react/src/views/ChatHeader/ChatHeader.js
+++ b/packages/react/src/views/ChatHeader/ChatHeader.js
@@ -73,6 +73,8 @@ const ChatHeader = ({
const setIsChannelPrivate = useChannelStore(
(state) => state.setIsChannelPrivate
);
+ const isRoomTeam = useChannelStore((state) => state.isRoomTeam);
+ const setIsRoomTeam = useChannelStore((state) => state.setIsRoomTeam);
const setIsChannelReadOnly = useChannelStore(
(state) => state.setIsChannelReadOnly
);
@@ -177,6 +179,7 @@ const ChatHeader = ({
if (res.success) {
setChannelInfo(res.room);
if (res.room.t === 'p') setIsChannelPrivate(true);
+ if (res.room?.teamMain) setIsRoomTeam(true);
if (res.room.ro) {
setIsChannelReadOnly(true);
setMessageAllowed();
@@ -377,7 +380,13 @@ const ChatHeader = ({
onClick={() => setExclusiveState(setShowChannelinfo)}
>
{
const styles = getRoomInformationStyles();
const channelInfo = useChannelStore((state) => state.channelInfo);
const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
+ const isRoomTeam = useChannelStore((state) => state.isRoomTeam);
const { variantOverrides } = useComponentOverrides('RoomMember');
const viewType = variantOverrides.viewType || 'Sidebar';
const setExclusiveState = useSetExclusiveState();
@@ -30,7 +31,7 @@ const Roominfo = () => {
return (
setExclusiveState(null)}
style={{ width: '400px', zIndex: window.innerWidth <= 780 ? 1 : null }}
@@ -59,12 +60,13 @@ const Roominfo = () => {
{channelInfo.name}
diff --git a/packages/ui-elements/src/components/Icon/icons/Team.js b/packages/ui-elements/src/components/Icon/icons/Team.js
new file mode 100644
index 0000000000..4602e9703c
--- /dev/null
+++ b/packages/ui-elements/src/components/Icon/icons/Team.js
@@ -0,0 +1,15 @@
+import React from 'react';
+
+const Team = (props) => (
+
+);
+
+export default Team;
diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js
index 3e23f0667d..234251edab 100644
--- a/packages/ui-elements/src/components/Icon/icons/index.js
+++ b/packages/ui-elements/src/components/Icon/icons/index.js
@@ -63,6 +63,7 @@ import Arc from './Arc';
import Avatar from './Avatar';
import FormatText from './FormatText';
import Cog from './Cog';
+import Team from './Team';
const icons = {
file: File,
@@ -76,6 +77,7 @@ const icons = {
computer: Computer,
cross: Cross,
copy: Copy,
+ team: Team,
mic: Mic,
'video-recorder': VideoRecorder,
'disabled-recorder': DisabledRecorder,
diff --git a/packages/ui-elements/tools/icons-generator.js b/packages/ui-elements/tools/icons-generator.js
index 4b2b2e6ca1..d12396c2b1 100644
--- a/packages/ui-elements/tools/icons-generator.js
+++ b/packages/ui-elements/tools/icons-generator.js
@@ -13,6 +13,7 @@ const iconsList = [
'computer',
'cross',
'mic',
+ 'team',
'circle-cross',
'circle-check',
'send',