summaryrefslogtreecommitdiff
path: root/packages/tweetdeck/src/App.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/tweetdeck/src/App.tsx')
-rw-r--r--packages/tweetdeck/src/App.tsx311
1 files changed, 8 insertions, 303 deletions
diff --git a/packages/tweetdeck/src/App.tsx b/packages/tweetdeck/src/App.tsx
index 924ff9a..44b6405 100644
--- a/packages/tweetdeck/src/App.tsx
+++ b/packages/tweetdeck/src/App.tsx
@@ -1,310 +1,15 @@
-import { useCallback, useEffect, useMemo, useState } from "react";
-import "./styles/normalize.css";
import "./styles/index.css";
-import { Sidebar, type NewAccountInput } from "./components/Sidebar";
-import { ColumnBoard } from "./components/ColumnBoard";
-import { AddColumnModal } from "./components/AddColumnModal";
-import { usePersistentState } from "./hooks/usePersistentState";
-import type {
- ColumnSnapshot,
- ColumnState,
- DeckAccount,
- DeckColumn,
- DeckListsCache,
- FullscreenState,
-} from "./types/app";
-import type { Tweet } from "./lib/fetching/types";
-import { generateId } from "./lib/utils/id";
-import { twitterClient } from "./lib/client/twitterClient";
-import { FullscreenColumn } from "./components/FullscreenColumn";
-
-const ACCOUNTS_KEY = "tweetdeck.accounts";
-const COLUMNS_KEY = "tweetdeck.columns";
+import "./styles/normalize.css";
+import { Toaster } from "react-hot-toast";
+import Deck from "./pages/Deck";
+import Test from "./Test";
export function App() {
- const [accounts, setAccounts] = usePersistentState<DeckAccount[]>(
- ACCOUNTS_KEY,
- [],
- );
- const [columns, setColumns] = usePersistentState<DeckColumn[]>(
- COLUMNS_KEY,
- [],
- );
- const [listsCache, setListsCache] = useState<DeckListsCache>({});
- const [activeAccountId, setActiveAccountId] = useState<string | undefined>(
- () => accounts[0]?.id,
- );
- const [isModalOpen, setModalOpen] = useState(false);
- const [toast, setToast] = useState<string | null>(null);
- const [fullscreen, setFullscreen] = useState<FullscreenState | null>(null);
- const [columnSnapshots, setColumnSnapshots] = useState<
- Record<string, ColumnSnapshot>
- >({});
-
- useEffect(() => {
- if (!activeAccountId) {
- const firstAccount = accounts[0];
- if (firstAccount) {
- setActiveAccountId(firstAccount.id);
- }
- }
- }, [accounts, activeAccountId]);
-
- useEffect(() => {
- const acs = accounts.filter((a) => !a.avatar || !a.username);
- console.log({ acs });
- const nacs = acs.map(async (acc) => {
- const our = await twitterClient.own({ cookie: acc.cookie });
- const nacc = {
- ...acc,
- handle: our.username,
- label: our.name,
- avatar: our.avatar,
- };
- return nacc;
- });
- Promise.all(nacs)
- .then((acs) => setAccounts(acs))
- .catch((err) => console.error(err));
- }, []);
-
- const handleAddAccount = useCallback(
- (payload: NewAccountInput) => {
- const label = `Session ${accounts.length + 1}`;
- const account: DeckAccount = {
- id: generateId(),
- label,
- accent: randomAccent(),
- cookie: payload.cookie.trim(),
- createdAt: Date.now(),
- };
- setAccounts((prev) => [...prev, account]);
- setActiveAccountId(account.id);
- setToast(`${account.label} is ready`);
- },
- [accounts.length, setAccounts],
- );
-
- const handleRemoveAccount = useCallback(
- (accountId: string) => {
- setAccounts((prev) => prev.filter((account) => account.id !== accountId));
- setColumns((prev) =>
- prev.filter((column) => column.accountId !== accountId),
- );
- setListsCache((prev) => {
- const next = { ...prev };
- delete next[accountId];
- return next;
- });
- if (activeAccountId === accountId) {
- setActiveAccountId(undefined);
- }
- },
- [activeAccountId, setAccounts, setColumns],
- );
-
- const handleAddColumn = useCallback(
- (column: Omit<DeckColumn, "id">) => {
- const nextColumn = { ...column, id: generateId() };
- setColumns((prev) => [...prev, nextColumn]);
- setToast(`${nextColumn.title} added to deck`);
- },
- [setColumns],
- );
-
- const handleRemoveColumn = useCallback(
- (id: string) => {
- setColumns((prev) => prev.filter((column) => column.id !== id));
- },
- [setColumns],
- );
-
- const fetchLists = useCallback(
- async (accountId: string) => {
- const account = accounts.find((acc) => acc.id === accountId);
- if (!account) throw new Error("Account not found");
- if (listsCache[accountId]) return listsCache[accountId];
- console.log({ listsCache });
- const lists = await twitterClient.lists({ cookie: account.cookie });
- console.log({ lists });
- setListsCache((prev) => ({ ...prev, [accountId]: lists }));
- return lists;
- },
- [accounts, listsCache],
- );
-
- const handleColumnStateChange = useCallback(
- (columnId: string, state: ColumnState) => {
- setColumns((prev) =>
- prev.map((column) =>
- column.id === columnId ? { ...column, state } : column,
- ),
- );
- },
- [setColumns],
- );
-
- const handleColumnSnapshot = useCallback(
- (columnId: string, snapshot: ColumnSnapshot) => {
- setColumnSnapshots((prev) => {
- const existing = prev[columnId];
- if (
- existing &&
- existing.tweets === snapshot.tweets &&
- existing.label === snapshot.label
- ) {
- return prev;
- }
- return {
- ...prev,
- [columnId]: { tweets: snapshot.tweets, label: snapshot.label },
- };
- });
- },
- [],
- );
-
- const openFullscreen = useCallback(
- (payload: FullscreenState) => {
- const snapshot = columnSnapshots[payload.column.id];
- setFullscreen({
- ...payload,
- tweets: snapshot?.tweets ?? payload.tweets,
- columnLabel: snapshot?.label ?? payload.columnLabel,
- });
- },
- [columnSnapshots],
- );
-
- useEffect(() => {
- if (!fullscreen) return;
- const snapshot = columnSnapshots[fullscreen.column.id];
- if (!snapshot) return;
- if (
- snapshot.tweets === fullscreen.tweets &&
- snapshot.label === fullscreen.columnLabel
- ) {
- return;
- }
- setFullscreen((prev) => {
- if (!prev) return prev;
- if (prev.column.id !== fullscreen.column.id) return prev;
- const tweets = snapshot.tweets;
- const index = Math.min(prev.index, Math.max(tweets.length - 1, 0));
- return {
- ...prev,
- tweets,
- columnTitle: snapshot.label,
- index,
- };
- });
- }, [columnSnapshots, fullscreen]);
-
- const content = useMemo(
- () => (
- <ColumnBoard
- columns={columns}
- accounts={accounts}
- onRemove={handleRemoveColumn}
- onStateChange={handleColumnStateChange}
- onSnapshot={handleColumnSnapshot}
- onEnterFullscreen={openFullscreen}
- />
- ),
- [
- accounts,
- columns,
- handleRemoveColumn,
- handleColumnStateChange,
- handleColumnSnapshot,
- openFullscreen,
- ],
- );
-
return (
- <div className="app-shell">
- <Sidebar
- accounts={accounts}
- activeAccountId={activeAccountId}
- onActivate={(id) => setActiveAccountId(id)}
- onAddAccount={handleAddAccount}
- onRemoveAccount={handleRemoveAccount}
- onAddColumn={() => setModalOpen(true)}
- />
-
- <main>{content}</main>
-
- <AddColumnModal
- accounts={accounts}
- activeAccountId={activeAccountId}
- isOpen={isModalOpen}
- onClose={() => setModalOpen(false)}
- onAdd={handleAddColumn}
- fetchLists={fetchLists}
- listsCache={listsCache}
- />
-
- {toast && (
- <div className="toast" onAnimationEnd={() => setToast(null)}>
- {toast}
- </div>
- )}
-
- {fullscreen && (
- <FullscreenColumn
- state={fullscreen}
- onExit={() => setFullscreen(null)}
- onNavigate={(step) => {
- setFullscreen((prev) => {
- if (!prev) return prev;
- if (!prev.tweets.length) return prev;
- const nextIndex = Math.min(
- prev.tweets.length - 1,
- Math.max(0, prev.index + step),
- );
- if (nextIndex === prev.index) return prev;
- return { ...prev, index: nextIndex };
- });
- }}
- hasPrevColumn={fullscreen.columnIndex > 0}
- hasNextColumn={fullscreen.columnIndex < columns.length - 1}
- onSwitchColumn={(direction) => {
- setFullscreen((prev) => {
- if (!prev) return prev;
- const nextIndex = prev.columnIndex + direction;
- if (nextIndex < 0) return prev;
- if (nextIndex >= columns.length) {
- setModalOpen(true);
- return prev;
- }
- const nextColumn = columns[nextIndex];
- if (!nextColumn) return prev;
- const snapshot = columnSnapshots[nextColumn.id];
- const account = accounts.find(
- (acc) => acc.id === nextColumn.accountId,
- );
- const tweets = snapshot?.tweets ?? [];
- return {
- column: nextColumn,
- columnIndex: nextIndex,
- columnLabel: snapshot?.label ?? nextColumn.title,
- accent: account?.accent ?? prev.accent,
- tweets,
- index: 0,
- };
- });
- }}
- onAddColumn={() => setModalOpen(true)}
- />
- )}
- </div>
+ <>
+ <Test />
+ <Toaster position="top-center" />
+ </>
);
}
-
-function randomAccent(): string {
- const palette = ["#7f5af0", "#2cb67d", "#f25f4c", "#f0a500", "#19a7ce"];
- const pick = palette[Math.floor(Math.random() * palette.length)];
- return pick ?? "#7f5af0";
-}
-
export default App;