diff --git a/packages/react/src/store/settingsStore.js b/packages/react/src/store/settingsStore.js index 4f9d78b68..2d8091fd2 100644 --- a/packages/react/src/store/settingsStore.js +++ b/packages/react/src/store/settingsStore.js @@ -1,8 +1,18 @@ import { create } from 'zustand'; +const DEFAULT_MESSAGE_LIMIT = 5000; + const useSettingsStore = create((set) => ({ - messageLimit: 5000, - setMessageLimit: (messageLimit) => set(() => ({ messageLimit })), + // Default fallback value; will be overridden from RC server (Message_MaxAllowedSize) when available + messageLimit: DEFAULT_MESSAGE_LIMIT, + setMessageLimit: (messageLimit) => + set(() => ({ + // If server does not return a valid value, keep using the fallback + messageLimit: + typeof messageLimit === 'number' && Number.isFinite(messageLimit) + ? messageLimit + : DEFAULT_MESSAGE_LIMIT, + })), })); export default useSettingsStore; diff --git a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js index 01123dafb..3d668e903 100644 --- a/packages/react/src/views/AttachmentPreview/AttachmentPreview.js +++ b/packages/react/src/views/AttachmentPreview/AttachmentPreview.js @@ -1,10 +1,18 @@ import React, { useContext, useState, useRef, useEffect } from 'react'; import { css } from '@emotion/react'; -import { Box, Icon, Button, Input, Modal } from '@embeddedchat/ui-elements'; +import { + Box, + Icon, + Button, + Input, + Modal, + useTheme, +} from '@embeddedchat/ui-elements'; import useAttachmentWindowStore from '../../store/attachmentwindow'; import CheckPreviewType from './CheckPreviewType'; import RCContext from '../../context/RCInstance'; import { useMessageStore, useMemberStore } from '../../store'; +import useSettingsStore from '../../store/settingsStore'; import getAttachmentPreviewStyles from './AttachmentPreview.styles'; import { parseEmoji } from '../../lib/emoji'; import MembersList from '../Mentions/MembersList'; @@ -13,29 +21,30 @@ import useSearchMentionUser from '../../hooks/useSearchMentionUser'; const AttachmentPreview = () => { const { RCInstance, ECOptions } = useContext(RCContext); + const { theme } = useTheme(); const styles = getAttachmentPreviewStyles(); const toggle = useAttachmentWindowStore((state) => state.toggle); const data = useAttachmentWindowStore((state) => state.data); const setData = useAttachmentWindowStore((state) => state.setData); + const [isPending, setIsPending] = useState(false); const messageRef = useRef(null); const [showMembersList, setShowMembersList] = useState(false); const [filteredMembers, setFilteredMembers] = useState([]); const [mentionIndex, setMentionIndex] = useState(-1); const [startReadMentionUser, setStartReadMentionUser] = useState(false); - const [keyPressed, setKeyPressed] = useState(null); - const [fileName, setFileName] = useState(data?.name); + const [fileName, setFileName] = useState(data?.name ?? ''); + useEffect(() => setFileName(data?.name ?? ''), [data?.name]); - const threadId = useMessageStore((state) => state.threadMainMessage?._id); - const handleFileName = (e) => { - setFileName(e.target.value); - }; + const [description, setDescription] = useState(''); + const charCount = description.length; + const msgMaxLength = useSettingsStore((s) => s?.messageLimit); + const isOverLimit = msgMaxLength && charCount > msgMaxLength; - const { members } = useMemberStore((state) => ({ - members: state.members, - })); + const threadId = useMessageStore((state) => state.threadMainMessage?._id); + const { members } = useMemberStore((state) => ({ members: state.members })); const searchMentionUser = useSearchMentionUser( members, @@ -46,47 +55,47 @@ const AttachmentPreview = () => { setShowMembersList ); + const handleFileName = (e) => setFileName(e.target.value); + const handleFileDescription = (e) => { - const description = e.target.value; - messageRef.current.value = parseEmoji(description); - searchMentionUser(description); + const raw = e.target.value || ''; + setDescription(raw); + + if (messageRef.current && typeof messageRef.current.value !== 'undefined') { + try { + messageRef.current.value = raw; + } catch (err) { + } + } + + searchMentionUser(raw); }; const submit = async () => { + if (isPending) return; + if (msgMaxLength && description.length > msgMaxLength) return; + setIsPending(true); - await RCInstance.sendAttachment( - data, - fileName, - messageRef.current.value, - ECOptions?.enableThreads ? threadId : undefined - ); - toggle(); - setData(null); - if (isPending) { + try { + await RCInstance.sendAttachment( + data, + fileName, + parseEmoji(description), + ECOptions?.enableThreads ? threadId : undefined + ); + toggle(); + setData(null); + } finally { setIsPending(false); } }; - useEffect(() => { - const keyHandler = (e) => { - if (e.key === 'Enter') { - e.preventDefault(); - setKeyPressed('Enter'); - } - }; - - document.addEventListener('keydown', keyHandler); - return () => { - document.removeEventListener('keydown', keyHandler); - }; - }, []); - - useEffect(() => { - if (keyPressed === 'Enter') { + const onDescKeyDown = (e) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); submit(); - setKeyPressed(null); } - }, [keyPressed, submit]); + }; return ( @@ -98,11 +107,12 @@ const AttachmentPreview = () => { css={css` margin-right: 0.5rem; `} - />{' '} + /> File Upload + { > + { File name { - handleFileName(e); - }} + onChange={handleFileName} value={fileName} type="text" css={styles.input} @@ -150,6 +159,7 @@ const AttachmentPreview = () => { > File description + {showMembersList && ( @@ -161,21 +171,73 @@ const AttachmentPreview = () => { setFilteredMembers={setFilteredMembers} setStartReadMentionUser={setStartReadMentionUser} setShowMembersList={setShowMembersList} - css={css` - width: auto; - `} /> )} + { - handleFileDescription(e); - }} + onChange={handleFileDescription} + onKeyDown={onDescKeyDown} type="text" - css={styles.input} placeholder="Description" ref={messageRef} + value={description} + css={css` + ${styles.input}; + border-color: ${isOverLimit + ? theme.colors.destructive + : null}; + color: ${isOverLimit ? theme.colors.destructive : null}; + `} /> + + {msgMaxLength && ( + + + {isOverLimit + ? `Cannot upload file, description is over the ${msgMaxLength} character limit` + : ''} + + + + + )} @@ -190,12 +252,8 @@ const AttachmentPreview = () => { - diff --git a/packages/react/src/views/ChatHeader/ChatHeader.js b/packages/react/src/views/ChatHeader/ChatHeader.js index 9143598d3..60563fd7e 100644 --- a/packages/react/src/views/ChatHeader/ChatHeader.js +++ b/packages/react/src/views/ChatHeader/ChatHeader.js @@ -150,8 +150,14 @@ const ChatHeader = ({ useEffect(() => { const getMessageLimit = async () => { - const messageLimitObj = await RCInstance.getMessageLimit(); - setMessageLimit(messageLimitObj?.value); + try { + const messageLimitObj = await RCInstance.getMessageLimit(); + setMessageLimit(messageLimitObj?.value); + } catch (e) { + // In case the server call fails, settingsStore keeps using its fallback (5000) + console.error('Failed to fetch message limit', e); + setMessageLimit(undefined); + } }; const setMessageAllowed = async () => {