137 lines
3.9 KiB
TypeScript
137 lines
3.9 KiB
TypeScript
|
import { useCallback, useRef, useState } from "react";
|
||
|
import {
|
||
|
FormControl,
|
||
|
IconButton,
|
||
|
InputAdornment,
|
||
|
InputBase,
|
||
|
useMediaQuery,
|
||
|
useTheme,
|
||
|
} from "@mui/material";
|
||
|
import SendIcon from "@icons/SendIcon";
|
||
|
import AttachFileIcon from "@mui/icons-material/AttachFile";
|
||
|
import { checkAcceptableMediaType } from "@utils/checkAcceptableMediaType";
|
||
|
import { enqueueSnackbar } from "notistack";
|
||
|
|
||
|
interface ChatInputProps {
|
||
|
sendMessage: (message: string) => Promise<boolean>;
|
||
|
sendFile: (file: File | undefined) => Promise<void>;
|
||
|
isMessageSending: boolean;
|
||
|
}
|
||
|
|
||
|
const ChatInput = ({ sendMessage, sendFile, isMessageSending }: ChatInputProps) => {
|
||
|
const theme = useTheme();
|
||
|
const upMd = useMediaQuery(theme.breakpoints.up("md"));
|
||
|
const [messageField, setMessageField] = useState<string>("");
|
||
|
const [disableFileButton, setDisableFileButton] = useState(false);
|
||
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
||
|
|
||
|
const handleSendMessage = useCallback(async () => {
|
||
|
const successful = await sendMessage(messageField);
|
||
|
if (successful) {
|
||
|
setMessageField("");
|
||
|
}
|
||
|
}, [sendMessage, messageField]);
|
||
|
|
||
|
const handleSendFile = useCallback(async (file: File) => {
|
||
|
const check = checkAcceptableMediaType(file);
|
||
|
if (check.length > 0) {
|
||
|
enqueueSnackbar(check);
|
||
|
return;
|
||
|
}
|
||
|
setDisableFileButton(true);
|
||
|
await sendFile(file);
|
||
|
setDisableFileButton(false);
|
||
|
}, [sendFile]);
|
||
|
|
||
|
const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
if (e.target.files?.[0]) {
|
||
|
handleSendFile(e.target.files[0]);
|
||
|
}
|
||
|
}, [handleSendFile]);
|
||
|
|
||
|
const handleFileButtonClick = useCallback(() => {
|
||
|
if (!disableFileButton) {
|
||
|
fileInputRef.current?.click();
|
||
|
}
|
||
|
}, [disableFileButton]);
|
||
|
|
||
|
const handleTextfieldKeyPress: React.KeyboardEventHandler<
|
||
|
HTMLInputElement | HTMLTextAreaElement
|
||
|
> = useCallback((e) => {
|
||
|
if (e.key === "Enter" && !e.shiftKey) {
|
||
|
e.preventDefault();
|
||
|
handleSendMessage();
|
||
|
}
|
||
|
}, [handleSendMessage]);
|
||
|
|
||
|
const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||
|
setMessageField(e.target.value);
|
||
|
}, []);
|
||
|
|
||
|
return (
|
||
|
<FormControl fullWidth sx={{ borderTop: "1px solid black" }}>
|
||
|
<InputBase
|
||
|
value={messageField}
|
||
|
fullWidth
|
||
|
placeholder="Введите сообщение..."
|
||
|
id="message"
|
||
|
multiline
|
||
|
onKeyDown={handleTextfieldKeyPress}
|
||
|
sx={{
|
||
|
width: "100%",
|
||
|
p: 0,
|
||
|
}}
|
||
|
inputProps={{
|
||
|
sx: {
|
||
|
fontWeight: 400,
|
||
|
fontSize: "16px",
|
||
|
lineHeight: "19px",
|
||
|
pt: upMd ? "30px" : "28px",
|
||
|
pb: upMd ? "30px" : "24px",
|
||
|
px: "19px",
|
||
|
maxHeight: "calc(19px * 5)",
|
||
|
color: "black",
|
||
|
},
|
||
|
}}
|
||
|
onChange={handleInputChange}
|
||
|
endAdornment={
|
||
|
<InputAdornment position="end">
|
||
|
<IconButton
|
||
|
disabled={disableFileButton}
|
||
|
onClick={handleFileButtonClick}
|
||
|
>
|
||
|
<AttachFileIcon />
|
||
|
</IconButton>
|
||
|
<input
|
||
|
ref={fileInputRef}
|
||
|
id="fileinput"
|
||
|
onChange={handleFileInputChange}
|
||
|
style={{ display: "none" }}
|
||
|
type="file"
|
||
|
/>
|
||
|
<IconButton
|
||
|
disabled={isMessageSending}
|
||
|
onClick={handleSendMessage}
|
||
|
sx={{
|
||
|
height: "53px",
|
||
|
width: "53px",
|
||
|
mr: "13px",
|
||
|
p: 0,
|
||
|
opacity: isMessageSending ? 0.3 : 1,
|
||
|
}}
|
||
|
>
|
||
|
<SendIcon
|
||
|
style={{
|
||
|
width: "100%",
|
||
|
height: "100%",
|
||
|
}}
|
||
|
/>
|
||
|
</IconButton>
|
||
|
</InputAdornment>
|
||
|
}
|
||
|
/>
|
||
|
</FormControl>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default ChatInput;
|