@@ -27,15 +27,15 @@ const PAGE_SIZE = 10;
2727export function ConversationListApp ( ) {
2828 const [ appState , setAppState ] = useState < AppState > ( "loading" ) ;
2929 const [ authData , setAuthData ] = useState < AuthRequiredResponse | null > ( null ) ;
30- const [ conversations , setConversations ] = useState < ConversationItem [ ] > ( [ ] ) ;
30+ // All conversations from server
31+ const [ allConversations , setAllConversations ] = useState < ConversationItem [ ] > (
32+ [ ]
33+ ) ;
34+ // Number of conversations to display (for client-side pagination)
35+ const [ displayCount , setDisplayCount ] = useState ( PAGE_SIZE ) ;
3136 const [ username , setUsername ] = useState < string > ( "" ) ;
32- const [ totalCount , setTotalCount ] = useState ( 0 ) ;
33- const [ hasMore , setHasMore ] = useState ( false ) ;
34- const [ _offset , setOffset ] = useState ( 0 ) ;
35- const [ isLoadingMore , setIsLoadingMore ] = useState ( false ) ;
3637 const [ errorMessage , setErrorMessage ] = useState < string | null > ( null ) ;
3738
38- const offsetRef = useRef ( 0 ) ;
3939 const hasFetchedInitial = useRef ( false ) ;
4040
4141 const { initialData, callTool, openLink, parseResult } = useMcpApp <
@@ -61,61 +61,44 @@ export function ConversationListApp() {
6161 [ callTool , parseResult ]
6262 ) ;
6363
64- // Fetch conversations
65- const fetchConversations = useCallback (
66- async ( loadMore = false ) => {
67- try {
68- const currentOffset = offsetRef . current ;
69- const newOffset = loadMore ? currentOffset + PAGE_SIZE : 0 ;
70- const result = await callTool ( "x_get_conversations" , {
71- offset : newOffset ,
72- limit : PAGE_SIZE ,
73- } ) ;
64+ // Fetch all conversations from server
65+ const fetchConversations = useCallback ( async ( ) => {
66+ try {
67+ const result = await callTool ( "x_get_conversations" , { } ) ;
7468
75- const data = parseResult <
76- ConversationsData | { error : boolean ; message : string }
77- > ( result ) ;
78- if ( typeof data === "string" || ! data ) {
79- return ;
80- }
69+ const data = parseResult <
70+ ConversationsData | { error : boolean ; message : string }
71+ > ( result ) ;
72+ if ( typeof data === "string" || ! data ) {
73+ return ;
74+ }
8175
82- // Check for auth error - tool returns error when username not set
83- if ( "error" in data && data . error ) {
84- await handleAuthError ( ( data as { message ?: string } ) . message || "" ) ;
85- return ;
86- }
76+ // Check for auth error - tool returns error when username not set
77+ if ( "error" in data && data . error ) {
78+ await handleAuthError ( ( data as { message ?: string } ) . message || "" ) ;
79+ return ;
80+ }
8781
88- if ( "conversations" in data ) {
89- if ( loadMore ) {
90- setConversations ( ( prev ) => [ ...prev , ...data . conversations ] ) ;
91- } else {
92- setConversations ( data . conversations ) ;
93- }
94- setUsername ( data . username ) ;
95- setTotalCount ( data . totalCount ) ;
96- setHasMore ( data . hasMore ) ;
97- offsetRef . current = newOffset ;
98- setOffset ( newOffset ) ;
99- setAppState ( "loaded" ) ;
100- }
101- } catch ( error ) {
102- console . error ( "Failed to fetch conversations:" , error ) ;
103- setErrorMessage (
104- error instanceof Error
105- ? error . message
106- : "Failed to load conversations"
107- ) ;
108- setAppState ( "error" ) ;
82+ if ( "conversations" in data ) {
83+ setAllConversations ( data . conversations ) ;
84+ setUsername ( data . username ) ;
85+ setDisplayCount ( PAGE_SIZE ) ; // Reset display count on fresh fetch
86+ setAppState ( "loaded" ) ;
10987 }
110- } ,
111- [ callTool , parseResult , handleAuthError ]
112- ) ;
88+ } catch ( error ) {
89+ console . error ( "Failed to fetch conversations:" , error ) ;
90+ setErrorMessage (
91+ error instanceof Error ? error . message : "Failed to load conversations"
92+ ) ;
93+ setAppState ( "error" ) ;
94+ }
95+ } , [ callTool , parseResult , handleAuthError ] ) ;
11396
11497 // Auth poller
11598 const authPoller = useAuthPoller ( {
11699 callTool,
117100 openLink,
118- onAuthComplete : ( ) => fetchConversations ( false ) ,
101+ onAuthComplete : ( ) => fetchConversations ( ) ,
119102 } ) ;
120103
121104 // Handle initial data
@@ -133,7 +116,7 @@ export function ConversationListApp() {
133116 // Not JSON - treat as text message, fetch conversations
134117 if ( ! hasFetchedInitial . current ) {
135118 hasFetchedInitial . current = true ;
136- fetchConversations ( false ) ;
119+ fetchConversations ( ) ;
137120 }
138121 return ;
139122 }
@@ -147,15 +130,14 @@ export function ConversationListApp() {
147130 parsedData !== null &&
148131 "conversations" in parsedData
149132 ) {
150- setConversations ( parsedData . conversations ) ;
133+ setAllConversations ( parsedData . conversations ) ;
151134 setUsername ( parsedData . username ) ;
152- setTotalCount ( parsedData . totalCount ) ;
153- setHasMore ( parsedData . hasMore ) ;
135+ setDisplayCount ( PAGE_SIZE ) ;
154136 setAppState ( "loaded" ) ;
155137 } else if ( ! hasFetchedInitial . current ) {
156138 // Unknown format - try fetching
157139 hasFetchedInitial . current = true ;
158- fetchConversations ( false ) ;
140+ fetchConversations ( ) ;
159141 }
160142 } , [ initialData , fetchConversations ] ) ;
161143
@@ -165,10 +147,9 @@ export function ConversationListApp() {
165147 }
166148 } ;
167149
168- const handleLoadMore = async ( ) => {
169- setIsLoadingMore ( true ) ;
170- await fetchConversations ( true ) ;
171- setIsLoadingMore ( false ) ;
150+ // Client-side pagination - just show more items
151+ const handleLoadMore = ( ) => {
152+ setDisplayCount ( ( prev ) => prev + PAGE_SIZE ) ;
172153 } ;
173154
174155 const handleDismiss = async ( tweetId : string , replyCount : number ) => {
@@ -177,8 +158,7 @@ export function ConversationListApp() {
177158 tweet_id : tweetId ,
178159 reply_count : replyCount ,
179160 } ) ;
180- setConversations ( ( prev ) => prev . filter ( ( c ) => c . tweet_id !== tweetId ) ) ;
181- setTotalCount ( ( prev ) => prev - 1 ) ;
161+ setAllConversations ( ( prev ) => prev . filter ( ( c ) => c . tweet_id !== tweetId ) ) ;
182162 } catch ( error ) {
183163 console . error ( "Failed to dismiss:" , error ) ;
184164 }
@@ -207,7 +187,7 @@ export function ConversationListApp() {
207187 setAppState ( "loading" ) ;
208188 setErrorMessage ( null ) ;
209189 hasFetchedInitial . current = false ;
210- fetchConversations ( false ) ;
190+ fetchConversations ( ) ;
211191 } ;
212192
213193 // Use StateContainer for loading, auth, and error states
@@ -226,9 +206,11 @@ export function ConversationListApp() {
226206 ) ;
227207 }
228208
229- // Render conversations
230- const displayedCount = conversations . length ;
231- const remaining = totalCount - displayedCount ;
209+ // Client-side pagination - slice all conversations to display count
210+ const visibleConversations = allConversations . slice ( 0 , displayCount ) ;
211+ const totalCount = allConversations . length ;
212+ const hasMore = displayCount < totalCount ;
213+ const remaining = totalCount - visibleConversations . length ;
232214
233215 return (
234216 < div className = "loaded container" >
@@ -239,20 +221,20 @@ export function ConversationListApp() {
239221 < h2 className = "heading-flush" > Conversations</ h2 >
240222 < p className = "text-muted" style = { { fontSize : "var(--font-size-sm)" } } >
241223 @{ username } ·{ " " }
242- { displayedCount === 0 ? "All caught up!" : `${ totalCount } total` }
224+ { totalCount === 0 ? "All caught up!" : `${ totalCount } total` }
243225 </ p >
244226 </ div >
245227
246228 < div className = "p-16" >
247- { displayedCount === 0 ? (
229+ { totalCount === 0 ? (
248230 < div className = "empty-state" >
249231 < div className = "icon" > ✨</ div >
250232 < h3 > All caught up!</ h3 >
251233 < p > No conversations need your attention right now.</ p >
252234 </ div >
253235 ) : (
254236 < >
255- { conversations . map ( ( conv ) => (
237+ { visibleConversations . map ( ( conv ) => (
256238 < ConversationCard
257239 conversation = { conv }
258240 key = { conv . tweet_id }
@@ -265,11 +247,7 @@ export function ConversationListApp() {
265247
266248 { hasMore && (
267249 < div className = "mt-4 text-center" >
268- < Button
269- loading = { isLoadingMore }
270- onClick = { handleLoadMore }
271- variant = "secondary"
272- >
250+ < Button onClick = { handleLoadMore } variant = "secondary" >
273251 Load more ({ remaining } remaining)
274252 </ Button >
275253 </ div >
0 commit comments