1
- import React , { useState , useEffect } from "react" ;
1
+ import React , { useState } from "react" ;
2
2
import {
3
3
useExternalStoreRuntime ,
4
4
ThreadMessageLike ,
5
5
AppendMessage ,
6
6
AssistantRuntimeProvider ,
7
7
ExternalStoreThreadListAdapter ,
8
8
} from "@assistant-ui/react" ;
9
- import { useThreadContext , MyMessage , ThreadProvider } from "./context/ThreadContext" ;
10
9
import { Thread } from "./assistant-ui/thread" ;
11
10
import { ThreadList } from "./assistant-ui/thread-list" ;
12
- import { chatStorage , ThreadData as StoredThreadData } from "../utils/chatStorage" ;
13
- import { useChatStorage } from "../hooks/useChatStorage" ;
11
+ import {
12
+ useChatContext ,
13
+ MyMessage ,
14
+ ThreadData ,
15
+ RegularThreadData ,
16
+ ArchivedThreadData
17
+ } from "./context/ChatContext" ;
14
18
import styled from "styled-components" ;
15
19
16
-
17
-
18
-
19
20
const ChatContainer = styled . div `
20
21
display: flex;
21
22
height: 500px;
22
23
23
24
.aui-thread-list-root {
24
25
width: 250px;
25
- background-color: #333;
26
+ background-color: #fff;
27
+ padding: 10px;
26
28
}
27
29
28
30
.aui-thread-root {
29
31
flex: 1;
30
- background-color: #f0f0f0 ;
32
+ background-color: #f9fafb ;
31
33
}
32
34
33
- ` ;
34
-
35
- // Define thread data interfaces to match ExternalStoreThreadData requirements
36
- interface RegularThreadData {
37
- threadId : string ;
38
- status : "regular" ;
39
- title : string ;
40
- }
35
+ .aui-thread-list-item {
36
+ cursor: pointer;
37
+ transition: background-color 0.2s ease;
41
38
42
- interface ArchivedThreadData {
43
- threadId : string ;
44
- status : "archived" ;
45
- title : string ;
46
- }
47
-
48
- type ThreadData = RegularThreadData | ArchivedThreadData ;
39
+ &[data-active="true"] {
40
+ background-color: #dbeafe;
41
+ border: 1px solid #bfdbfe;
42
+ }
43
+ }
44
+ ` ;
49
45
50
46
const generateId = ( ) => Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 ) ;
51
47
@@ -59,22 +55,14 @@ const callYourAPI = async (text: string) => {
59
55
} ;
60
56
} ;
61
57
62
- function ChatWithThreads ( ) {
63
- const { currentThreadId, setCurrentThreadId, threads, setThreads } =
64
- useThreadContext ( ) ;
58
+ export function ChatMain ( ) {
59
+ const { state, actions } = useChatContext ( ) ;
65
60
const [ isRunning , setIsRunning ] = useState ( false ) ;
66
- const [ threadList , setThreadList ] = useState < ThreadData [ ] > ( [
67
- { threadId : "default" , status : "regular" , title : "New Chat" } as RegularThreadData ,
68
- ] ) ;
69
- const { isInitialized } = useChatStorage ( {
70
- threadList,
71
- threads,
72
- setThreadList,
73
- setThreads,
74
- setCurrentThreadId,
75
- } ) ;
61
+
62
+ console . log ( "STATE" , state ) ;
63
+
76
64
// Get messages for current thread
77
- const currentMessages = threads . get ( currentThreadId ) || [ ] ;
65
+ const currentMessages = actions . getCurrentMessages ( ) ;
78
66
79
67
// Convert custom format to ThreadMessageLike
80
68
const convertMessage = ( message : MyMessage ) : ThreadMessageLike => ( {
@@ -99,8 +87,7 @@ function ChatWithThreads() {
99
87
} ;
100
88
101
89
// Update current thread with new user message
102
- const updatedMessages = [ ...currentMessages , userMessage ] ;
103
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , updatedMessages ) ) ;
90
+ await actions . addMessage ( state . currentThreadId , userMessage ) ;
104
91
setIsRunning ( true ) ;
105
92
106
93
try {
@@ -115,8 +102,7 @@ function ChatWithThreads() {
115
102
} ;
116
103
117
104
// Update current thread with assistant response
118
- const finalMessages = [ ...updatedMessages , assistantMessage ] ;
119
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , finalMessages ) ) ;
105
+ await actions . addMessage ( state . currentThreadId , assistantMessage ) ;
120
106
} catch ( error ) {
121
107
// Handle errors gracefully
122
108
const errorMessage : MyMessage = {
@@ -126,8 +112,7 @@ function ChatWithThreads() {
126
112
timestamp : Date . now ( ) ,
127
113
} ;
128
114
129
- const finalMessages = [ ...updatedMessages , errorMessage ] ;
130
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , finalMessages ) ) ;
115
+ await actions . addMessage ( state . currentThreadId , errorMessage ) ;
131
116
} finally {
132
117
setIsRunning ( false ) ;
133
118
}
@@ -155,7 +140,8 @@ function ChatWithThreads() {
155
140
} ;
156
141
newMessages . push ( editedMessage ) ;
157
142
158
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , newMessages ) ) ;
143
+ // Update messages using the new context action
144
+ await actions . updateMessages ( state . currentThreadId , newMessages ) ;
159
145
setIsRunning ( true ) ;
160
146
161
147
try {
@@ -170,7 +156,7 @@ function ChatWithThreads() {
170
156
} ;
171
157
172
158
newMessages . push ( assistantMessage ) ;
173
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , newMessages ) ) ;
159
+ await actions . updateMessages ( state . currentThreadId , newMessages ) ;
174
160
} catch ( error ) {
175
161
// Handle errors gracefully
176
162
const errorMessage : MyMessage = {
@@ -181,89 +167,44 @@ function ChatWithThreads() {
181
167
} ;
182
168
183
169
newMessages . push ( errorMessage ) ;
184
- setThreads ( prev => new Map ( prev ) . set ( currentThreadId , newMessages ) ) ;
170
+ await actions . updateMessages ( state . currentThreadId , newMessages ) ;
185
171
} finally {
186
172
setIsRunning ( false ) ;
187
173
}
188
174
} ;
189
175
190
176
// Thread list adapter for managing multiple threads
191
177
const threadListAdapter : ExternalStoreThreadListAdapter = {
192
- threadId : currentThreadId ,
193
- threads : threadList . filter ( ( t ) : t is RegularThreadData => t . status === "regular" ) ,
194
- archivedThreads : threadList . filter ( ( t ) : t is ArchivedThreadData => t . status === "archived" ) ,
178
+ threadId : state . currentThreadId ,
179
+ threads : state . threadList . filter ( ( t ) : t is RegularThreadData => t . status === "regular" ) ,
180
+ archivedThreads : state . threadList . filter ( ( t ) : t is ArchivedThreadData => t . status === "archived" ) ,
195
181
196
182
onSwitchToNewThread : async ( ) => {
197
- const newId = `thread-${ Date . now ( ) } ` ;
198
- const newThread : RegularThreadData = {
199
- threadId : newId ,
200
- status : "regular" ,
201
- title : "New Chat" ,
202
- } ;
203
-
204
- setThreadList ( ( prev ) => [ ...prev , newThread ] ) ;
205
- setThreads ( ( prev ) => new Map ( prev ) . set ( newId , [ ] ) ) ;
206
- setCurrentThreadId ( newId ) ;
207
-
208
- // Save new thread to storage
209
- try {
210
- const storedThread : StoredThreadData = {
211
- threadId : newId ,
212
- status : "regular" ,
213
- title : "New Chat" ,
214
- createdAt : Date . now ( ) ,
215
- updatedAt : Date . now ( ) ,
216
- } ;
217
- await chatStorage . saveThread ( storedThread ) ;
218
- } catch ( error ) {
219
- console . error ( "Failed to save new thread:" , error ) ;
220
- }
183
+ const threadId = await actions . createThread ( "New Chat" ) ;
184
+ actions . setCurrentThread ( threadId ) ;
221
185
} ,
222
186
223
187
onSwitchToThread : ( threadId ) => {
224
- setCurrentThreadId ( threadId ) ;
188
+ actions . setCurrentThread ( threadId ) ;
225
189
} ,
226
190
227
- onRename : ( threadId , newTitle ) => {
228
- setThreadList ( ( prev ) =>
229
- prev . map ( ( t ) =>
230
- t . threadId === threadId ? { ...t , title : newTitle } : t ,
231
- ) ,
232
- ) ;
191
+ onRename : async ( threadId , newTitle ) => {
192
+ await actions . updateThread ( threadId , { title : newTitle } ) ;
233
193
} ,
234
194
235
- onArchive : ( threadId ) => {
236
- setThreadList ( ( prev ) =>
237
- prev . map ( ( t ) =>
238
- t . threadId === threadId ? { ...t , status : "archived" } : t ,
239
- ) ,
240
- ) ;
195
+ onArchive : async ( threadId ) => {
196
+ await actions . updateThread ( threadId , { status : "archived" } ) ;
241
197
} ,
242
198
243
199
onDelete : async ( threadId ) => {
244
- setThreadList ( ( prev ) => prev . filter ( ( t ) => t . threadId !== threadId ) ) ;
245
- setThreads ( ( prev ) => {
246
- const next = new Map ( prev ) ;
247
- next . delete ( threadId ) ;
248
- return next ;
249
- } ) ;
250
- if ( currentThreadId === threadId ) {
251
- setCurrentThreadId ( "default" ) ;
252
- }
253
-
254
- // Delete thread from storage
255
- try {
256
- await chatStorage . deleteThread ( threadId ) ;
257
- } catch ( error ) {
258
- console . error ( "Failed to delete thread from storage:" , error ) ;
259
- }
200
+ await actions . deleteThread ( threadId ) ;
260
201
} ,
261
202
} ;
262
203
263
204
const runtime = useExternalStoreRuntime ( {
264
205
messages : currentMessages ,
265
206
setMessages : ( messages ) => {
266
- setThreads ( ( prev ) => new Map ( prev ) . set ( currentThreadId , messages ) ) ;
207
+ actions . updateMessages ( state . currentThreadId , messages ) ;
267
208
} ,
268
209
convertMessage,
269
210
isRunning,
@@ -274,7 +215,7 @@ function ChatWithThreads() {
274
215
} ,
275
216
} ) ;
276
217
277
- if ( ! isInitialized ) {
218
+ if ( ! state . isInitialized ) {
278
219
return < div > Loading...</ div > ;
279
220
}
280
221
@@ -288,13 +229,3 @@ function ChatWithThreads() {
288
229
) ;
289
230
}
290
231
291
- // Main App component with proper context wrapping
292
- export function ChatApp ( ) {
293
- return (
294
- < ThreadProvider >
295
- < ChatWithThreads />
296
- </ ThreadProvider >
297
- ) ;
298
- }
299
-
300
- export { ChatWithThreads } ;
0 commit comments