Files
cozsweet-frontend-nextjs/src/app/chat/components/chat-input-bar.tsx
T

110 lines
3.0 KiB
TypeScript

"use client";
import { useRef, useState } from "react";
import { useChatDispatch } from "@/stores/chat/chat-context";
import { useUserState } from "@/stores/user/user-context";
import { useKeyboardHeight } from "@/hooks";
import { Logger } from "@/utils";
import { ChatInputActionPanel } from "./chat-input-action-panel";
import { ChatInputTextField } from "./chat-input-text-field";
import { ChatSendButton } from "./chat-send-button";
import styles from "./chat-input-bar.module.css";
const log = new Logger("AppChatComponentsChatInputBar");
export interface ChatInputBarProps {
disabled?: boolean;
}
export function ChatInputBar({ disabled = false }: ChatInputBarProps) {
const dispatch = useChatDispatch();
const { currentUser } = useUserState();
const [input, setInput] = useState("");
const [isFocused, setIsFocused] = useState(false);
const [isActionPanelOpen, setIsActionPanelOpen] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const hasContent = input.trim().length > 0;
const isActive = isFocused || isActionPanelOpen;
const voiceMinutesRemaining = currentUser?.voiceMinutesRemaining ?? 0;
useKeyboardHeight({
targetRef: textareaRef,
active: isFocused,
});
const handleInputChange = (value: string) => {
setInput(value);
if (value.trim().length > 0) {
setIsActionPanelOpen(false);
}
};
const handleSend = () => {
if (!hasContent) return;
log.debug("[chat-input-bar] handleSend", {
contentLength: input.length,
contentPreview: input.slice(0, 50),
hasContent,
disabled,
isFocused,
});
dispatch({ type: "ChatSendMessage", content: input });
setInput("");
textareaRef.current?.focus();
};
const handleActionButtonClick = () => {
if (hasContent) {
handleSend();
return;
}
textareaRef.current?.blur();
setIsFocused(false);
setIsActionPanelOpen((open) => !open);
};
const handleVoiceMessageClick = () => {
log.debug("[chat-input-bar] voice message action clicked", {
voiceMinutesRemaining,
});
};
return (
<div
className={`${styles.bar} ${isActive ? styles.barFocused : ""} ${
isActionPanelOpen ? styles.barExpanded : ""
}`}
>
<div
className={`${styles.row} ${isActive ? styles.rowFocused : ""} ${
isActionPanelOpen ? styles.rowExpanded : ""
}`}
>
<ChatInputTextField
ref={textareaRef}
value={input}
onChange={handleInputChange}
onSubmit={handleSend}
onFocusChange={setIsFocused}
disabled={disabled}
/>
<ChatSendButton
disabled={disabled}
hasContent={hasContent}
isExpanded={isActionPanelOpen}
onClick={handleActionButtonClick}
/>
</div>
{isActionPanelOpen ? (
<ChatInputActionPanel
voiceMinutesRemaining={voiceMinutesRemaining}
onVoiceMessageClick={handleVoiceMessageClick}
/>
) : null}
</div>
);
}