fix: Ensure Message Send Requires Key 🔑 (#1281)

* fix: only allow message send when key is provided when required
- create useRequiresKey hook
- pass same disabled prop to Textarea, AttachFile, and SendButton
- EndpointItem: add localization, stopPropagation, and remove commented code
- separate some hooks to new Input dir
- completely remove textareaHeight recoil state as is not needed
- update imports for moved hooks
- pass disabled prop to useTextarea

* feat: add localization to textarea placeholders
This commit is contained in:
Danny Avila 2023-12-05 09:38:04 -05:00 committed by GitHub
parent f6118879e5
commit 00b6af8c74
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 54 additions and 50 deletions

View file

@ -0,0 +1,115 @@
import { useEffect, useRef } from 'react';
import { TEndpointOption, getResponseSender } from 'librechat-data-provider';
import type { KeyboardEvent } from 'react';
import { useChatContext } from '~/Providers/ChatContext';
import useFileHandling from '~/hooks/useFileHandling';
import useLocalize from '~/hooks/useLocalize';
type KeyEvent = KeyboardEvent<HTMLTextAreaElement>;
export default function useTextarea({ setText, submitMessage, disabled = false }) {
const { conversation, isSubmitting, latestMessage, setShowBingToneSetting, setFilesLoading } =
useChatContext();
const isComposing = useRef(false);
const inputRef = useRef<HTMLTextAreaElement | null>(null);
const { handleFiles } = useFileHandling();
const localize = useLocalize();
const isNotAppendable = (latestMessage?.unfinished && !isSubmitting) || latestMessage?.error;
const { conversationId, jailbreak } = conversation || {};
// auto focus to input, when enter a conversation.
useEffect(() => {
if (!conversationId) {
return;
}
// Prevents Settings from not showing on new conversation, also prevents showing toneStyle change without jailbreak
if (conversationId === 'new' || !jailbreak) {
setShowBingToneSetting(false);
}
if (conversationId !== 'search') {
inputRef.current?.focus();
}
// setShowBingToneSetting is a recoil setter, so it doesn't need to be in the dependency array
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [conversationId, jailbreak]);
useEffect(() => {
const timeoutId = setTimeout(() => {
inputRef.current?.focus();
}, 100);
return () => clearTimeout(timeoutId);
}, [isSubmitting]);
const handleKeyDown = (e: KeyEvent) => {
if (e.key === 'Enter' && isSubmitting) {
return;
}
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
}
if (e.key === 'Enter' && !e.shiftKey && !isComposing?.current) {
submitMessage();
}
};
const handleKeyUp = (e: KeyEvent) => {
const target = e.target as HTMLTextAreaElement;
if (e.keyCode === 8 && target.value.trim() === '') {
setText(target.value);
}
if (e.key === 'Enter' && e.shiftKey) {
return console.log('Enter + Shift');
}
if (isSubmitting) {
return;
}
};
const handleCompositionStart = () => {
isComposing.current = true;
};
const handleCompositionEnd = () => {
isComposing.current = false;
};
const getPlaceholderText = () => {
if (disabled) {
return localize('com_endpoint_config_placeholder');
}
if (isNotAppendable) {
return localize('com_endpoint_message_not_appendable');
}
const sender = getResponseSender(conversation as TEndpointOption);
return `${localize('com_endpoint_message')} ${sender ? sender : 'ChatGPT'}`;
};
const handlePaste = (e: React.ClipboardEvent<HTMLTextAreaElement>) => {
if (e.clipboardData && e.clipboardData.files.length > 0) {
e.preventDefault();
setFilesLoading(true);
handleFiles(e.clipboardData.files);
}
};
return {
inputRef,
handleKeyDown,
handleKeyUp,
handlePaste,
handleCompositionStart,
handleCompositionEnd,
placeholder: getPlaceholderText(),
};
}