Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions packages/react/src/store/settingsStore.js
Original file line number Diff line number Diff line change
@@ -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;
172 changes: 115 additions & 57 deletions packages/react/src/views/AttachmentPreview/AttachmentPreview.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
Expand All @@ -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 (
<Modal onClose={toggle}>
Expand All @@ -98,11 +107,12 @@ const AttachmentPreview = () => {
css={css`
margin-right: 0.5rem;
`}
/>{' '}
/>
File Upload
</Modal.Title>
<Modal.Close onClick={toggle} />
</Modal.Header>

<Modal.Content>
<Box css={styles.modalContent}>
<Box
Expand All @@ -113,6 +123,7 @@ const AttachmentPreview = () => {
>
<CheckPreviewType data={data} />
</Box>

<Box
css={css`
margin: 30px;
Expand All @@ -129,9 +140,7 @@ const AttachmentPreview = () => {
File name
</Box>
<Input
onChange={(e) => {
handleFileName(e);
}}
onChange={handleFileName}
value={fileName}
type="text"
css={styles.input}
Expand All @@ -150,6 +159,7 @@ const AttachmentPreview = () => {
>
File description
</Box>

<Box css={styles.fileDescription}>
<Box css={styles.mentionListContainer}>
{showMembersList && (
Expand All @@ -161,21 +171,73 @@ const AttachmentPreview = () => {
setFilteredMembers={setFilteredMembers}
setStartReadMentionUser={setStartReadMentionUser}
setShowMembersList={setShowMembersList}
css={css`
width: auto;
`}
/>
)}
</Box>

<Input
onChange={(e) => {
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 && (
<Box
css={css`
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 6px;
gap: 12px;
font-size: 0.875rem;
`}
>
<Box
css={css`
color: ${isOverLimit
? theme.colors.destructive
: 'transparent'};
font-weight: 500;
text-align: left;
flex: 1 1 auto;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`}
aria-hidden={!isOverLimit}
role={isOverLimit ? 'alert' : undefined}
>
{isOverLimit
? `Cannot upload file, description is over the ${msgMaxLength} character limit`
: ''}
</Box>

<Box
css={css`
color: ${isOverLimit
? theme.colors.destructive
: '#6b7280'};
min-width: 68px;
text-align: right;
flex: 0 0 auto;
`}
aria-hidden="true"
>
({charCount}/{msgMaxLength})
</Box>
</Box>
)}
</Box>
</Box>
</Box>
Expand All @@ -190,12 +252,8 @@ const AttachmentPreview = () => {
<Button type="secondary" onClick={toggle}>
Cancel
</Button>
<Button
disabled={isPending}
onClick={() => {
submit();
}}
>

<Button disabled={isPending || isOverLimit} onClick={submit}>
{isPending ? 'Sending...' : 'Send'}
</Button>
</Modal.Footer>
Expand Down
10 changes: 8 additions & 2 deletions packages/react/src/views/ChatHeader/ChatHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () => {
Expand Down
Loading