Agregar documentacion completa del proyecto
- README.md actualizado con descripcion detallada del sistema - DOCUMENTATION.md con documentacion tecnica exhaustiva Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
611
DOCUMENTATION.md
Normal file
611
DOCUMENTATION.md
Normal file
@@ -0,0 +1,611 @@
|
|||||||
|
# Documentacion Tecnica - Water Project GRH
|
||||||
|
|
||||||
|
Documentacion tecnica detallada del Sistema de Gestion de Recursos Hidricos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tabla de Contenidos
|
||||||
|
|
||||||
|
1. [Arquitectura del Sistema](#arquitectura-del-sistema)
|
||||||
|
2. [Componentes Principales](#componentes-principales)
|
||||||
|
3. [Capa de API](#capa-de-api)
|
||||||
|
4. [Hooks Personalizados](#hooks-personalizados)
|
||||||
|
5. [Sistema de Autenticacion](#sistema-de-autenticacion)
|
||||||
|
6. [Gestion de Estado](#gestion-de-estado)
|
||||||
|
7. [Sistema de Temas](#sistema-de-temas)
|
||||||
|
8. [Guia de Desarrollo](#guia-de-desarrollo)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Arquitectura del Sistema
|
||||||
|
|
||||||
|
### Vision General
|
||||||
|
|
||||||
|
El proyecto sigue una arquitectura **frontend SPA (Single Page Application)** con las siguientes capas:
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────┐
|
||||||
|
│ Capa de Presentacion │
|
||||||
|
│ (React Components, Pages, Layout) │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Capa de Logica │
|
||||||
|
│ (Custom Hooks, State Management) │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ Capa de Datos │
|
||||||
|
│ (API Services, localStorage) │
|
||||||
|
├─────────────────────────────────────────────────────────┤
|
||||||
|
│ API Externa │
|
||||||
|
│ (REST API Backend) │
|
||||||
|
└─────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Patron de Diseno
|
||||||
|
|
||||||
|
El proyecto utiliza varios patrones de diseno:
|
||||||
|
|
||||||
|
1. **Container/Presentational Pattern**: Separacion entre componentes con logica (pages) y componentes de UI puros (components)
|
||||||
|
2. **Custom Hooks Pattern**: Encapsulacion de logica reutilizable en hooks (`useMeters`, `useConcentrators`)
|
||||||
|
3. **Module Pattern**: Organizacion de codigo relacionado en modulos (meters/, concentrators/)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Componentes Principales
|
||||||
|
|
||||||
|
### App.tsx - Componente Raiz
|
||||||
|
|
||||||
|
El componente raiz maneja:
|
||||||
|
- Autenticacion global
|
||||||
|
- Routing interno (sin react-router)
|
||||||
|
- Estado de pagina actual
|
||||||
|
- Modales globales (perfil, configuracion, logout)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Estados principales
|
||||||
|
const [isAuth, setIsAuth] = useState<boolean>(() => {
|
||||||
|
return Boolean(localStorage.getItem(AUTH_KEY));
|
||||||
|
});
|
||||||
|
const [currentPage, setCurrentPage] = useState("home");
|
||||||
|
const [currentSubpage, setCurrentSubpage] = useState<string | null>(null);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Sidebar.tsx - Menu Lateral
|
||||||
|
|
||||||
|
Caracteristicas:
|
||||||
|
- Estados: colapsado/expandido
|
||||||
|
- Hover expansion con delay
|
||||||
|
- Pin/unpin para mantener expandido
|
||||||
|
- Menu jerarquico con submenus
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface SidebarProps {
|
||||||
|
currentPage: string;
|
||||||
|
setCurrentPage: (page: string) => void;
|
||||||
|
currentSubpage: string | null;
|
||||||
|
setCurrentSubpage: (subpage: string | null) => void;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### TopMenu.tsx - Barra Superior
|
||||||
|
|
||||||
|
Funcionalidades:
|
||||||
|
- Breadcrumb de navegacion
|
||||||
|
- Notificaciones (placeholder)
|
||||||
|
- Menu de usuario con dropdown
|
||||||
|
- Acciones: perfil, configuracion, logout
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Capa de API
|
||||||
|
|
||||||
|
### Estructura de Archivos
|
||||||
|
|
||||||
|
```
|
||||||
|
src/api/
|
||||||
|
├── me.ts # Perfil de usuario
|
||||||
|
├── meters.ts # Operaciones CRUD de medidores
|
||||||
|
├── concentrators.ts # Operaciones CRUD de concentradores
|
||||||
|
└── projects.ts # Operaciones CRUD de proyectos
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuracion
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
const API_TOKEN = import.meta.env.VITE_API_TOKEN;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funciones de API - Medidores
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// meters.ts
|
||||||
|
|
||||||
|
// Obtener todos los medidores
|
||||||
|
export async function fetchMeters(): Promise<Meter[]>
|
||||||
|
|
||||||
|
// Crear medidor
|
||||||
|
export async function createMeter(meterData: Partial<Meter>): Promise<Meter>
|
||||||
|
|
||||||
|
// Actualizar medidor
|
||||||
|
export async function updateMeter(
|
||||||
|
id: string,
|
||||||
|
meterData: Partial<Meter>
|
||||||
|
): Promise<Meter>
|
||||||
|
|
||||||
|
// Eliminar medidor
|
||||||
|
export async function deleteMeter(id: string): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funciones de API - Concentradores
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// concentrators.ts
|
||||||
|
|
||||||
|
export async function fetchConcentrators(): Promise<Concentrator[]>
|
||||||
|
export async function createConcentrator(data: Partial<Concentrator>): Promise<Concentrator>
|
||||||
|
export async function updateConcentrator(id: string, data: Partial<Concentrator>): Promise<Concentrator>
|
||||||
|
export async function deleteConcentrator(id: string): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Funciones de API - Proyectos
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// projects.ts
|
||||||
|
|
||||||
|
export async function fetchProjects(): Promise<Project[]>
|
||||||
|
export async function fetchProjectNames(): Promise<string[]>
|
||||||
|
export async function createProject(data: Partial<Project>): Promise<Project>
|
||||||
|
export async function updateProject(id: string, data: Partial<Project>): Promise<Project>
|
||||||
|
export async function deleteProject(id: string): Promise<void>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manejo de Errores
|
||||||
|
|
||||||
|
Todas las funciones de API siguen el patron:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, options);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Error: ${response.status}`);
|
||||||
|
}
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("API Error:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Hooks Personalizados
|
||||||
|
|
||||||
|
### useMeters.ts
|
||||||
|
|
||||||
|
Hook para gestion completa del modulo de medidores.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface UseMetersReturn {
|
||||||
|
// Data
|
||||||
|
meters: Meter[];
|
||||||
|
filteredMeters: Meter[];
|
||||||
|
projectNames: string[];
|
||||||
|
|
||||||
|
// State
|
||||||
|
loading: boolean;
|
||||||
|
selectedMeter: Meter | null;
|
||||||
|
selectedProject: string | null;
|
||||||
|
searchTerm: string;
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
setSelectedMeter: (meter: Meter | null) => void;
|
||||||
|
setSelectedProject: (project: string | null) => void;
|
||||||
|
setSearchTerm: (term: string) => void;
|
||||||
|
refreshData: () => Promise<void>;
|
||||||
|
|
||||||
|
// CRUD
|
||||||
|
handleCreate: (data: Partial<Meter>) => Promise<void>;
|
||||||
|
handleUpdate: (id: string, data: Partial<Meter>) => Promise<void>;
|
||||||
|
handleDelete: (id: string) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMeters(): UseMetersReturn
|
||||||
|
```
|
||||||
|
|
||||||
|
### useConcentrators.ts
|
||||||
|
|
||||||
|
Hook similar para concentradores con estructura equivalente.
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface UseConcentratorsReturn {
|
||||||
|
concentrators: Concentrator[];
|
||||||
|
filteredConcentrators: Concentrator[];
|
||||||
|
projectNames: string[];
|
||||||
|
loading: boolean;
|
||||||
|
selectedConcentrator: Concentrator | null;
|
||||||
|
// ... similar a useMeters
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useConcentrators(): UseConcentratorsReturn
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sistema de Autenticacion
|
||||||
|
|
||||||
|
### Flujo de Autenticacion
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────┐ ┌─────────────┐ ┌──────────────┐
|
||||||
|
│ LoginPage │────>│ Validacion │────>│ localStorage│
|
||||||
|
└──────────────┘ └─────────────┘ └──────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ App.tsx │
|
||||||
|
│ (isAuth) │
|
||||||
|
└─────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### Almacenamiento de Token
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const AUTH_KEY = "grh_auth";
|
||||||
|
|
||||||
|
interface AuthData {
|
||||||
|
token: string;
|
||||||
|
ts: number; // timestamp de login
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guardar
|
||||||
|
localStorage.setItem(AUTH_KEY, JSON.stringify({ token: "demo", ts: Date.now() }));
|
||||||
|
|
||||||
|
// Verificar
|
||||||
|
const isAuth = Boolean(localStorage.getItem(AUTH_KEY));
|
||||||
|
|
||||||
|
// Eliminar (logout)
|
||||||
|
localStorage.removeItem(AUTH_KEY);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Proteccion de Rutas
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// App.tsx
|
||||||
|
if (!isAuth) {
|
||||||
|
return <LoginPage onSuccess={handleLogin} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si esta autenticado, renderiza la aplicacion
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen">
|
||||||
|
<Sidebar {...props} />
|
||||||
|
<main>{renderPage()}</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gestion de Estado
|
||||||
|
|
||||||
|
### Estado Local (useState)
|
||||||
|
|
||||||
|
La aplicacion utiliza principalmente `useState` de React para gestion de estado local:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Ejemplo en MeterPage.tsx
|
||||||
|
const [meters, setMeters] = useState<Meter[]>([]);
|
||||||
|
const [selectedMeter, setSelectedMeter] = useState<Meter | null>(null);
|
||||||
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [modalMode, setModalMode] = useState<"add" | "edit">("add");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Estado Persistente (localStorage)
|
||||||
|
|
||||||
|
Para datos que deben persistir entre sesiones:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Configuraciones de usuario
|
||||||
|
const SETTINGS_KEY = "water_project_settings_v1";
|
||||||
|
|
||||||
|
interface Settings {
|
||||||
|
theme: "system" | "light" | "dark";
|
||||||
|
compactMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guardar
|
||||||
|
localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
|
||||||
|
|
||||||
|
// Cargar
|
||||||
|
const settings = JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flujo de Datos en Modulos
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐
|
||||||
|
│ API Layer │
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Custom Hook │ (useMeters, useConcentrators)
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────┐
|
||||||
|
│ Page │ (MeterPage, ConcentratorsPage)
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
├────────────────┬────────────────┐
|
||||||
|
▼ ▼ ▼
|
||||||
|
┌───────────┐ ┌───────────┐ ┌───────────┐
|
||||||
|
│ Sidebar │ │ Table │ │ Modal │
|
||||||
|
└───────────┘ └───────────┘ └───────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sistema de Temas
|
||||||
|
|
||||||
|
### Configuracion de Tema
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type Theme = "system" | "light" | "dark";
|
||||||
|
|
||||||
|
const applyTheme = (theme: Theme) => {
|
||||||
|
if (theme === "system") {
|
||||||
|
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
|
document.documentElement.classList.toggle("dark", prefersDark);
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.toggle("dark", theme === "dark");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clases CSS con Tailwind
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Ejemplo de clases con soporte dark mode */
|
||||||
|
.card {
|
||||||
|
@apply bg-white dark:bg-gray-800;
|
||||||
|
@apply text-gray-900 dark:text-white;
|
||||||
|
@apply border-gray-200 dark:border-gray-700;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modal de Configuracion
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// SettingsModals.tsx
|
||||||
|
interface SettingsModalsProps {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opciones de tema
|
||||||
|
const themeOptions = [
|
||||||
|
{ value: "system", label: "Sistema" },
|
||||||
|
{ value: "light", label: "Claro" },
|
||||||
|
{ value: "dark", label: "Oscuro" },
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Guia de Desarrollo
|
||||||
|
|
||||||
|
### Agregar una Nueva Pagina
|
||||||
|
|
||||||
|
1. **Crear el archivo de pagina**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/pages/nueva/NuevaPage.tsx
|
||||||
|
export default function NuevaPage() {
|
||||||
|
return (
|
||||||
|
<div className="p-6">
|
||||||
|
<h1>Nueva Pagina</h1>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Agregar al Sidebar**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Sidebar.tsx - agregar al menuItems
|
||||||
|
{
|
||||||
|
label: "Nueva Pagina",
|
||||||
|
page: "nueva",
|
||||||
|
icon: <IconComponent className="w-5 h-5" />,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Agregar al renderizado en App.tsx**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// App.tsx - agregar case en renderPage()
|
||||||
|
case "nueva":
|
||||||
|
return <NuevaPage />;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Agregar un Nuevo Endpoint de API
|
||||||
|
|
||||||
|
1. **Crear archivo de API**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/api/nuevo.ts
|
||||||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
const API_TOKEN = import.meta.env.VITE_API_TOKEN;
|
||||||
|
|
||||||
|
export interface NuevoItem {
|
||||||
|
id: string;
|
||||||
|
// ... campos
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchNuevos(): Promise<NuevoItem[]> {
|
||||||
|
const response = await fetch(`${API_BASE_URL}/endpoint`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${API_TOKEN}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) throw new Error("Error fetching data");
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return data.records.map((r: any) => ({ id: r.id, ...r.fields }));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Crear hook personalizado (opcional)**
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/pages/nuevo/useNuevo.ts
|
||||||
|
export function useNuevo() {
|
||||||
|
const [items, setItems] = useState<NuevoItem[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchNuevos()
|
||||||
|
.then(setItems)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { items, loading };
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Agregar un Nuevo Componente Reutilizable
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/components/layout/common/NuevoComponente.tsx
|
||||||
|
interface NuevoComponenteProps {
|
||||||
|
title: string;
|
||||||
|
onAction: () => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function NuevoComponente({
|
||||||
|
title,
|
||||||
|
onAction,
|
||||||
|
children,
|
||||||
|
}: NuevoComponenteProps) {
|
||||||
|
return (
|
||||||
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-4">
|
||||||
|
<h3 className="text-lg font-semibold">{title}</h3>
|
||||||
|
{children}
|
||||||
|
<button onClick={onAction}>Accion</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convenios de Codigo
|
||||||
|
|
||||||
|
1. **Nombres de archivos**: PascalCase para componentes, camelCase para utilidades
|
||||||
|
2. **Interfaces**: Prefijo descriptivo (ej: `MeterFormData`, `UserSettings`)
|
||||||
|
3. **Hooks**: Prefijo `use` (ej: `useMeters`, `useAuth`)
|
||||||
|
4. **Constantes**: UPPER_SNAKE_CASE (ej: `API_BASE_URL`)
|
||||||
|
5. **CSS**: Utilizar Tailwind CSS, evitar CSS custom
|
||||||
|
|
||||||
|
### Testing (Pendiente de Implementacion)
|
||||||
|
|
||||||
|
El proyecto actualmente no tiene tests configurados. Para agregar:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install -D vitest @testing-library/react @testing-library/jest-dom
|
||||||
|
```
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// vitest.config.ts
|
||||||
|
import { defineConfig } from "vitest/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
environment: "jsdom",
|
||||||
|
globals: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables de Entorno
|
||||||
|
|
||||||
|
| Variable | Descripcion | Requerida |
|
||||||
|
|----------|-------------|-----------|
|
||||||
|
| `VITE_API_BASE_URL` | URL base de la API | Si |
|
||||||
|
| `VITE_API_TOKEN` | Token de autenticacion API | Si |
|
||||||
|
|
||||||
|
### Ejemplo .env
|
||||||
|
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=https://api.example.com
|
||||||
|
VITE_API_TOKEN=your-api-token-here
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencias Principales
|
||||||
|
|
||||||
|
| Paquete | Version | Uso |
|
||||||
|
|---------|---------|-----|
|
||||||
|
| react | 18.2.0 | Framework UI |
|
||||||
|
| react-dom | 18.2.0 | Renderizado DOM |
|
||||||
|
| typescript | 5.2.2 | Type safety |
|
||||||
|
| vite | 5.2.0 | Build tool |
|
||||||
|
| tailwindcss | 4.1.18 | Estilos |
|
||||||
|
| @mui/material | 7.3.6 | Componentes UI |
|
||||||
|
| @material-table/core | 6.5.2 | Tablas avanzadas |
|
||||||
|
| recharts | 3.6.0 | Graficas |
|
||||||
|
| lucide-react | 0.559.0 | Iconos |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comandos Utiles
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Desarrollo
|
||||||
|
npm run dev
|
||||||
|
|
||||||
|
# Build produccion
|
||||||
|
npm run build
|
||||||
|
|
||||||
|
# Preview del build
|
||||||
|
npm run preview
|
||||||
|
|
||||||
|
# Linting
|
||||||
|
npm run lint
|
||||||
|
|
||||||
|
# Type check
|
||||||
|
npx tsc --noEmit
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Error: CORS al conectar con API
|
||||||
|
|
||||||
|
Verificar que el backend tenga configurados los headers CORS correctos o usar un proxy en desarrollo.
|
||||||
|
|
||||||
|
### Error: Module not found
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf node_modules
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error: TypeScript type errors
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx tsc --noEmit
|
||||||
|
```
|
||||||
|
|
||||||
|
Revisar los errores y corregir los tipos.
|
||||||
|
|
||||||
|
### La aplicacion no carga
|
||||||
|
|
||||||
|
1. Verificar que las variables de entorno estan configuradas
|
||||||
|
2. Verificar la consola del navegador por errores
|
||||||
|
3. Verificar que la API esta accesible
|
||||||
385
README.md
385
README.md
@@ -1,30 +1,375 @@
|
|||||||
# React + TypeScript + Vite
|
# Water Project - Sistema de Gestion de Recursos Hidricos (GRH)
|
||||||
|
|
||||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
Sistema de gestion y monitoreo de infraestructura hidrica desarrollado con React, TypeScript y Vite.
|
||||||
|
|
||||||
Currently, two official plugins are available:
|
## Descripcion General
|
||||||
|
|
||||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
|
El **Sistema de Gestion de Recursos Hidricos (GRH)** es una aplicacion web frontend disenada para el monitoreo, administracion y control de infraestructura de toma de agua. Permite gestionar medidores, concentradores, proyectos, usuarios y roles a traves de una interfaz moderna y responsiva.
|
||||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
|
||||||
|
|
||||||
## Expanding the ESLint configuration
|
### Caracteristicas Principales
|
||||||
|
|
||||||
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
|
- **Dashboard interactivo** con KPIs, alertas e historial de actividades
|
||||||
|
- **Gestion de Medidores (Tomas de Agua)** - CRUD completo con filtros por proyecto
|
||||||
|
- **Gestion de Concentradores** - Configuracion de gateways LoRa/LoRaWAN
|
||||||
|
- **Gestion de Proyectos** - Administracion de proyectos de infraestructura
|
||||||
|
- **Gestion de Usuarios y Roles** - Control de acceso al sistema
|
||||||
|
- **Tema claro/oscuro** - Personalizacion de la interfaz
|
||||||
|
- **Diseno responsive** - Compatible con desktop, tablet y movil
|
||||||
|
|
||||||
- Configure the top-level `parserOptions` property like this:
|
---
|
||||||
|
|
||||||
```js
|
## Stack Tecnologico
|
||||||
export default {
|
|
||||||
// other rules...
|
### Frontend
|
||||||
parserOptions: {
|
| Tecnologia | Version | Proposito |
|
||||||
ecmaVersion: 'latest',
|
|------------|---------|-----------|
|
||||||
sourceType: 'module',
|
| React | 18.2.0 | Framework UI |
|
||||||
project: ['./tsconfig.json', './tsconfig.node.json'],
|
| TypeScript | 5.2.2 | Type safety |
|
||||||
tsconfigRootDir: __dirname,
|
| Vite | 5.2.0 | Build tool y dev server |
|
||||||
},
|
| Tailwind CSS | 4.1.18 | Estilos utility-first |
|
||||||
|
| Material-UI | 7.3.6 | Componentes UI |
|
||||||
|
| Recharts | 3.6.0 | Visualizacion de datos |
|
||||||
|
| Lucide React | 0.559.0 | Iconos SVG |
|
||||||
|
|
||||||
|
### Herramientas de Desarrollo
|
||||||
|
- **ESLint** - Linting de codigo
|
||||||
|
- **TypeScript ESLint** - Analisis estatico
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Instalacion
|
||||||
|
|
||||||
|
### Prerrequisitos
|
||||||
|
|
||||||
|
- Node.js >= 18.x
|
||||||
|
- npm >= 9.x o yarn >= 1.22
|
||||||
|
|
||||||
|
### Pasos de Instalacion
|
||||||
|
|
||||||
|
1. **Clonar el repositorio**
|
||||||
|
```bash
|
||||||
|
git clone <url-del-repositorio>
|
||||||
|
cd water-project
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Instalar dependencias**
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Configurar variables de entorno**
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Editar el archivo `.env`:
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=https://tu-api-url.com
|
||||||
|
VITE_API_TOKEN=tu-token-de-api
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Iniciar servidor de desarrollo**
|
||||||
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
La aplicacion estara disponible en `http://localhost:5173`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Scripts Disponibles
|
||||||
|
|
||||||
|
| Comando | Descripcion |
|
||||||
|
|---------|-------------|
|
||||||
|
| `npm run dev` | Inicia el servidor de desarrollo |
|
||||||
|
| `npm run build` | Compila TypeScript y genera build de produccion |
|
||||||
|
| `npm run preview` | Previsualiza el build de produccion |
|
||||||
|
| `npm run lint` | Ejecuta ESLint en el codigo |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estructura del Proyecto
|
||||||
|
|
||||||
|
```
|
||||||
|
water-project/
|
||||||
|
├── public/ # Assets estaticos
|
||||||
|
│ └── grhWatermark.jpg
|
||||||
|
│
|
||||||
|
├── src/
|
||||||
|
│ ├── api/ # Capa de comunicacion con API
|
||||||
|
│ │ ├── me.ts # Endpoints de perfil
|
||||||
|
│ │ ├── meters.ts # CRUD de medidores
|
||||||
|
│ │ ├── concentrators.ts # CRUD de concentradores
|
||||||
|
│ │ └── projects.ts # CRUD de proyectos
|
||||||
|
│ │
|
||||||
|
│ ├── components/
|
||||||
|
│ │ ├── layout/ # Componentes de layout
|
||||||
|
│ │ │ ├── Sidebar.tsx # Menu lateral
|
||||||
|
│ │ │ ├── TopMenu.tsx # Barra superior
|
||||||
|
│ │ │ └── common/ # Componentes reutilizables
|
||||||
|
│ │ │ ├── ProfileModal.tsx
|
||||||
|
│ │ │ ├── ConfirmModal.tsx
|
||||||
|
│ │ │ └── Watermark.tsx
|
||||||
|
│ │ └── SettingsModals.tsx
|
||||||
|
│ │
|
||||||
|
│ ├── pages/ # Paginas principales
|
||||||
|
│ │ ├── Home.tsx # Dashboard
|
||||||
|
│ │ ├── LoginPage.tsx # Login
|
||||||
|
│ │ ├── UsersPage.tsx # Gestion de usuarios
|
||||||
|
│ │ ├── RolesPage.tsx # Gestion de roles
|
||||||
|
│ │ ├── projects/
|
||||||
|
│ │ │ └── ProjectsPage.tsx
|
||||||
|
│ │ ├── meters/ # Modulo de medidores
|
||||||
|
│ │ │ ├── MeterPage.tsx
|
||||||
|
│ │ │ ├── useMeters.ts # Hook personalizado
|
||||||
|
│ │ │ ├── MetersTable.tsx
|
||||||
|
│ │ │ ├── MetersModal.tsx
|
||||||
|
│ │ │ └── MetersSidebar.tsx
|
||||||
|
│ │ └── concentrators/ # Modulo de concentradores
|
||||||
|
│ │ ├── ConcentratorsPage.tsx
|
||||||
|
│ │ ├── useConcentrators.ts
|
||||||
|
│ │ ├── ConcentratorsTable.tsx
|
||||||
|
│ │ ├── ConcentratorsModal.tsx
|
||||||
|
│ │ └── ConcentratorsSidebar.tsx
|
||||||
|
│ │
|
||||||
|
│ ├── assets/
|
||||||
|
│ │ └── images/
|
||||||
|
│ │
|
||||||
|
│ ├── App.tsx # Componente raiz
|
||||||
|
│ ├── main.tsx # Punto de entrada
|
||||||
|
│ └── index.css # Estilos globales
|
||||||
|
│
|
||||||
|
├── index.html
|
||||||
|
├── package.json
|
||||||
|
├── tsconfig.json
|
||||||
|
├── vite.config.ts
|
||||||
|
└── .env.example
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modulos Funcionales
|
||||||
|
|
||||||
|
### 1. Dashboard (Home)
|
||||||
|
|
||||||
|
El dashboard principal ofrece:
|
||||||
|
- Selector de organismos operadores (CESPT TIJUANA, TECATE, MEXICALI)
|
||||||
|
- Grafico de barras: "Numero de Medidores por Proyecto"
|
||||||
|
- Tarjetas de acceso rapido: Tomas, Alertas, Mantenimiento, Reportes
|
||||||
|
- Historial reciente de actividades
|
||||||
|
- Panel de ultimas alertas
|
||||||
|
|
||||||
|
### 2. Gestion de Medidores
|
||||||
|
|
||||||
|
Modulo completo para administrar medidores/tomas de agua:
|
||||||
|
|
||||||
|
**Funcionalidades:**
|
||||||
|
- Listado con busqueda y filtros
|
||||||
|
- Filtrado por proyecto
|
||||||
|
- Tipos de toma: GENERAL, LORA, LORAWAN, GRANDES
|
||||||
|
- CRUD completo (Crear, Leer, Actualizar, Eliminar)
|
||||||
|
|
||||||
|
**Campos principales:**
|
||||||
|
- Area, Numero de cuenta, Usuario, Direccion
|
||||||
|
- Serial del medidor, Nombre, Estado
|
||||||
|
- Tipo de protocolo, Particion DMA
|
||||||
|
- Configuracion de dispositivo (Device EUI, AppKey, etc.)
|
||||||
|
|
||||||
|
### 3. Gestion de Concentradores
|
||||||
|
|
||||||
|
Administracion de concentradores y gateways:
|
||||||
|
|
||||||
|
**Funcionalidades:**
|
||||||
|
- Listado con filtros por proyecto
|
||||||
|
- Configuracion de Gateway (ID, EUI, Nombre)
|
||||||
|
- Seleccion de ubicacion de antena (Indoor/Outdoor)
|
||||||
|
- CRUD completo
|
||||||
|
|
||||||
|
### 4. Gestion de Proyectos
|
||||||
|
|
||||||
|
Administracion de proyectos de infraestructura:
|
||||||
|
- Tabla con busqueda integrada
|
||||||
|
- Estados: ACTIVE/INACTIVE
|
||||||
|
- Informacion de operador y tiempos
|
||||||
|
|
||||||
|
### 5. Gestion de Usuarios
|
||||||
|
|
||||||
|
Control de usuarios del sistema:
|
||||||
|
- Listado de usuarios
|
||||||
|
- Asignacion de roles
|
||||||
|
- Estados: ACTIVE/INACTIVE
|
||||||
|
|
||||||
|
### 6. Gestion de Roles
|
||||||
|
|
||||||
|
Administracion de roles de acceso:
|
||||||
|
- Roles predefinidos: SUPER_ADMIN, USER
|
||||||
|
- Descripcion de permisos
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## API y Comunicacion
|
||||||
|
|
||||||
|
### Configuracion
|
||||||
|
|
||||||
|
La aplicacion se conecta a una API REST externa. Configurar en `.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
VITE_API_BASE_URL=https://tu-api.com
|
||||||
|
VITE_API_TOKEN=tu-token
|
||||||
|
```
|
||||||
|
|
||||||
|
### Endpoints Principales
|
||||||
|
|
||||||
|
| Recurso | Endpoint Base |
|
||||||
|
|---------|---------------|
|
||||||
|
| Medidores | `/api/v3/data/.../m4hzpnopjkppaav/records` |
|
||||||
|
| Concentradores | `/api/v3/data/.../mheif1vdgnyt8x2/records` |
|
||||||
|
| Proyectos | `/api/v3/data/.../m9882vn3xb31e29/records` |
|
||||||
|
|
||||||
|
### Estructura de Respuesta
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface ApiResponse<T> {
|
||||||
|
records: Array<{
|
||||||
|
id: string;
|
||||||
|
fields: T;
|
||||||
|
}>;
|
||||||
|
next?: string;
|
||||||
|
prev?: string;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
|
---
|
||||||
- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
|
|
||||||
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
|
## Modelos de Datos
|
||||||
|
|
||||||
|
### Meter (Medidor)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Meter {
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
areaName: string;
|
||||||
|
accountNumber: string | null;
|
||||||
|
userName: string | null;
|
||||||
|
userAddress: string | null;
|
||||||
|
meterSerialNumber: string;
|
||||||
|
meterName: string;
|
||||||
|
meterStatus: string;
|
||||||
|
protocolType: string;
|
||||||
|
priceNo: string | null;
|
||||||
|
priceName: string | null;
|
||||||
|
dmaPartition: string | null;
|
||||||
|
supplyTypes: string;
|
||||||
|
deviceId: string;
|
||||||
|
deviceName: string;
|
||||||
|
deviceType: string;
|
||||||
|
usageAnalysisType: string;
|
||||||
|
installedTime: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Concentrator
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Concentrator {
|
||||||
|
id: string;
|
||||||
|
"Area Name": string;
|
||||||
|
"Device S/N": string;
|
||||||
|
"Device Name": string;
|
||||||
|
"Device Time": string;
|
||||||
|
"Device Status": string;
|
||||||
|
"Operator": string;
|
||||||
|
"Installed Time": string;
|
||||||
|
"Communication Time": string;
|
||||||
|
"Instruction Manual": string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Project
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
interface Project {
|
||||||
|
id: string;
|
||||||
|
areaName: string;
|
||||||
|
deviceSN: string;
|
||||||
|
deviceName: string;
|
||||||
|
deviceType: string;
|
||||||
|
deviceStatus: "ACTIVE" | "INACTIVE";
|
||||||
|
operator: string;
|
||||||
|
installedTime: string;
|
||||||
|
communicationTime: string;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Autenticacion
|
||||||
|
|
||||||
|
### Flujo de Login
|
||||||
|
|
||||||
|
1. Usuario ingresa credenciales
|
||||||
|
2. Validacion del checkbox "No soy un robot"
|
||||||
|
3. Token almacenado en `localStorage` (`grh_auth`)
|
||||||
|
4. Redireccion al Dashboard
|
||||||
|
|
||||||
|
### Almacenamiento
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// localStorage keys
|
||||||
|
grh_auth: { token: string, ts: number }
|
||||||
|
water_project_settings_v1: { theme: string, compactMode: boolean }
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuracion de Temas
|
||||||
|
|
||||||
|
El sistema soporta tres modos de tema:
|
||||||
|
- **Sistema** - Detecta preferencia del OS
|
||||||
|
- **Claro** - Tema light
|
||||||
|
- **Oscuro** - Tema dark
|
||||||
|
|
||||||
|
Configuracion persistida en `localStorage` bajo `water_project_settings_v1`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Despliegue
|
||||||
|
|
||||||
|
### Build de Produccion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
Los archivos compilados se generan en la carpeta `dist/`.
|
||||||
|
|
||||||
|
### Configuracion de Vite
|
||||||
|
|
||||||
|
El servidor de desarrollo esta configurado para:
|
||||||
|
- Puerto: 5173
|
||||||
|
- Host: habilitado para acceso remoto
|
||||||
|
- Hosts permitidos: localhost, 127.0.0.1, dominios personalizados
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribucion
|
||||||
|
|
||||||
|
1. Fork del repositorio
|
||||||
|
2. Crear rama feature (`git checkout -b feature/nueva-funcionalidad`)
|
||||||
|
3. Commit de cambios (`git commit -m 'Agregar nueva funcionalidad'`)
|
||||||
|
4. Push a la rama (`git push origin feature/nueva-funcionalidad`)
|
||||||
|
5. Crear Pull Request
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Licencia
|
||||||
|
|
||||||
|
Este proyecto es privado y pertenece a GRH - Gestion de Recursos Hidricos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contacto
|
||||||
|
|
||||||
|
Para soporte o consultas sobre el sistema, contactar al equipo de desarrollo.
|
||||||
|
|||||||
Reference in New Issue
Block a user