Initial commit: Horux Strategy Platform
- Laravel 11 backend with API REST - React 18 + TypeScript + Vite frontend - Multi-parser architecture for accounting systems (CONTPAQi, Aspel, SAP) - 27+ financial metrics calculation - PDF report generation with Browsershot - Complete documentation (10 documents) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
271
docs/05-frontend.md
Normal file
271
docs/05-frontend.md
Normal file
@@ -0,0 +1,271 @@
|
||||
# 5. Guía del Frontend
|
||||
|
||||
## Stack Tecnológico
|
||||
|
||||
- **React 18** - Biblioteca de UI
|
||||
- **TypeScript** - Tipado estático
|
||||
- **Vite** - Build tool y dev server
|
||||
- **React Router** - Navegación
|
||||
- **Axios** - Cliente HTTP
|
||||
- **Recharts** - Gráficas
|
||||
- **Tailwind CSS** - Estilos
|
||||
- **react-hot-toast** - Notificaciones
|
||||
- **react-dropzone** - Upload de archivos
|
||||
|
||||
---
|
||||
|
||||
## Estructura de Carpetas
|
||||
|
||||
```
|
||||
frontend/src/
|
||||
├── components/
|
||||
│ ├── charts/ # Componentes de gráficas
|
||||
│ │ ├── BarChart.tsx
|
||||
│ │ └── LineChart.tsx
|
||||
│ ├── cards/ # Tarjetas y tablas
|
||||
│ │ ├── KPICard.tsx
|
||||
│ │ └── MetricTable.tsx
|
||||
│ ├── forms/ # Formularios
|
||||
│ │ ├── ClienteForm.tsx
|
||||
│ │ ├── UploadBalanza.tsx
|
||||
│ │ └── GenerarReporte.tsx
|
||||
│ └── layout/ # Estructura de página
|
||||
│ ├── Layout.tsx
|
||||
│ ├── Sidebar.tsx
|
||||
│ └── Header.tsx
|
||||
├── pages/
|
||||
│ ├── Login.tsx
|
||||
│ ├── Clientes/
|
||||
│ │ ├── ClientesList.tsx
|
||||
│ │ └── ClienteDetail.tsx
|
||||
│ ├── Dashboard/
|
||||
│ │ └── index.tsx
|
||||
│ ├── PdfView/
|
||||
│ │ └── index.tsx
|
||||
│ └── Admin/
|
||||
│ ├── Usuarios.tsx
|
||||
│ ├── Giros.tsx
|
||||
│ ├── Umbrales.tsx
|
||||
│ └── ReglasMapeeo.tsx
|
||||
├── context/
|
||||
│ └── AuthContext.tsx
|
||||
├── services/
|
||||
│ └── api.ts
|
||||
├── types/
|
||||
│ └── index.ts
|
||||
└── hooks/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contexto de Autenticación
|
||||
|
||||
```tsx
|
||||
// Uso del contexto
|
||||
import { useAuth } from '../context/AuthContext';
|
||||
|
||||
function MyComponent() {
|
||||
const { user, login, logout, isAdmin, isAnalista } = useAuth();
|
||||
|
||||
if (!user) return <Navigate to="/login" />;
|
||||
|
||||
return <div>Hola {user.nombre}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
### Propiedades disponibles:
|
||||
- `user` - Usuario actual o null
|
||||
- `loading` - Estado de carga inicial
|
||||
- `login(email, password)` - Iniciar sesión
|
||||
- `logout()` - Cerrar sesión
|
||||
- `isAdmin` - Es administrador
|
||||
- `isAnalista` - Es analista
|
||||
- `isCliente` - Es cliente
|
||||
- `isEmpleado` - Es empleado
|
||||
|
||||
---
|
||||
|
||||
## Servicio API
|
||||
|
||||
```tsx
|
||||
import { clientesApi, balanzasApi, reportesApi } from '../services/api';
|
||||
|
||||
// Listar clientes
|
||||
const clientes = await clientesApi.list();
|
||||
|
||||
// Crear cliente
|
||||
const formData = new FormData();
|
||||
formData.append('nombre_empresa', 'Mi Empresa');
|
||||
formData.append('giro_id', '1');
|
||||
const cliente = await clientesApi.create(formData);
|
||||
|
||||
// Subir balanza
|
||||
const balanza = await balanzasApi.upload(clienteId, formData);
|
||||
|
||||
// Generar reporte
|
||||
const reporte = await reportesApi.create(clienteId, 'Reporte 2024', [1, 2]);
|
||||
|
||||
// Descargar PDF
|
||||
const blob = await reportesApi.downloadPdf(reporteId);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tipos TypeScript
|
||||
|
||||
```tsx
|
||||
// Principales tipos disponibles
|
||||
interface User {
|
||||
id: number;
|
||||
nombre: string;
|
||||
email: string;
|
||||
role: 'admin' | 'analista' | 'cliente' | 'empleado';
|
||||
cliente_id: number | null;
|
||||
}
|
||||
|
||||
interface Cliente {
|
||||
id: number;
|
||||
nombre_empresa: string;
|
||||
logo: string | null;
|
||||
giro_id: number;
|
||||
moneda: string;
|
||||
giro?: Giro;
|
||||
}
|
||||
|
||||
interface Balanza {
|
||||
id: number;
|
||||
cliente_id: number;
|
||||
periodo_inicio: string;
|
||||
periodo_fin: string;
|
||||
sistema_origen: string;
|
||||
status: 'pendiente' | 'procesando' | 'completado' | 'error';
|
||||
}
|
||||
|
||||
interface Reporte {
|
||||
id: number;
|
||||
nombre: string;
|
||||
periodo_tipo: 'mensual' | 'trimestral' | 'anual';
|
||||
data_calculada: DataCalculada | null;
|
||||
status: string;
|
||||
}
|
||||
|
||||
type Tendencia = 'muy_positivo' | 'positivo' | 'neutral' | 'negativo' | 'muy_negativo';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Componentes Reutilizables
|
||||
|
||||
### KPICard
|
||||
```tsx
|
||||
<KPICard
|
||||
title="Ingresos"
|
||||
value="$1,500,000"
|
||||
subtitle="12% vs mes anterior"
|
||||
tendencia="positivo"
|
||||
/>
|
||||
```
|
||||
|
||||
### MetricTable
|
||||
```tsx
|
||||
<MetricTable
|
||||
title="Márgenes"
|
||||
metricas={[
|
||||
{ nombre: 'Margen Bruto', valor: 0.45, tendencia: 'positivo' },
|
||||
{ nombre: 'Margen Neto', valor: 0.12, tendencia: 'neutral' },
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
### BarChart
|
||||
```tsx
|
||||
<BarChartComponent
|
||||
data={[
|
||||
{ name: 'Ingresos', valor: 1500000 },
|
||||
{ name: 'Gastos', valor: -800000 },
|
||||
]}
|
||||
horizontal={false}
|
||||
/>
|
||||
```
|
||||
|
||||
### LineChart
|
||||
```tsx
|
||||
<LineChartComponent
|
||||
data={periodos.map(p => ({
|
||||
periodo: p.periodo,
|
||||
'Margen Bruto': p.margen_bruto * 100,
|
||||
'Margen Neto': p.margen_neto * 100,
|
||||
}))}
|
||||
lines={['Margen Bruto', 'Margen Neto']}
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Estilos con Tailwind
|
||||
|
||||
### Clases personalizadas (index.css)
|
||||
```css
|
||||
.btn { @apply px-4 py-2 rounded-lg font-medium transition-colors; }
|
||||
.btn-primary { @apply bg-primary-600 text-white hover:bg-primary-700; }
|
||||
.btn-secondary { @apply bg-gray-200 text-gray-800 hover:bg-gray-300; }
|
||||
.input { @apply w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-primary-500; }
|
||||
.card { @apply bg-white rounded-xl shadow-sm border border-gray-100 p-6; }
|
||||
.label { @apply block text-sm font-medium text-gray-700 mb-1; }
|
||||
```
|
||||
|
||||
### Colores de marca (tailwind.config.js)
|
||||
```js
|
||||
colors: {
|
||||
horux: {
|
||||
dark: '#1a1a2e',
|
||||
primary: '#16213e',
|
||||
accent: '#0f3460',
|
||||
highlight: '#e94560',
|
||||
},
|
||||
status: {
|
||||
'muy-positivo': '#10b981',
|
||||
'positivo': '#34d399',
|
||||
'neutral': '#fbbf24',
|
||||
'negativo': '#f97316',
|
||||
'muy-negativo': '#ef4444',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rutas
|
||||
|
||||
| Ruta | Componente | Rol requerido |
|
||||
|------|------------|---------------|
|
||||
| `/login` | Login | Público |
|
||||
| `/clientes` | ClientesList | Autenticado |
|
||||
| `/clientes/:id` | ClienteDetail | Autenticado |
|
||||
| `/dashboard/:clienteId/:reporteId` | Dashboard | Autenticado |
|
||||
| `/pdf-view/:id` | PdfView | Token especial |
|
||||
| `/admin/usuarios` | AdminUsuarios | Admin |
|
||||
| `/admin/giros` | AdminGiros | Admin |
|
||||
| `/admin/umbrales` | AdminUmbrales | Admin |
|
||||
| `/admin/reglas-mapeo` | AdminReglasMapeeo | Admin |
|
||||
|
||||
---
|
||||
|
||||
## Desarrollo
|
||||
|
||||
```bash
|
||||
# Instalar dependencias
|
||||
npm install
|
||||
|
||||
# Servidor de desarrollo
|
||||
npm run dev
|
||||
|
||||
# Build para producción
|
||||
npm run build
|
||||
|
||||
# Preview del build
|
||||
npm run preview
|
||||
|
||||
# Linting
|
||||
npm run lint
|
||||
```
|
||||
Reference in New Issue
Block a user