infoalloggi-monorepo/apps/infoalloggi/src/components/chat/chat-bottombar.tsx

172 lines
5.1 KiB
TypeScript
Raw Normal View History

2025-08-04 17:45:44 +02:00
"use client";
import { SendHorizontal, SmilePlusIcon, ThumbsUp } from "lucide-react";
import {
useCallback,
useEffect,
useRef,
useState,
type ChangeEvent,
} from "react";
import { Button } from "~/components/ui/button";
import {
AutosizeTextarea,
type AutosizeTextAreaRef,
} from "~/components/custom_ui/autoResizeTextArea";
import { api } from "~/utils/api";
import { ChatAttachments } from "~/components/chat/chat-attachments";
import { useMediaQuery } from "~/hooks/use-media-query";
import { useThrottledIsTypingMutation } from "~/hooks/chatHooks";
import type { Session } from "~/server/api/trpc";
import type { ChatsChatid } from "~/schemas/public/Chats";
import type { ChatUserInfo } from "~/server/services/chat.service";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "~/components/ui/popover";
import {
EmojiPickerContent,
EmojiPickerSearch,
EmojiPicker,
} from "~/components/custom_ui/emoji-picker";
import { useTranslation } from "~/providers/I18nProvider";
type ChatBottombarProps = {
chatId: ChatsChatid;
userData: Session;
chatUserData: ChatUserInfo;
};
export default function ChatBottombar({
chatId,
userData,
chatUserData,
}: ChatBottombarProps) {
const { locale } = useTranslation();
const [message, setMessage] = useState("");
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef<AutosizeTextAreaRef>(null);
const { mutate: addMutation } = api.messagesSSE.add.useMutation({});
const handleThumbsUp = useCallback(() => {
addMutation({
chatId,
message: "👍",
sender: userData.id,
});
setMessage("");
}, [chatId, addMutation, userData]);
const handleSend = () => {
if (message.length !== 0) {
addMutation({
chatId,
message: message.trim(),
sender: userData.id,
});
setMessage("");
if (inputRef.current) {
inputRef.current.textArea.focus();
inputRef.current.textArea.style.height = "auto";
}
}
};
const isTypingMutation = useThrottledIsTypingMutation({
chatId,
username: userData.username,
});
useEffect(() => {
// update isTyping state
isTypingMutation(isFocused && message.trim().length > 0);
}, [isFocused, message, isTypingMutation]);
useEffect(() => {
if (inputRef.current) {
inputRef.current.textArea.focus();
}
}, []);
const [openEmoji, setOpenEmoji] = useState(false);
const isMobile = useMediaQuery("(min-width: 426px)");
return (
<div className="flex min-h-[74px] w-full items-center justify-between gap-2 p-2">
<div className="flex">
<ChatAttachments userData={userData} chatUserData={chatUserData} />
</div>
<div className="relative w-full">
<AutosizeTextarea
autoComplete="off"
value={message}
minHeight={56}
ref={inputRef}
onKeyDown={(e) => {
if (e.key === "Enter") {
e.preventDefault();
if (e.shiftKey) {
setMessage((prev) => `${prev}\n`);
} else {
handleSend();
}
}
}}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
onChange={(e: ChangeEvent<HTMLTextAreaElement>) => {
setMessage(e.target.value);
}}
name="message"
placeholder="Aa"
className="bg-background flex h-14 min-h-14 w-full resize-none items-center overflow-hidden rounded-xl border pr-8 ring-0 outline-hidden hover:border-neutral-400 focus:border-neutral-600 focus:ring-0 focus-visible:ring-0 focus-visible:ring-offset-0"
/>
{isMobile && (
<div className="absolute top-0 right-2 flex h-full items-center">
<Popover open={openEmoji} onOpenChange={setOpenEmoji}>
<PopoverTrigger asChild>
<Button variant="ghost">
<SmilePlusIcon className="stroke-muted-foreground" />
</Button>
</PopoverTrigger>
<PopoverContent align="end" className="w-fit p-0">
<EmojiPicker
locale={locale as "it" | "en"}
className="h-84"
onEmojiSelect={({ emoji }) => {
setMessage(message + emoji);
// if (inputRef.current) {
// inputRef.current.textArea.focus();
// }
}}
>
<EmojiPickerSearch
placeholder={locale == "en" ? "Search..." : "Cerca..."}
/>
<EmojiPickerContent />
</EmojiPicker>
</PopoverContent>
</Popover>
</div>
)}
</div>
<Button
aria-label="Send Message"
variant="ghost"
className="shrink-0"
onClick={
message.length != 0 ? () => handleSend() : () => handleThumbsUp()
}
>
{message.length != 0 ? (
<SendHorizontal size={20} className="text-muted-foreground" />
) : (
<ThumbsUp size={20} className="text-muted-foreground" />
)}
</Button>
</div>
);
}