diff options
Diffstat (limited to 'packages/tweetdeck/src/components/ChatColumn.tsx')
| -rw-r--r-- | packages/tweetdeck/src/components/ChatColumn.tsx | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/packages/tweetdeck/src/components/ChatColumn.tsx b/packages/tweetdeck/src/components/ChatColumn.tsx new file mode 100644 index 0000000..0c336e5 --- /dev/null +++ b/packages/tweetdeck/src/components/ChatColumn.tsx @@ -0,0 +1,62 @@ +import { useCallback, useEffect, useState } from "react"; +import type { DeckAccount, DeckColumn, ChatState } from "../types/app"; +import { twitterClient } from "../lib/client/twitterClient"; +import { ChatCard } from "./ChatCard"; + +interface ChatColumnProps { + column: DeckColumn & { kind: "chat" }; + account: DeckAccount; + onRemove: () => void; +} + +export function ChatColumn({ column, account, onRemove }: ChatColumnProps) { + const [state, setState] = useState<ChatState>({ entries: [], isLoading: false }); + const [error, setError] = useState<string | undefined>(); + + const refresh = useCallback(async () => { + setState(prev => ({ ...prev, isLoading: true })); + setError(undefined); + try { + const notifications = await twitterClient.notifications({ cookie: account.cookie }); + setState({ entries: notifications, isLoading: false }); + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to refresh chat"); + setState(prev => ({ ...prev, isLoading: false })); + } + }, [account.cookie]); + + useEffect(() => { + refresh(); + }, [refresh, account.id]); + + return ( + <article className="column"> + <header> + <div> + <p className="eyebrow">Signal</p> + <h3>{column.title || "Chat"}</h3> + <p className="muted tiny">Mentions, follows and notifications for {account.label}</p> + </div> + <div className="column-actions"> + <button className="ghost" onClick={refresh} aria-label="Refresh chat"> + ↻ + </button> + <button className="ghost" onClick={onRemove} aria-label="Remove column"> + × + </button> + </div> + </header> + {error && <p className="error">{error}</p>} + {state.isLoading && !state.entries.length ? ( + <div className="column-loading">Loading…</div> + ) : ( + <div className="chat-stack"> + {state.entries.map(entry => ( + <ChatCard key={entry.id} notification={entry} accent={account.accent} /> + ))} + {!state.entries.length && <p className="muted">No recent notifications.</p>} + </div> + )} + </article> + ); +} |
