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>
This commit is contained in:
160
frontend/src/layouts/MainLayout.tsx
Normal file
160
frontend/src/layouts/MainLayout.tsx
Normal file
@@ -0,0 +1,160 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user