feat: edit and resubmit messages (#592)
This commit is contained in:
parent
2e479ccce7
commit
64d1aad2bb
12 changed files with 302 additions and 25 deletions
113
components/message-editor.tsx
Normal file
113
components/message-editor.tsx
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
'use client';
|
||||
|
||||
import { ChatRequestOptions, Message } from 'ai';
|
||||
import { Button } from './ui/button';
|
||||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
|
||||
import { Textarea } from './ui/textarea';
|
||||
import { deleteTrailingMessages } from '@/app/(chat)/actions';
|
||||
import { toast } from 'sonner';
|
||||
import { useUserMessageId } from '@/hooks/use-user-message-id';
|
||||
|
||||
export type MessageEditorProps = {
|
||||
message: Message;
|
||||
setMode: Dispatch<SetStateAction<'view' | 'edit'>>;
|
||||
setMessages: (
|
||||
messages: Message[] | ((messages: Message[]) => Message[]),
|
||||
) => void;
|
||||
reload: (
|
||||
chatRequestOptions?: ChatRequestOptions,
|
||||
) => Promise<string | null | undefined>;
|
||||
};
|
||||
|
||||
export function MessageEditor({
|
||||
message,
|
||||
setMode,
|
||||
setMessages,
|
||||
reload,
|
||||
}: MessageEditorProps) {
|
||||
const { userMessageIdFromServer } = useUserMessageId();
|
||||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false);
|
||||
|
||||
const [draftContent, setDraftContent] = useState<string>(message.content);
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) {
|
||||
adjustHeight();
|
||||
}
|
||||
}, []);
|
||||
|
||||
const adjustHeight = () => {
|
||||
if (textareaRef.current) {
|
||||
textareaRef.current.style.height = 'auto';
|
||||
textareaRef.current.style.height = `${textareaRef.current.scrollHeight + 2}px`;
|
||||
}
|
||||
};
|
||||
|
||||
const handleInput = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setDraftContent(event.target.value);
|
||||
adjustHeight();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<Textarea
|
||||
ref={textareaRef}
|
||||
className="bg-transparent outline-none overflow-hidden resize-none !text-base rounded-xl w-full"
|
||||
value={draftContent}
|
||||
onChange={handleInput}
|
||||
/>
|
||||
|
||||
<div className="flex flex-row gap-2 justify-end">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-fit py-2 px-3"
|
||||
onClick={() => {
|
||||
setMode('view');
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="default"
|
||||
className="h-fit py-2 px-3"
|
||||
disabled={isSubmitting}
|
||||
onClick={async () => {
|
||||
setIsSubmitting(true);
|
||||
const messageId = userMessageIdFromServer ?? message.id;
|
||||
|
||||
if (!messageId) {
|
||||
toast.error('Something went wrong, please try again!');
|
||||
setIsSubmitting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await deleteTrailingMessages({
|
||||
id: messageId,
|
||||
});
|
||||
|
||||
setMessages((messages) => {
|
||||
const index = messages.findIndex((m) => m.id === message.id);
|
||||
|
||||
if (index !== -1) {
|
||||
const updatedMessage = {
|
||||
...message,
|
||||
content: draftContent,
|
||||
};
|
||||
|
||||
return [...messages.slice(0, index), updatedMessage];
|
||||
}
|
||||
|
||||
return messages;
|
||||
});
|
||||
|
||||
setMode('view');
|
||||
reload();
|
||||
}}
|
||||
>
|
||||
{isSubmitting ? 'Sending...' : 'Send'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue