fix contact layout and chat ui

This commit is contained in:
2026-04-15 23:12:23 -06:00
parent 73c4bc6cc7
commit 95b45c2e54
4 changed files with 119 additions and 106 deletions

View File

@@ -92,6 +92,7 @@ function AiChatPage() {
const lastMessageIdRef = useRef(null);
const fileInputRef = useRef(null);
const lastScrolledIdRef = useRef(null);
const initialLoadDoneRef = useRef(false);
useEffect(() => {
if (!authLoading && !user) {
@@ -103,6 +104,7 @@ function AiChatPage() {
if (messages.length === 0) return;
const lastMsg = messages[messages.length - 1];
if (lastMsg.id === lastScrolledIdRef.current) return;
if (!initialLoadDoneRef.current) return;
lastScrolledIdRef.current = lastMsg.id;
const area = messagesAreaRef.current;
if (!area) return;
@@ -114,6 +116,7 @@ function AiChatPage() {
const fetchMessages = useCallback(async (convId) => {
if (!token || !convId) return;
initialLoadDoneRef.current = false;
try {
const res = await fetch(`${API_BASE}/api/v1/chat/conversations/${convId}/messages`, {
headers: { Authorization: `Bearer ${token}` },
@@ -122,10 +125,17 @@ function AiChatPage() {
const data = await res.json();
if (Array.isArray(data)) {
setMessages(data);
if (data.length > 0) lastMessageIdRef.current = data[data.length - 1].id;
if (data.length > 0) {
lastMessageIdRef.current = data[data.length - 1].id;
lastScrolledIdRef.current = data[data.length - 1].id;
}
setTimeout(() => {
const area = messagesAreaRef.current;
if (area) area.scrollTop = area.scrollHeight;
initialLoadDoneRef.current = true;
}, 50);
}
} catch {
// silent
}
}, [token]);
@@ -491,34 +501,31 @@ function AiChatPage() {
</div>
</button>
))}
{conversations.some(c => c.status === "CLOSED") && (
<>
<button
style={s.closedSectionToggle}
onClick={() => setClosedExpanded(p => !p)}
>
<span>Closed ({conversations.filter(c => c.status === "CLOSED").length})</span>
<span>{closedExpanded ? "▲" : "▼"}</span>
</button>
{closedExpanded && conversations.filter(c => c.status === "CLOSED").map((conv) => (
<button
key={conv.id}
style={{ ...s.convItem, ...s.convItemClosed, ...(conv.id === conversation?.id ? s.convItemActive : {}) }}
onClick={() => switchConversation(conv.id)}
>
<div style={s.convItemTop}>
<span style={s.convItemSubject}>{conv.subject || `Conversation #${conv.id}`}</span>
<span style={{ ...s.convStatusBadge, ...s.convStatusClosed }}>CLOSED</span>
</div>
<div style={s.convItemBottom}>
<span style={s.convItemMode}>{conv.mode === "HUMAN" ? "👤 Live" : "🤖 AI"}</span>
<span style={s.convItemDate}>{conv.createdAt ? new Date(conv.createdAt).toLocaleDateString() : ""}</span>
</div>
</button>
))}
</>
)}
</div>
{conversations.some(c => c.status === "CLOSED") && (
<>
<button style={s.closedSectionToggle} onClick={() => setClosedExpanded(p => !p)}>
<span>Closed ({conversations.filter(c => c.status === "CLOSED").length})</span>
<span>{closedExpanded ? "▲" : "▼"}</span>
</button>
{closedExpanded && conversations.filter(c => c.status === "CLOSED").map((conv) => (
<button
key={conv.id}
style={{ ...s.convItem, ...s.convItemClosed, ...(conv.id === conversation?.id ? s.convItemActive : {}) }}
onClick={() => switchConversation(conv.id)}
>
<div style={s.convItemTop}>
<span style={s.convItemSubject}>{conv.subject || `Conversation #${conv.id}`}</span>
<span style={{ ...s.convStatusBadge, ...s.convStatusClosed }}>CLOSED</span>
</div>
<div style={s.convItemBottom}>
<span style={s.convItemMode}>{conv.mode === "HUMAN" ? "👤 Live" : "🤖 AI"}</span>
<span style={s.convItemDate}>{conv.createdAt ? new Date(conv.createdAt).toLocaleDateString() : ""}</span>
</div>
</button>
))}
</>
)}
<button style={s.newConvSidebarBtn} onClick={handleNewConversation}>
+ New Conversation
</button>