chat UI updates #303

Merged
RecentRunner merged 2 commits from chat-ui-updates into main 2026-04-15 01:37:53 -06:00
2 changed files with 766 additions and 278 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,6 @@ function ChatPage() {
const [error, setError] = useState(null);
const [conversations, setConversations] = useState([]);
const [convsLoading, setConvsLoading] = useState(false);
const [showSidebar, setShowSidebar] = useState(false);
const [selectedFile, setSelectedFile] = useState(null);
const messagesEndRef = useRef(null);
@@ -172,13 +171,17 @@ function ChatPage() {
}
if (!convId) {
await fetchConversations();
setLoadingConv(false);
setConversation(null);
return;
}
await fetchConversation(convId);
await fetchMessages(convId);
await Promise.all([
fetchConversation(convId),
fetchMessages(convId),
fetchConversations(),
]);
setLoadingConv(false);
startPolling(convId);
}
@@ -188,11 +191,7 @@ function ChatPage() {
return () => {
if (pollRef.current) clearInterval(pollRef.current);
};
}, [token, authLoading, conversationIdParam, fetchConversation, fetchMessages, startPolling]);
useEffect(() => {
if (showSidebar && token) fetchConversations();
}, [showSidebar, token, fetchConversations]);
}, [token, authLoading, conversationIdParam, fetchConversation, fetchMessages, startPolling, fetchConversations]);
async function handleSend(e) {
e?.preventDefault();
@@ -334,7 +333,7 @@ function ChatPage() {
});
setConversation(conv);
await fetchMessages(conv.id);
await Promise.all([fetchMessages(conv.id), fetchConversations()]);
setLoadingConv(false);
startPolling(conv.id);
router.replace(`/chat?id=${conv.id}`, { scroll: false });
@@ -354,7 +353,26 @@ function ChatPage() {
setLoadingConv(false);
startPolling(convId);
router.replace(`/chat?id=${convId}`, { scroll: false });
setShowSidebar(false);
}
async function handleCloseConversation() {
if (!conversation || conversation.status === "CLOSED") return;
try {
const res = await fetch(`${API_BASE}/api/v1/chat/conversations/${conversation.id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({ status: "CLOSED" }),
});
if (!res.ok) return;
const updated = await res.json();
setConversation(updated);
await fetchConversations();
} catch {
// silent
}
}
if (authLoading || loadingConv) {
@@ -392,11 +410,9 @@ function ChatPage() {
<section style={s.chatSection}>
<div style={{ display: "flex", gap: "1rem", alignItems: "flex-start" }}>
{showSidebar && (
<div style={s.sidebar}>
<div style={s.sidebarHeader}>
<span style={s.sidebarTitle}>All Conversations</span>
<button style={s.sidebarClose} onClick={() => setShowSidebar(false)}></button>
</div>
{convsLoading && <p style={s.sidebarEmpty}>Loading...</p>}
{!convsLoading && conversations.length === 0 && (
@@ -422,12 +438,11 @@ function ChatPage() {
</button>
))}
</div>
<button style={s.newConvSidebarBtn} onClick={() => { setShowSidebar(false); handleNewConversation(); }}>
<button style={s.newConvSidebarBtn} onClick={() => handleNewConversation()}>
+ New Conversation
</button>
</div>
)}
<div style={{ flex: 1, minWidth: 0 }}>
<div style={{ flex: 1, minWidth: 0 }}>
{!conversation ? (
<div style={s.noConvCard}>
<div style={s.noConvIcon}>💬</div>
@@ -437,9 +452,6 @@ function ChatPage() {
<button style={s.startBtn} onClick={handleNewConversation}>
Start a Conversation
</button>
<button style={s.backBtn} onClick={() => setShowSidebar(true)}>
View Past Conversations
</button>
<button style={s.backBtn} onClick={() => router.push("/ai-chat")}>
Back to AI Assistant
</button>
@@ -460,12 +472,15 @@ function ChatPage() {
</div>
</div>
<div style={{ display: "flex", gap: "0.5rem" }}>
<button
style={{ ...s.historyBtn, ...(showSidebar ? s.historyBtnActive : {}) }}
onClick={() => setShowSidebar((v) => !v)}
>
History
</button>
{!isClosed && (
<button
style={s.closeConvBtn}
onClick={handleCloseConversation}
title="Close this conversation"
>
Close Chat
</button>
)}
<button
style={s.aiBtn}
onClick={() => router.push("/ai-chat")}
@@ -992,10 +1007,10 @@ const s = {
padding: "0 0.15rem",
flexShrink: 0,
},
historyBtn: {
closeConvBtn: {
background: "white",
border: "2px solid #555",
color: "#555",
border: "2px solid #c0392b",
color: "#c0392b",
borderRadius: 8,
padding: "0.45rem 0.9rem",
fontSize: "0.82rem",
@@ -1003,10 +1018,6 @@ const s = {
cursor: "pointer",
whiteSpace: "nowrap",
},
historyBtnActive: {
background: "#555",
color: "white",
},
sidebar: {
width: 230,
flexShrink: 0,
@@ -1028,14 +1039,6 @@ const s = {
flexShrink: 0,
},
sidebarTitle: { fontWeight: 700, fontSize: "0.88rem", color: "#333" },
sidebarClose: {
background: "none",
border: "none",
cursor: "pointer",
fontSize: "0.85rem",
color: "#999",
padding: "0.1rem 0.25rem",
},
sidebarEmpty: {
color: "#aaa",
fontSize: "0.82rem",