Files
WhatsAppCentralizado/frontend/src/layouts/MainLayout.tsx
Claude AI dcb7fb5974 feat: add Layer 3 - API Gateway main app, WhatsApp routes, Frontend pages
API Gateway:
- main.py with FastAPI app, CORS, health endpoints
- WhatsApp routes: accounts CRUD, conversations, messages, internal events
- WhatsApp schemas for request/response validation

Frontend:
- Login page with register option for first admin
- MainLayout with sidebar navigation and user dropdown
- Dashboard with statistics cards (accounts, conversations)
- WhatsApp Accounts page with QR modal for connection
- Inbox page with conversation list and real-time chat

Full feature set for Fase 1 Foundation complete.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 10:01:06 +00:00

161 lines
4.0 KiB
TypeScript

import { useState } from 'react';
import { Routes, Route, useNavigate, useLocation } from 'react-router-dom';
import { Layout, Menu, Button, Avatar, Dropdown, Typography } from 'antd';
import {
DashboardOutlined,
MessageOutlined,
WhatsAppOutlined,
SettingOutlined,
LogoutOutlined,
UserOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons';
import { useAuthStore } from '../store/auth';
import Dashboard from '../pages/Dashboard';
import WhatsAppAccounts from '../pages/WhatsAppAccounts';
import Inbox from '../pages/Inbox';
const { Header, Sider, Content } = Layout;
const { Text } = Typography;
export default function MainLayout() {
const [collapsed, setCollapsed] = useState(false);
const navigate = useNavigate();
const location = useLocation();
const { user, logout } = useAuthStore();
const handleLogout = () => {
logout();
navigate('/login');
};
const menuItems = [
{
key: '/',
icon: <DashboardOutlined />,
label: 'Dashboard',
},
{
key: '/inbox',
icon: <MessageOutlined />,
label: 'Inbox',
},
{
key: '/whatsapp',
icon: <WhatsAppOutlined />,
label: 'WhatsApp',
},
{
key: '/settings',
icon: <SettingOutlined />,
label: 'Configuración',
},
];
const userMenu = [
{
key: 'profile',
icon: <UserOutlined />,
label: 'Mi perfil',
},
{
type: 'divider' as const,
},
{
key: 'logout',
icon: <LogoutOutlined />,
label: 'Cerrar sesión',
onClick: handleLogout,
},
];
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider
trigger={null}
collapsible
collapsed={collapsed}
style={{
background: '#fff',
borderRight: '1px solid #f0f0f0',
}}
>
<div
style={{
height: 64,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
borderBottom: '1px solid #f0f0f0',
}}
>
<WhatsAppOutlined
style={{
fontSize: collapsed ? 24 : 32,
color: '#25D366',
}}
/>
{!collapsed && (
<Text strong style={{ marginLeft: 8, fontSize: 16 }}>
WA Central
</Text>
)}
</div>
<Menu
mode="inline"
selectedKeys={[location.pathname]}
items={menuItems}
onClick={({ key }) => navigate(key)}
style={{ border: 'none' }}
/>
</Sider>
<Layout>
<Header
style={{
padding: '0 24px',
background: '#fff',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
borderBottom: '1px solid #f0f0f0',
}}
>
<Button
type="text"
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
onClick={() => setCollapsed(!collapsed)}
/>
<Dropdown menu={{ items: userMenu }} placement="bottomRight">
<div style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}>
<Avatar style={{ backgroundColor: '#25D366' }}>
{user?.name?.charAt(0).toUpperCase()}
</Avatar>
<Text style={{ marginLeft: 8 }}>{user?.name}</Text>
</div>
</Dropdown>
</Header>
<Content
style={{
margin: 24,
padding: 24,
background: '#fff',
borderRadius: 8,
minHeight: 280,
}}
>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/inbox" element={<Inbox />} />
<Route path="/whatsapp" element={<WhatsAppAccounts />} />
<Route path="/settings" element={<div>Configuración (próximamente)</div>} />
</Routes>
</Content>
</Layout>
</Layout>
);
}