diff --git a/packages/react/src/views/FileMessage/FileMessage.js b/packages/react/src/views/FileMessage/FileMessage.js index a074e981ef..ff433f74d0 100644 --- a/packages/react/src/views/FileMessage/FileMessage.js +++ b/packages/react/src/views/FileMessage/FileMessage.js @@ -6,9 +6,12 @@ import { Modal, Button, Icon, + useTheme, useToastBarDispatch, useComponentOverrides, appendClassNames, + lighten, + darken, } from '@embeddedchat/ui-elements'; import FilePreviewContainer from './FilePreviewContainer'; import FileBodyContainer from '../Message/MessageBodyContainer'; @@ -17,7 +20,7 @@ import FilePreviewHeader from './FilePreviewHeader'; import { MessageBody as FileBody } from '../Message/MessageBody'; import { FileMetrics } from './FileMetrics'; import { useRCContext } from '../../context/RCInstance'; -import { useMessageStore } from '../../store'; +import { useMessageStore, useSidebarStore } from '../../store'; import { fileDisplayStyles as styles } from './Files.styles'; const FileMessage = ({ fileMessage }) => { @@ -25,6 +28,9 @@ const FileMessage = ({ fileMessage }) => { const dispatchToastMessage = useToastBarDispatch(); const { RCInstance } = useRCContext(); const messages = useMessageStore((state) => state.messages); + const setShowSidebar = useSidebarStore((state) => state.setShowSidebar); + const { theme } = useTheme(); + const { mode } = useTheme(); const [fileToDelete, setFileToDelete] = useState({}); @@ -37,6 +43,39 @@ const FileMessage = ({ fileMessage }) => { document.body.removeChild(anchor); }, []); + const navigateToFile = (msg) => { + if (!msg || !msg._id) { + console.error('Invalid message object:', msg); + return; + } + + const message = messages.find((mg) => mg?.file?._id === msg._id); + + if (message) { + let element; + setTimeout(() => { + const childElement = document.getElementById( + `ec-message-body-${message._id}` + ); + element = childElement.closest('.ec-message'); + + if (element) { + setShowSidebar(false); + element.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + + element.style.backgroundColor = + mode === 'light' + ? darken(theme.colors.warning, 0.03) + : lighten(theme.colors.warningForeground, 0.03); + + setTimeout(() => { + element.style.backgroundColor = ''; + }, 2000); + } + }, 300); + } + }; + const deleteFile = useCallback( async (file) => { messages.forEach(async (message) => { @@ -92,10 +131,16 @@ const FileMessage = ({ fileMessage }) => { }, { id: 'delete', - action: () => setFileToDelete(fileMessage), + action: () => setFileToDelete(fileMessage._id), label: 'Delete', icon: 'trash', }, + { + id: 'navigate', + action: () => navigateToFile(fileMessage), + label: 'Jump to message', + icon: 'arrow-jump', + }, ]} /> diff --git a/packages/ui-elements/src/components/Icon/icons/ArrowJump.js b/packages/ui-elements/src/components/Icon/icons/ArrowJump.js new file mode 100644 index 0000000000..17e69514b9 --- /dev/null +++ b/packages/ui-elements/src/components/Icon/icons/ArrowJump.js @@ -0,0 +1,9 @@ +import React from 'react'; + +const ArrowJump = (props) => ( + + + +); + +export default ArrowJump; diff --git a/packages/ui-elements/src/components/Icon/icons/index.js b/packages/ui-elements/src/components/Icon/icons/index.js index 77cd6a4511..f348ba0673 100644 --- a/packages/ui-elements/src/components/Icon/icons/index.js +++ b/packages/ui-elements/src/components/Icon/icons/index.js @@ -61,6 +61,7 @@ import Arc from './Arc'; import Avatar from './Avatar'; import FormatText from './FormatText'; import Cog from './Cog'; +import ArrowJump from './ArrowJump'; const icons = { file: File, @@ -126,6 +127,7 @@ const icons = { avatar: Avatar, 'format-text': FormatText, cog: Cog, + 'arrow-jump': ArrowJump, }; export default icons;