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
33 changes: 26 additions & 7 deletions app/buscador/BuscadorPrincipalContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import styles from '../styles/BuscadorPrincipal.module.css';
import { listProjectsAction, searchProjectsAction, fetchAllAreasAction, filterProjectsAction } from '@/app/protected/actions';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import Swal from 'sweetalert2';

const BuscadorPrincipalContent = () => {
const searchParams = useSearchParams();
Expand Down Expand Up @@ -37,7 +38,11 @@ const BuscadorPrincipalContent = () => {
setProjects(mappedProjects);
} catch (error) {
console.error('Error al cargar proyectos:', error);
alert('Error al cargar los proyectos');
Swal.fire({
title: "Error",
text: "Error al cargar los proyectos",
icon: "error"
});
}
}, []);

Expand All @@ -60,15 +65,24 @@ const BuscadorPrincipalContent = () => {

const handleSearchClick = async () => {
if (!searchTerm.trim()) {
alert('Por favor, ingrese un título para buscar.');
Swal.fire({
title: "Atención",
text: "Por favor, ingrese un título para buscar.",
icon: "info"
});
setProjects([]);
return;
}
try {
const data = await searchProjectsAction(searchTerm);
if (!data || data.length === 0) {
alert('No se encontró un proyecto con ese título.');
Swal.fire({
title: "Sin resultados",
text: "No se encontró un proyecto con ese título.",
icon: "warning"
});
setProjects([]);

} else {
const mappedProjects = data.map(project => ({
idproyecto: project.id,
Expand All @@ -81,7 +95,11 @@ const BuscadorPrincipalContent = () => {
}
} catch (error) {
console.error('Error al buscar proyectos:', error);
alert('Error al buscar proyectos');
Swal.fire({
title: "Error",
text: "Error al buscar proyectos",
icon: "error"
});
}
};

Expand All @@ -99,11 +117,12 @@ const BuscadorPrincipalContent = () => {
};

return (
<div className="min-h-screen flex flex-col bg-background">
<div className="min-h-screen flex flex-col bg-background" suppressHydrationWarning>
<Header />

<div className={styles.container}>
<div className={styles.searchSection}>
{/* Contenedor principal ajustado para evitar colapso del footer (mainSearchContainer aplica flex: 1) */}
<div className={`${styles.container} ${styles.mainSearchContainer}`} suppressHydrationWarning>
<div className={styles.searchSection} suppressHydrationWarning>
<div className={styles.searchBar}>
<div className="input-group mb-3">
<input type="text" className="form-control" value={searchTerm} onChange={handleSearchChange} aria-describedby="button-addon2" />
Expand Down
Binary file added app/icon3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 6 additions & 2 deletions app/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { icons } from 'lucide-react'
import './globals.css'
import '@fortawesome/fontawesome-free/css/all.min.css'

export const metadata = {
title: 'BUMI-UNEFA',
description: 'Buscador de Material de Investigación de la UNEFA',
icons: {
icon: '/icon.png',
},
}

export default function RootLayout({ children }) {
return (
<html lang="es">
<html lang="es" suppressHydrationWarning>
<head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
Expand All @@ -27,7 +31,7 @@ export default function RootLayout({ children }) {
defer
/>
</head>
<body>{children}</body>
<body suppressHydrationWarning>{children}</body>
</html>
)
}
Expand Down
45 changes: 12 additions & 33 deletions app/page.jsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,36 @@
'use client';

import Image from 'next/image';
import Header from '@/components/Header';
import Testimonials from '@/components/Testimonials';
import Footer from '@/components/Footer';
import { listProjectsAction, searchProjectsAction, fetchAllAreasAction, filterProjectsAction } from '@/app/protected/actions';

import BannerPatriotico from '@/components/BannerPatriotico';
import Hero from '@/components/Hero';
import Image from 'next/image';
import Swal from 'sweetalert2';

const PaginaPrincipal = () => {
const handleBuscarClick = () => {
const handleBuscarClick = () => {
const searchInput = document.querySelector('input[placeholder="¿Qué necesitas buscar?"]');
const searchTerm = searchInput?.value || '';

if (searchTerm) {
window.location.href = `/buscador?q=${encodeURIComponent(searchTerm)}`;
} else {
window.location.href = "/buscador";
alert("No se encontraron coincidencias para la búsqueda");
Swal.fire({
title: "Sin coincidencias",
text: "No se encontraron coincidencias para la búsqueda",
icon: "info"
});
}
};

return (
<div className="min-h-screen flex flex-col bg-background"> {/* Exacto Index.tsx */}
<Header />
<BannerPatriotico />
<main className="flex-1"> {/* flex-1 para Footer sticky abajo */}
{/* TU HERO/SEARCH (movido de viejo <header>, clases globals.css intactas) */}
<header className="header"> {/* Mantengo tu .header globals (teal) */}
<div className="header-main">
<div className="header-search-section">
<h1>BUSCADOR DE MATERIAL DE INVESTIGACIÓN</h1>
<p>
Bumi es básicamente un Google Academy, un sitio web al cual puedes
acceder desde cualquier parte del mundo para consultar los
trabajos de investigación hechos por la comunidad de estudiantes e
investigadores Unefista.....
</p>

<div className="input-group mb-3">
<input type="text" className="form-control" placeholder="¿Qué necesitas buscar?" aria-label="¿Qué necesitas buscar?" aria-describedby="button-addon2" />
<button className="btn btn-outline-secondary" type="button" id="button-addon2" onClick={handleBuscarClick}>Buscar</button>
</div>
</div>
<div className="header-image-card">
<Image
src="/image/logo.png"
alt="BUMI Logo con birrete"
width={280}
height={200}
className="card-image"
/>
</div>
</div>
</header>
<Hero handleBuscarClick={handleBuscarClick} />

{/* TU MAIN CONTENT (intacto, globals.css) */}
<main className="main-content">
Expand Down
115 changes: 95 additions & 20 deletions app/protected/dashboard/moduloGrupos/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useState, useEffect, useCallback } from 'react';
import Image from 'next/image';
import styles from '../../../styles/ModuloGrupos.module.css';
import Sidebar from '@/components/ui/Sidebar';
import Swal from 'sweetalert2';
import {
getUserAreaAction,
groupsListAction,
Expand Down Expand Up @@ -81,7 +82,11 @@ const ModuloGrupos = () => {
setGroups(result || []);
} catch (error) {
console.error('Error fetching groups:', error);
alert('No se pudieron cargar los grupos');
Swal.fire({
title: "Error",
text: "No se pudieron cargar los grupos",
icon: "error"
});
setGroups([]);
} finally {
setLoading(false);
Expand Down Expand Up @@ -124,7 +129,11 @@ const ModuloGrupos = () => {

const handleNewClick = () => {
if (!userAreaId) {
alert('No puedes crear grupos sin un área asignada.');
Swal.fire({
title: "No puedes crear grupos",
text: "No puedes crear grupos sin un área asignada.",
icon: "warning"
});
return;
}
setIsWizardOpen(true);
Expand All @@ -142,18 +151,30 @@ const ModuloGrupos = () => {

const handleEditClick = () => {
if (!selectedRowKey) {
alert('Selecciona un grupo para modificar.');
Swal.fire({
title: "Atención",
text: "Selecciona un grupo para modificar.",
icon: "info"
});
return;
}

const groupToEdit = groups.find(g => g.compositeKey === selectedRowKey);
if (!groupToEdit) {
alert('Grupo no encontrado.');
Swal.fire({
title: "Error",
text: "Grupo no encontrado.",
icon: "error"
});
return;
}

if (groupToEdit.id_area_investigacion !== userAreaId) {
alert('No tienes permiso para modificar grupos de otras áreas.');
Swal.fire({
title: "Permiso denegado",
text: "No tienes permiso para modificar grupos de otras áreas.",
icon: "error"
});
return;
}

Expand Down Expand Up @@ -217,31 +238,62 @@ const ModuloGrupos = () => {

const handleDeleteClick = async () => {
if (!selectedRowKey) {
alert('Selecciona un grupo para eliminar.');
Swal.fire({
title: "Atención",
text: "Selecciona un grupo para eliminar.",
icon: "info"
});
return;
}

const group = groups.find(g => g.compositeKey === selectedRowKey);
if (!group) {
alert('Grupo no encontrado.');
Swal.fire({
title: "Error",
text: "Grupo no encontrado.",
icon: "error"
});
return;
}

if (group.id_area_investigacion !== userAreaId) {
alert('No tienes permiso para eliminar grupos de otras áreas.');
Swal.fire({
title: "Permiso denegado",
text: "No tienes permiso para eliminar grupos de otras áreas.",
icon: "error"
});
return;
}

if (window.confirm(`¿Estás seguro de eliminar el grupo "${group.nombre_grupo}"?`)) {
const result = await Swal.fire({
title: "¿Estás seguro?",
text: `¿Estás seguro de eliminar el grupo "${group.nombre_grupo}"?`,
icon: "warning",
showCancelButton: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
confirmButtonText: "Sí, eliminar",
cancelButtonText: "Cancelar"
});

if (result.isConfirmed) {
setLoading(true);
try {
await deleteGroupByNameAction(group.nombre_grupo, group.id_proyecto, group.periodo_academico);
alert(`Grupo "${group.nombre_grupo}" eliminado correctamente`);
Swal.fire({
title: "Eliminado",
text: `Grupo "${group.nombre_grupo}" eliminado correctamente`,
icon: "success"
});
fetchGroups();
setSelectedRowKey(null);
} catch (error) {
console.error('Error al eliminar grupo:', error);
alert('Error al eliminar grupo: ' + (error.message || 'Error desconocido'));
Swal.fire({
title: "Error",
text: 'Error al eliminar grupo: ' + (error.message || 'Error desconocido'),
icon: "error"
});
} finally {
setLoading(false);
}
Expand All @@ -251,15 +303,27 @@ const ModuloGrupos = () => {
const handleWizardNext = () => {
// Validaciones por paso
if (currentStep === 1 && wizardData.selectedStudents.length === 0) {
alert('Debes seleccionar al menos un estudiante.');
Swal.fire({
title: "Selección requerida",
text: "Debes seleccionar al menos un estudiante.",
icon: "warning"
});
return;
}
if (currentStep === 2 && !wizardData.id_proyecto) {
alert('Debes seleccionar un proyecto.');
Swal.fire({
title: "Selección requerida",
text: "Debes seleccionar un proyecto.",
icon: "warning"
});
return;
}
if (currentStep === 3 && !wizardData.periodo) {
alert('Debes ingresar el periodo académico.');
Swal.fire({
title: "Campo requerido",
text: "Debes ingresar el periodo académico.",
icon: "warning"
});
return;
}
if (currentStep < 4) {
Expand All @@ -275,7 +339,11 @@ const ModuloGrupos = () => {

const handleWizardFinish = async () => {
if (!wizardData.selectedStudents.length || !wizardData.id_proyecto || !wizardData.periodo) {
alert('Faltan datos requeridos.');
Swal.fire({
title: "Datos incompletos",
text: "Faltan datos requeridos.",
icon: "error"
});
return;
}

Expand Down Expand Up @@ -303,10 +371,13 @@ const ModuloGrupos = () => {
nombreGrupo: wizardData.nombreGrupo,
});

alert(editingGroupKey
? `Grupo "${wizardData.nombreGrupo}" actualizado exitosamente`
: `Se creó el grupo "${wizardData.nombreGrupo}" con ${wizardData.selectedStudents.length} estudiante(s)`
);
Swal.fire({
title: "¡Éxito!",
text: editingGroupKey
? `Grupo "${wizardData.nombreGrupo}" actualizado exitosamente`
: `Se creó el grupo "${wizardData.nombreGrupo}" con ${wizardData.selectedStudents.length} estudiante(s)`,
icon: "success"
});

setIsWizardOpen(false);
setEditingGroupKey(null);
Expand All @@ -315,7 +386,11 @@ const ModuloGrupos = () => {
fetchGroups();
} catch (error) {
console.error('Error al guardar grupos:', error);
alert('Error al guardar los grupos: ' + (error.message || 'Error desconocido'));
Swal.fire({
title: "Error",
text: 'Error al guardar los grupos: ' + (error.message || 'Error desconocido'),
icon: "error"
});
} finally {
setLoading(false);
}
Expand Down
Loading
Loading