Chat popup

This commit is contained in:
2025-10-09 12:33:45 +05:00
parent 0b8edce9d6
commit b348055eee
5 changed files with 221 additions and 8 deletions
+188
View File
@@ -0,0 +1,188 @@
import { useRef, useState, useEffect } from "react";
import SendIcon from "../icons/SendIcon";
import Button from "../ui/Button";
import { useMe } from "../../hooks/useAuth";
import clsx from "clsx";
export default function ChatPopup() {
const [messages, setMessages] = useState<MessageItemProps[]>([
{
senderId: "1",
timestamp: "12:22",
content:
"У меня все сломалось, ничего не работает, картинки нет, все пошло по пизде, помогите мне кто-нибудь, пожалуйста",
},
{
senderId: "2",
timestamp: "12:22",
content: "🤡🤡🤡",
},
]);
function onMessageSend(message: string) {
setMessages([
...messages,
{
senderId: "1",
timestamp: "12:22",
content: message,
},
]);
}
return (
<div className="flex flex-col w-full h-full relative">
<MessageFeed messages={messages} />
<MessageInput onMessageSend={onMessageSend} />
</div>
);
}
function MessageFeed({ messages }: { messages: MessageItemProps[] }) {
const messagesEndRef = useRef<HTMLDivElement>(null);
// Скролл к концу при получении нового сообщения
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
return (
<div
className="flex flex-col w-full h-[calc(100%-4.444vw)] bg-[#F0F0F0] p-[1.111vw] pb-[0] overflow-y-auto"
style={{ scrollbarWidth: "none", msOverflowStyle: "none" }}
>
<style>
{`
.flex::-webkit-scrollbar {
display: none;
}
`}
</style>
{messages.length === 0 ? (
<div className="w-full flex flex-col gap-[1.667vw] items-center justify-center px-[2.778vw] m-auto">
<img
src="/img/popups/EmptyMessageFeed.svg"
className="size-[8.333vw]"
/>
<span className="text-center text-s">
Здесь пока нет сообщений. <br /> Можно начать беседу с приветствия
</span>
</div>
) : (
<div className="flex flex-col gap-[1.111vw] items-end mt-auto">
{messages.map((message, index) => (
<MessageItem key={index} {...message} />
))}
<div ref={messagesEndRef} />
</div>
)}
</div>
);
}
interface MessageItemProps {
senderId: string;
timestamp: string;
content: string;
}
function MessageItem({ senderId, timestamp, content }: MessageItemProps) {
const { data: user } = useMe();
const isFromMe = senderId === "1";
return (
<div
className={clsx(
"flex w-full items-end gap-[0.556vw] justify-end",
isFromMe ? "" : "flex-row-reverse"
)}
>
<div
className={clsx(
"p-[1.111vw] w-[16.667vw] flex items-end justify-between",
isFromMe
? "bg-[#7B60F3] rounded-[1.111vw_1.111vw_0_1.111vw] text-white"
: "bg-[#FFFFFF] rounded-[1.111vw_1.111vw_1.111vw_0] c text-[#141414]"
)}
>
<div className="break-words text-s w-[12.917vw]">
{!isFromMe && (
<div className="caption-s text-[#7B60F3] mb-[0.278vw]">
{user?.fullName}
</div>
)}
<div>{content}</div>
</div>
<span className="caption-xs opacity-30">{timestamp}</span>
</div>
<div className="size-[2.222vw rounded-full">
<img
src="/img/popups/MessageUserPfp.png"
className="size-full object-cover"
alt="user"
/>
</div>
</div>
);
}
function MessageInput({
onMessageSend,
}: {
onMessageSend: (message: string) => void;
}) {
const [message, setMessage] = useState("");
const textareaRef = useRef<HTMLTextAreaElement>(null);
useEffect(() => {
const textarea = textareaRef.current;
if (!textarea) return;
textarea.style.height = "auto";
const computedStyle = window.getComputedStyle(textarea);
const lineHeight = parseInt(computedStyle.lineHeight);
const maxHeight = lineHeight * 4;
const newHeight = Math.min(textarea.scrollHeight, maxHeight);
textarea.style.height = `${newHeight}px`;
textarea.style.overflowY =
textarea.scrollHeight > maxHeight ? "auto" : "hidden";
}, [message]);
function handleChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
setMessage(e.target.value);
}
function sendMessage() {
setMessage("");
onMessageSend(message);
}
return (
<div
onClick={() => textareaRef.current?.focus()}
className="flex w-full min-h-[4.444vw] p-[1.111vw] items-end justify-between absolute bottom-0 left-0 bg-white"
>
<textarea
ref={textareaRef}
value={message}
onChange={handleChange}
className="w-[80%] resize-none focus:outline-none my-auto text-s"
rows={1}
placeholder="Сообщение..."
/>
<Button
size="small"
variant="cta"
disabled={message.length === 0}
className="size-[2.222vw]"
onClick={sendMessage}
>
<div className="size-full">
<SendIcon />
</div>
</Button>
</div>
);
}
@@ -2,7 +2,7 @@ import Button from "../ui/Button";
import LinkShare from "../ui/LinkShare";
import ShareFilledIcon from "../icons/ShareFilledIcon";
export default function ShareModal() {
export default function SharePopup() {
return (
<>
<div className="mb-[1.389vw]">
+1 -7
View File
@@ -1,4 +1,4 @@
import ShareModal from "../components/modals/ShareModal";
import ChatPopup from "../components/popups/ChatPopup";
import Button from "../components/ui/Button";
import { useMe, useLogout } from "../hooks/useAuth";
import { useNavigate } from "react-router";
@@ -19,12 +19,6 @@ function HomePage() {
<div className="p-8 bg-white rounded-lg shadow-md">
<h1 className="mb-6 text-3xl font-bold">Главная страница</h1>
{/* Потестить модалки */}
{/* <div className="w-[21.667vw] outline-1 outline">
<ShareModal />
</div> */}
<div className="space-y-4">
<div className="p-4 bg-blue-50 rounded-lg border border-blue-200">
<h2 className="mb-2 text-xl font-semibold">