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>
161 lines
4.0 KiB
TypeScript
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>
|
|
);
|
|
}
|