Matou-Garou / patches /src /components /MessageInput.tsx
Jofthomas's picture
Jofthomas HF staff
bulk2
90cbf22
raw
history blame
2.84 kB
import clsx from 'clsx';
import { useMutation, useQuery } from 'convex/react';
import { KeyboardEvent, useRef, useState } from 'react';
import { api } from '../../convex/_generated/api';
import { Id } from '../../convex/_generated/dataModel';
import { useSendInput } from '../hooks/sendInput';
import { Player } from '../../convex/aiTown/player';
import { Conversation } from '../../convex/aiTown/conversation';
export function MessageInput({
worldId,
engineId,
humanPlayer,
conversation,
}: {
worldId: Id<'worlds'>;
engineId: Id<'engines'>;
humanPlayer: Player;
conversation: Conversation;
}) {
const descriptions = useQuery(api.world.gameDescriptions, { worldId });
const humanName = descriptions?.playerDescriptions.find((p) => p.playerId === humanPlayer.id)
?.name;
const inputRef = useRef<HTMLParagraphElement>(null);
const inflightUuid = useRef<string | undefined>();
const writeMessage = useMutation(api.messages.writeMessage);
const startTyping = useSendInput(engineId, 'startTyping');
const currentlyTyping = conversation.isTyping;
const onKeyDown = async (e: KeyboardEvent) => {
e.stopPropagation();
// Set the typing indicator if we're not submitting.
if (e.key !== 'Enter') {
console.log(inflightUuid.current);
if (currentlyTyping || inflightUuid.current !== undefined) {
return;
}
inflightUuid.current = crypto.randomUUID();
try {
// Don't show a toast on error.
await startTyping({
playerId: humanPlayer.id,
conversationId: conversation.id,
messageUuid: inflightUuid.current,
});
} finally {
inflightUuid.current = undefined;
}
return;
}
// Send the current message.
e.preventDefault();
if (!inputRef.current) {
return;
}
const text = inputRef.current.innerText;
inputRef.current.innerText = '';
if (!text) {
return;
}
let messageUuid = inflightUuid.current;
if (currentlyTyping && currentlyTyping.playerId === humanPlayer.id) {
messageUuid = currentlyTyping.messageUuid;
}
messageUuid = messageUuid || crypto.randomUUID();
await writeMessage({
worldId,
playerId: humanPlayer.id,
conversationId: conversation.id,
text,
messageUuid,
});
};
return (
<div className="leading-tight mb-6">
<div className="flex gap-4">
<span className="uppercase flex-grow">{humanName}</span>
</div>
<div className={clsx('bubble', 'bubble-mine')}>
<p
className="bg-white -mx-3 -my-1"
ref={inputRef}
contentEditable
style={{ outline: 'none' }}
tabIndex={0}
placeholder="Type here"
onKeyDown={(e) => onKeyDown(e)}
/>
</div>
</div>
);
}