const { componentOwnerId, selectedChat, sendMessage, openThread, isThread, isReadOnly, isOwner, isModerator, fetchAccounts, } = props; const Container = styled.div` position: absolute; width: 100%; bottom: 16px; padding-left: 16px; padding-right: 16px; padding-top: 12px; padding-bottom: 12px; background-color: #1d1d21; display: flex; align-items: end; @media (min-width: 1025px) { gap: 8px; border-radius: 4px; } @media (max-width: 1024px) { position: fixed; margin: 0 !important; left: 0; right: 0; bottom: 0px; border-top-left-radius: 4px; border-top-right-radius: 4px; gap: 4px; margin: 0px; padding-left: 8px; padding-right: 8px; padding-bottom: 12px; padding-top: 12px; width: 100% !important; } `; const EmojiPopupContainer = styled.div` position: absolute; bottom: 70px; right: 2.5rem; `; const UploadPopupContainer = styled.div` position: absolute; bottom: 46px; left: 16px; @media (max-width: 1024px) { left: 8px; } `; const UploadContainer = styled.div` background-color: #25252a; border-radius: 2px; width: fit-content; `; const [showUpload, setShowUpload] = useState(false); const [message, setMessage] = useState(''); //Message is cleaned in Quill after it is returned to bos components so //this ref is setting value from callback to be used after sending with ENTER key const messageRef = useRef(null); const [uploadedFile, setUploadedFile] = useState(null); const [uploadedImage, setUploadedImage] = useState(null); const [emojiSelectorOpen, setEmojiSelectorOpen] = useState(false); const [error, setError] = useState(''); const [sendFromLib, setSendFromLib] = useState(false); const handleMessageChange = useCallback((mesage) => { setMessage(mesage); }, []); const resetFile = useCallback(() => { setUploadedFile(null); setShowUpload(false); }, []); const resetImage = useCallback(() => { setUploadedImage(null); setShowUpload(false); }, []); const emptyText = /^(\s*<p><br><\/p>\s*)*$/; const markdownParser = (text) => { const toHTML = text.replace( /(\b(https?:\/\/[^\s<]+\/?)\b)|^(#####|####|###|##|#) (.*)$|(@everyone)|(@here)|(@[a-z\d]+[-_]*[a-z\d]+[-_]*[a-z\d]+\.(near|testnet))|<p><br><\/p>(?=\s*$)/gim, ( match, url, url2, heading, text, everyoneMention, hereMention, validMention, ) => { if (url || url2) { return `<a href="${url || url2}" class="url-link" target="_blank">${ url || url2 }</a>`; } else if (heading) { return text; } else if (everyoneMention) { return `<span class='mention-everyone'>@everyone</span>`; } else if (hereMention) { return `<span class='mention-here'>@here</span>`; } else if (validMention) { return `<span class='mention mention-user-${validMention .replace('@', '') .replace(/\./g, '\\.') .replace(/_/g, '\\_')}'>${validMention}</span>`; } else { return ''; } }, ); return toHTML; }; const isActive = (message && !emptyText.test(markdownParser(message))) || uploadedImage || uploadedFile; const handleSendMessage = useCallback( (vmValue) => { const messageToSend = vmValue || message; if ( (uploadedFile && !uploadedFile.file.cid) || (uploadedImage && !uploadedImage.file.cid) ) { return; } else if ( emptyText.test(markdownParser(messageToSend)) && !uploadedImage && !uploadedFile ) { handleMessageChange(''); messageRef.current = ''; } else { sendMessage( markdownParser(messageToSend), uploadedImage, selectedChat, uploadedFile, openThread, ); resetImage(); resetFile(); setShowUpload(false); setEmojiSelectorOpen(false); handleMessageChange(''); messageRef.current = ''; } }, [message, uploadedImage, uploadedFile, openThread, selectedChat], ); useEffect(() => { if (sendFromLib) { handleSendMessage(messageRef.current); setSendFromLib(false); } }, [sendFromLib]); //Hack for https://stackoverflow.com/questions/57847594/react-hooks-accessing-up-to-date-state-from-within-a-callback //as passed handleSendMessage to input field component use staled useState values const handleSendMessageFromLib = (value) => { messageRef.current = value; setSendFromLib(true); }; const Wrapper = styled.div` flex-grow: 1; display: contents; align-items: start; background-color: #111111; `; const FullWidthWrapper = styled.div` display: flow; flex-direction: row; overflow: hidden; align-items: start; width: 100%; `; // const IconUploadWrapper = styled.div` // height: 34px; // width: 34px; // padding: 8px; // display: flex; // justify-content: center; // border-radius: 2px; // align-items: center; // :hover { // background-color: #686672; // fill: #fff; // } // cursor: pointer; // fill: #686672; // `; // const IconUpload = ({ onClick }) => ( // <IconUploadWrapper> // <svg // onClick={onClick} // xmlns="http://www.w3.org/2000/svg" // width="18" // height="18" // className="bi bi-plus-circle" // viewBox="0 0 16 16" // > // <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" /> // <path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" /> // </svg> // </IconUploadWrapper> // ); const EmojiContainer = styled.div` fill: #686672; height: 2rem; width: 2rem; display: flex; justify-content: center; align-items: center; cursor: pointer; :hover { fill: #ffdd1d; } `; const IconEmojiSvg = styled.svg` cursor: pointer; height: 1.5em; width: 1.5em; `; const IconEmoji = () => { return ( <EmojiContainer> <IconEmojiSvg xmlns="http://www.w3.org/2000/svg"> <path d="M10 0C12.6522 0 15.1957 1.05357 17.0711 2.92893C18.9464 4.8043 20 7.34784 20 10C20 12.6522 18.9464 15.1957 17.0711 17.0711C15.1957 18.9464 12.6522 20 10 20C7.34784 20 4.8043 18.9464 2.92893 17.0711C1.05357 15.1957 0 12.6522 0 10C0 7.34784 1.05357 4.8043 2.92893 2.92893C4.8043 1.05357 7.34784 0 10 0V0ZM8.75 8.125C8.75 7.09 8.19 6.25 7.5 6.25C6.81 6.25 6.25 7.09 6.25 8.125C6.25 9.16 6.81 10 7.5 10C8.19 10 8.75 9.16 8.75 8.125ZM5.35625 11.9588C5.2127 12.0416 5.10796 12.1781 5.06506 12.3383C5.02216 12.4984 5.04462 12.669 5.1275 12.8125C5.6211 13.6679 6.33132 14.3783 7.18668 14.872C8.04204 15.3657 9.01237 15.6254 10 15.625C10.9876 15.6252 11.9578 15.3654 12.8131 14.8717C13.6684 14.378 14.3787 13.6678 14.8725 12.8125C14.9142 12.7414 14.9414 12.6627 14.9526 12.5811C14.9637 12.4994 14.9586 12.4163 14.9376 12.3367C14.9165 12.257 14.8799 12.1822 14.8298 12.1168C14.7797 12.0513 14.7172 11.9964 14.6458 11.9551C14.5744 11.9139 14.4956 11.8872 14.4139 11.8766C14.3321 11.866 14.2491 11.8716 14.1696 11.8932C14.09 11.9148 14.0155 11.952 13.9504 12.0025C13.8852 12.053 13.8307 12.1158 13.79 12.1875C13.4061 12.8529 12.8537 13.4055 12.1883 13.7895C11.523 14.1735 10.7682 14.3755 10 14.375C9.23178 14.3755 8.47701 14.1735 7.81166 13.7895C7.14632 13.4055 6.59389 12.8529 6.21 12.1875C6.12712 12.044 5.99061 11.9392 5.8305 11.8963C5.67039 11.8534 5.4998 11.8759 5.35625 11.9588ZM11.7963 7.82125C11.7564 7.74952 11.7027 7.68634 11.6384 7.63533C11.5741 7.58432 11.5004 7.54648 11.4215 7.52396C11.3425 7.50144 11.26 7.49469 11.1784 7.50409C11.0969 7.51349 11.018 7.53886 10.9462 7.57875C10.8745 7.61864 10.8113 7.67227 10.7603 7.73657C10.7093 7.80088 10.6715 7.8746 10.649 7.95353C10.6264 7.03246 10.6197 8.11505 10.6291 8.19659C10.6385 8.27813 10.6639 8.35702 10.7037 8.42875C11.1163 9.1725 11.9012 9.6875 12.8125 9.6875C13.725 9.6875 14.5075 9.1725 14.9213 8.42875C14.9611 8.35702 14.9865 8.27813 14.9959 8.19659C15.0053 8.11505 14.9986 8.03246 14.976 7.95353C14.9535 7.8746 14.9157 7.80088 14.8647 7.73657C14.8137 7.67227 14.7505 7.61864 14.6788 7.57875C14.607 7.53886 14.5281 7.51349 14.4466 7.50409C14.365 7.49469 14.2825 7.50144 14.2035 7.52396C14.1246 7.54648 14.0509 7.58432 13.9866 7.63533C13.9223 7.68634 13.8686 7.74952 13.8287 7.82125C13.7301 8.00555 13.5837 8.15996 13.4049 8.26837C13.2261 8.37677 13.0216 8.43518 12.8125 8.4375C12.6034 8.43518 12.3989 8.37677 12.2201 8.26837C12.0413 8.15996 11.8949 8.00555 11.7963 7.82125Z" /> </IconEmojiSvg> </EmojiContainer> ); }; const IconContainer = styled.div` display: flex; justify-content: center; align-items: center; cursor: pointer; height: 2em; width: 2em; flex: 1 0 auto; `; const IconSendSvg = styled.svg` :hover { fill: #4e95ff; } cursor: pointer; height: 1.5em; width: 1.5em; `; const IconSend = ({ onClick, isActive }) => ( <IconContainer onClick={onClick}> <IconSendSvg xmlns="http://www.w3.org/2000/svg" fill={`${isActive ? '#4E95FF' : '#686672'}`} > <path fillRule="evenodd" clipRule="evenodd" d="M23.9459 1.02895C24.0005 0.892657 24.0138 0.743347 23.9843 0.599532C23.9548 0.455718 23.8838 0.323724 23.7799 0.219914C23.6761 0.116105 23.5441 0.0450444 23.4003 0.0155432C23.2565 -0.013958 23.1072 -0.00060275 22.9709 0.0539533L1.1504 8.78245H1.1489L0.470904 9.05245C0.342489 9.10368 0.230732 9.1894 0.147977 9.30015C0.0652226 9.4109 0.0146909 9.54237 0.00196413 9.68004C-0.0107627 9.8177 0.0148107 9.95621 0.0758594 10.0803C0.136908 10.2043 0.231056 10.3091 0.347904 10.383L0.962904 10.773L0.964404 10.776L8.4569 15.543L13.2239 23.0355L13.2269 23.0385L13.6169 23.6535C13.691 23.7699 13.7959 23.8635 13.9198 23.9242C14.0438 23.9849 14.182 24.0102 14.3194 23.9973C14.4568 23.9844 14.588 23.9339 14.6986 23.8512C14.8091 23.7686 14.8947 23.6571 14.9459 23.529L23.9459 1.02895ZM21.1964 3.86395L21.9029 2.09695L20.1359 2.80345L8.8949 14.0445L9.4019 14.367C9.49494 14.426 9.57381 14.5049 9.6329 14.598L9.9554 15.105L21.1964 3.86395Z" /> </IconSendSvg> </IconContainer> ); const Placeholder = styled.div` position: absolute; z-index: 10; bottom: ${({ placeholderPosition }) => placeholderPosition && placeholderPosition}; left: 68px; color: #686672; font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; pointer-events: none; @media (max-width: 1024px) { font-size: 14px; font-style: normal; font-weight: 400; line-height: 150%; bottom: ${({ placeholderPositionMobile }) => placeholderPositionMobile && placeholderPositionMobile}; left: 56px; } `; const getCustomStyle = (openThread) => { const customStyle = { width: 'calc(100% - 440px)', marginLeft: '2.5rem', marginRight: '2.5rem', }; if (openThread && !isThread) { customStyle.width = 'calc(60% - 262px)'; customStyle.marginRight = '1.25rem'; } else if (!openThread && !isThread) { customStyle.width = 'calc(100% - 440px)'; } else if (openThread && isThread) { customStyle.width = 'calc(40% - 212px)'; customStyle.marginLeft = '0rem'; customStyle.marginRight = '1.25rem'; } return customStyle; }; const ReadOnlyField = styled.div` background-color: #111111; height: 2rem; border-radius: 4px; padding: 4px 8px 4px 8px; font-family: Helvetica Neue; font-size: 16px; font-style: normal; font-weight: 400; line-height: 150%; color: #797978; flex: 1; @media (max-width: 1024px) { font-size: 14px; display: flex; align-items: center; } `; let canWriteMessage = false; if (isReadOnly) { if (isModerator || isOwner) { canWriteMessage = true; } else { canWriteMessage = false; } } else { canWriteMessage = true; } let placeholderPosition = '16px'; if (uploadedFile.file.cid) { placeholderPosition = '61px'; } else if (uploadedImage.file.cid) { placeholderPosition = '86px'; } const [showAutocomplete, setShowAutocomplete] = useState(false); const autoCompleteAccountId = (accountId) => { let text = message.replace(/[\s]{0,1}@[^\s]*$/, ''); text = `${text} @${accountId}`.trim() + ' \u200B'; setMessage(text); setShowAutocomplete(false); }; useEffect(() => { const showAccountAutocomplete = /@[\w][^\s]*$/.test(message); setShowAutocomplete(showAccountAutocomplete); }, [message]); const ImageIconSvg = () => ( <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg" > <path d="M15.75 12.75C15.75 13.7446 15.3549 14.6984 14.6517 15.4017C13.9484 16.1049 12.9946 16.5 12 16.5C11.0054 16.5 10.0516 16.1049 9.34835 15.4017C8.64509 14.6984 8.25 13.7446 8.25 12.75C8.25 11.7554 8.64509 10.8016 9.34835 10.0983C10.0516 9.39509 11.0054 9 12 9C12.9946 9 13.9484 9.39509 14.6517 10.0983C15.3549 10.8016 15.75 11.7554 15.75 12.75Z" fill="white" /> <path d="M3 6C2.20435 6 1.44129 6.31607 0.87868 6.87868C0.316071 7.44129 0 8.20435 0 9V18C0 18.7956 0.316071 19.5587 0.87868 20.1213C1.44129 20.6839 2.20435 21 3 21H21C21.7956 21 22.5587 20.6839 23.1213 20.1213C23.6839 19.5587 24 18.7956 24 18V9C24 8.20435 23.6839 7.44129 23.1213 6.87868C22.5587 6.31607 21.7956 6 21 6H19.242C18.4464 5.99983 17.6835 5.68365 17.121 5.121L15.879 3.879C15.3165 3.31635 14.5536 3.00017 13.758 3H10.242C9.44641 3.00017 8.68348 3.31635 8.121 3.879L6.879 5.121C6.31652 5.68365 5.55358 5.99983 4.758 6H3ZM3.75 9C3.55109 9 3.36032 8.92098 3.21967 8.78033C3.07902 8.63968 3 8.44891 3 8.25C3 8.05109 3.07902 7.86032 3.21967 7.71967C3.36032 7.57902 3.55109 7.5 3.75 7.5C3.94891 7.5 4.13968 7.57902 4.28033 7.71967C4.42098 7.86032 4.5 8.05109 4.5 8.25C4.5 8.44891 4.42098 8.63968 4.28033 8.78033C4.13968 8.92098 3.94891 9 3.75 9ZM17.25 12.75C17.25 14.1424 16.6969 15.4777 15.7123 16.4623C14.7277 17.4469 13.3924 18 12 18C10.6076 18 9.27226 17.4469 8.28769 16.4623C7.30312 15.4777 6.75 14.1424 6.75 12.75C6.75 11.3576 7.30312 10.0223 8.28769 9.03769C9.27226 8.05312 10.6076 7.5 12 7.5C13.3924 7.5 14.7277 8.05312 15.7123 9.03769C16.6969 10.0223 17.25 11.3576 17.25 12.75Z" fill="white" /> </svg> ); const FileIconSvg = () => ( <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff" xmlns="http://www.w3.org/2000/svg" > <g clipPath="url(#clip0_952_64107)"> <path d="M13.9395 0H6C5.20435 0 4.44129 0.316071 3.87868 0.87868C3.31607 1.44129 3 2.20435 3 3V21C3 21.7956 3.31607 22.5587 3.87868 23.1213C4.44129 23.6839 5.20435 24 6 24H18C18.7956 24 19.5587 23.6839 20.1213 23.1213C20.6839 22.5587 21 21.7956 21 21V7.0605C20.9999 6.66271 20.8418 6.28124 20.5605 6L15 0.4395C14.7188 0.158176 14.3373 8.49561e-05 13.9395 0V0ZM14.25 5.25V2.25L18.75 6.75H15.75C15.3522 6.75 14.9706 6.59196 14.6893 6.31066C14.408 6.02936 14.25 5.64782 14.25 5.25ZM9.75 8.25V9.201L10.5735 8.7255C10.6588 8.67548 10.7532 8.64283 10.8512 8.62943C10.9492 8.61603 11.0489 8.62214 11.1445 8.64743C11.2401 8.67271 11.3298 8.71665 11.4084 8.77674C11.487 8.83682 11.5529 8.91185 11.6023 8.9975C11.6518 9.08316 11.6838 9.17776 11.6966 9.27584C11.7093 9.37393 11.7025 9.47357 11.6766 9.56902C11.6507 9.66447 11.6062 9.75386 11.5456 9.83203C11.4849 9.9102 11.4095 9.97561 11.3235 10.0245L10.5 10.5L11.3235 10.9755C11.4095 11.0244 11.4849 11.0898 11.5456 11.168C11.6062 11.2461 11.6507 11.3355 11.6766 11.431C11.7025 11.5264 11.7093 11.6261 11.6966 11.7242C11.6838 11.8222 11.6518 11.9168 11.6023 12.0025C11.5529 12.0882 11.487 12.1632 11.4084 12.2233C11.3298 12.2833 11.2401 12.3273 11.1445 12.3526C11.0489 12.3779 10.9492 12.384 10.8512 12.3706C10.7532 12.3572 10.6588 12.3245 10.5735 12.2745L9.75 11.799V12.75C9.75 12.9489 9.67098 13.1397 9.53033 13.2803C9.38968 13.421 9.19891 13.5 9 13.5C8.80109 13.5 8.61032 13.421 8.46967 13.2803C8.32902 13.1397 8.25 12.9489 8.25 12.75V11.799L7.4265 12.2745C7.34117 12.3245 7.24679 12.3572 7.14879 12.3706C7.0508 12.384 6.95111 12.3779 6.85549 12.3526C6.75987 12.3273 6.67019 12.2833 6.59162 12.2233C6.51304 12.1632 6.44713 12.0882 6.39768 12.0025C6.34822 11.9168 6.3162 11.8222 6.30345 11.7242C6.2907 11.6261 6.29748 11.5264 6.32339 11.431C6.34931 11.3355 6.39385 11.2461 6.45445 11.168C6.51505 11.0898 6.59052 11.0244 6.6765 10.9755L7.5 10.5L6.6765 10.0245C6.50565 9.92434 6.38134 9.76066 6.33072 9.56919C6.2801 9.37772 6.30727 9.174 6.40629 9.00248C6.50532 8.83096 6.66817 8.70558 6.8593 8.65369C7.05043 8.6018 7.25433 8.62761 7.4265 8.7255L8.25 9.201V8.25C8.25 8.05109 8.32902 7.86032 8.46967 7.71967C8.61032 7.57902 8.80109 7.5 9 7.5C9.19891 7.5 9.38968 7.57902 9.53033 7.71967C9.67098 7.86032 9.75 8.05109 9.75 8.25ZM6.75 15H14.25C14.4489 15 14.6397 15.079 14.7803 15.2197C14.921 15.3603 15 15.5511 15 15.75C15 15.9489 14.921 16.1397 14.7803 16.2803C14.6397 16.421 14.4489 16.5 14.25 16.5H6.75C6.55109 16.5 6.36032 16.421 6.21967 16.2803C6.07902 16.1397 6 15.9489 6 15.75C6 15.5511 6.07902 15.3603 6.21967 15.2197C6.36032 15.079 6.55109 15 6.75 15ZM6.75 18H14.25C14.4489 18 14.6397 18.079 14.7803 18.2197C14.921 18.3603 15 18.5511 15 18.75C15 18.9489 14.921 19.1397 14.7803 19.2803C14.6397 19.421 14.4489 19.5 14.25 19.5H6.75C6.55109 19.5 6.36032 19.421 6.21967 19.2803C6.07902 19.1397 6 18.9489 6 18.75C6 18.5511 6.07902 18.3603 6.21967 18.2197C6.36032 18.079 6.55109 18 6.75 18Z" fill="white" /> </g> <defs> <clipPath id="clip0_952_64107"> <rect width="24" height="24" fill="white" /> </clipPath> </defs> </svg> ); const ErrorContainer = styled.div` position: relative; top: 0; padding-top: 4px; padding-bottom: 4px; padding-left: 8px; display: flex; width: 206px; color: #dc3545; font-family: Helvetica Neue; font-size: 14px; font-style: normal; font-weight: 400; line-height: 150%; background-color: #25252a; border-radius: 2px; `; const filterHtml = (message, emoji) => { if (!message) { return `<p>${emoji}</p>`; } const endingsToCheck = [ '<br>', '<br></p>', '</p>', '</strong>', '<br></li></ul>', '</li></ul>', '</em>', '</u>', '<br></li></ol>', '</li></ol>', ]; for (const ending of endingsToCheck) { if (message.endsWith(ending)) { const lastIndex = message.lastIndexOf(ending); return message.substring(0, lastIndex) + emoji + ending; } } }; const addEmojiToMessage = (emoji) => { const text = filterHtml(message, emoji); setMessage(text); }; const [accountData, setAccountData] = useState([]); const debouncedFetchUsers = (value) => { setTimeout( () => fetchAccounts(value.toLowerCase()).then((users) => { const accounts = users.map((account) => { return { id: account.id, active: account.active, }; }); setAccountData(accounts); }), 500, ); }; useEffect(() => { const term = message.split('@').pop().split('<')[0]; if (term) { debouncedFetchUsers(term); } }, [showAutocomplete]); return ( <> {canWriteMessage && ( <Container style={getCustomStyle(openThread, isThread)} key={openThread.id} > {/* <IconUpload onClick={() => { setError(''); if (!uploadedFile.file.cid && !uploadedImage.file.cid) { setEmojiSelectorOpen(false); setShowUpload(!showUpload); } }} /> */} <Wrapper> <FullWidthWrapper> <ChatInputField setValue={setMessage} value={message} handleMessageSend={handleSendMessageFromLib} /> {showAutocomplete && accountData.length > 0 && ( <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.AutocompleteList`} props={{ componentOwnerId, onSelect: autoCompleteAccountId, accountData, }} /> )} </FullWidthWrapper> {(!message || emptyText.test(markdownParser(message))) && ( <Placeholder placeholderPosition={placeholderPosition}> {openThread && isThread ? `Reply in thread` : `Type message in ${selectedChat}`} </Placeholder> )} {uploadedFile.file.cid && ( <> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.MessageFileField`} props={{ file: uploadedFile.file, resetFile, }} /> </> )} {uploadedImage.file.cid && ( <> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.MessageImageField`} props={{ file: uploadedImage.file, resetImage, }} /> </> )} </Wrapper> <div onClick={() => setEmojiSelectorOpen(!emojiSelectorOpen)}> <IconEmoji /> </div> <IconSend onClick={() => { if (isActive) { handleSendMessage(); } }} isActive={isActive} /> {emojiSelectorOpen && ( <EmojiPopupContainer> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.EmojiSelector.EmojiSelector`} props={{ OnEmojiSelected: (emoji) => addEmojiToMessage(emoji), }} key={'message-input-emoji-component'} /> </EmojiPopupContainer> )} {showUpload && !uploadedFile.file.cid && !uploadedImage.file.cid && ( <UploadPopupContainer> {error && <ErrorContainer>{error}</ErrorContainer>} <UploadContainer> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.UploadComponent`} props={{ uploadedFile: uploadedImage, setUploadedFile: setUploadedImage, type: ['image/jpeg', 'image/png', 'image/gif'], icon: <ImageIconSvg />, text: 'Upload Image', setError: setError, }} key="images-component" /> <Widget src={`${componentOwnerId}/widget/Calimero.Curb.Chat.UploadComponent`} props={{ uploadedFile: uploadedFile, setUploadedFile: setUploadedFile, type: ['*/*'], icon: <FileIconSvg />, text: 'Upload File', setError: setError, }} key="files-component" /> </UploadContainer> </UploadPopupContainer> )} </Container> )} {!canWriteMessage && ( <Container style={getCustomStyle(openThread, isThread)} key={openThread.id} > <ReadOnlyField> You don't have permissions to write in this channel </ReadOnlyField> </Container> )} </> );