Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
name: CI/CD Pipeline ELysium
name: CI/CD Pipeline ELysium Production

on:
push:
branches:
- main
pull_request:
branches:
- develop
- main

env:
AZURE_WEBAPP_NAME: elysiumFrontEnd
AZURE_WEBAPP_NAME: Eros
AZURE_WEBAPP_PACKAGE_PATH: '.'
NODE_VERSION: '18.x'
NODE_VERSION: '22.x'

jobs:
build-and-deploy:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/ci-cd-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: CI/CD Pipeline ELysium Testing

on:
push:
branches:
- develop
pull_request:
branches:
- develop

env:
AZURE_WEBAPP_NAME: cicero
AZURE_WEBAPP_PACKAGE_PATH: '.'
NODE_VERSION: '22.x'

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4

- uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_TEST_ENVIRONMENT }}

- name: Cache Node.js modules
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm run test --if-present

- name: Build project
run: npm run build --if-present

- name: Deploy to Azure Web Apps
uses: azure/webapps-deploy@v3
with:
app-name: ${{ env.AZURE_WEBAPP_NAME }}
package: ./build

- name: Logout from Azure
run: az logout
13 changes: 11 additions & 2 deletions src/components/Admin/charts/RangoFechasChart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ const RangoFechasChart = ({ reservas }) => {
const svg = d3.select(container);
svg.selectAll("*").remove(); // Limpiar el SVG

if (!reservas || reservas.length === 0) return;

// Ajustar tamaño dinámico según el contenedor
const containerWidth = container.clientWidth || 600;
const containerHeight = containerWidth * 0.6; // Mantener proporción
Expand All @@ -21,6 +19,17 @@ const RangoFechasChart = ({ reservas }) => {

const margin = { top: 20, right: 20, bottom: 30, left: 100 };

if (reservas.length === 0) {
svg.append("text")
.attr("x", containerWidth / 2)
.attr("y", containerHeight / 2)
.attr("text-anchor", "middle")
.attr("font-size", "16px")
.attr("fill", "#666")
.text("No hay datos disponibles");
return;
}

// Agrupar reservas por salón
const reservasPorSalon = d3.rollup(reservas, (v) => v.length, (d) => d.idSalon);
const data = Array.from(reservasPorSalon, ([salon, count]) => ({ salon, count }));
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table/UserRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const RoleBadge = styled.span`
background-color: ${props => props.$isAdmin ? '#e3f2fd' : '#f5f5f5'};
color: ${props => props.$isAdmin ? '#1976d2' : '#616161'};
`;
function UserRow({ user, onUpdateUser, onEditUser }) {
function UserRow({ user, onEditUser }) {
// Extraemos las propiedades del usuario
const {idInstitucional, nombre, apellido, correoInstitucional, isAdmin, activo } = user;

Expand Down
1 change: 0 additions & 1 deletion src/components/Table/UserTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ function UserTable({ users, onUpdateUser }) {
<UserRow
key={user.idInstitucional}
user={user}
onUpdateUser={onUpdateUser}
onEditUser={handleEditUser}
/>
))}
Expand Down
14 changes: 12 additions & 2 deletions src/components/popup/CRUDSalonModal/AddSalonModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ import CRUDSalonForm from "./CRUDSalonForm";

function AddSalonModal({ onClose, newSalon, setNewSalon, handleAddSalon }) {
const [tempSalon, setTempSalon] = useState({
mnemonico: newSalon?.mnemonico || "",
nombre: newSalon?.nombre || "",
descripcion: newSalon?.descripcion || "",
mnemonico: newSalon?.mnemonico || "",
ubicacion: newSalon?.ubicacion || "",
capacidad: newSalon?.capacidad || 0,
recursos: newSalon?.recursos || [{ nombre: "", cantidad: 1, especificaciones: [], activo: true }],
});

const isFormComplete = () => {
return (
tempSalon.mnemonico.trim() !== "" &&
tempSalon.nombre.trim() !== "" &&
tempSalon.descripcion.trim() !== "" &&
tempSalon.ubicacion.trim() !== "" &&
tempSalon.capacidad > 0
);
};

const handleGuardar = () => {
setNewSalon({
...tempSalon,
Expand All @@ -32,7 +42,7 @@ function AddSalonModal({ onClose, newSalon, setNewSalon, handleAddSalon }) {
/>
<div className="modal-buttons">
<button className="cancel-button" onClick={onClose}>Cancelar</button>
<button className="save-button" onClick={handleGuardar}>Agregar</button>
<button className="save-button" onClick={handleGuardar} disabled={!isFormComplete()}>Agregar</button>
</div>
</div>
</div>
Expand Down
8 changes: 8 additions & 0 deletions src/components/popup/CRUDSalonModal/CRUDSalonModal.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@
cursor: pointer;
}

.popup-overlay .salon-modal .save-button:disabled {
background: #ddd;
color: #999;
cursor: not-allowed;
opacity: 0.6;
}


.popup-overlay .modal-content .capacity-container {
display: flex;
flex-direction: column;
Expand Down
41 changes: 28 additions & 13 deletions src/components/popup/CRUDSalonModal/EditarSalonModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,40 @@ import "./CRUDSalonModal.css";
import CRUDSalonForm from "./CRUDSalonForm";

function EditarSalonModal({ onClose, newSalon, setNewSalon, handleEdit }) {
const defaultSalon = {
nombre: "",
descripcion: "",
mnemonico: "",
ubicacion: "",
capacidad: 0,
recursos: [],
const [isInitialized, setIsInitialized] = useState(false);
const [tempSalon, setTempSalon] = useState({
mnemonico: newSalon?.mnemonico || "",
nombre: newSalon?.nombre || "",
descripcion: newSalon?.descripcion || "",
ubicacion: newSalon?.ubicacion || "",
capacidad: newSalon?.capacidad || 0,
recursos: newSalon?.recursos || [{ nombre: "", cantidad: 1, especificaciones: [], activo: true }],
});

const isFormComplete = () => {
return (
tempSalon.mnemonico.trim() !== "" &&
tempSalon.nombre.trim() !== "" &&
tempSalon.descripcion.trim() !== "" &&
tempSalon.ubicacion.trim() !== "" &&
tempSalon.capacidad > 0
);
};
const [tempSalon, setTempSalon] = useState(newSalon || defaultSalon);

useEffect(() => {
if (newSalon) {
if (!isInitialized && newSalon) {
setTempSalon(newSalon);
setIsInitialized(true);
}
}, [newSalon]);
}, [newSalon, isInitialized]);

const handleGuardar = () => {
setNewSalon(tempSalon);
handleEdit();
const updatedSalon = {
...tempSalon,
recursos: tempSalon.recursos?.length > 0 ? tempSalon.recursos : [{ nombre: "", cantidad: 1, especificaciones: [], activo: true }],
};
setNewSalon(updatedSalon);
handleEdit(updatedSalon);
};

return (
Expand All @@ -36,7 +51,7 @@ function EditarSalonModal({ onClose, newSalon, setNewSalon, handleEdit }) {
/>
<div className="modal-buttons">
<button className="cancel-button" onClick={onClose}>Cancelar</button>
<button className="save-button" onClick={handleGuardar}>Guardar</button>
<button className="save-button" onClick={handleGuardar} disabled={!isFormComplete()}>Guardar</button>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/config/config.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const BASE_URL = "http://localhost:8080/api";
export const BASE_URL = "https://hades-g4apbhdua4gtbbf5.canadacentral-01.azurewebsites.net/api";
4 changes: 2 additions & 2 deletions src/pages/Admin/AddUserModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ function AddUserModal({ onClose, onAdd }) {

try {
// Crear nuevo usuario
const nuevoUsuario = await agregarUsuario({
await agregarUsuario({
idInstitucional: parseInt(formData.idInstitucional),
nombre: formData.nombre,
apellido: formData.apellido,
Expand All @@ -230,7 +230,7 @@ function AddUserModal({ onClose, onAdd }) {

// Notificar al componente padre sobre la creación exitosa
if (onAdd) {
onAdd(nuevoUsuario);
onAdd();
}

onClose(); // Cerrar modal tras guardar
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Admin/EditUserModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ function EditUserModal({ user, onClose, onUpdate }) {

try {
// Solo enviamos los campos que deseamos actualizar
const usuarioActualizado = await actualizarInformacionUsuario(
await actualizarInformacionUsuario(
formData.idInstitucional,
{
nombre: formData.nombre,
Expand All @@ -222,7 +222,7 @@ function EditUserModal({ user, onClose, onUpdate }) {

// Notificar al componente padre sobre la actualización exitosa
if (onUpdate) {
onUpdate(usuarioActualizado || { ...user, ...formData });
onUpdate();
}

onClose(); // Cerrar modal tras guardar cambios
Expand Down
83 changes: 43 additions & 40 deletions src/pages/Admin/GestionarUsuarios.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useCallback } from 'react';
import styled from 'styled-components';
import { consultarUsuarios } from '../../api/usuario';
import UserFilters from '../../components/UserFilters';
Expand Down Expand Up @@ -130,38 +130,39 @@ function GestionarUsuarios() {
isAdmin: null // null = sin filtro, true = admins, false = no admins
});

// Efecto para cargar usuarios con los filtros aplicados
useEffect(() => {
const loadUsers = async () => {
setLoading(true);
setError(null);
// Manejador para cargar usuarios
const loadUsers = useCallback(async () => {
setLoading(true);
setError(null);

try {
// Obtener usuarios con filtros
const data = await consultarUsuarios(filters);

try {
// Obtener usuarios con filtros
const data = await consultarUsuarios(filters);

// Filtrar por término de búsqueda si existe
let filteredUsers = data || [];
if (searchTerm) {
const searchLower = searchTerm.toLowerCase();
filteredUsers = filteredUsers.filter(user =>
user.nombre?.toLowerCase().includes(searchLower) ||
user.apellido?.toLowerCase().includes(searchLower) ||
user.correoInstitucional?.toLowerCase().includes(searchLower)
);
}

setUsers(filteredUsers);
} catch (err) {
console.error("Error al cargar usuarios:", err);
setError(err.message || "No se pudieron cargar los usuarios");
} finally {
setLoading(false);
// Filtrar por término de búsqueda si existe
let filteredUsers = data || [];
if (searchTerm) {
const searchLower = searchTerm.toLowerCase();
filteredUsers = filteredUsers.filter(user =>
user.nombre?.toLowerCase().includes(searchLower) ||
user.apellido?.toLowerCase().includes(searchLower) ||
user.correoInstitucional?.toLowerCase().includes(searchLower)
);
}
};


setUsers(filteredUsers);
} catch (err) {
console.error("Error al cargar usuarios:", err);
setError(err.message || "No se pudieron cargar los usuarios");
} finally {
setLoading(false);
}
}, [filters, searchTerm]);

// Efecto para cargar usuarios con los filtros aplicados
useEffect(() => {
loadUsers();
}, [filters, searchTerm]); // Re-fetch cuando cambian los filtros o el término de búsqueda
}, [loadUsers]);

// Manejador para la búsqueda
const handleSearch = (e) => {
Expand All @@ -170,19 +171,21 @@ function GestionarUsuarios() {
};

// Manejador para añadir un nuevo usuario
const handleAddUser = (newUser) => {
setUsers(prevUsers => [...prevUsers, newUser]);
const handleAddUser = async () => {
try {
await loadUsers();
} catch (err) {
console.error("Error actualizando usuarios tras añadir:", err);
}
};

// Manejador para actualizar un usuario existente
const handleUpdateUser = (updatedUser) => {
setUsers(prevUsers =>
prevUsers.map(user =>
user.idInstitucional === updatedUser.idInstitucional
? updatedUser
: user
)
);
const handleUpdateUser = async () => {
try {
await loadUsers();
} catch (err) {
console.error("Error actualizando usuarios tras editar:", err);
}
};

return (
Expand Down
Loading