test / src /components /message_bar.tsx
aiioe's picture
Automated build & deploy
e454383 verified
Raw History Blame Contribute Delete
4.34 kB
"use client";
import React, { useCallback, useEffect, useState, useRef } from "react";
import { Textarea } from "@/components/ui/textarea-chat";
import { Send, Loader2, Sparkles } from "lucide-react";
import { Button } from "@/components/ui/button";
import { useChatLogic } from "@/hooks/useChatLogic";
import type { Chat } from "@/lib/types";
type Props = {
selectedChat: Chat | null;
selectedChatId: string | null;
scrollToBottom: () => void;
};
const MessageBar: React.FC<Props> = ({
selectedChat,
selectedChatId,
scrollToBottom,
}) => {
const { isLoading, handleSubmit } = useChatLogic(
selectedChat,
selectedChatId,
scrollToBottom
);
const [input, setInput] = useState<string>("");
const textareaRef = useRef<HTMLTextAreaElement>(null);
// Auto-resize function
const adjustTextareaHeight = useCallback(() => {
const textarea = textareaRef.current;
if (textarea) {
textarea.style.height = "auto";
const newHeight = Math.min(textarea.scrollHeight, 120); // Reduced max height for mobile
textarea.style.height = `${newHeight}px`;
}
}, []);
useEffect(() => {
adjustTextareaHeight();
}, [input, adjustTextareaHeight]);
const handleFormSubmit = useCallback(
async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (input.trim()) {
await handleSubmit(input);
setInput("");
setTimeout(() => adjustTextareaHeight(), 0);
}
},
[handleSubmit, input, adjustTextareaHeight]
);
const handleKeyDown = useCallback(
async (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
if (input.trim()) {
await handleSubmit(input);
setInput("");
setTimeout(() => adjustTextareaHeight(), 0);
}
}
},
[handleSubmit, input, adjustTextareaHeight]
);
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
if (e.key === "/" && document.activeElement?.tagName !== "TEXTAREA") {
e.preventDefault();
textareaRef.current?.focus();
}
};
window.addEventListener("keydown", handleKeyPress);
return () => window.removeEventListener("keydown", handleKeyPress);
}, []);
return (
<div className="p-2 max-w-4xl mx-auto w-full">
<form
onSubmit={handleFormSubmit}
className="flex items-end gap-2 sm:gap-3 bg-gradient-to-r from-background to-muted/20 border border-border/50 rounded-xl sm:rounded-2xl p-2 sm:p-3 shadow-lg backdrop-blur-sm"
>
<div className="flex-1 relative min-w-0">
<Textarea
ref={textareaRef}
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Ask about your transcripts..."
className="resize-none border-none bg-transparent focus:ring-0 focus:outline-none overflow-y-auto placeholder:text-muted-foreground/60 text-sm sm:text-base"
style={{ minHeight: "36px", maxHeight: "120px" }}
disabled={isLoading}
aria-label="Message input"
/>
{!input && (
<div className="absolute top-2 sm:top-3 right-2 sm:right-3 text-muted-foreground/40 pointer-events-none">
<Sparkles className="h-3.5 w-3.5 sm:h-4 sm:w-4" />
</div>
)}
</div>
<Button
type="submit"
size="icon"
className="h-9 w-9 sm:h-10 sm:w-10 rounded-lg sm:rounded-xl bg-gradient-to-r from-primary to-primary/80 hover:from-primary/90 hover:to-primary/70 transition-all duration-200 shadow-md hover:shadow-lg hover:scale-105 flex-shrink-0"
disabled={isLoading || selectedChatId === null || !input.trim()}
aria-label="Send message"
>
{isLoading ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Send className="h-4 w-4" />
)}
</Button>
</form>
<div className="text-center mt-2 hidden sm:block">
<p className="text-xs text-muted-foreground/60">
Answers are generated by AI and may not be accurate. Use at your own
discretion.
</p>
</div>
</div>
);
};
export default React.memo(MessageBar);