Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#485 files menu option - sidebar #491

Merged
merged 13 commits into from
Mar 12, 2024
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
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]);
Copy link
Collaborator

@Spiral-Memory Spiral-Memory Mar 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it will cause an issue here with dependencies, still confirm it

Also confirm, there is no console errors. Rest LGTM!


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
Loading