|
@@ -22,6 +22,8 @@ export default function ChatbotWidgetLive() {
|
|
|
const [isTyping, setIsTyping] = useState(false);
|
|
const [isTyping, setIsTyping] = useState(false);
|
|
|
const [showQuickReplies, setShowQuickReplies] = useState(true);
|
|
const [showQuickReplies, setShowQuickReplies] = useState(true);
|
|
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
const messagesEndRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
+ const scrollContainerRef = useRef<HTMLDivElement>(null);
|
|
|
|
|
+ const isNearBottomRef = useRef(true);
|
|
|
|
|
|
|
|
const startSession = trpc.chat.startSession.useMutation({
|
|
const startSession = trpc.chat.startSession.useMutation({
|
|
|
onSuccess: (data) => {
|
|
onSuccess: (data) => {
|
|
@@ -55,11 +57,19 @@ export default function ChatbotWidgetLive() {
|
|
|
}
|
|
}
|
|
|
}, [messagesData]);
|
|
}, [messagesData]);
|
|
|
|
|
|
|
|
- // Auto-scroll
|
|
|
|
|
|
|
+ // Auto-scroll — only when user is already near the bottom
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
|
|
|
|
|
+ if (isNearBottomRef.current) {
|
|
|
|
|
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
|
|
|
+ }
|
|
|
}, [localMessages, isTyping]);
|
|
}, [localMessages, isTyping]);
|
|
|
|
|
|
|
|
|
|
+ const handleScroll = () => {
|
|
|
|
|
+ const el = scrollContainerRef.current;
|
|
|
|
|
+ if (!el) return;
|
|
|
|
|
+ isNearBottomRef.current = el.scrollHeight - el.scrollTop - el.clientHeight < 100;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const handleOpen = () => {
|
|
const handleOpen = () => {
|
|
|
setIsOpen(true);
|
|
setIsOpen(true);
|
|
|
if (!sessionId) {
|
|
if (!sessionId) {
|
|
@@ -74,6 +84,9 @@ export default function ChatbotWidgetLive() {
|
|
|
setIsTyping(true);
|
|
setIsTyping(true);
|
|
|
setShowQuickReplies(false);
|
|
setShowQuickReplies(false);
|
|
|
|
|
|
|
|
|
|
+ // Always scroll to bottom when user sends a message
|
|
|
|
|
+ isNearBottomRef.current = true;
|
|
|
|
|
+
|
|
|
// Optimistically add user message
|
|
// Optimistically add user message
|
|
|
setLocalMessages(prev => [...prev, {
|
|
setLocalMessages(prev => [...prev, {
|
|
|
id: Date.now(),
|
|
id: Date.now(),
|
|
@@ -150,7 +163,7 @@ export default function ChatbotWidgetLive() {
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
{/* Messages */}
|
|
{/* Messages */}
|
|
|
- <div className="flex-1 overflow-y-auto p-3 space-y-3">
|
|
|
|
|
|
|
+ <div ref={scrollContainerRef} onScroll={handleScroll} className="flex-1 overflow-y-auto p-3 space-y-3">
|
|
|
{startSession.isPending ? (
|
|
{startSession.isPending ? (
|
|
|
<div className="flex items-center justify-center py-8">
|
|
<div className="flex items-center justify-center py-8">
|
|
|
<Loader2 className="w-5 h-5 animate-spin" style={{ color: "#14532D" }} />
|
|
<Loader2 className="w-5 h-5 animate-spin" style={{ color: "#14532D" }} />
|