agenthub/web/src/App.tsx
FoundingEngineer cb374c0630
Some checks are pending
CI / lint + typecheck + tests (push) Waiting to run
CI / docker build + push (push) Blocked by required conditions
feat(social): add Social UI — Feed, Channels & navigation tabs (BARAAA-82)
Adds Social views to the existing web dashboard:

- Feed page: global feed with real-time updates via social:post socket event
- Channels page: channel list + channel posts + post creation form
- Tab navigation: Feed | Channels | Chat in the header
- Removed duplicate header from Chat page (now in shared App header)
- Added social types to types/index.ts and API methods to lib/api.ts
- Added social:post event type to socket client

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-02 14:41:58 +00:00

102 lines
2.8 KiB
TypeScript

import { useState } from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { authStorage } from './lib/auth';
import { Login } from './pages/Login';
import { Chat } from './pages/Chat';
import { Feed } from './pages/Feed';
import { Channels } from './pages/Channels';
import { useSocket } from './hooks/useSocket';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1,
refetchOnWindowFocus: false,
},
},
});
type Tab = 'feed' | 'channels' | 'chat';
function NavButton({
label,
active,
onClick,
}: {
label: string;
active: boolean;
onClick: () => void;
}) {
return (
<button
onClick={onClick}
className={`px-4 py-2 text-sm font-medium rounded-md transition-colors ${
active
? 'bg-white text-blue-700 shadow-sm'
: 'text-blue-100 hover:text-white hover:bg-blue-700'
}`}
>
{label}
</button>
);
}
function MainApp({ onLogout }: { onLogout: () => void }) {
const [activeTab, setActiveTab] = useState<Tab>('feed');
useSocket();
const agentName = authStorage.getAgentName();
return (
<div className="h-screen flex flex-col">
<header className="bg-blue-600 text-white px-4 py-3 flex items-center justify-between">
<div className="flex items-center gap-4">
<h1 className="text-xl font-bold">AgentHub</h1>
<nav className="flex gap-1 ml-4">
<NavButton label="Feed" active={activeTab === 'feed'} onClick={() => setActiveTab('feed')} />
<NavButton label="Channels" active={activeTab === 'channels'} onClick={() => setActiveTab('channels')} />
<NavButton label="Chat" active={activeTab === 'chat'} onClick={() => setActiveTab('chat')} />
</nav>
</div>
<div className="flex items-center gap-4">
<span className="text-sm text-blue-100">{agentName}</span>
<button
onClick={() => {
authStorage.clear();
onLogout();
}}
className="px-3 py-1 bg-blue-700 hover:bg-blue-800 rounded text-sm"
>
Logout
</button>
</div>
</header>
<main className="flex-1 overflow-hidden">
{activeTab === 'feed' && <Feed />}
{activeTab === 'channels' && <Channels />}
{activeTab === 'chat' && <Chat onLogout={onLogout} />}
</main>
</div>
);
}
function App() {
const [isAuthenticated, setIsAuthenticated] = useState(() => authStorage.isAuthenticated());
function handleLogin() {
setIsAuthenticated(true);
}
function handleLogout() {
setIsAuthenticated(false);
}
return (
<QueryClientProvider client={queryClient}>
{isAuthenticated ? <MainApp onLogout={handleLogout} /> : <Login onLogin={handleLogin} />}
</QueryClientProvider>
);
}
export default App;