Skip to content
This repository was archived by the owner on Mar 16, 2026. It is now read-only.

Commit 0f1421c

Browse files
authored
Merge pull request #241 from aibtcdev/more-hot-fixes
More hot fixes
2 parents 45beac1 + 93488da commit 0f1421c

7 files changed

Lines changed: 603 additions & 180 deletions

File tree

src/components/chat/chat-window.tsx

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export function ChatWindow() {
6060
};
6161
}, [accessToken, memoizedConnect, isConnected]);
6262

63+
// Show thread list even when no active thread
6364
if (!accessToken) {
6465
return (
6566
<div className="flex items-center justify-center h-full">
@@ -70,21 +71,9 @@ export function ChatWindow() {
7071
);
7172
}
7273

73-
if (!activeThreadId) {
74-
return (
75-
<div className="flex items-center justify-center h-[calc(100vh-4rem)] backdrop-blur-sm">
76-
<div className="text-center space-y-4 p-4 sm:p-6 lg:p-8 -mt-20">
77-
<div className="flex justify-center gap-3">
78-
<CreateThreadButton />
79-
</div>
80-
</div>
81-
</div>
82-
);
83-
}
84-
8574
return (
8675
<div className="relative flex h-[94dvh] md:h-[100dvh] w-full">
87-
{/* Fixed Sidebar */}
76+
{/* Fixed Sidebar - Always visible regardless of active thread */}
8877
<div
8978
className={`
9079
hidden md:block fixed left-0 top-15 h-full
@@ -126,11 +115,13 @@ export function ChatWindow() {
126115

127116
<div className="flex items-center gap-2 min-w-0 flex-1">
128117
<div>
129-
<AgentWalletSelector
130-
selectedAgentId={selectedAgentId}
131-
onSelect={setSelectedAgent}
132-
disabled={isChatLoading || !isConnected}
133-
/>
118+
{activeThreadId && (
119+
<AgentWalletSelector
120+
selectedAgentId={selectedAgentId}
121+
onSelect={setSelectedAgent}
122+
disabled={isChatLoading || !isConnected}
123+
/>
124+
)}
134125
</div>
135126
</div>
136127
</div>
@@ -140,35 +131,51 @@ export function ChatWindow() {
140131
</div>
141132
</div>
142133

143-
{/* Message list */}
144-
<div className="flex-1 overflow-hidden w-full min-w-0 max-w-full">
145-
<ScrollArea className="h-full w-full pb-4">
146-
<div className="flex flex-col justify-end min-h-full w-full max-w-full">
147-
{chatError && (
148-
<Alert
149-
variant="destructive"
150-
className="mx-2 md:mx-4 my-2 md:my-4"
151-
>
152-
<AlertDescription>{chatError}</AlertDescription>
153-
</Alert>
154-
)}
155-
<MessageList messages={threadMessages} />
134+
{!activeThreadId ? (
135+
<div className="flex items-center justify-center h-full backdrop-blur-sm">
136+
<div className="text-center space-y-4 p-4 sm:p-6 lg:p-8 -mt-20">
137+
<div className="flex justify-center gap-3">
138+
<p className="text-muted-foreground mb-4">
139+
Select a thread or create a new one
140+
</p>
141+
</div>
142+
</div>
143+
</div>
144+
) : (
145+
<>
146+
{/* Message list with increased bottom padding */}
147+
<div className="flex-1 overflow-hidden w-full min-w-0 max-w-full">
148+
<ScrollArea className="h-full w-full">
149+
<div className="flex flex-col justify-end min-h-full w-full max-w-full">
150+
{chatError && (
151+
<Alert
152+
variant="destructive"
153+
className="mx-2 md:mx-4 my-2 md:my-4"
154+
>
155+
<AlertDescription>{chatError}</AlertDescription>
156+
</Alert>
157+
)}
158+
<MessageList messages={threadMessages} />
159+
{/* Add extra padding div at the bottom to ensure content isn't hidden */}
160+
<div className="h-32"></div>
161+
</div>
162+
</ScrollArea>
156163
</div>
157-
</ScrollArea>
158-
</div>
159164

160-
{/* Input with shadow */}
161-
<div className="sticky bottom-0 w-full min-w-0 pb-safe shadow-lg z-20">
162-
<div className="px-2 md:px-4">
163-
<div className="relative">
164-
<ChatInput
165-
selectedAgentId={selectedAgentId}
166-
onAgentSelect={setSelectedAgent}
167-
disabled={isChatLoading || !isConnected}
168-
/>
165+
{/* Input with shadow */}
166+
<div className="sticky bottom-0 w-full min-w-0 pb-safe shadow-lg z-20 bg-background">
167+
<div className="px-2 md:px-4 pt-2">
168+
<div className="relative">
169+
<ChatInput
170+
selectedAgentId={selectedAgentId}
171+
onAgentSelect={setSelectedAgent}
172+
disabled={isChatLoading || !isConnected}
173+
/>
174+
</div>
175+
</div>
169176
</div>
170-
</div>
171-
</div>
177+
</>
178+
)}
172179
</div>
173180
</div>
174181
);
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
"use client";
2+
3+
import type React from "react";
4+
5+
import { useState, useCallback, useRef } from "react";
6+
import { Button } from "@/components/ui/button";
7+
import { Input } from "@/components/ui/input";
8+
import { Wallet } from "lucide-react";
9+
import { cn } from "@/lib/utils";
10+
import { useChatStore } from "@/store/chat";
11+
import { useSessionStore } from "@/store/session";
12+
13+
interface TokenBuyInputProps {
14+
tokenName: string;
15+
contractPrincipal: string;
16+
disabled?: boolean;
17+
onSend: () => void;
18+
}
19+
20+
export function TokenBuyInput({
21+
tokenName,
22+
contractPrincipal,
23+
disabled = false,
24+
onSend,
25+
}: TokenBuyInputProps) {
26+
const [amount, setAmount] = useState("");
27+
const inputRef = useRef<HTMLInputElement>(null);
28+
const containerRef = useRef<HTMLDivElement>(null);
29+
const { sendMessage, activeThreadId } = useChatStore();
30+
const { accessToken } = useSessionStore();
31+
32+
const handleSubmit = useCallback(
33+
async (e: React.FormEvent) => {
34+
e.preventDefault();
35+
if (!amount.trim() || !accessToken || !activeThreadId) return;
36+
37+
const message = `Buy ${amount} satoshis of ${tokenName}.\nToken DEX: ${contractPrincipal}`;
38+
39+
try {
40+
await sendMessage(activeThreadId, message);
41+
setAmount("");
42+
onSend(); // Call the onSend callback after successful message send
43+
} catch (error) {
44+
console.error("Failed to send message:", error);
45+
}
46+
},
47+
[
48+
activeThreadId,
49+
amount,
50+
tokenName,
51+
contractPrincipal,
52+
sendMessage,
53+
accessToken,
54+
onSend,
55+
]
56+
);
57+
58+
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
59+
// Only allow numbers and decimal points
60+
const value = e.target.value.replace(/[^\d.]/g, "");
61+
setAmount(value);
62+
}, []);
63+
64+
const handleFocus = () => {
65+
// Mobile scroll fix
66+
setTimeout(() => {
67+
inputRef.current?.scrollIntoView({ behavior: "smooth", block: "end" });
68+
}, 300);
69+
};
70+
71+
if (!accessToken) return null;
72+
73+
return (
74+
<div ref={containerRef} className="w-full backdrop-blur">
75+
<div className="mx-auto max-w-5xl px-2 md:px-4 py-2 w-full">
76+
<form onSubmit={handleSubmit} className="flex gap-2 w-full">
77+
<div className="flex flex-1 gap-2 items-end w-full">
78+
<div className="relative flex-1 min-w-0">
79+
<Input
80+
ref={inputRef}
81+
type="text"
82+
value={amount}
83+
onChange={handleChange}
84+
onClick={handleFocus}
85+
onFocus={handleFocus}
86+
placeholder={`Enter amount of ${tokenName} to buy...`}
87+
disabled={disabled}
88+
className={cn(
89+
"h-11",
90+
"py-2.5 px-4 border border-muted",
91+
"text-base placeholder:text-muted-foreground",
92+
"rounded-xl md:rounded-2xl",
93+
"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
94+
"transition-all duration-200"
95+
)}
96+
/>
97+
</div>
98+
<Button type="submit" disabled={disabled || !amount.trim()}>
99+
Buy
100+
<Wallet className="h-4 w-4" />
101+
</Button>
102+
</div>
103+
</form>
104+
</div>
105+
</div>
106+
);
107+
}

0 commit comments

Comments
 (0)