Bot Command Tooltip: Fix sending wrong command

This commit is contained in:
Alexander Zinchuk 2023-02-22 23:48:42 +01:00
parent 6d5625ce0c
commit a219f67624
5 changed files with 41 additions and 10 deletions

View File

@ -4,6 +4,7 @@ import React, {
} from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { Signal } from '../../../util/signals';
import type { ApiBotCommand, ApiUser } from '../../../api/types';
import buildClassName from '../../../util/buildClassName';
@ -20,6 +21,7 @@ export type OwnProps = {
isOpen: boolean;
withUsername?: boolean;
botCommands?: ApiBotCommand[];
getHtml: Signal<string>;
onClick: NoneToVoidFunction;
onClose: NoneToVoidFunction;
};
@ -33,6 +35,7 @@ const BotCommandTooltip: FC<OwnProps & StateProps> = ({
isOpen,
withUsername,
botCommands,
getHtml,
onClick,
onClose,
}) => {
@ -50,10 +53,20 @@ const BotCommandTooltip: FC<OwnProps & StateProps> = ({
onClick();
}, [onClick, sendBotCommand, usersById, withUsername]);
const handleSelect = useCallback((botCommand: ApiBotCommand) => {
// We need an additional check because tooltip is updated with throttling
if (!botCommand.command.startsWith(getHtml())) {
return false;
}
handleSendCommand(botCommand);
return true;
}, [getHtml, handleSendCommand]);
const selectedCommandIndex = useKeyboardNavigation({
isActive: isOpen,
items: botCommands,
onSelect: handleSendCommand,
onSelect: handleSelect,
onClose,
});

View File

@ -1267,6 +1267,7 @@ const Composer: FC<OwnProps & StateProps> = ({
isOpen={isBotCommandTooltipOpen}
withUsername={Boolean(chatBotCommands)}
botCommands={botTooltipCommands}
getHtml={getHtml}
onClick={handleBotCommandSelect}
onClose={closeBotCommandTooltip}
/>

View File

@ -8,7 +8,7 @@ import useFlag from '../../../../hooks/useFlag';
import useDerivedSignal from '../../../../hooks/useDerivedSignal';
import { useThrottledResolver } from '../../../../hooks/useAsyncResolvers';
const RE_COMMAND = /^\/([\w@]{1,32}\s?)?/i;
const RE_COMMAND = /^\/([\w@]{1,32})?$/i;
const THROTTLE = 300;

View File

@ -20,7 +20,7 @@ export function useKeyboardNavigation({
noArrowNavigation?: boolean;
items?: any[];
shouldSelectOnTab?: boolean;
onSelect: AnyToVoidFunction;
onSelect: (item: any) => void | boolean;
onClose: NoneToVoidFunction;
}) {
const [selectedItemIndex, setSelectedItemIndex] = useState(-1);
@ -42,10 +42,15 @@ export function useKeyboardNavigation({
if (items && items.length && selectedItemIndex > -1) {
const item = items[selectedItemIndex];
if (item) {
if (onSelect(item) === false) {
return false;
}
e.preventDefault();
onSelect(item);
}
}
return true;
}, [items, onSelect, selectedItemIndex]);
const isSelectionOutOfRange = !items || selectedItemIndex > items.length - 1;

View File

@ -1,6 +1,14 @@
type HandlerName = 'onEnter' | 'onBackspace' | 'onDelete' | 'onEsc' | 'onUp' | 'onDown' | 'onLeft' | 'onRight'
| 'onTab';
type Handler = (e: KeyboardEvent) => void;
type HandlerName =
'onEnter'
| 'onBackspace'
| 'onDelete'
| 'onEsc'
| 'onUp'
| 'onDown'
| 'onLeft'
| 'onRight'
| 'onTab';
type Handler = (e: KeyboardEvent) => void | boolean;
type CaptureOptions = Partial<Record<HandlerName, Handler>>;
const keyToHandlerName: Record<string, HandlerName> = {
@ -64,10 +72,14 @@ function handleKeyDown(e: KeyboardEvent) {
if (!length) {
return;
}
e.stopPropagation();
const handler = handlers[handlerName][length - 1];
handler!(e);
for (let i = length - 1; i >= 0; i--) {
const handler = handlers[handlerName][i]!;
if (handler(e) !== false) {
e.stopPropagation();
break;
}
}
}
function releaseKeyboardListener(options: CaptureOptions) {