Hamdast1/src/app/components/public-chat/ChatMessages.tsx
reza7321 213c0a70f0 امروز ۳۱ اردیبهشت
چت بات عمومی خرابه
2026-05-21 14:50:03 +03:30

140 lines
4.9 KiB
TypeScript

import { motion } from "motion/react";
import React from "react";
import { TypingText } from "./TypingText";
import { EmojiText } from "../chatbot/EmojiText";
import chatbotAvatarIcon from "../../../assets/chatbot-bot-avatar.png";
import { toPersianDigits } from "../../../utils/persianNumberUtils";
export interface ChatMessage {
id: string;
type: "user" | "other" | "loading";
content: string;
author?: string;
timestamp: string;
isTyping?: boolean;
}
interface ChatMessagesProps {
messages: ChatMessage[];
containerRef: React.RefObject<HTMLDivElement>;
endRef: React.RefObject<HTMLDivElement>;
onTyping?: () => void;
}
const messageStyles = {
user: {
background:
"linear-gradient(145deg, rgba(218, 94, 142, 0.96) 0%, rgba(162, 56, 110, 0.95) 100%)",
boxShadow:
"0 0 24px rgba(240,110,168,0.28), 0 12px 28px rgba(84, 22, 60, 0.38), inset 0 1px 0 rgba(255,255,255,0.16)",
border: "1px solid rgba(255, 178, 214, 0.58)",
backdropFilter: "blur(14px)",
WebkitBackdropFilter: "blur(14px)",
},
other: {
background:
"linear-gradient(145deg, rgba(52, 34, 76, 0.94) 0%, rgba(35, 24, 62, 0.94) 100%)",
backgroundImage:
"linear-gradient(145deg, rgba(52, 34, 76, 0.94) 0%, rgba(35, 24, 62, 0.94) 100%), linear-gradient(120deg, #7c3aed 0%, #f97316 58%, #facc15 100%)",
backgroundOrigin: "border-box",
backgroundClip: "padding-box, border-box",
boxShadow: "0 0 24px rgba(152,104,235,0.24), 0 12px 28px rgba(12, 8, 30, 0.4), inset 0 1px 0 rgba(255,255,255,0.12)",
border: "0.5px solid transparent",
backdropFilter: "blur(14px)",
WebkitBackdropFilter: "blur(14px)",
},
};
export function ChatMessages({
messages,
containerRef,
endRef,
onTyping,
}: ChatMessagesProps) {
return (
<div
ref={containerRef}
className="flex-1 overflow-y-auto px-4 pb-20"
dir="rtl"
>
<div className="space-y-3">
{messages.map((message) => {
const isUser = message.type === "user";
const isLoading = message.type === "loading";
return (
<motion.div
key={message.id}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className={`flex ${isUser ? "justify-start" : "justify-end"} items-start gap-2`}
>
<div
className="relative max-w-[75%] rounded-[18px] px-4 py-3"
style={isUser ? messageStyles.user : messageStyles.other}
>
{message.author && (
<p
className="text-xs font-bold mb-1"
style={{ color: "#8ACEE0" }}
>
{message.author}
</p>
)}
{isLoading ? (
<div className="flex items-center gap-1">
<motion.span
className="w-2 h-2 rounded-full bg-white"
animate={{ opacity: [0.3, 1, 0.3] }}
transition={{ duration: 1.5, repeat: Infinity, delay: 0 }}
/>
<motion.span
className="w-2 h-2 rounded-full bg-white"
animate={{ opacity: [0.3, 1, 0.3] }}
transition={{ duration: 1.5, repeat: Infinity, delay: 0.2 }}
/>
<motion.span
className="w-2 h-2 rounded-full bg-white"
animate={{ opacity: [0.3, 1, 0.3] }}
transition={{ duration: 1.5, repeat: Infinity, delay: 0.4 }}
/>
</div>
) : message.type === "other" && message.isTyping ? (
<TypingText text={message.content} speed={30} onTyping={onTyping} />
) : (
<p className="text-white text-sm break-words whitespace-pre-wrap">
<EmojiText text={message.content} />
</p>
)}
<p className="text-white/60 text-xs mt-1 text-left">
{toPersianDigits(message.timestamp)}
</p>
</div>
{!isUser && (
<div
className="-mr-1 mt-1 flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-full"
style={{
background: "radial-gradient(circle, rgba(255,104,205,0.18) 0%, transparent 68%)",
filter:
"drop-shadow(0 0 8px rgba(255, 104, 205, 0.55)) drop-shadow(0 0 16px rgba(255, 104, 205, 0.28))",
}}
>
<img
src={chatbotAvatarIcon}
alt="چت‌بات"
className="h-10 w-10 object-contain"
/>
</div>
)}
</motion.div>
);
})}
<div ref={endRef} />
</div>
</div>
);
}