in src/components/Chat/ChatComposer/ChatComposer.js [162:302]
export default function ChatComposer({ addMessage, addAttachment, onTyping, contactId, contactStatus, onTypingValidityTime, textInputRef, composerConfig }) {
const [message, setMessage] = useState("");
const [attachment, setAttachment] = useState(null);
const fileInputRef = useRef(null);
useLayoutEffect(() => {
if (!textInputRef || !textInputRef.current || !textInputRef.current.focus) {
return;
}
textInputRef.current.focus();
}, [attachment]);
function hasSameContent(event) {
return event.target.innerText === message;
}
function onInput(event) {
if (!event.shiftKey && event.key === KEYBOARD_KEY_CONSTANTS.ENTER) {
event.preventDefault();
sendMessage();
return false;
} else {
if (!hasSameContent(event)) {
throttledOnTyping();
}
setMessage(event.target.value);
}
if (event.key === KEYBOARD_KEY_CONSTANTS.DELETE || event.key === KEYBOARD_KEY_CONSTANTS.BACKSPACE) {
if (attachment && message === "") {
event.preventDefault();
clearFileInput();
return;
}
}
}
/**
* Cancel any pending (not flushed) typing events, send the message (and attachment if applicable), and clear input bar.
*/
function sendMessage() {
throttledOnTyping.cancel();
sendTextMessage(message);
setMessage("");
if (attachment) {
sendAttachment();
clearFileInput();
}
}
const throttledOnTyping = useCallback(
throttle(() => {
onTyping().then(() => {
console.log("CCP", "ChatComposer", "On typing event sent successfully");
});
}, onTypingValidityTime),
[onTypingValidityTime]
);
function sendTextMessage(text) {
if (text.trim()) {
addMessage(contactId, { text });
}
}
function onFileInput(e) {
const file = e.target.files[0];
setAttachment(file);
}
function clearFileInput() {
setAttachment(null);
fileInputRef.current.value = null;
}
function sendAttachment() {
addAttachment(contactId, attachment);
}
const ariaLabel = "Type a message";
const placeholder = attachment == null ? ariaLabel : "";
return (
<ChatComposerWrapper>
{(contactStatus === CONTACT_STATUS.CONNECTED) && (
<React.Fragment>
{composerConfig.attachmentsEnabled &&
<PaperClipContainer>
<IconButton aria-label={"Attach a file"}>
<label htmlFor={`customer-chat-file-select-${contactId}`}>
<PaperClipIcon>
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5v10.5c0 .55-.45 1-1 1s-1-.45-1-1V6H10v9.5c0 1.38 1.12 2.5 2.5 2.5s2.5-1.12 2.5-2.5V5c0-2.21-1.79-4-4-4S7 2.79 7 5v12.5c0 3.04 2.46 5.5 5.5 5.5s5.5-2.46 5.5-5.5V6h-1.5z"/>
</svg>
</PaperClipIcon>
<input ref={fileInputRef} type="file" id={`customer-chat-file-select-${contactId}`} data-testid={`customer-chat-file-select`}
accept={ATTACHMENT_ACCEPT_CONTENT_TYPES.join(',')}
onChange={onFileInput} aria-label={"Attach a file"} tabIndex={-1}/>
</label>
</IconButton>
</PaperClipContainer>}
{(attachment != null) && (
<AttachmentContainer>
<div>
<span>{attachment.name}</span>
<IconButton onClick={clearFileInput} aria-label={"Remove attachment"}>
<CloseIcon>
<svg viewBox="0 0 13 13" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
<path d="M13 1.3L11.7 0 6.5 5.2 1.3 0 0 1.3l5.2 5.2L0 11.7 1.3 13l5.2-5.2 5.2 5.2 1.3-1.3-5.2-5.2z" fillRule="evenodd"/>
</svg>
</CloseIcon>
</IconButton>
</div>
</AttachmentContainer>
)}
<TextInput
data-testid={`customer-chat-text-input`}
ref={textInputRef}
value={message}
onInput={onInput}
onKeyPress={onInput}
onKeyDown={onInput}
aria-label={ariaLabel}
placeholder={placeholder}
tabIndex="0"
spellCheck="true"
/>
<SendMessageButtonContainer>
<SendMessageButton
isActive={!!message || attachment}
sendMessage={sendMessage.bind(this)}
/>
</SendMessageButtonContainer>
</React.Fragment>
)}
</ChatComposerWrapper>
);
}