AW-496-connect-chats

edits
This commit is contained in:
gofnnp 2025-07-23 22:41:20 +04:00
parent ccffd32511
commit 3244655e38
8 changed files with 32 additions and 67 deletions

View File

@ -10,3 +10,9 @@
justify-content: center; justify-content: center;
padding-top: 16px; padding-top: 16px;
} }
.suggestions.suggestions {
position: sticky;
bottom: 0;
padding: 0 16px 36px;
}

View File

@ -7,7 +7,7 @@ import { useChat } from "@/providers/chat-provider";
import { useChatStore } from "@/providers/chat-store-provider"; import { useChatStore } from "@/providers/chat-store-provider";
import { formatTime } from "@/shared/utils/date"; import { formatTime } from "@/shared/utils/date";
import { ChatMessages } from ".."; import { ChatMessages, Suggestions } from "..";
import styles from "./ChatMessagesWrapper.module.scss"; import styles from "./ChatMessagesWrapper.module.scss";
@ -20,9 +20,10 @@ export default function ChatMessagesWrapper() {
messagesWrapperRef, messagesWrapperRef,
loadOlder, loadOlder,
scrollToBottom, scrollToBottom,
send,
} = useChat(); } = useChat();
const { suggestionsHeight, _hasHydrated } = useChatStore(state => state); const { _hasHydrated } = useChatStore(state => state);
const isInitialScrollDone = useRef(false); const isInitialScrollDone = useRef(false);
@ -48,47 +49,19 @@ export default function ChatMessagesWrapper() {
}, [socketMessages]); }, [socketMessages]);
useEffect(() => { useEffect(() => {
if ( if (socketMessages.length > 0 && _hasHydrated) {
socketMessages.length > 0 &&
!isInitialScrollDone.current &&
_hasHydrated
) {
scrollToBottom();
const timeout = setTimeout(() => { const timeout = setTimeout(() => {
isInitialScrollDone.current = true; scrollToBottom();
}, 1000); });
return () => clearTimeout(timeout); return () => clearTimeout(timeout);
} }
}, [socketMessages.length, scrollToBottom, _hasHydrated]); }, [socketMessages.length, scrollToBottom, _hasHydrated]);
// useEffect(() => {
// if (suggestionsHeight) {
// const timeout = setTimeout(() => {
// scrollToBottom();
// console.log("scrollToBottom 2");
// }, 0);
// return () => clearTimeout(timeout);
// }
// }, [suggestionsHeight, scrollToBottom]);
useEffect(() => {
if (messagesWrapperRef.current?.style.paddingBottom) {
scrollToBottom();
}
}, [
scrollToBottom,
messagesWrapperRef.current?.style.paddingBottom,
messagesWrapperRef,
]);
return ( return (
<div <div
className={styles.messagesWrapper} className={styles.messagesWrapper}
ref={messagesWrapperRef} ref={messagesWrapperRef}
onScroll={handleScroll} onScroll={handleScroll}
style={{
paddingBottom: suggestionsHeight,
}}
> >
{isLoadingOlder && hasMoreOlderMessages && ( {isLoadingOlder && hasMoreOlderMessages && (
<div className={styles.loaderTop}> <div className={styles.loaderTop}>
@ -99,6 +72,12 @@ export default function ChatMessagesWrapper() {
messages={mappedMessages} messages={mappedMessages}
isLoadingAdvisorMessage={isLoadingAdvisorMessage} isLoadingAdvisorMessage={isLoadingAdvisorMessage}
/> />
<Suggestions
className={styles.suggestions}
onSuggestionClick={suggestion => {
send(suggestion);
}}
/>
</div> </div>
); );
} }

View File

@ -2,7 +2,7 @@
import { useChat } from "@/providers/chat-provider"; import { useChat } from "@/providers/chat-provider";
import { MessageInput, Suggestions } from ".."; import { MessageInput } from "..";
import styles from "./MessageInputWrapper.module.scss"; import styles from "./MessageInputWrapper.module.scss";
@ -11,11 +11,6 @@ export default function MessageInputWrapper() {
return ( return (
<div className={styles.container}> <div className={styles.container}>
<Suggestions
onSuggestionClick={suggestion => {
send(suggestion);
}}
/>
<div className={styles.inputWrapper}> <div className={styles.inputWrapper}>
<MessageInput onSend={send} /> <MessageInput onSend={send} />
</div> </div>

View File

@ -1,6 +1,4 @@
.container { .container {
position: absolute;
bottom: 100%;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 12px; gap: 12px;

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import { useEffect, useRef } from "react"; import { useRef } from "react";
import clsx from "clsx";
import { Typography } from "@/components/ui"; import { Typography } from "@/components/ui";
import { useChatStore } from "@/providers/chat-store-provider"; import { useChatStore } from "@/providers/chat-store-provider";
@ -8,21 +9,21 @@ import { useChatStore } from "@/providers/chat-store-provider";
import styles from "./Suggestions.module.scss"; import styles from "./Suggestions.module.scss";
interface SuggestionsProps { interface SuggestionsProps {
className?: string;
onSuggestionClick: (suggestion: string) => void; onSuggestionClick: (suggestion: string) => void;
} }
export default function Suggestions({ onSuggestionClick }: SuggestionsProps) { export default function Suggestions({
const { suggestions, setSuggestionsHeight } = useChatStore(state => state); className,
onSuggestionClick,
}: SuggestionsProps) {
const { suggestions } = useChatStore(state => state);
const suggestionsRef = useRef<HTMLDivElement>(null); const suggestionsRef = useRef<HTMLDivElement>(null);
useEffect(() => {
setSuggestionsHeight(suggestionsRef.current?.clientHeight ?? 0);
}, [setSuggestionsHeight, suggestions]);
return ( return (
<> <>
{!!suggestions?.length && ( {!!suggestions?.length && (
<div className={styles.container} ref={suggestionsRef}> <div className={clsx(styles.container, className)} ref={suggestionsRef}>
{suggestions?.map((suggestion, index) => ( {suggestions?.map((suggestion, index) => (
<div <div
key={`suggestion-${index}`} key={`suggestion-${index}`}
@ -35,6 +36,7 @@ export default function Suggestions({ onSuggestionClick }: SuggestionsProps) {
as="p" as="p"
weight="medium" weight="medium"
className={styles.suggestionText} className={styles.suggestionText}
align="left"
> >
{suggestion} {suggestion}
</Typography> </Typography>

View File

@ -63,8 +63,6 @@ export const useChatSocket = (
const [isSessionExpired, setIsSessionExpired] = useState(false); const [isSessionExpired, setIsSessionExpired] = useState(false);
const [refillModals, setRefillModals] = useState<IRefillModals | null>(null); const [refillModals, setRefillModals] = useState<IRefillModals | null>(null);
const { suggestions, setSuggestions } = useChatStore(state => state); const { suggestions, setSuggestions } = useChatStore(state => state);
const [isSuggestionsInitialized, setIsSuggestionsInitialized] =
useState(false);
const isLoadingAdvisorMessage = useMemo(() => { const isLoadingAdvisorMessage = useMemo(() => {
return messages.length > 0 && messages[0].role !== "assistant"; return messages.length > 0 && messages[0].role !== "assistant";
@ -166,8 +164,6 @@ export const useChatSocket = (
if (data[0].role === "user") setIsLoadingSelfMessage(false); if (data[0].role === "user") setIsLoadingSelfMessage(false);
// if (data[0].role === "assistant") setIsLoadingAdvisorMessage(false); // if (data[0].role === "assistant") setIsLoadingAdvisorMessage(false);
setSuggestions(data[0].suggestions);
setMessages(prev => { setMessages(prev => {
const map = new Map<string, UIMessage>(); const map = new Map<string, UIMessage>();
@ -182,6 +178,7 @@ export const useChatSocket = (
text: d.text, text: d.text,
createdDate: d.createdDate, createdDate: d.createdDate,
isRead: d.isRead, isRead: d.isRead,
suggestions: d.suggestions,
}) })
); );
return Array.from(map.values()).sort( return Array.from(map.values()).sort(
@ -230,14 +227,8 @@ export const useChatSocket = (
}, [socket, status, joinChat, leaveChat, fetchBalance]); }, [socket, status, joinChat, leaveChat, fetchBalance]);
useEffect(() => { useEffect(() => {
if (!isSuggestionsInitialized) { setSuggestions(messages[0]?.suggestions);
setSuggestions([]); }, [messages, setSuggestions]);
}
if (messages[0]?.suggestions && !isSuggestionsInitialized) {
setSuggestions(messages[0].suggestions);
setIsSuggestionsInitialized(true);
}
}, [messages, setSuggestions, isSuggestionsInitialized]);
useEffect(() => { useEffect(() => {
if (session && status === ESocketStatus.CONNECTED) { if (session && status === ESocketStatus.CONNECTED) {

View File

@ -42,7 +42,6 @@ export function ChatProvider({
const value = useChatSocket(chatId, { const value = useChatSocket(chatId, {
initialMessages, initialMessages,
initialTotal, initialTotal,
onNewMessage: _message => scrollToBottom(),
}); });
const messagesWrapperRef = useRef<HTMLDivElement>(null); const messagesWrapperRef = useRef<HTMLDivElement>(null);

View File

@ -9,7 +9,6 @@ interface ChatState {
currentChat: IChat | null; currentChat: IChat | null;
isAutoTopUp: boolean; isAutoTopUp: boolean;
suggestions: IChatMessage["suggestions"]; suggestions: IChatMessage["suggestions"];
suggestionsHeight: number;
_hasHydrated: boolean; _hasHydrated: boolean;
} }
@ -17,7 +16,6 @@ export type ChatActions = {
setCurrentChat: (chat: IChat) => void; setCurrentChat: (chat: IChat) => void;
setIsAutoTopUp: (isAutoTopUp: boolean) => void; setIsAutoTopUp: (isAutoTopUp: boolean) => void;
setSuggestions: (suggestions: IChatMessage["suggestions"]) => void; setSuggestions: (suggestions: IChatMessage["suggestions"]) => void;
setSuggestionsHeight: (height: number) => void;
clearChatData: () => void; clearChatData: () => void;
setHasHydrated: (hasHydrated: boolean) => void; setHasHydrated: (hasHydrated: boolean) => void;
}; };
@ -28,7 +26,6 @@ const initialState: ChatState = {
currentChat: null, currentChat: null,
isAutoTopUp: false, isAutoTopUp: false,
suggestions: [], suggestions: [],
suggestionsHeight: 0,
_hasHydrated: false, _hasHydrated: false,
}; };
@ -41,8 +38,6 @@ export const createChatStore = (initState: ChatState = initialState) => {
setIsAutoTopUp: (isAutoTopUp: boolean) => set({ isAutoTopUp }), setIsAutoTopUp: (isAutoTopUp: boolean) => set({ isAutoTopUp }),
setSuggestions: (suggestions: IChatMessage["suggestions"]) => setSuggestions: (suggestions: IChatMessage["suggestions"]) =>
set({ suggestions }), set({ suggestions }),
setSuggestionsHeight: (height: number) =>
set({ suggestionsHeight: height }),
clearChatData: () => set(initialState), clearChatData: () => set(initialState),
setHasHydrated: (hasHydrated: boolean) => setHasHydrated: (hasHydrated: boolean) =>