summaryrefslogtreecommitdiff
path: root/packages/tweetdeck/src/components/ChatColumn.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tweetdeck/src/components/ChatColumn.tsx')
-rw-r--r--packages/tweetdeck/src/components/ChatColumn.tsx62
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>
+ );
+}