Skip to content

Commit

Permalink
Merge branch 'develop' into fix/message-box-UI
Browse files Browse the repository at this point in the history
  • Loading branch information
abirc8010 authored Dec 22, 2024
2 parents 8e8c7a4 + 2a418cd commit f1363b0
Show file tree
Hide file tree
Showing 12 changed files with 158 additions and 19 deletions.
17 changes: 17 additions & 0 deletions packages/api/src/EmbeddedChatApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1124,4 +1124,21 @@ export default class EmbeddedChatApi {
const data = response.json();
return data;
}

async userData(username: string) {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(
`${this.host}/api/v1/users.info?username=${username}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
"X-User-Id": userId,
},
}
);
const data = response.json();
return data;
}
}
29 changes: 28 additions & 1 deletion packages/markups/src/mentions/UserMention.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import { Box } 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';
import { MarkupInteractionContext } from '../MarkupInteractionContext';
import useMentionStyles from '../elements/elements.styles';

const UserMention = ({ contents }) => {
const { members, username } = useContext(MarkupInteractionContext);
const { RCInstance } = useContext(RCContext);
const setExclusiveState = useSetExclusiveState();
const { setShowCurrentUserInfo, setCurrentUser } = useUserStore((state) => ({
setShowCurrentUserInfo: state.setShowCurrentUserInfo,
setCurrentUser: state.setCurrentUser,
}));

const handleUserInfo = async (uname) => {
const data = await RCInstance.userData(uname);
setCurrentUser({
_id: data.user._id,
username: data.user.username,
name: data.user.name,
});
setExclusiveState(setShowCurrentUserInfo);
};

const hasMember = (user) => {
if (user === 'all' || user === 'here') return true;
Expand All @@ -23,7 +42,15 @@ const UserMention = ({ contents }) => {
return (
<>
{hasMember(contents.value) ? (
<Box is="span" css={styles.mention}>
<Box
is="span"
css={styles.mention}
onClick={
['here', 'all'].includes(contents.value)
? null
: () => handleUserInfo(contents.value)
}
>
{contents.value}
</Box>
) : (
Expand Down
11 changes: 10 additions & 1 deletion packages/react/src/hooks/useRCAuth.js
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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) => {
Expand Down Expand Up @@ -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',
Expand Down
3 changes: 3 additions & 0 deletions packages/react/src/store/messageStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) =>
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/views/ChatInput/ChatInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
6 changes: 5 additions & 1 deletion packages/react/src/views/EmbeddedChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/views/Markdown/Markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { Box } from '@embeddedchat/ui-elements';
import { Markup, MarkupInteractionContext } from '@embeddedchat/markups';
import { Markup, MarkupInteractionContext } from '@embeddedchat/markups/src';
import EmojiReaction from '../EmojiReaction/EmojiReaction';
import { useMemberStore, useUserStore } from '../../store';

Expand Down
46 changes: 46 additions & 0 deletions packages/react/src/views/Message/Message.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]
);
Expand All @@ -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 : {};
Expand Down Expand Up @@ -114,6 +118,45 @@ 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 getMessageLink = async (id) => {
const host = await RCInstance.getHost();
const res = await RCInstance.channelInfo();
return `${host}/channel/${res.room.name}/?msg=${id}`;
};

const handleCopyMessageLink = async (msg) => {
try {
const messageLink = await getMessageLink(msg._id);
await navigator.clipboard.writeText(messageLink);
dispatchToastMessage({
type: 'success',
message: 'Message link copied successfully',
});
} catch (err) {
dispatchToastMessage({
type: 'error',
message: 'Error in copying message link',
});
}
};

const handleDeleteMessage = async (msg) => {
const res = await RCInstance.deleteMessage(msg._id);

Expand Down Expand Up @@ -210,6 +253,9 @@ const Message = ({
authenticatedUserId={authenticatedUserId}
userRoles={userRoles}
pinRoles={pinRoles}
editMessageRoles={editMessageRoles}
handleCopyMessage={handleCopyMessage}
handleCopyMessageLink={handleCopyMessageLink}
handleOpenThread={handleOpenThread}
handleDeleteMessage={handleDeleteMessage}
handleStarMessage={handleStarMessage}
Expand Down
32 changes: 29 additions & 3 deletions packages/react/src/views/Message/MessageToolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = '',
Expand All @@ -23,12 +23,15 @@ export const MessageToolbox = ({
authenticatedUserId,
userRoles,
pinRoles,
editMessageRoles,
handleOpenThread,
handleEmojiClick,
handlePinMessage,
handleStarMessage,
handleDeleteMessage,
handlerReportMessage,
handleCopyMessage,
handleCopyMessageLink,
handleEditMessage,
handleQuoteMessage,
isEditing = false,
Expand All @@ -38,6 +41,8 @@ export const MessageToolbox = ({
'reply',
'quote',
'star',
'copy',
'link',
'pin',
'edit',
'delete',
Expand Down Expand Up @@ -70,6 +75,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: {
Expand Down Expand Up @@ -120,10 +130,24 @@ export const MessageToolbox = ({
id: 'edit',
onClick: () => handleEditMessage(message),
iconName: 'edit',
visible: message.u._id === authenticatedUserId,
visible: isAllowedToEditMessage,
color: isEditing ? 'secondary' : 'default',
ghost: !isEditing,
},
copy: {
label: 'Copy message',
id: 'copy',
onClick: () => handleCopyMessage(message),
iconName: 'copy',
visible: true,
},
link: {
label: 'Copy link',
id: 'link',
onClick: () => handleCopyMessageLink(message),
iconName: 'link',
visible: true,
},
delete: {
label: 'Delete',
id: 'delete',
Expand Down Expand Up @@ -152,6 +176,8 @@ export const MessageToolbox = ({
handlePinMessage,
handleEditMessage,
handlerReportMessage,
handleCopyMessage,
isAllowedToPin,
]
);

Expand Down Expand Up @@ -243,7 +269,7 @@ export const MessageToolbox = ({
padding: '0 0.5rem 0.5rem',
}}
>
{parseEmoji(message.msg)}
<Markdown body={message} isReaction={false} />
</Modal.Content>
<Modal.Footer>
<Button type="secondary" onClick={handleOnClose}>
Expand Down
5 changes: 3 additions & 2 deletions packages/react/src/views/MessageAggregators/FileGallery.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState, useMemo, useEffect } from 'react';
import { useComponentOverrides } from '@embeddedchat/ui-elements';
import { useChannelStore } from '../../store';
import { useChannelStore, useMessageStore } from '../../store';
import { useRCContext } from '../../context/RCInstance';
import { MessageAggregator } from './common/MessageAggregator';

Expand All @@ -10,6 +10,7 @@ const FileGallery = () => {
const viewType = variantOverrides.viewType || 'Sidebar';

const isChannelPrivate = useChannelStore((state) => state.isChannelPrivate);
const messages = useMessageStore((state) => state.messages);

const [text, setText] = useState('');
const [isFetching, setIsFetching] = useState(true);
Expand Down Expand Up @@ -39,7 +40,7 @@ const FileGallery = () => {
}
};
fetchAllFiles();
}, [RCInstance, isChannelPrivate]);
}, [RCInstance, isChannelPrivate, messages]);

return (
<MessageAggregator
Expand Down
17 changes: 9 additions & 8 deletions packages/react/src/views/QuoteMessage/QuoteMessage.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import RCContext from '../../context/RCInstance';
import { useMessageStore } from '../../store';
import getQuoteMessageStyles from './QuoteMessage.styles';
import Attachment from '../AttachmentHandler/Attachment';
import { Markdown } from '../Markdown';

const QuoteMessage = ({ className = '', style = {}, message }) => {
const { RCInstance } = useContext(RCContext);
Expand Down Expand Up @@ -83,19 +84,19 @@ const QuoteMessage = ({ className = '', style = {}, message }) => {
</audio>
) : (
<Box css={styles.message}>
{message.msg
? message.msg
: `${message.file?.name} (${
message.file?.size
? (message.file.size / 1024).toFixed(2)
: 0
} kB)`}
{message.msg ? (
<Markdown body={message} isReaction={false} />
) : (
`${message.file?.name} (${
message.file?.size ? (message.file.size / 1024).toFixed(2) : 0
} kB)`
)}
</Box>
)
) : message?.msg[0] === '[' ? (
message?.msg.match(/\n(.*)/)[1]
) : (
message?.msg
<Markdown body={message} isReaction={false} />
)}
{message.attachments &&
message.attachments.length > 0 &&
Expand Down
Loading

0 comments on commit f1363b0

Please sign in to comment.