# 🎨 Documentación del Frontend — Frontend-Hotel

## Índice
1. [Introducción](#introducción)
2. [Estructura de Carpetas](#estructura-de-carpetas)
3. [Entry Points](#entry-points)
4. [Enrutamiento](#enrutamiento)
5. [Manejo de Estado Global](#manejo-de-estado-global)
6. [Sistema de Permisos (Roles)](#sistema-de-permisos-roles)
7. [Comunicación con el Backend](#comunicación-con-el-backend)
8. [Componentes Reutilizables](#componentes-reutilizables)
9. [Estilos](#estilos)
10. [Páginas por Dominio](#páginas-por-dominio)
11. [Guía para Agregar una Nueva Página](#guía-para-agregar-una-nueva-página)
12. [Bugs y Limitaciones Conocidas](#bugs-y-limitaciones-conocidas)

---

## Introducción

El frontend es una **Single Page Application (SPA)** construida con **React 19**, **Vite** y **React Router DOM**. Es una aplicación cliente que consume la API REST del backend.

**Tecnologías clave:**
- React 19.1.1 (JSX, JavaScript puro, sin TypeScript)
- Vite 7.1.2 con SWC para compilación rápida
- React Router DOM 7.8.2 (BrowserRouter)
- Estado global: React Context API
- HTTP: mezcla de `fetch` nativo y `axios`
- Estilos: Tailwind CSS + Bootstrap 5 + CSS puro

---

## Estructura de Carpetas

```
Frontend-Hotel/
├── index.html                    # Entry HTML (título: "Hacienda San Angel")
├── vite.config.js               # Config Vite (puerto 5172)
├── tailwind.config.cjs          # Config Tailwind
├── postcss-config.js            # PostCSS con Tailwind + Autoprefixer
├── eslint.config.js             # ESLint 9 flat config
├── public/
│   ├── logoHotel.png
│   ├── IconoHotel.svg
│   └── ...
├── src/
│   ├── main.jsx                 # Entry point React
│   ├── App.jsx                  # Definición central de rutas
│   ├── index.css                # Tailwind directives + estilos base
│   ├── App.css
│   ├── constants/
│   │   └── menuconfig.js        # Configuración del menú de navegación
│   ├── context/
│   │   ├── AuthContext.jsx      # Estado de autenticación
│   │   └── LenguageContext.jsx  # Estado de idioma (EN/ES)
│   ├── routes/
│   │   └── ProtectedRoute.jsx   # Ruta protegida (NO usada en App.jsx)
│   ├── services/
│   │   ├── api.js               # Instancia axios (baseURL desde env)
│   │   ├── employeeService.js
│   │   ├── incomeService.js
│   │   ├── userService.js
│   │   └── contractService.js
│   ├── styles/
│   │   ├── global.css
│   │   ├── Dashboard.css
│   │   ├── Login.css
│   │   ├── Layout.css
│   │   └── Sidebar.css
│   ├── assets/
│   │   └── pages/login.jsx
│   ├── components/
│   │   ├── Layout2.jsx          # Layout activo (Sidebar + Topbar + Outlet)
│   │   ├── Layout.jsx           # Layout antiguo (comentado)
│   │   ├── Sidebar.jsx
│   │   ├── topbar/Topbar.jsx
│   │   ├── Navbar/Navbar.jsx
│   │   ├── Table/HotelTable.jsx
│   │   ├── ExcelExportButton.jsx
│   │   ├── SummaryCard.jsx
│   │   ├── FormInput.jsx
│   │   ├── FormSelect.jsx
│   │   ├── Switch.jsx
│   │   ├── Modals/
│   │   ├── Buttons/
│   │   ├── Filters/
│   │   └── Inputs/
│   └── pages/                   # ~50+ páginas organizadas por dominio
│       ├── Login.jsx
│       ├── Dashboard.jsx
│       ├── Dashboard/
│       ├── Expenses/
│       ├── ExpensesToBeApproval/
│       ├── Inventory/
│       ├── Hotel/
│       ├── Income/
│       ├── Payroll/
│       ├── Settings/
│       └── ...
```

---

## Entry Points

### `index.html`

Carga la fuente Roboto desde Google Fonts y el script `src/main.jsx`.

### `src/main.jsx`

```jsx
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import { LangProvider } from "./context/LenguageContext";
import App from "./App.jsx";

ReactDOM.createRoot(document.getElementById("root")).render(
  <AuthProvider>
    <LangProvider>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </LangProvider>
  </AuthProvider>
);
```

**Jerarquía de providers:**
1. `AuthProvider` — disponible en toda la app
2. `LangProvider` — depende de `AuthContext` (lee el rol para forzar español a housekeepers)
3. `BrowserRouter` — enrutamiento

---

## Enrutamiento

### `src/App.jsx`

Define todas las rutas de la aplicación. No usa `ProtectedRoute`. Todas las rutas internas están bajo `/app` y renderizan `<Layout />` (que es `Layout2.jsx`).

```jsx
<Route path="/" element={<Login />} />
<Route path="/app" element={<Layout />}>
  <Route path="income" element={<Income/>} />
  <Route path="employees" element={<Employees />} />
  <Route path="contracts" element={<Contracts />} />
  <Route path="hotelpl" element={<HotelPL />} />
  <Route path="restaurantpl" element={<RestaurantPL />} />
  <Route path="expenses" element={<Expenses />} />
  <Route path="new-expense" element={<NewExpense />} />
  <Route path="products" element={<Products />} />
  <Route path="payroll" element={<Payroll />} />
  {/* ... ~40 rutas más */}
</Route>
```

**Convenciones de rutas:**
- Páginas de listado: plural simple (`/products`, `/payroll`)
- Páginas de creación: prefijo `new-` (`/new-product`, `/new-expense`)
- Páginas de edición: `:id` como parámetro (`/expenses/edit/:id`, `/payroll/employee/:id`)
- Detalles: segmento fijo + `:id` (`/expenses/:id`, `/properties/:id`)

---

## Manejo de Estado Global

### AuthContext (`src/context/AuthContext.jsx`)

```jsx
export const AuthContext = createContext();

function AuthProvider({ children }) {
  const [user, setUser] = useState(null);     // rol numérico
  const [userData, setUserData] = useState(null);

  useEffect(() => {
    const savedUser = localStorage.getItem("rol");
    if (savedUser) setUser(JSON.parse(savedUser));
  }, []);

  const login = (userData, data) => {
    setUserData(data);
    setUser(userData);
    localStorage.setItem("rol", JSON.stringify(userData));
  };

  const logout = () => {
    setUser(null);
    localStorage.removeItem("rol");
  };

  return (
    <AuthContext.Provider value={{ user, login, logout, userData }}>
      {children}
    </AuthContext.Provider>
  );
}
```

**Observaciones:**
- Guarda el rol como número en `localStorage` bajo la clave `"rol"`.
- **NO exporta `useAuth`**, lo cual es un bug conocido.
- No usa JWT ni tokens.

### LangContext (`src/context/LenguageContext.jsx`)

```jsx
export const langContext = createContext();

export const LangProvider = ({ children }) => {
    const authContext = useContext(AuthContext);
    const user = authContext?.user || null;

    const [lang, setLang] = useState(user === 6 ? "es" : "en");

    const toggleLang = (event) => setLang(event.target.value);

    return (
        <langContext.Provider value={{ lang, toggleLang }}>
            {children}
        </langContext.Provider>
    );
};

export const useLang = () => useContext(langContext);
```

**Observaciones:**
- Forza español si `user === 6` (Housekeeper).
- No persiste en localStorage.
- Se accede con `useContext(langContext)` o `useLang()`.

---

## Sistema de Permisos (Roles)

Los permisos son **numéricos y hardcodeados** en `Layout2.jsx`. No hay backend de ACL.

### Roles Definidos

| Rol | Acceso |
|-----|--------|
| 1 | Admin — Todo |
| 2 | Supervisor limitado — Dashboards, Expenses (Report/Monthly Report), Payroll (Report/Attendance/Employees/Contracts), Expenses to be approved |
| 3-4 | Rangos intermedios (según lógica de rangos) |
| 5 | Compras — Solo: New Expense, Purchase Entries, New Suppliers |
| 6 | Housekeeper — Solo Outcomes, forzado a español |

### Lógica de Permisos en `Layout2.jsx`

```javascript
const menuConfigWithPermissions = Object.values(menuConfig).map(section => ({
  ...section,
  hidden:
    section.label === "Dashboards" ? (user >= 1 && user <= 2 ? false : true) :
    section.label === "Expenses to be approved" ? (user === 1 || user === 2 ? false : true) :
    section.label === "Expenses" ? (user >= 1 && user <= 5 ? false : true) :
    section.label === "Inventory" ? (user >= 1 && user <= 5 ? false : true) :
    section.label === "Payroll" ? (user >= 1 && user <= 4 ? false : true) :
    section.label === "Hotel" ? (user === 1 ? false : true) :
    section.label === "Income" ? (user >= 1 && user <= 4 ? false : true) :
    section.label === "Housekeeper" ? (user === 6 ? false : true) :
    false,
  // ... lógica de submenús
}));
```

**Regla:** Si `hidden === true`, la sección no aparece en el sidebar.

---

## Comunicación con el Backend

### Variable de Entorno

```env
VITE_API_BASE_URL=http://localhost:4000/api
```

Se accede en el frontend como:
```javascript
import.meta.env.VITE_API_BASE_URL
```

### Instancia Axios (`src/services/api.js`)

```javascript
import axios from "axios";

const api = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 15000,
});

export default api;
```

**Problema:** Esta instancia está infrautilizada. Muchas páginas usan `fetch` directo o axios sin la instancia base.

### Patrón Fetch (más común)

```javascript
fetch(import.meta.env.VITE_API_BASE_URL + '/purchases/getpurchases')
  .then(res => res.json())
  .then(data => setState(data))
  .catch(err => console.error(err));
```

### Patrón Axios

```javascript
axios.put(`${import.meta.env.VITE_API_BASE_URL}/purchases/entry/${id}`, {
  checking: parseInt(checking)
})
.then(res => { ... })
.catch(err => { ... });
```

**Problemas conocidos:**
- Varios archivos en `services/` tienen URLs hardcodeadas a `localhost:3000` o `localhost:4000`.
- No hay interceptores para manejo centralizado de errores.
- No se envían headers de autorización.

---

## Componentes Reutilizables

### `HotelTable.jsx` (`src/components/Table/`)

Tabla genérica que recibe:
- `columns`: array de `{ header, key, render?, headerStyle? }`
- `data`: array de objetos

```jsx
<Table 
  columns={[
    { header: "Nombre", key: "name" },
    { header: "Acciones", key: "id", render: (id) => <button>Editar</button> }
  ]} 
  data={products} 
/>
```

### `ExcelExportButton.jsx`

Exporta datos a `.xlsx` usando la librería `xlsx`.

### `SummaryCard.jsx`

Card de resumen con indicador de loading.

### `FormInput.jsx` / `FormSelect.jsx`

Wrappers básicos de inputs HTML con estilos consistentes.

### Modales (`src/components/Modals/`)

- `ConfirmationModal.jsx` — Confirmación genérica
- `DiscardConfirmModal.jsx` — Confirmación de descarte
- `ConfirmationMontlyPay.jsx` — Confirmación de pago mensual
- `ConfirmationOutcome.jsx` — Confirmación de salida

---

## Estilos

### Mezcla de Tecnologías

El proyecto usa tres sistemas de estilos simultáneamente:

1. **Tailwind CSS** — Configurado pero usado esporádicamente.
2. **Bootstrap 5** — Clases como `btn btn-primary`, `btn btn-secondary`.
3. **CSS Puro** — Un archivo `.css` por página/componente.

### Convención Actual

Cada página tiene su propio archivo CSS:
```
src/pages/Expenses/NewExpense.css
src/pages/Inventory/Products.css
src/components/Table/Table.css
```

### Fuente

Roboto cargada desde Google Fonts en `index.html`.

---

## Páginas por Dominio

| Dominio | Páginas | Ruta Base |
|---------|---------|-----------|
| **Dashboards** | Income, HotelPL, RestaurantPL, RoomAnalysis, RestaurantAnalysis, Budget, CostPerRoom, Expenses | `/app/income`, `/app/hotelpl`... |
| **Income** | NewIncome, IncomeReport | `/app/new-income-form`, `/app/new-income-report` |
| **Expenses to Approve** | PendingApproval, Approved, Rejected | `/app/pending-approval`... |
| **Expenses** | NewExpense, EditExpense, ExpenseDetail, ReportExpense, Payments, MonthlyPayments, MonthlyReport, NewMonthlyPayment, NewSuppliers, PurchaseEntries | `/app/new-expense`... |
| **Inventory** | Products, NewProduct, AlterProduct, InventoryReport, Adjustments, Outcomes, HousekeeperOutcomes, DiscardProduct | `/app/products`... |
| **Hotel** | Properties, PropertiesId | `/app/properties`... |
| **Payroll** | Payroll, Plantillapayroll, EditPayroll, PayrollEmployees, NewEmployee, PayrollAttendance, PayrollContract, ContractsDetail | `/app/payroll`... |
| **Settings** | Settings, SettingsId, RoomsManagement | `/app/settings`... |

---

## Guía para Agregar una Nueva Página

1. **Crear el componente** en `src/pages/[Dominio]/NombrePagina.jsx`.
2. **Crear los estilos** opcionales en `src/pages/[Dominio]/NombrePagina.css`.
3. **Agregar la ruta** en `src/App.jsx` dentro de `<Route path="/app" element={<Layout />}>`.
4. **Agregar al menú** (si aplica):
   - Editar `src/constants/menuconfig.js`
   - Agregar la ruta a la sección correspondiente
5. **Actualizar permisos** en `src/components/Layout2.jsx`:
   - Agregar lógica de `hidden` para la sección/submenú
   - Agregar detección de ruta en `activeSection` si la ruta no sigue el patrón estándar
6. **Agregar traducciones** EN/ES si es texto visible.
7. **Consumir la API** usando `import.meta.env.VITE_API_BASE_URL`.

---

## Bugs y Limitaciones Conocidas

1. **`useAuth` no existe** — `AuthContext.jsx` no exporta `useAuth`, pero `ProtectedRoute.jsx` y `Navbar.jsx` lo intentan importar.
2. **No hay rutas protegidas** — `App.jsx` no usa `ProtectedRoute`. Cualquiera puede acceder a `/app/*`.
3. **URLs hardcodeadas** — Varios `*Service.js` apuntan a `localhost` en vez de usar `VITE_API_BASE_URL`.
4. **Código comentado masivo** — Especialmente en `Layout.jsx` y páginas grandes.
5. **`multer` en frontend** — Es un middleware de Node.js, inapropiado para React.
6. **Sin tests** — No hay Jest, Vitest, ni Playwright configurados.
