Skip to content

Commit

Permalink
Merge branch 'develop' into commandMenu
Browse files Browse the repository at this point in the history
  • Loading branch information
Akshun-01 authored Mar 12, 2024
2 parents c99bca0 + b6fe5d1 commit 5816d76
Show file tree
Hide file tree
Showing 22 changed files with 505 additions and 22 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ yarn storybook

Storybook should now be operational. Experiment with `EmbeddedChat` and its components, observing real-time changes in Storybook.

Note: Please make sure the "Enable CORS" option is ON in your Rocket.Chat server. It can be found in Administration > Settings > General > REST API > Enable CORS. It has to enabled to access the functionality of the app.

#### Custom Rocket Chat Server Configuration

By default, Storybook connects to `http://localhost:3000`. To use a different Rocket Chat server:
Expand Down
21 changes: 21 additions & 0 deletions packages/api/src/EmbeddedChatApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,27 @@ export default class EmbeddedChatApi {
}
}

async getAllFiles(isChannelPrivate = false) {
const roomType = isChannelPrivate ? "groups" : "channels";
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
const response = await fetch(
`${this.host}/api/v1/${roomType}.files?roomId=${this.rid}`,
{
headers: {
"Content-Type": "application/json",
"X-Auth-Token": authToken,
"X-User-Id": userId,
},
method: "GET",
}
);
return await response.json();
} catch (err) {
console.error(err);
}
}

async starMessage(mid: string) {
try {
const { userId, authToken } = (await this.auth.getCurrentUser()) || {};
Expand Down
14 changes: 14 additions & 0 deletions packages/react/src/components/ChatHeader/ChatHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
useToastStore,
useThreadsMessageStore,
useMentionsStore,
useFileStore,
} from '../../store';
import { DynamicHeader } from '../DynamicHeader';
import { Tooltip } from '../Tooltip';
Expand Down Expand Up @@ -74,6 +75,7 @@ const ChatHeader = ({
const setShowAllThreads = useThreadsMessageStore(
(state) => state.setShowAllThreads
);
const setShowAllFiles = useFileStore((state) => state.setShowAllFiles);
const setShowMentions = useMentionsStore((state) => state.setShowMentions);
const toastPosition = useToastStore((state) => state.position);

Expand Down Expand Up @@ -143,6 +145,11 @@ const ChatHeader = ({
setShowSearch(false);
}, [setShowAllThreads, setShowSearch]);

const showAllFiles = useCallback(async () => {
setShowAllFiles(true);
setShowSearch(false);
}, [setShowAllFiles, setShowSearch]);

const showMentions = useCallback(async () => {
setShowMentions(true);
setShowSearch(false);
Expand Down Expand Up @@ -242,6 +249,12 @@ const ChatHeader = ({
label: 'Members',
icon: 'members',
},
{
id: 'files',
action: showAllFiles,
label: 'Files',
icon: 'clip',
},
{
id: 'starred',
action: showStarredMessage,
Expand Down Expand Up @@ -285,6 +298,7 @@ const ChatHeader = ({
isUserAuthenticated,
moreOpts,
setFullScreen,
showAllFiles,
showAllThreads,
showMentions,
showChannelMembers,
Expand Down
24 changes: 12 additions & 12 deletions packages/react/src/components/ChatInput/ChatInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const ChatInput = ({ scrollToBottom }) => {
(state) => state.setIsLoginModalOpen
);

const [msgLongMsgLongErrorModal, setMsgLongErrorModal] = useState(false);
const [isMsgLong, setIsMsgLong] = useState(false);

const {
editMessage,
Expand Down Expand Up @@ -130,11 +130,11 @@ const ChatInput = ({ scrollToBottom }) => {
const openLoginModal = () => {
setIsLoginModalOpen(true);
};
const openMsgLongErrorModal = () => {
setMsgLongErrorModal(true);
const openMsgLongModal = () => {
setIsMsgLong(true);
};
const closeMsgLongErrorModal = () => {
setMsgLongErrorModal(false);
const closeMsgLongModal = () => {
setIsMsgLong(false);
};

const onJoin = async () => {
Expand Down Expand Up @@ -177,7 +177,7 @@ const ChatInput = ({ scrollToBottom }) => {

const msgMaxLength = 500;
if (message.length > msgMaxLength) {
openMsgLongErrorModal();
openMsgLongModal();
return;
}

Expand Down Expand Up @@ -248,7 +248,7 @@ const ChatInput = ({ scrollToBottom }) => {
};

const handleConvertToAttachment = () => {
closeMsgLongErrorModal();
closeMsgLongModal();
sendMessage(true);
};

Expand Down Expand Up @@ -566,7 +566,7 @@ const ChatInput = ({ scrollToBottom }) => {
<ActionButton
ghost
size="medium"
onClick={sendMessage}
onClick={() => sendMessage()}
disabled={disableButton || isRecordingMessage}
>
<Icon className={styles.chatInputIconCursor} name="send" />
Expand All @@ -585,20 +585,20 @@ const ChatInput = ({ scrollToBottom }) => {
/>
)}
</Box>
{msgLongMsgLongErrorModal && (
{isMsgLong && (
<Modal>
<Modal
css={css`
padding: 1em;
`}
onClose={closeMsgLongErrorModal}
onClose={closeMsgLongModal}
>
<Modal.Header>
<Modal.Title>
<Icon name="report" size="1.25rem" />
Message Too Long!
</Modal.Title>
<Modal.Close onClick={closeMsgLongErrorModal} />
<Modal.Close onClick={closeMsgLongModal} />
</Modal.Header>
<Modal.Content
css={css`
Expand All @@ -609,7 +609,7 @@ const ChatInput = ({ scrollToBottom }) => {
Send it as attachment instead?{' '}
</Modal.Content>
<Modal.Footer>
<Button color="secondary" onClick={closeMsgLongErrorModal}>
<Button color="secondary" onClick={closeMsgLongModal}>
Cancel
</Button>
<Button onClick={handleConvertToAttachment} color="primary">
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/EmbeddedChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const EmbeddedChat = ({
useEffect(() => {
setToastbarPosition(toastBarPosition);
setShowAvatar(showAvatar);
}, [toastBarPosition, showAvatar]);
}, [toastBarPosition, showAvatar, setShowAvatar, setToastbarPosition]);

const {
onDrag,
Expand Down
61 changes: 61 additions & 0 deletions packages/react/src/components/Files/FileMetrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { css } from '@emotion/react';
import { formatDistance } from 'date-fns';
import useComponentOverrides from '../../theme/useComponentOverrides';
import { Box } from '../Box';
import { appendClassNames } from '../../lib/appendClassNames';
import { Icon } from '../Icon';

const FileMetricsCss = css`
display: flex;
margin-left: -0.25rem;
margin-right: -0.25rem;
margin-inline: -0.25rem;
margin-top: 0.5rem;
`;

const FileMetricsItemCss = css`
letter-spacing: 0rem;
font-size: 0.625rem;
font-weight: 700;
line-height: 0.75rem;
display: flex;
justify-content: center;
align-items: center;
margin-left: 0.25rem;
color: #6c727a;
`;

const FileMetricsItemLabelCss = css`
margin: 0.25rem;
margin-inline-start: 0.25rem;
white-space: nowrap;
`;

export const FileMetrics = ({ className = '', file, style = {}, ...props }) => {
const { styleOverrides, classNames } = useComponentOverrides(
'MessageMetrics',
className,
style
);
return (
<Box
css={FileMetricsCss}
className={appendClassNames('ec-message-metrics', classNames)}
style={styleOverrides}
{...props}
>
<div
css={FileMetricsItemCss}
title={new Date(file.uploadedAt).toLocaleString()}
>
<Icon size="1.25rem" name="clock" />
<div css={FileMetricsItemLabelCss}>
{formatDistance(new Date(file.uploadedAt), new Date(), {
addSuffix: true,
})}
</div>
</div>
</Box>
);
};
27 changes: 27 additions & 0 deletions packages/react/src/components/Files/FilePreviewContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { css } from '@emotion/react';
import { Avatar } from '../Avatar';
import { Box } from '../Box';
import { Icon } from '../Icon';

const FilePreviewContainer = ({ file, sequential, isStarred }) => {
const FilePreviewContainerCss = css`
margin: 3px;
width: 2.25em;
max-height: 2.25em;
display: flex;
justify-content: flex-end;
`;

return (
<Box css={FilePreviewContainerCss}>
{!sequential ? (
<Avatar url={file.url} alt="file" size="2.25em" />
) : isStarred ? (
<Icon style={{ opacity: 0.5 }} name="star-filled" size="1.2em" />
) : null}
</Box>
);
};

export default FilePreviewContainer;
96 changes: 96 additions & 0 deletions packages/react/src/components/Files/FilePreviewHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/react';
import { format } from 'date-fns';
import { useUserStore } from '../../store';
import { Icon } from '../Icon';
import useComponentOverrides from '../../theme/useComponentOverrides';
import { Box } from '../Box';
import { appendClassNames } from '../../lib/appendClassNames';

const FilePreviewHeaderCss = css`
display: flex;
overflow-x: hidden;
flex-direction: row;
flex-grow: 0;
flex-shrink: 1;
min-width: 1px;
padding-right: 3px;
margin-top: 0.125rem;
margin-bottom: 0.125rem;
margin-block: 0.125rem;
gap: 0.125rem;
align-items: center;
max-width: 85%;
`;

const FilePreviewHeaderNameCss = css`
letter-spacing: 0rem;
display: inline-block;
font-size: 0.875rem;
font-weight: 700;
line-height: 1.25rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex-shrink: 1;
color: #2f343d;
`;

const FilePreviewHeaderTimestapCss = css`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
letter-spacing: 0rem;
font-size: 0.75rem;
font-weight: 400;
line-height: 1rem;
flex-shrink: 0;
color: #9ea2a8;
`;

const FilePreviewHeader = ({ file, isTimeStamped = true }) => {
const { styleOverrides, classNames } = useComponentOverrides('MessageHeader');
const authenticatedUserId = useUserStore((state) => state.userId);
const isStarred =
file.starred && file.starred.find((u) => u._id === authenticatedUserId);

return (
<Box
css={FilePreviewHeaderCss}
className={appendClassNames('ec-file-header', classNames)}
style={styleOverrides}
>
<Box
is="span"
css={FilePreviewHeaderNameCss}
className={appendClassNames('ec-file-header-name')}
>
{file.name}
</Box>

{isTimeStamped && (
<Box
is="span"
css={FilePreviewHeaderTimestapCss}
className={appendClassNames('ec-file-header-timestamp')}
>
{format(new Date(file.ts), 'h:mm a')}
</Box>
)}
{isStarred ? (
<Icon
style={{ marginInlineEnd: '0.4rem', opacity: 0.5 }}
name="star-filled"
size="1em"
/>
) : null}
</Box>
);
};

export default FilePreviewHeader;

FilePreviewHeader.propTypes = {
file: PropTypes.any,
};
Loading

0 comments on commit 5816d76

Please sign in to comment.