Se agregarn vistas faltantes al proyecto. Queda pendiente funcionaildades de API

This commit is contained in:
Fimm committed 2026-09-23 13:09:46 +00:00
1 parent eed3b45de3
commit a2fbd4b675
17 files changed
+7223 -101

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
Proyecto Web/Web (solo archivos .aspx)
├── Academico/
│ ├── CodigosSence.aspx
│ ├── CodigosSencePC.aspx
│ ├── Cursos.aspx
│ ├── CursosPC.aspx
│ ├── index.aspx
│ ├── Libros.aspx
│ ├── PlanDeEstudio.aspx
│ └── Ponderaciones.aspx
├── Administrador/
│ └── ActualizarSesiones.aspx
├── Alumnos/
│ ├── EvaluacionPresencial.aspx
│ ├── Ficha.aspx
│ └── Index.aspx
├── Clientes/
│ ├── Autorizador.aspx
│ ├── DesactivaContratos.aspx
│ ├── Ficha.aspx
│ ├── Index.aspx
│ └── InfoEmpresas.aspx
├── Cursos/
│ ├── Administrador.aspx
│ ├── Index.aspx
│ └── Reemplazo.aspx
├── Informes/
│ ├── AlumnosActivos.aspx
│ ├── AlumnosCursos.aspx
│ ├── AlumnosEmpresas.aspx
│ ├── AlumnosPeriodos.aspx
│ ├── Autorizados.aspx
│ ├── ContratosHistorial.aspx
│ ├── CursosActivos.aspx
│ ├── CursosAsistencias.aspx
│ ├── CursosDocentes.aspx
│ ├── CursosDocentesFinalizados.aspx
│ ├── CursosFechas.aspx
│ ├── CursosInicios.aspx
│ ├── Index.aspx
│ ├── PollAnalysis.aspx
│ ├── PollStudents.aspx
│ ├── SesionesEstipuladas.aspx
│ └── SesionesProfesores.aspx
├── Profesor/
│ └── Ficha.aspx
└── Index.aspx
+352
View File
@@ -0,0 +1,352 @@
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<link href="../css/check-radio.css" rel="stylesheet" />
<script src="../js/jquery-ui-1.9.2.custom.min.js"></script>
<link href="../css/jquery-ui.css" rel="stylesheet" />
<script>
$(document).ready(function () {
$(".cargando").click(function () {
$("#mensajeCargando").modal("show");
});
});
</script>
<script>
$(function () {
$(".datepicker").datepicker({
changeMonth: true,
changeYear: true,
dateFormat: "yy-mm-dd",
});
});
$(function ($) {
$.datepicker.dates = {
closeText: 'Cerrar',
prevText: '< Ant',
nextText: 'Sig >',
currentText: 'Hoy',
monthNames: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'],
monthNamesShort: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic'],
dayNames: ["Domingo", "Lunes", "Martes", "Miércoles", "Jueves", "Viernes", "Sábado"],
dayNamesShort: ['Dom', 'Lun', 'Mar', 'Mié', 'Juv', 'Vie', 'Sáb'],
dayNamesMin: ["Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sá"],
weekHeader: 'Sm',
dateFormat: 'dd-mm-yy',
firstDay: 1,
isRTL: false,
showMonthAfterYear: false,
yearSuffix: ''
};
$.datepicker.setDefaults($.datepicker.regional['es']);
});
function valideKey(evt) {
// code is the decimal ASCII representation of the pressed key.
var code = (evt.which) ? evt.which : evt.keyCode;
if (code == 8) { // backspace.
return true;
} else if (code >= 48 && code <= 57) { // is a number.
return true;
} else { // other keys.
return false;
}
}
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-5">
<div class="alert alert-light text-dark" role="alert">
<div class="row">
<div class="col">
<strong>
<i class='bx bx-user' style="font-size: 24px"></i>
</strong>
<strong>
<span class="ms-2">Empresas por mes</span>
</strong>
</div>
<div class="col text-end">
<a href="<%=Page.ResolveUrl("~/Alumnos/Index.aspx") %>" class="btn btn-warning text-dark btn-sm"><strong>Volver</strong></a>
</div>
</div>
</div>
</div>
<div class="col-md-7">
<div class="alert alert-light text-dark" role="alert">
<div class="row">
<div class="col">
<span class="fw-bold">Mes</span>
</div>
<div class="col">
<asp:DropDownList ID="ListaMeses" runat="server" CssClass="form-select"></asp:DropDownList>
</div>
<div class="col">
<span class="fw-bold">Agno</span>
</div>
<div class="col">
<asp:TextBox ID="TextBoxYear" class="form-control form-control-sm" runat="server"></asp:TextBox>
</div>
<div class="col">
<asp:LinkButton ID="LinkButtonBuscar" CssClass="btn btn-primary btn-sm d-grid" runat="server" OnClick="LinkButtonBuscar_Click">Buscar</asp:LinkButton>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-12" runat="server" id="div_reporte">
<div class="alert alert-light shadow text-dark" role="alert">
<div class="row">
<div class="col-md-3 mt-5">
<div class="row">
<div class="col-md-12 mx-auto" runat="server">
<asp:LinkButton ID="LinkButtonExcel" runat="server" CssClass="text-decoration-none" OnClick="LinkButtonExcel_Click">
<div class="alert alert-success shadow" role="alert">
<div class="row">
<div class="col-md-3">
<h1><i class='bx bx-export'></i></h1>
</div>
<div class="col text-center">
<span class="text-muted"><strong>Excel</strong></span>
<h5><strong>
<asp:Label ID="Label1" runat="server" Text="Exportar"></asp:Label>
</strong>
</h5>
</div>
</div>
</div>
</asp:LinkButton>
</div>
<div class="col-md-12" runat="server">
<div class="alert alert-light shadow text-dark" role="alert">
<div class="row">
<div class="col-md-3 text-center">
<h1><i class="fa-solid fa-users-line"></i></h1>
<span class="fw-bold"><strong>Alumnos</strong></span>
</div>
<div class="col text-center mt-3">
<span class="text-muted"><strong>Total</strong></span>
<h5><strong>
<asp:Label ID="LabelTotAlumnos" runat="server" Text="0"></asp:Label>
</strong>
</h5>
</div>
</div>
</div>
</div>
<div class="col-md-12" runat="server">
<div class="alert alert-light shadow text-dark" role="alert">
<div class="row">
<div class="col-md-3 text-center">
<h1><i class='bx bx-building-house bx-lg'></i></h1>
<span class="fw-bold"><strong>Empresas</strong></span>
</div>
<div class="col text-center mt-3">
<span class="text-muted"><strong>Total</strong></span>
<h5><strong>
<asp:Label ID="LabelEmpTotal" runat="server" Text="0"></asp:Label>
</strong>
</h5>
</div>
</div>
</div>
</div>
<div class="col-md-12" runat="server">
<div class="alert alert-light shadow text-dark" role="alert">
<div class="row">
<div class="col-md-12 text-start">
<h1><i class="fa-solid fa-swatchbook"></i></h1>
<span class="fw-bold"><strong>Alumnos</strong></span>
</div>
<div class="col-md-12 text-start">
<span class="text-muted"><strong>Con SENCE</strong></span>
<h5><strong>
<asp:Label ID="LabelAlmConSNC" runat="server" Text="0"></asp:Label>
</strong>
</h5>
</div>
<div class="col-md-12 text-start">
<span class="text-muted"><strong>Sin SENCE</strong></span>
<h5><strong>
<asp:Label ID="LabelAlmSinSNC" runat="server" Text="0"></asp:Label>
</strong>
</h5>
</div>
<div class="col-md-12 text-start">
<span class="text-muted"><strong>Total</strong></span>
<h5><strong>
<asp:Label ID="LabelAlumnosTotal" runat="server" Text="0"></asp:Label>
</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="row">
<div class="col-md-12 mt-3" runat="server">
<div class="alert alert-light" role="alert">
<div class="table-responsive" width="100%">
<h3>Alumnos de empresas</h3>
<table class="table table-sm mb-0 table-hover" style="font-size: 12px;">
<thead>
<tr>
<th class="text-start" style="width: 20%">Tipo</th>
<th class="text-start" style="width: 5%">Cantidad</th>
</tr>
</thead>
<tbody>
<tr>
<td class="text-start" style="width: 20%">Cursos Abierto
</td>
<td class="text-start" style="width: 5%">
<asp:Label ID="Labelcnttipoabierto" runat="server" Text="0"></asp:Label>
</td>
</tr>
<tr>
<td class="text-start" style="width: 20%">Cursos Cerrado
</td>
<td class="text-start" style="width: 5%">
<asp:Label ID="Labelcnttipocerrado" runat="server" Text="0"></asp:Label>
</td>
</tr>
<tr>
<th class="text-start" style="width: 20%">Total
</th>
<th class="text-start" style="width: 5%">
<asp:Label ID="LabelcnttipoTotal" runat="server" Text="0"></asp:Label>
</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-12" runat="server">
<div class="alert alert-light text-dark" role="alert">
<div class="row">
<h4 class="text-center"><small><u>Sedes con alumnos de empresas</u></small></h4>
<div class="col-md-8 text-start">
<h1><i class="fa-solid fa-school"></i></h1>
<span class="fw-bold"><strong>Sedes</strong></span>
</div>
<div class="col-md-4 text-center mt-1">
<div class="progress" role="progressbar" aria-label="Default striped example" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar progress-bar-striped" style="width: 100%">Alumnos sin SENCE</div>
</div>
<br />
<div class="progress" role="progressbar" aria-label="Warning striped example" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar progress-bar-striped bg-warning text-dark" style="width: 100%">Alumnos con SENCE</div>
</div>
</div>
<div class="col-md-12 text-center">
<h5>
<strong>Moneda</strong>
</h5>
<div class="progress-stacked">
<div class="progress" role="progressbar" aria-label="Segment one" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div id="mone" runat="server" class="progress-bar progress-bar-striped progress-bar-animated"></div>
<div id="moneSNC" runat="server" class="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"></div>
</div>
</div>
<hr />
<h5>
<strong>Providencia</strong>
</h5>
<div class="progress-stacked">
<div class="progress" role="progressbar" aria-label="Info example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div id="prov" runat="server" class="progress-bar progress-bar-striped progress-bar-animated"></div>
<div id="provSNC" runat="server" class="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"></div>
</div>
</div>
<hr />
<h5>
<strong>La Florida</strong>
</h5>
<div class="progress-stacked">
<div class="progress" role="progressbar" aria-label="Info example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div id="flor" runat="server" class="progress-bar progress-bar-striped progress-bar-animated"></div>
<div id="florSNC" runat="server" class="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"></div>
</div>
</div>
<hr />
<h5>
<strong>Online</strong>
</h5>
<div class="progress-stacked">
<div class="progress" role="progressbar" aria-label="Info example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div id="onli" runat="server" class="progress-bar progress-bar-striped progress-bar-animated"></div>
<div id="onliSNC" runat="server" class="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"></div>
</div>
</div>
<hr />
<h5>
<strong>Empresas</strong>
</h5>
<div class="progress-stacked">
<div class="progress" role="progressbar" aria-label="Info example" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<div id="corp" runat="server" class="progress-bar progress-bar-striped progress-bar-animated"></div>
<div id="corpSNC" runat="server" class="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-5 align-middle mt-5">
<div class="row">
<div class="col-md-12" id="TipoDeVentas">
<div class="alert alert-light text-dark offcanvas-lg offcanvas-sm container-md container-sm"
role="alert">
<h3><span><b><u>Tipos de ventas</u></b></span></h3>
<canvas id="ventaPie" class="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<asp:Literal ID="Literal1" runat="server"></asp:Literal>
<script>
var pieLabels;
var pieData;
const ctz = document.getElementById('ventaPie');
new Chart(ctz, {
type: 'doughnut',
data: {
labels: pieLabels,
datasets: [{
label: 'Cantidad',
data: pieData,
borderWidth: 1
}]
},
options: {
responsive: true,
}
});
var $canvas = $("#canvas");
var $parent = $canvas.parent();
$canvas.width($parent.width());
$canvas.height($parent.height());
</script>
</asp:Content>
+1
View File
@@ -11,6 +11,7 @@
"dependencies": {
"@boxicons/react": "^1.0.3",
"bootstrap": "5.3.8",
"chart.js": "^4.5.1",
"next": "16.2.12",
"react": "19.2.4",
"react-dom": "19.2.4",
+115 -95
View File
@@ -14,9 +14,12 @@ importers:
bootstrap:
specifier: 5.3.8
version: 5.3.8(@popperjs/core@2.11.8)
chart.js:
specifier: ^4.5.1
version: 4.5.1
next:
specifier: 16.2.12
version: 16.2.12(@babel/core@7.29.7)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
version: 16.2.12(@babel/core@7.29.7(supports-color@7.2.0))(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
react:
specifier: 19.2.4
version: 19.2.4
@@ -44,10 +47,10 @@ importers:
version: 1.0.0
eslint:
specifier: ^9
version: 9.39.5
version: 9.39.5(supports-color@7.2.0)
eslint-config-next:
specifier: 16.2.12
version: 16.2.12(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
version: 16.2.12(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
typescript:
specifier: ^5
version: 5.9.3
@@ -365,6 +368,9 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@kurkle/color@0.3.4':
resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==}
'@napi-rs/wasm-runtime@1.2.0':
resolution: {integrity: sha512-kDoONqMa+VnZ4vvvu/ZUurpJ4gkZU57e7g69qpNgWhYcZFPUHZM2CEMKm+cG6ufDVALbjMvfmMjFVqaK7uEMnA==}
engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0}
@@ -802,6 +808,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
chart.js@4.5.1:
resolution: {integrity: sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==}
engines: {pnpm: '>=8'}
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
@@ -1869,20 +1879,20 @@ snapshots:
'@babel/compat-data@7.29.7': {}
'@babel/core@7.29.7':
'@babel/core@7.29.7(supports-color@7.2.0)':
dependencies:
'@babel/code-frame': 7.29.7
'@babel/generator': 7.29.7
'@babel/helper-compilation-targets': 7.29.7
'@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7)
'@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)
'@babel/helpers': 7.29.7
'@babel/parser': 7.29.7
'@babel/template': 7.29.7
'@babel/traverse': 7.29.7
'@babel/traverse': 7.29.7(supports-color@7.2.0)
'@babel/types': 7.29.7
'@jridgewell/remapping': 2.3.5
convert-source-map: 2.0.0
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
gensync: 1.0.0-beta.2
json5: 2.2.3
semver: 6.3.1
@@ -1907,19 +1917,19 @@ snapshots:
'@babel/helper-globals@7.29.7': {}
'@babel/helper-module-imports@7.29.7':
'@babel/helper-module-imports@7.29.7(supports-color@7.2.0)':
dependencies:
'@babel/traverse': 7.29.7
'@babel/traverse': 7.29.7(supports-color@7.2.0)
'@babel/types': 7.29.7
transitivePeerDependencies:
- supports-color
'@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)':
'@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@7.2.0))(supports-color@7.2.0)':
dependencies:
'@babel/core': 7.29.7
'@babel/helper-module-imports': 7.29.7
'@babel/core': 7.29.7(supports-color@7.2.0)
'@babel/helper-module-imports': 7.29.7(supports-color@7.2.0)
'@babel/helper-validator-identifier': 7.29.7
'@babel/traverse': 7.29.7
'@babel/traverse': 7.29.7(supports-color@7.2.0)
transitivePeerDependencies:
- supports-color
@@ -1944,7 +1954,7 @@ snapshots:
'@babel/parser': 7.29.7
'@babel/types': 7.29.7
'@babel/traverse@7.29.7':
'@babel/traverse@7.29.7(supports-color@7.2.0)':
dependencies:
'@babel/code-frame': 7.29.7
'@babel/generator': 7.29.7
@@ -1952,7 +1962,7 @@ snapshots:
'@babel/parser': 7.29.7
'@babel/template': 7.29.7
'@babel/types': 7.29.7
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
transitivePeerDependencies:
- supports-color
@@ -1986,17 +1996,17 @@ snapshots:
tslib: 2.8.1
optional: true
'@eslint-community/eslint-utils@4.10.1(eslint@9.39.5)':
'@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(supports-color@7.2.0))':
dependencies:
eslint: 9.39.5
eslint: 9.39.5(supports-color@7.2.0)
eslint-visitor-keys: 3.4.3
'@eslint-community/regexpp@4.12.2': {}
'@eslint/config-array@0.21.2':
'@eslint/config-array@0.21.2(supports-color@7.2.0)':
dependencies:
'@eslint/object-schema': 2.1.7
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
minimatch: 3.1.5
transitivePeerDependencies:
- supports-color
@@ -2009,10 +2019,10 @@ snapshots:
dependencies:
'@types/json-schema': 7.0.15
'@eslint/eslintrc@3.3.6':
'@eslint/eslintrc@3.3.6(supports-color@7.2.0)':
dependencies:
ajv: 6.15.0
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
espree: 10.4.0
globals: 14.0.0
ignore: 5.3.2
@@ -2164,6 +2174,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@kurkle/color@0.3.4': {}
'@napi-rs/wasm-runtime@1.2.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
dependencies:
'@emnapi/core': 1.10.0
@@ -2250,15 +2262,15 @@ snapshots:
dependencies:
csstype: 3.2.3
'@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)':
'@typescript-eslint/eslint-plugin@8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@eslint-community/regexpp': 4.12.2
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/scope-manager': 8.65.0
'@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/type-utils': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.65.0
eslint: 9.39.5
eslint: 9.39.5(supports-color@7.2.0)
ignore: 7.0.6
natural-compare: 1.4.0
ts-api-utils: 2.5.0(typescript@5.9.3)
@@ -2266,23 +2278,23 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
'@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/scope-manager': 8.65.0
'@typescript-eslint/types': 8.65.0
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.65.0(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/visitor-keys': 8.65.0
debug: 4.4.3
eslint: 9.39.5
debug: 4.4.3(supports-color@7.2.0)
eslint: 9.39.5(supports-color@7.2.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
'@typescript-eslint/project-service@8.65.0(typescript@5.9.3)':
'@typescript-eslint/project-service@8.65.0(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
'@typescript-eslint/types': 8.65.0
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -2296,13 +2308,13 @@ snapshots:
dependencies:
typescript: 5.9.3
'@typescript-eslint/type-utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
'@typescript-eslint/type-utils@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/types': 8.65.0
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
debug: 4.4.3
eslint: 9.39.5
'@typescript-eslint/typescript-estree': 8.65.0(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
debug: 4.4.3(supports-color@7.2.0)
eslint: 9.39.5(supports-color@7.2.0)
ts-api-utils: 2.5.0(typescript@5.9.3)
typescript: 5.9.3
transitivePeerDependencies:
@@ -2310,13 +2322,13 @@ snapshots:
'@typescript-eslint/types@8.65.0': {}
'@typescript-eslint/typescript-estree@8.65.0(typescript@5.9.3)':
'@typescript-eslint/typescript-estree@8.65.0(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@typescript-eslint/project-service': 8.65.0(typescript@5.9.3)
'@typescript-eslint/project-service': 8.65.0(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/tsconfig-utils': 8.65.0(typescript@5.9.3)
'@typescript-eslint/types': 8.65.0
'@typescript-eslint/visitor-keys': 8.65.0
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
minimatch: 10.2.6
semver: 7.8.5
tinyglobby: 0.2.17
@@ -2325,13 +2337,13 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@typescript-eslint/utils@8.65.0(eslint@9.39.5)(typescript@5.9.3)':
'@typescript-eslint/utils@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)':
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5)
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(supports-color@7.2.0))
'@typescript-eslint/scope-manager': 8.65.0
'@typescript-eslint/types': 8.65.0
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
eslint: 9.39.5
'@typescript-eslint/typescript-estree': 8.65.0(supports-color@7.2.0)(typescript@5.9.3)
eslint: 9.39.5(supports-color@7.2.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
@@ -2579,6 +2591,10 @@ snapshots:
ansi-styles: 4.3.0
supports-color: 7.2.0
chart.js@4.5.1:
dependencies:
'@kurkle/color': 0.3.4
client-only@0.0.1: {}
codepage@1.15.0: {}
@@ -2623,13 +2639,17 @@ snapshots:
es-errors: 1.3.0
is-data-view: 1.0.2
debug@3.2.7:
debug@3.2.7(supports-color@7.2.0):
dependencies:
ms: 2.1.3
optionalDependencies:
supports-color: 7.2.0
debug@4.4.3:
debug@4.4.3(supports-color@7.2.0):
dependencies:
ms: 2.1.3
optionalDependencies:
supports-color: 7.2.0
deep-is@0.1.4: {}
@@ -2777,18 +2797,18 @@ snapshots:
escape-string-regexp@4.0.0: {}
eslint-config-next@16.2.12(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3):
eslint-config-next@16.2.12(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3):
dependencies:
'@next/eslint-plugin-next': 16.2.12
eslint: 9.39.5
eslint-import-resolver-node: 0.3.10
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5)
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5)
eslint-plugin-react: 7.37.5(eslint@9.39.5)
eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5)
eslint: 9.39.5(supports-color@7.2.0)
eslint-import-resolver-node: 0.3.10(supports-color@7.2.0)
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(supports-color@7.2.0))
eslint-plugin-react: 7.37.5(eslint@9.39.5(supports-color@7.2.0))
eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
globals: 16.4.0
typescript-eslint: 8.65.0(eslint@9.39.5)(typescript@5.9.3)
typescript-eslint: 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
optionalDependencies:
typescript: 5.9.3
transitivePeerDependencies:
@@ -2797,52 +2817,52 @@ snapshots:
- eslint-plugin-import-x
- supports-color
eslint-import-resolver-node@0.3.10:
eslint-import-resolver-node@0.3.10(supports-color@7.2.0):
dependencies:
debug: 3.2.7
debug: 3.2.7(supports-color@7.2.0)
is-core-module: 2.16.2
resolve: 2.0.0-next.7
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5):
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.3
eslint: 9.39.5
debug: 4.4.3(supports-color@7.2.0)
eslint: 9.39.5(supports-color@7.2.0)
get-tsconfig: 4.14.0
is-bun-module: 2.0.0
stable-hash: 0.0.5
tinyglobby: 0.2.17
unrs-resolver: 1.12.2
optionalDependencies:
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5)
eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5):
eslint-module-utils@2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0):
dependencies:
debug: 3.2.7
debug: 3.2.7(supports-color@7.2.0)
optionalDependencies:
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
eslint: 9.39.5
eslint-import-resolver-node: 0.3.10
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5)
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
eslint: 9.39.5(supports-color@7.2.0)
eslint-import-resolver-node: 0.3.10(supports-color@7.2.0)
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5):
eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
array.prototype.findlastindex: 1.2.6
array.prototype.flat: 1.3.3
array.prototype.flatmap: 1.3.3
debug: 3.2.7
debug: 3.2.7(supports-color@7.2.0)
doctrine: 2.1.0
eslint: 9.39.5
eslint-import-resolver-node: 0.3.10
eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5))(eslint@9.39.5))(eslint@9.39.5)
eslint: 9.39.5(supports-color@7.2.0)
eslint-import-resolver-node: 0.3.10(supports-color@7.2.0)
eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint-import-resolver-node@0.3.10(supports-color@7.2.0))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)
hasown: 2.0.4
is-core-module: 2.16.2
is-glob: 4.0.3
@@ -2854,13 +2874,13 @@ snapshots:
string.prototype.trimend: 1.0.10
tsconfig-paths: 3.15.0
optionalDependencies:
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
transitivePeerDependencies:
- eslint-import-resolver-typescript
- eslint-import-resolver-webpack
- supports-color
eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5):
eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(supports-color@7.2.0)):
dependencies:
aria-query: 5.3.2
array-includes: 3.1.9
@@ -2870,7 +2890,7 @@ snapshots:
axobject-query: 4.1.0
damerau-levenshtein: 1.0.8
emoji-regex: 9.2.2
eslint: 9.39.5
eslint: 9.39.5(supports-color@7.2.0)
hasown: 2.0.4
jsx-ast-utils: 3.3.5
language-tags: 1.0.9
@@ -2879,18 +2899,18 @@ snapshots:
safe-regex-test: 1.1.0
string.prototype.includes: 2.0.1
eslint-plugin-react-hooks@7.1.1(eslint@9.39.5):
eslint-plugin-react-hooks@7.1.1(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0):
dependencies:
'@babel/core': 7.29.7
'@babel/core': 7.29.7(supports-color@7.2.0)
'@babel/parser': 7.29.7
eslint: 9.39.5
eslint: 9.39.5(supports-color@7.2.0)
hermes-parser: 0.25.1
zod: 4.4.3
zod-validation-error: 4.0.2(zod@4.4.3)
transitivePeerDependencies:
- supports-color
eslint-plugin-react@7.37.5(eslint@9.39.5):
eslint-plugin-react@7.37.5(eslint@9.39.5(supports-color@7.2.0)):
dependencies:
array-includes: 3.1.9
array.prototype.findlast: 1.2.5
@@ -2898,7 +2918,7 @@ snapshots:
array.prototype.tosorted: 1.1.4
doctrine: 2.1.0
es-iterator-helpers: 1.4.0
eslint: 9.39.5
eslint: 9.39.5(supports-color@7.2.0)
estraverse: 5.3.0
hasown: 2.0.4
jsx-ast-utils: 3.3.5
@@ -2923,14 +2943,14 @@ snapshots:
eslint-visitor-keys@5.0.1: {}
eslint@9.39.5:
eslint@9.39.5(supports-color@7.2.0):
dependencies:
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5)
'@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(supports-color@7.2.0))
'@eslint-community/regexpp': 4.12.2
'@eslint/config-array': 0.21.2
'@eslint/config-array': 0.21.2(supports-color@7.2.0)
'@eslint/config-helpers': 0.4.2
'@eslint/core': 0.17.0
'@eslint/eslintrc': 3.3.6
'@eslint/eslintrc': 3.3.6(supports-color@7.2.0)
'@eslint/js': 9.39.5
'@eslint/plugin-kit': 0.4.1
'@humanfs/node': 0.16.8
@@ -2940,7 +2960,7 @@ snapshots:
ajv: 6.15.0
chalk: 4.1.2
cross-spawn: 7.0.6
debug: 4.4.3
debug: 4.4.3(supports-color@7.2.0)
escape-string-regexp: 4.0.0
eslint-scope: 8.4.0
eslint-visitor-keys: 4.2.1
@@ -3352,7 +3372,7 @@ snapshots:
natural-compare@1.4.0: {}
next@16.2.12(@babel/core@7.29.7)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
next@16.2.12(@babel/core@7.29.7(supports-color@7.2.0))(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
'@next/env': 16.2.12
'@swc/helpers': 0.5.15
@@ -3361,7 +3381,7 @@ snapshots:
postcss: 8.4.31
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.4)
styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@7.2.0))(react@19.2.4)
optionalDependencies:
'@next/swc-darwin-arm64': 16.2.12
'@next/swc-darwin-x64': 16.2.12
@@ -3717,12 +3737,12 @@ snapshots:
strip-json-comments@3.1.1: {}
styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.4):
styled-jsx@5.1.6(@babel/core@7.29.7(supports-color@7.2.0))(react@19.2.4):
dependencies:
client-only: 0.0.1
react: 19.2.4
optionalDependencies:
'@babel/core': 7.29.7
'@babel/core': 7.29.7(supports-color@7.2.0)
supports-color@7.2.0:
dependencies:
@@ -3789,13 +3809,13 @@ snapshots:
possible-typed-array-names: 1.1.0
reflect.getprototypeof: 1.0.10
typescript-eslint@8.65.0(eslint@9.39.5)(typescript@5.9.3):
typescript-eslint@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3):
dependencies:
'@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5)(typescript@5.9.3))(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.65.0(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5)(typescript@5.9.3)
eslint: 9.39.5
'@typescript-eslint/eslint-plugin': 8.65.0(@typescript-eslint/parser@8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3))(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/parser': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/typescript-estree': 8.65.0(supports-color@7.2.0)(typescript@5.9.3)
'@typescript-eslint/utils': 8.65.0(eslint@9.39.5(supports-color@7.2.0))(supports-color@7.2.0)(typescript@5.9.3)
eslint: 9.39.5(supports-color@7.2.0)
typescript: 5.9.3
transitivePeerDependencies:
- supports-color
+483
View File
@@ -0,0 +1,483 @@
"use client";
import React, { useState } from "react";
import {
User,
Buildings,
Book,
UserCircle,
// Export,
CheckCircle,
// ErrorCircle,
} from "@boxicons/react";
// Interfaz para el listado de cursos
interface CursoItem {
Codigo: string;
Curso: string;
TipoCurso: string;
Periodo: string;
Titular: string;
Sede: string;
Alumnos: number;
Inicio: string;
Termino: string;
Schedule: string;
Estado: "Finalizado" | "En curso" | string;
}
export default function CursosPorMesPage() {
// Filtros de búsqueda (Mes y Año)
const [mes, setMes] = useState("1");
const [agno, setAgno] = useState(new Date().getFullYear().toString());
// Visibilidad del reporte
const [mostrarReporte, setMostrarReporte] = useState(false);
// Totales
const [empTotal, setEmpTotal] = useState("0");
const [cursosTotal, setCursosTotal] = useState("0 %");
const [almConSnc, setAlmConSnc] = useState("0");
const [almSinSnc, setAlmSinSnc] = useState("0");
const [alumnosTotal, setAlumnosTotal] = useState("0");
// Lista de cursos
const [cursos, setCursos] = useState<CursoItem[]>([]);
// Modales de estado
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState<{
show: boolean;
mensaje: string;
}>({ show: false, mensaje: "" });
// Manejador del botón Buscar
const handleBuscar = () => {
if (!agno) {
setModalAlerta({
show: true,
mensaje: "Por favor, ingrese un año válido.",
});
return;
}
setIsLoading(true);
// Simulación de carga de datos
setTimeout(() => {
setIsLoading(false);
setMostrarReporte(true);
// Datos de ejemplo
setEmpTotal("8");
setCursosTotal("90 %");
setAlmConSnc("32");
setAlmSinSnc("10");
setAlumnosTotal("42");
setCursos([
{
Codigo: "CUR-201",
Curso: "Inglés de Negocios A2",
TipoCurso: "Cerrado",
Periodo: `${agno}-${mes}`,
Titular: "Carlos Mendoza",
Sede: "Santiago Centro",
Alumnos: 12,
Inicio: `01/${mes.padStart(2, "0")}/${agno}`,
Termino: `28/${mes.padStart(2, "0")}/${agno}`,
Schedule: "Lun-Mié 10:00 - 12:00",
Estado: "Finalizado",
},
{
Codigo: "CUR-202",
Curso: "Inglés Conversacional B1",
TipoCurso: "Abierto",
Periodo: `${agno}-${mes}`,
Titular: "Patricia Silva",
Sede: "Providencia",
Alumnos: 15,
Inicio: `05/${mes.padStart(2, "0")}/${agno}`,
Termino: `30/${mes.padStart(2, "0")}/${agno}`,
Schedule: "Mar-Jue 19:00 - 21:00",
Estado: "En curso",
},
]);
}, 1000);
};
// Restablecer vista
const handleVolver = () => {
setMostrarReporte(false);
setCursos([]);
};
// Exportar Excel
const handleExportarExcel = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({
show: true,
mensaje: "El reporte en Excel ha sido generado con éxito.",
});
}, 800);
};
return (
<>
<div className="row">
<div className="col-md-12" id="cursos_periodo">
<div className="row">
{/* ENCABEZADO Y VOLVER */}
<div className="col-md-5">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Cursos por Mes</span>
</strong>
</div>
<div className="col text-end">
<button
type="button"
className="btn btn-warning text-dark btn-sm"
onClick={handleVolver}
>
<strong>Volver</strong>
</button>
</div>
</div>
</div>
</div>
{/* FILTROS MES Y AÑO */}
<div className="col-md-7">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<span className="fw-bold">Mes</span>
</div>
<div className="col">
<select
className="form-select form-select-sm"
value={mes}
onChange={(e) => setMes(e.target.value)}
>
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
<option value="6">Junio</option>
<option value="7">Julio</option>
<option value="8">Agosto</option>
<option value="9">Septiembre</option>
<option value="10">Octubre</option>
<option value="11">Noviembre</option>
<option value="12">Diciembre</option>
</select>
</div>
<div className="col">
<span className="fw-bold">Agno</span>
</div>
<div className="col">
<input
type="number"
className="form-control form-control-sm"
value={agno}
onChange={(e) => setAgno(e.target.value)}
/>
</div>
<div className="col">
<button
type="button"
className="btn btn-primary btn-sm d-grid w-100"
onClick={handleBuscar}
>
Buscar
</button>
</div>
</div>
</div>
</div>
{/* REPORTE Y RESULTADOS */}
{mostrarReporte && (
<div className="col-md-12" id="div_reporte">
<div className="row">
{/* METRICA EMPRESAS */}
<div className="col-md-2" id="promedio_emp">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<Buildings />
</h1>
<span className="fw-bold">
<strong>Empresas</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{empTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
{/* METRICA CURSOS */}
<div className="col-md-2" id="promedio_cursos">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<Book />
</h1>
<span className="fw-bold">
<strong>Cursos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{cursosTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
{/* METRICA ALUMNOS */}
<div className="col-md-6" id="Div1">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<UserCircle />
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col-md-9 text-center mt-3">
<div className="row">
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>{almConSnc}</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>{almSinSnc}</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{alumnosTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
{/* BOTÓN EXPORTAR EXCEL */}
<div className="col-md-2 mx-auto" id="Div2">
<div className="alert alert-success shadow-sm" role="alert">
<div className="row mt-2 align-items-center">
<div className="col-md-3 text-center">
<h1 className="mb-0">
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<button
type="button"
className="btn btn-link text-decoration-none p-0 d-block mx-auto"
onClick={handleExportarExcel}
>
<h5 className="mb-0 text-success">
<strong>Exportar</strong>
</h5>
</button>
</div>
</div>
</div>
</div>
{/* TABLA DE RESULTADOS */}
<div className="col-md-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "12px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "3%" }}></th>
<th className="text-center" style={{ width: "5%" }}>Tipo de Curso</th>
<th className="text-start" style={{ width: "23%" }}>Curso</th>
<th className="text-start" style={{ width: "6%" }}>Periodo</th>
<th className="text-start" style={{ width: "14%" }}>Profesor</th>
<th className="text-center" style={{ width: "7%" }}>Sede</th>
<th className="text-center" style={{ width: "4%" }}>Alumnos</th>
<th className="text-center" style={{ width: "12%" }}>Fecha</th>
<th className="text-center" style={{ width: "20%" }}>Schedule</th>
<th className="text-center" style={{ width: "8%" }}>Estado</th>
</tr>
</thead>
<tbody>
{cursos.map((item, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "3%" }}>
{item.TipoCurso === "Cerrado" ? (
<a href={`../Cursos/Administrador.aspx?codigo=${item.Codigo}&type=Cerrado`}>
<span className="badge bg-primary" style={{ fontWeight: "normal" }}>
Ver
</span>
</a>
) : (
<a href={`https://sam.norteamericano.cl/academico/Empresas/Cursos/Administrador.aspx?codigo=${item.Codigo}`}>
<span className="badge bg-primary" style={{ fontWeight: "normal" }}>
Ver
</span>
</a>
)}
</td>
<td className="text-center" style={{ width: "5%" }}>
{item.TipoCurso}
</td>
<td className="text-start" style={{ width: "23%" }}>
{`${item.Codigo} - ${item.Curso}`}
</td>
<td className="text-start" style={{ width: "6%" }}>
{item.Periodo}
</td>
<td className="text-start" style={{ width: "14%" }}>
{item.Titular}
</td>
<td className="text-center" style={{ width: "7%" }}>
{item.Sede}
</td>
<td className="text-center" style={{ width: "4%" }}>
{item.Alumnos}
</td>
<td className="text-center" style={{ width: "12%" }}>
{`${item.Inicio} || ${item.Termino}`}
</td>
<td className="text-center" style={{ width: "20%" }}>
{item.Schedule}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.Estado === "Finalizado" ? (
<span className="text-success d-inline-flex align-items-center">
<CheckCircle className="me-1" /> Finalizado
</span>
) : (
<span className="text-warning d-inline-flex align-items-center">
{/* <ErrorCircle className="me-1" /> */} En curso
</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* MODAL DE ALERTA / MENSAJE */}
{modalAlerta.show && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
aria-labelledby="resultPreAdvanced"
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="float-start mt-2">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button
type="button"
className="btn-close float-end mt-1"
aria-label="Close"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row">
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.mensaje}</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL DE CARGANDO */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="col-md-12 text-center py-3">
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<p className="mt-2 mb-0 fw-bold">Cargando información...</p>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
+285
View File
@@ -0,0 +1,285 @@
"use client";
import React, { useState } from "react";
import { User, InfoCircle } from "@boxicons/react";
// Interfaz para la estructura del listado del informe
interface InformeItem {
Codigo: string;
Curso: string;
idAlumno: string;
Alumno: string;
RegsitroAcademico: string;
idEmpresas: string;
Empresa: string;
contrato: string;
Sede: string;
Jornada: string;
Fecha: string;
}
export default function InformeCursosPage() {
// Estados para textos e información dinámica
const [mensajeLabel, setMensajeLabel] = useState("Información del reporte cargada correctamente.");
const [fechTypeLabel, setFechTypeLabel] = useState("Fecha Inicio");
// Estado para el listado de datos
const [informeList, setInformeList] = useState<InformeItem[]>([
{
Codigo: "CUR-101",
Curso: "Inglés Técnico para Empresas",
idAlumno: "18.765.432-1",
Alumno: "Roberto Gómez",
RegsitroAcademico: "REG-2026-01",
idEmpresas: "76.543.210-K",
Empresa: "Servicios Tecnológicos SpA",
contrato: "CTR-88",
Sede: "Santiago Centro",
Jornada: "Vespertina",
Fecha: "15/03/2026",
},
{
Codigo: "CUR-102",
Curso: "Inglés Negocios B1",
idAlumno: "19.123.456-7",
Alumno: "Andrea Morales",
RegsitroAcademico: "REG-2026-02",
idEmpresas: "77.111.222-3",
Empresa: "Consultoras Unidas S.A.",
contrato: "CTR-92",
Sede: "Providencia",
Jornada: "Diurna",
Fecha: "18/03/2026",
},
]);
// Estados para modales
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState<{
show: boolean;
mensaje: string;
}>({ show: false, mensaje: "" });
// Evento para descargar Excel
const handleDescargarExcel = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({
show: true,
mensaje: "El archivo Excel se ha generado y descargado con éxito.",
});
}, 1200);
};
return (
<>
<div className="row">
<div className="col-md-12">
<div className="row">
{/* ENCABEZADO Y BOTÓN VOLVER */}
<div className="col-md-5">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Informe</span>
</strong>
</div>
<div className="col text-end">
<a
href="../Cursos/Index.aspx"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</a>
</div>
</div>
</div>
</div>
{/* SECCIÓN INFORMACIÓN Y DESCARGA EXCEL */}
<div className="col-md-7">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col m-1 d-flex align-items-center">
<strong>
<InfoCircle style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="fw-bold ms-2">{mensajeLabel}</span>
</strong>
</div>
<div className="col m-1 text-end">
<button
type="button"
className="btn btn-success"
onClick={handleDescargarExcel}
>
Descargar Excel
</button>
</div>
</div>
</div>
</div>
{/* TABLA PRINCIPAL DEL INFORME */}
<div className="col-md-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="table-responsive">
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "5%" }}>
Curso ID
</th>
<th className="text-start" style={{ width: "15%" }}>
Curso
</th>
<th className="text-start" style={{ width: "7%" }}>
Alumno RUN
</th>
<th className="text-start" style={{ width: "15%" }}>
Alumno
</th>
<th className="text-start" style={{ width: "7%" }}>
Registro
</th>
<th className="text-start" style={{ width: "7%" }}>
Empresa Rut
</th>
<th className="text-start" style={{ width: "15%" }}>
Empresa
</th>
<th className="text-start" style={{ width: "5%" }}>
Contrato
</th>
<th className="text-start" style={{ width: "6%" }}>
Sede
</th>
<th className="text-start" style={{ width: "6%" }}>
Jornada
</th>
<th className="text-center" style={{ width: "12%" }}>
{fechTypeLabel} Curso
</th>
</tr>
</thead>
<tbody>
{informeList.map((item, index) => (
<tr key={index}>
<td className="text-start" style={{ width: "5%" }}>
{item.Codigo}
</td>
<td className="text-start" style={{ width: "15%" }}>
{item.Curso}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.idAlumno}
</td>
<td className="text-start" style={{ width: "15%" }}>
{item.Alumno}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.RegsitroAcademico}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.idEmpresas}
</td>
<td className="text-start" style={{ width: "15%" }}>
{item.Empresa}
</td>
<td className="text-start" style={{ width: "5%" }}>
{item.contrato}
</td>
<td className="text-start" style={{ width: "6%" }}>
{item.Sede}
</td>
<td className="text-start" style={{ width: "6%" }}>
{item.Jornada}
</td>
<td className="text-center" style={{ width: "12%" }}>
{item.Fecha}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ALERTA / MENSAJE DE ERROR O ÉXITO */}
{modalAlerta.show && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="float-start mt-2">
<strong>Módulo Académico - Informe</strong>
</h5>
<button
type="button"
className="btn-close float-end mt-1"
aria-label="Close"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row">
<div className="col-md-12 text-center py-2">
<h5>
<strong>{modalAlerta.mensaje}</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL DE CARGANDO / LOADING */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="col-md-12 text-center py-3">
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Procesando...</span>
</div>
<p className="mt-2 mb-0 fw-bold">Procesando descarga...</p>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
+483
View File
@@ -0,0 +1,483 @@
"use client";
import React, { useState } from "react";
import {
User,
Buildings,
Book,
UserCircle,
//Export,
CheckCircle,
//ErrorCircle,
} from "@boxicons/react";
// Interfaz para la estructura del listado de cursos
interface CursoItem {
Codigo: string;
Curso: string;
TipoCurso: string;
Periodo: string;
Titular: string;
Sede: string;
Alumnos: number;
Inicio: string;
Termino: string;
Schedule: string;
Estado: "Finalizado" | "En curso" | string;
}
export default function CursosIniciadosPage() {
// Filtros de fecha
const [fechaInicio, setFechaInicio] = useState("");
const [fechaTermino, setFechaTermino] = useState("");
// Visibilidad de datos / reporte
const [mostrarReporte, setMostrarReporte] = useState(false);
// Totales
const [empTotal, setEmpTotal] = useState("0");
const [cursosTotal, setCursosTotal] = useState("0 %");
const [almConSnc, setAlmConSnc] = useState("0");
const [almSinSnc, setAlmSinSnc] = useState("0");
const [alumnosTotal, setAlumnosTotal] = useState("0");
// Lista de datos
const [cursos, setCursos] = useState<CursoItem[]>([]);
// Modals de estado
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState<{
show: boolean;
mensaje: string;
}>({ show: false, mensaje: "" });
// Manejador del botón Buscar
const handleBuscar = () => {
if (!fechaInicio || !fechaTermino) {
setModalAlerta({
show: true,
mensaje: "Por favor, seleccione un rango de fechas válido.",
});
return;
}
setIsLoading(true);
// Simulación de consulta API
setTimeout(() => {
setIsLoading(false);
setMostrarReporte(true);
// Datos ficticios de prueba basados en el modelo
setEmpTotal("12");
setCursosTotal("85 %");
setAlmConSnc("45");
setAlmSinSnc("15");
setAlumnosTotal("60");
setCursos([
{
Codigo: "CUR-001",
Curso: "Inglés Avanzado B2",
TipoCurso: "Cerrado",
Periodo: "2026-1",
Titular: "Juan Pérez",
Sede: "Santiago Centro",
Alumnos: 15,
Inicio: "01/03/2026",
Termino: "30/06/2026",
Schedule: "Lun-Mié 09:00 - 11:00",
Estado: "Finalizado",
},
{
Codigo: "CUR-002",
Curso: "Inglés Intermedio A2",
TipoCurso: "Abierto",
Periodo: "2026-1",
Titular: "María González",
Sede: "Providencia",
Alumnos: 20,
Inicio: "10/03/2026",
Termino: "15/07/2026",
Schedule: "Mar-Jue 18:30 - 20:30",
Estado: "En curso",
},
]);
}, 1000);
};
// Manejador para volver o limpiar
const handleVolver = () => {
setMostrarReporte(false);
setFechaInicio("");
setFechaTermino("");
setCursos([]);
};
// Manejador para exportar a Excel
const handleExportarExcel = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({
show: true,
mensaje: "El reporte en Excel ha sido generado con éxito.",
});
}, 800);
};
return (
<>
<div className="row">
<div className="col-md-12" id="cursos_periodo">
<div className="row">
{/* ENCABEZADO Y BOTÓN VOLVER */}
<div className="col-md-5">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Cursos iniciados por fecha</span>
</strong>
</div>
<div className="col text-end">
<button
type="button"
className="btn btn-warning text-dark btn-sm"
onClick={handleVolver}
>
<strong>Volver</strong>
</button>
</div>
</div>
</div>
</div>
{/* FILTROS DE FECHA Y BÚSQUEDA */}
<div className="col-md-7">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<span className="fw-bold">Inicio</span>
</div>
<div className="col">
<input
type="date"
className="form-control form-control-sm"
value={fechaInicio}
onChange={(e) => setFechaInicio(e.target.value)}
/>
</div>
<div className="col">
<span className="fw-bold">Termino</span>
</div>
<div className="col">
<input
type="date"
className="form-control form-control-sm"
value={fechaTermino}
onChange={(e) => setFechaTermino(e.target.value)}
/>
</div>
<div className="col">
<button
type="button"
className="btn btn-primary btn-sm d-grid w-100"
onClick={handleBuscar}
>
Buscar
</button>
</div>
</div>
</div>
</div>
{/* SECCIÓN REPORTE / RESULTADOS */}
{mostrarReporte && (
<div className="col-md-12" id="div_reporte">
<div className="row">
{/* METRICA EMPRESAS */}
<div className="col-md-2" id="promedio_emp">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<Buildings />
</h1>
<span className="fw-bold">
<strong>Empresas</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{empTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
{/* METRICA CURSOS */}
<div className="col-md-2" id="promedio_cursos">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<Book />
</h1>
<span className="fw-bold">
<strong>Cursos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{cursosTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
{/* METRICA ALUMNOS */}
<div className="col-md-6" id="Div1">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1 className="mb-0">
<UserCircle />
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col-md-9 text-center mt-3">
<div className="row">
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>{almConSnc}</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>{almSinSnc}</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>{alumnosTotal}</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
{/* BOTÓN EXPORTAR EXCEL */}
<div className="col-md-2 mx-auto" id="Div2">
<div className="alert alert-success shadow-sm" role="alert">
<div className="row mt-2 align-items-center">
<div className="col-md-3 text-center">
<h1 className="mb-0">
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<button
type="button"
className="btn btn-link text-decoration-none p-0 d-block mx-auto"
onClick={handleExportarExcel}
>
<h5 className="mb-0 text-success">
<strong>Exportar</strong>
</h5>
</button>
</div>
</div>
</div>
</div>
{/* TABLA DE RESULTADOS */}
<div className="col-md-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "12px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "3%" }}></th>
<th className="text-center" style={{ width: "5%" }}>Tipo de Curso</th>
<th className="text-start" style={{ width: "23%" }}>Curso</th>
<th className="text-start" style={{ width: "6%" }}>Periodo</th>
<th className="text-start" style={{ width: "14%" }}>Profesor</th>
<th className="text-center" style={{ width: "7%" }}>Sede</th>
<th className="text-center" style={{ width: "4%" }}>Alumnos</th>
<th className="text-center" style={{ width: "12%" }}>Fecha</th>
<th className="text-center" style={{ width: "20%" }}>Schedule</th>
<th className="text-center" style={{ width: "8%" }}>Estado</th>
</tr>
</thead>
<tbody>
{cursos.map((item, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "3%" }}>
{item.TipoCurso === "Cerrado" ? (
<a
href={`../Cursos/Administrador.aspx?codigo=${item.Codigo}&type=Cerrado`}
>
<span
className="badge bg-primary"
style={{ fontWeight: "normal" }}
>
Ver
</span>
</a>
) : (
<a
href={`https://modulos.sam.norteamericano.cl/proyectoSam/Cursos/Administrador.aspx?codigo=${item.Codigo}`}
>
<span
className="badge bg-primary"
style={{ fontWeight: "normal" }}
>
Ver
</span>
</a>
)}
</td>
<td className="text-center" style={{ width: "5%" }}>
{item.TipoCurso}
</td>
<td className="text-start" style={{ width: "23%" }}>
{`${item.Codigo} - ${item.Curso}`}
</td>
<td className="text-start" style={{ width: "6%" }}>
{item.Periodo}
</td>
<td className="text-start" style={{ width: "14%" }}>
{item.Titular}
</td>
<td className="text-center" style={{ width: "7%" }}>
{item.Sede}
</td>
<td className="text-center" style={{ width: "4%" }}>
{item.Alumnos}
</td>
<td className="text-center" style={{ width: "12%" }}>
{`${item.Inicio} || ${item.Termino}`}
</td>
<td className="text-center" style={{ width: "20%" }}>
{item.Schedule}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.Estado === "Finalizado" ? (
<span className="text-success d-inline-flex align-items-center">
<CheckCircle className="me-1" /> Finalizado
</span>
) : (
<span className="text-warning d-inline-flex align-items-center">
{/* <ErrorCircle className="me-1" /> En curso */}
</span>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* MODAL DE ALERTA / MENSAJE */}
{modalAlerta.show && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
aria-labelledby="resultPreAdvanced"
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="float-start mt-2">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button
type="button"
className="btn-close float-end mt-1"
aria-label="Close"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row">
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.mensaje}</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, mensaje: "" })}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL DE CARGANDO */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="col-md-12 text-center py-3">
<div className="spinner-border text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<p className="mt-2 mb-0 fw-bold">Cargando información...</p>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
+649
View File
@@ -0,0 +1,649 @@
"use client";
import React, { useState, useEffect } from "react";
import Link from "next/link";
import {
User,
// AlertOctagon,
// Export,
Buildings,
UserCircle,
BookLibrary,
// Error as ErrorIcon,
} from "@boxicons/react";
import Chart from "chart.js/auto";
export default function AlumnosPorMesPage() {
// Estados para controlar las vistas
const [divReporteV2, setDivReporteV2] = useState(true);
const [divReporte, setDivReporte] = useState(false);
// Estados para modales
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("");
// Datos simulados para tablas
const [regiones] = useState([
{ Region: "Región Metropolitana", Cantidad: 150 },
{ Region: "Valparaíso", Cantidad: 45 },
]);
const [comunas] = useState([
{ Comuna: "Santiago", Cantidad: 80 },
{ Comuna: "Providencia", Cantidad: 70 },
]);
// Manejador de búsqueda
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setShowLoadingModal(true);
setTimeout(() => {
setShowLoadingModal(false);
}, 1500);
};
// Inicialización de gráficos Chart.js
useEffect(() => {
// Gráfico de Ocupación (Bar)
const ctxOcupacion = document.getElementById(
"OcupacionBar"
) as HTMLCanvasElement;
let chartOcupacion: Chart | null = null;
if (ctxOcupacion) {
chartOcupacion = new Chart(ctxOcupacion, {
type: "bar",
data: {
labels: ["Enero", "Febrero", "Marzo"],
datasets: [
{
label: "Cantidad",
data: [12, 19, 3],
borderWidth: 1,
},
],
},
options: { responsive: true },
});
}
// Gráfico de Profesiones (Pie)
const ctxProfesion = document.getElementById(
"ProfesionPies"
) as HTMLCanvasElement;
let chartProfesion: Chart | null = null;
if (ctxProfesion) {
chartProfesion = new Chart(ctxProfesion, {
type: "pie",
data: {
labels: ["Ingeniería", "Medicina", "Educación", "Otros"],
datasets: [
{
label: "Cantidad",
data: [30, 20, 15, 35],
},
],
},
options: { responsive: true },
});
}
// Limpieza al desmontar componente
return () => {
if (chartOcupacion) chartOcupacion.destroy();
if (chartProfesion) chartProfesion.destroy();
};
}, [divReporteV2]);
return (
<div className="container-fluid py-3">
<div className="row">
{/* Encabezado y Filtros */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Alumnos por Mes</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Alumnos/Index"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</Link>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col">
<span className="fw-bold">Mes</span>
</div>
<div className="col">
<select id="ListaMeses" className="form-select form-select-sm">
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
{/* Agregar el resto de los meses */}
</select>
</div>
<div className="col">
<span className="fw-bold">Año</span>
</div>
<div className="col">
<input
type="number"
id="TextBoxAgno"
className="form-control form-control-sm"
defaultValue={2026}
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
>
Buscar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{/* Reporte V2 */}
{divReporteV2 && (
<div className="col-md-12" id="div_reporteV2">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
{/* Columna Izquierda (Totales, Exportar y Grafico Bar) */}
<div className="col-md-3 mt-5">
<div className="row">
<div className="col-md-12 mt-3 mx-auto">
<button
type="button"
className="btn p-0 border-0 w-100 text-decoration-none"
onClick={() => {
setMensajeAlerta("Generando reporte Excel...");
setShowAlertModal(true);
}}
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1>
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5>
<strong>Exportar</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-12 mt-3">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<UserCircle />
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12 mt-3" id="Ocupacion">
<div
className="alert alert-light shadow text-dark offcanvas-lg offcanvas-sm"
role="alert"
>
<canvas id="OcupacionBar" className="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
{/* Columna Central (Tablas Regiones y Comunas) */}
<div className="col-md-4">
<div className="row">
<div className="col-md-12 mt-3">
<div className="alert alert-light" role="alert">
<div className="table-responsive">
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Regiones
</th>
<th className="text-start" style={{ width: "20%" }}>
Cantidad
</th>
</tr>
</thead>
<tbody>
{regiones.map((item, index) => (
<tr key={index}>
<td className="text-start">{item.Region}</td>
<td className="text-start">{item.Cantidad}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light" role="alert">
<div className="table-responsive">
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Comuna
</th>
<th className="text-start" style={{ width: "20%" }}>
Cantidad
</th>
</tr>
</thead>
<tbody>
{comunas.map((item, index) => (
<tr key={index}>
<td className="text-start">{item.Comuna}</td>
<td className="text-start">{item.Cantidad}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{/* Columna Derecha (Gráfico de Profesiones) */}
<div className="col-md-5">
<div className="row">
<div className="col-md-12" id="Profesion">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm"
role="alert"
>
<h3>
<span>
<b>
<u>Profesiones</u>
</b>
</span>
</h3>
<canvas
id="ProfesionPies"
className="w-100 h-100"
></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* Reporte V1 (Oculto por defecto) */}
{divReporte && (
<div className="col-md-12" id="div_reporte">
<div className="row">
<div className="col-md-2">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<Buildings />
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-2">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<Buildings />
</h1>
<span className="fw-bold">
<strong>Cursos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-6">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<UserCircle />
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col-md-9 text-center mt-3">
<div className="row">
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-4">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<Buildings />
</h1>
<span className="fw-bold">
<strong>Empresas</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-4" id="resize">
<div className="alert alert-light shadow text-dark offcanvas-lg" role="alert">
<canvas id="myChart" className="w-100 h-100"></canvas>
</div>
</div>
<div className="col-md-2">
<div className="alert alert-primary" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<BookLibrary />
</h1>
<span className="fw-bold">
<strong>Alumnos por Planes</strong>
</span>
</div>
<div className="col-md-9 text-center mt-3" style={{ fontSize: "14px" }}>
<div className="row g-0 text-center">
<div className="col-6 col-md-4">
<span className="fw-bold">
<strong>Adults</strong>
</span>
</div>
<div className="col-sm-6 col-md-8">
<strong>0</strong>
</div>
</div>
<div className="row g-0 text-center">
<div className="col-6 col-md-4">
<span className="fw-bold">
<strong>Business</strong>
</span>
</div>
<div className="col-sm-6 col-md-8">
<strong>0</strong>
</div>
</div>
<div className="row g-0 text-center">
<div className="col-6 col-md-4">
<span className="fw-bold">
<strong>Teens</strong>
</span>
</div>
<div className="col-sm-6 col-md-8">
<strong>0</strong>
</div>
</div>
<div className="row g-0 text-center">
<div className="col-6 col-md-4">
<span className="fw-bold">
<strong>Kids</strong>
</span>
</div>
<div className="col-sm-6 col-md-8">
<strong>0</strong>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-4">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1>
<UserCircle />
</h1>
<span className="fw-bold">
<strong>Condicion de registro</strong>
</span>
</div>
<div className="col-md-9 text-center mt-3">
<div className="row">
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Plan Central</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Curso Cerrado</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-4" id="resizev2">
<div className="alert alert-light shadow text-dark offcanvas-lg" role="alert">
<canvas id="myLines" className="w-100 h-100"></canvas>
</div>
</div>
<div className="col-md-4" id="resizev3">
<div className="alert alert-light shadow text-dark offcanvas-lg" role="alert">
<canvas id="myPies" className="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
)}
</div>
{/* MODAL DE MENSAJES/ALERTAS */}
{showAlertModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>Módulo Académico - Reporte</strong>
</h5>
<button
type="button"
className="btn-close"
onClick={() => setShowAlertModal(false)}
></button>
</div>
<div className="modal-body text-center">
<h5>
<strong>{mensajeAlerta}</strong>
</h5>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowAlertModal(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{showLoadingModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>SAM - Académico Empresas</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5>
<strong>Procesando, espere un momento...</strong>
</h5>
<div className="mt-3">
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+658
View File
@@ -0,0 +1,658 @@
"use client";
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { User,
//Export
} from "@boxicons/react";
export default function CursosPorMesPage() {
// Estados para modales
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("");
// Datos simulados para la tabla de Planes (DataList en ASP.NET)
const [planes] = useState([
{ Plan: "Intensivo Adults", Cantidad: 45 },
{ Plan: "Regular Kids", Cantidad: 30 },
{ Plan: "Business Express", Cantidad: 25 },
]);
// Manejo de búsqueda
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setShowLoadingModal(true);
setTimeout(() => {
setShowLoadingModal(false);
}, 1500);
};
// Manejo de exportación a Excel
const handleExportarExcel = (e: React.MouseEvent) => {
e.preventDefault();
setMensajeAlerta("Generando y descargando archivo Excel...");
setShowAlertModal(true);
};
// Carga de Chart.js mediante importación dinámica
useEffect(() => {
let chartJornadas: any = null;
let chartPlan: any = null;
import("chart.js/auto").then(({ default: Chart }) => {
// Gráfico de Jornadas (Bar)
const ctxJornadas = document.getElementById(
"jornadasBar"
) as HTMLCanvasElement;
if (ctxJornadas) {
chartJornadas = new Chart(ctxJornadas, {
type: "bar",
data: {
labels: ["Mañana", "Tarde", "Noche", "Sábado"],
datasets: [
{
label: "Cantidad",
data: [15, 25, 40, 10],
borderWidth: 1,
},
],
},
options: {
responsive: true,
},
});
}
// Gráfico de Programas (Pie)
const ctxPlan = document.getElementById("planPie") as HTMLCanvasElement;
if (ctxPlan) {
chartPlan = new Chart(ctxPlan, {
type: "pie",
data: {
labels: ["Adults", "Kids", "Teens", "Business"],
datasets: [
{
label: "Cantidad",
data: [45, 30, 15, 25],
},
],
},
options: {
maintainAspectRatio: false,
responsive: true,
plugins: {
legend: {
position: "left",
labels: {
font: {
size: 11,
},
},
},
},
},
});
}
});
return () => {
if (chartJornadas) chartJornadas.destroy();
if (chartPlan) chartPlan.destroy();
};
}, []);
return (
<div className="container-fluid py-3">
<div className="row">
{/* Filtros superiores */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Cursos por mes</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Alumnos/Index"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</Link>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col">
<span className="fw-bold">Mes</span>
</div>
<div className="col">
<select
id="ListaMeses"
className="form-select form-select-sm"
>
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
<option value="6">Junio</option>
<option value="7">Julio</option>
<option value="8">Agosto</option>
<option value="9">Septiembre</option>
<option value="10">Octubre</option>
<option value="11">Noviembre</option>
<option value="12">Diciembre</option>
</select>
</div>
<div className="col">
<span className="fw-bold">Año</span>
</div>
<div className="col">
<input
type="number"
id="TextBoxAgno"
className="form-control form-control-sm"
defaultValue={2026}
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
>
Buscar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{/* Sección Reporte Principal */}
<div className="col-md-12" id="div_reporte">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
{/* Columna Izquierda: Tarjetas y métricas */}
<div className="col-md-3 mt-5">
<div className="row">
<div className="col-md-12 mx-auto">
<button
type="button"
onClick={handleExportarExcel}
className="btn p-0 border-0 w-100 text-decoration-none"
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1>
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5>
<strong>Exportar</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<i className="fa-solid fa-users-line"></i>
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<i className="fa-solid fa-book"></i>
</h1>
<span className="fw-bold">
<strong>Cursos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
<div className="col-md-12 text-start">
<h1>
<i className="fa-solid fa-swatchbook"></i>
</h1>
<span className="fw-bold">
<strong>Inscripción de Alumnos</strong>
</span>
</div>
<div className="col-md-12 text-start mt-2">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Columna Central: Tabla de Planes y Progreso de Sedes */}
<div className="col-md-4">
<div className="row">
<div className="col-md-12 mt-3">
<div className="alert alert-light" role="alert">
<div className="table-responsive" style={{ width: "100%" }}>
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Plan
</th>
<th className="text-start" style={{ width: "20%" }}>
Cantidad
</th>
</tr>
</thead>
<tbody>
{planes.map((item, index) => (
<tr key={index}>
<td className="text-start">{item.Plan}</td>
<td className="text-start">{item.Cantidad}</td>
</tr>
))}
</tbody>
</table>
<table
className="table table-sm mb-0 table-hover mt-2"
style={{ fontSize: "12px", width: "100%" }}
>
<tbody>
<tr>
<th className="text-start" style={{ width: "80%" }}>
<strong>TOTAL</strong>
</th>
<td className="text-start fw-bold" style={{ width: "20%" }}>
{planes.reduce((acc, curr) => acc + curr.Cantidad, 0)}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<h4 className="text-center">
<small>
<u>Cursos por sedes con alumnos de empresas</u>
</small>
</h4>
<div className="col-md-8 text-start">
<h1>
<i className="fa-solid fa-school"></i>
</h1>
<span className="fw-bold">
<strong>Sedes</strong>
</span>
</div>
<div className="col-md-4 text-center mt-1">
<div
className="progress"
role="progressbar"
aria-label="Default striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped"
style={{ width: "100%" }}
>
Cursos sin SENCE
</div>
</div>
<br />
<div
className="progress"
role="progressbar"
aria-label="Warning striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped bg-warning text-dark"
style={{ width: "100%" }}
>
Cursos con SENCE
</div>
</div>
</div>
<div className="col-md-12 text-center mt-3">
<h5>
<strong>Moneda</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Segment one"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="mone"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "50%" }}
></div>
<div
id="moneSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "50%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Providencia</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="prov"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "60%" }}
></div>
<div
id="provSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "40%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>La Florida</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="flor"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "70%" }}
></div>
<div
id="florSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "30%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Online</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="onli"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "80%" }}
></div>
<div
id="onliSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "20%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Empresas</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="corp"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "40%" }}
></div>
<div
id="corpSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "60%" }}
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Columna Derecha: Gráficos de Jornadas y Programas */}
<div className="col-md-5 align-middle">
<div className="row">
<div className="col-md-12" id="Jornadas">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm"
role="alert"
>
<h3>
<span>
<b>
<u>Jornadas</u>
</b>
</span>
</h3>
<canvas id="jornadasBar" className="w-100 h-100"></canvas>
</div>
</div>
<div className="col-md-12" id="Programas">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm container-md container-sm"
style={{ height: "40vh" }}
role="alert"
>
<h3>
<span>
<b>
<u>Programas</u>
</b>
</span>
</h3>
<canvas id="planPie" className="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL ALERTA / MENSAJES */}
{showAlertModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>Módulo Académico - Cursos</strong>
</h5>
<button
type="button"
className="btn-close"
onClick={() => setShowAlertModal(false)}
></button>
</div>
<div className="modal-body text-center py-3">
<h5>
<strong>{mensajeAlerta}</strong>
</h5>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowAlertModal(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{showLoadingModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>SAM - Académico Empresas</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5>
<strong>Procesando, espere un momento...</strong>
</h5>
<div className="mt-3">
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+666
View File
@@ -0,0 +1,666 @@
"use client";
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { User } from "@boxicons/react";
export default function CursosPlanCentralPage() {
// Estado para visibilidad del reporte (corresponde a visible="false" en ASP.NET)
const [divReporte, setDivReporte] = useState(true);
// Estados para modales de carga y mensajes/errores
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("");
// Estado para los filtros de Periodo y Letras
const [periodo, setPeriodo] = useState("");
const [letras, setLetras] = useState<string[]>([]);
// Datos para la tabla de Planes (DataList en ASP.NET)
const [planes] = useState([
{ Plan: "Plan Central General", Cantidad: 35 },
{ Plan: "Plan Intensivo", Cantidad: 20 },
]);
// Evento al cambiar Periodo (simula el AutoPostBack de ASP.NET)
const handlePeriodoChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const val = e.target.value;
setPeriodo(val);
// Actualización dinámica de select según el periodo seleccionado
if (val === "1") {
setLetras(["A", "B", "C"]);
} else if (val === "2") {
setLetras(["D", "E", "F"]);
} else {
setLetras([]);
}
};
// Manejo de búsqueda
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setShowLoadingModal(true);
setTimeout(() => {
setShowLoadingModal(false);
setDivReporte(true); // Hace visible el reporte tras buscar
}, 1200);
};
// Exportar a Excel
const handleExportarExcel = (e: React.MouseEvent) => {
e.preventDefault();
setMensajeAlerta("Generando y exportando reporte Excel...");
setShowAlertModal(true);
};
// Inicialización de Chart.js dinámico en cliente
useEffect(() => {
if (!divReporte) return;
let chartJornadas: any = null;
let chartPlan: any = null;
import("chart.js/auto").then(({ default: Chart }) => {
// Gráfico de Jornadas (Bar)
const ctxJornadas = document.getElementById(
"jornadasBar"
) as HTMLCanvasElement;
if (ctxJornadas) {
chartJornadas = new Chart(ctxJornadas, {
type: "bar",
data: {
labels: ["Mañana", "Tarde", "Noche"],
datasets: [
{
label: "Cantidad",
data: [12, 19, 8],
borderWidth: 1,
},
],
},
options: {
responsive: true,
},
});
}
// Gráfico de Programas (Pie)
const ctxPlan = document.getElementById("planPie") as HTMLCanvasElement;
if (ctxPlan) {
chartPlan = new Chart(ctxPlan, {
type: "pie",
data: {
labels: ["Programa A", "Programa B", "Programa C"],
datasets: [
{
label: "Cantidad",
data: [20, 15, 10],
borderWidth: 1,
},
],
},
options: {
maintainAspectRatio: false,
responsive: true,
plugins: {
legend: {
position: "left",
labels: {
font: {
size: 11,
},
},
},
},
},
});
}
});
return () => {
if (chartJornadas) chartJornadas.destroy();
if (chartPlan) chartPlan.destroy();
};
}, [divReporte]);
return (
<div className="container-fluid py-3">
<div className="row">
{/* Encabezado y Filtros */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">
Cursos plan central por mes
</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Alumnos/Index"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</Link>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col">
<span className="fw-bold">Año</span>
</div>
<div className="col">
<input
type="number"
id="TextBoxAgno"
className="form-control form-control-sm"
defaultValue={2026}
/>
</div>
<div className="col">
<span className="fw-bold">Periodo</span>
</div>
<div className="col">
<select
id="ListaPeriodo"
className="form-select form-select-sm"
value={periodo}
onChange={handlePeriodoChange}
>
<option value="">Seleccione</option>
<option value="1">Periodo 1</option>
<option value="2">Periodo 2</option>
</select>
</div>
<div className="col">
<select
id="ListaLetras"
className="form-select form-select-sm"
>
{letras.map((item, index) => (
<option key={index} value={item}>
{item}
</option>
))}
</select>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
>
Buscar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{/* Sección Reporte Principal */}
{divReporte && (
<div className="col-md-12" id="div_reporte">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
{/* Métricas y Tarjetas Izquierda */}
<div className="col-md-3 mt-5">
<div className="row">
<div className="col-md-12 mx-auto">
<button
type="button"
onClick={handleExportarExcel}
className="btn p-0 border-0 w-100 text-decoration-none"
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1>
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5>
<strong>Exportar</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<i className="fa-solid fa-users-line"></i>
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<i className="fa-solid fa-book"></i>
</h1>
<span className="fw-bold">
<strong>Cursos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
<div className="col-md-12 text-start">
<h1>
<i className="fa-solid fa-swatchbook"></i>
</h1>
<span className="fw-bold">
<strong>Inscripción de Alumnos</strong>
</span>
</div>
<div className="col-md-12 text-start mt-2">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Tabla de Planes y Progreso de Sedes */}
<div className="col-md-4">
<div className="row">
<div className="col-md-12 mt-3">
<div className="alert alert-light" role="alert">
<div className="table-responsive" style={{ width: "100%" }}>
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Plan
</th>
<th className="text-start" style={{ width: "20%" }}>
Cantidad
</th>
</tr>
</thead>
<tbody>
{planes.map((item, index) => (
<tr key={index}>
<td className="text-start">{item.Plan}</td>
<td className="text-start">{item.Cantidad}</td>
</tr>
))}
</tbody>
</table>
<table
className="table table-sm mb-0 table-hover mt-2"
style={{ fontSize: "12px", width: "100%" }}
>
<tbody>
<tr>
<th className="text-start" style={{ width: "80%" }}>
<strong>TOTAL</strong>
</th>
<td className="text-start fw-bold" style={{ width: "20%" }}>
{planes.reduce((acc, curr) => acc + curr.Cantidad, 0)}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<h4 className="text-center">
<small>
<u>Cursos por sedes con Alumnos de empresas</u>
</small>
</h4>
<div className="col-md-8 text-start">
<h1>
<i className="fa-solid fa-school"></i>
</h1>
<span className="fw-bold">
<strong>Sedes</strong>
</span>
</div>
<div className="col-md-4 text-center mt-1">
<div
className="progress"
role="progressbar"
aria-label="Default striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped"
style={{ width: "100%" }}
>
Cursos sin SENCE
</div>
</div>
<br />
<div
className="progress"
role="progressbar"
aria-label="Warning striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped bg-warning text-dark"
style={{ width: "100%" }}
>
Cursos con SENCE
</div>
</div>
</div>
<div className="col-md-12 text-center mt-3">
<h5>
<strong>Moneda</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Segment one"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="mone"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "50%" }}
></div>
<div
id="moneSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "50%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Providencia</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="prov"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "60%" }}
></div>
<div
id="provSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "40%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>La Florida</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="flor"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "70%" }}
></div>
<div
id="florSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "30%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Online</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="onli"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "80%" }}
></div>
<div
id="onliSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "20%" }}
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Canvas de Gráficos */}
<div className="col-md-5 align-middle">
<div className="row">
<div className="col-md-12" id="Jornadas">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm"
role="alert"
>
<h3>
<span>
<b>
<u>Jornadas</u>
</b>
</span>
</h3>
<canvas id="jornadasBar" className="w-100 h-100"></canvas>
</div>
</div>
<div className="col-md-12" id="Programas">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm container-md container-sm"
style={{ height: "40vh" }}
role="alert"
>
<h3>
<span>
<b>
<u>Programas</u>
</b>
</span>
</h3>
<canvas id="planPie" className="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
{/* MODAL ALERTA / MENSAJES */}
{showAlertModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>Módulo Académico - Plan Central</strong>
</h5>
<button
type="button"
className="btn-close"
onClick={() => setShowAlertModal(false)}
></button>
</div>
<div className="modal-body text-center py-3">
<h5>
<strong>{mensajeAlerta}</strong>
</h5>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowAlertModal(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{showLoadingModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>SAM - Académico Empresas</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5>
<strong>Procesando, espere un momento...</strong>
</h5>
<div className="mt-3">
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+611
View File
@@ -0,0 +1,611 @@
"use client";
import React, { useState, useEffect } from "react";
import Link from "next/link";
import { User, BuildingHouse } from "@boxicons/react";
export default function EmpresasPorMesPage() {
// Estado de visibilidad del reporte principal (div_reporte)
const [divReporte, setDivReporte] = useState(true);
// Estados para modales de Carga y Alertas/Errores
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("");
// Manejo de búsqueda
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setShowLoadingModal(true);
setTimeout(() => {
setShowLoadingModal(false);
setDivReporte(true);
}, 1200);
};
// Manejo de exportación Excel
const handleExportarExcel = (e: React.MouseEvent) => {
e.preventDefault();
setMensajeAlerta("Generando y exportando reporte Excel...");
setShowAlertModal(true);
};
// Carga e inicialización de Chart.js dinámico para Tipo de Ventas (Doughnut)
useEffect(() => {
if (!divReporte) return;
let chartVenta: any = null;
import("chart.js/auto").then(({ default: Chart }) => {
const ctxVenta = document.getElementById(
"ventaPie"
) as HTMLCanvasElement;
if (ctxVenta) {
chartVenta = new Chart(ctxVenta, {
type: "doughnut",
data: {
labels: ["Directa", "Licitación", "Convenio Marco", "Otros"],
datasets: [
{
label: "Cantidad",
data: [40, 25, 20, 15],
borderWidth: 1,
},
],
},
options: {
responsive: true,
},
});
}
});
return () => {
if (chartVenta) chartVenta.destroy();
};
}, [divReporte]);
return (
<div className="container-fluid py-3">
<div className="row">
{/* Encabezado y Filtros */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Empresas por mes</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Alumnos/Index"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</Link>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col">
<span className="fw-bold">Mes</span>
</div>
<div className="col">
<select
id="ListaMeses"
className="form-select form-select-sm"
>
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
<option value="6">Junio</option>
<option value="7">Julio</option>
<option value="8">Agosto</option>
<option value="9">Septiembre</option>
<option value="10">Octubre</option>
<option value="11">Noviembre</option>
<option value="12">Diciembre</option>
</select>
</div>
<div className="col">
<span className="fw-bold">Año</span>
</div>
<div className="col">
<input
type="number"
id="TextBoxYear"
className="form-control form-control-sm"
defaultValue={2026}
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
>
Buscar
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{/* Sección Reporte Principal */}
{divReporte && (
<div className="col-md-12" id="div_reporte">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
{/* Métricas y Tarjetas Izquierda */}
<div className="col-md-3 mt-5">
<div className="row">
<div className="col-md-12 mx-auto">
<button
type="button"
onClick={handleExportarExcel}
className="btn p-0 border-0 w-100 text-decoration-none"
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1>
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5>
<strong>Exportar</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<i className="fa-solid fa-users-line"></i>
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-3 text-center">
<h1>
<BuildingHouse style={{ fontSize: "36px" }} />
</h1>
<span className="fw-bold">
<strong>Empresas</strong>
</span>
</div>
<div className="col text-center mt-3">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light shadow text-dark" role="alert">
<div className="row">
<div className="col-md-12 text-start">
<h1>
<i className="fa-solid fa-swatchbook"></i>
</h1>
<span className="fw-bold">
<strong>Alumnos</strong>
</span>
</div>
<div className="col-md-12 text-start mt-2">
<span className="text-muted">
<strong>Con SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Sin SENCE</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
<div className="col-md-12 text-start">
<span className="text-muted">
<strong>Total</strong>
</span>
<h5>
<strong>0</strong>
</h5>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Tabla Alumnos de empresas y Progreso de Sedes */}
<div className="col-md-4">
<div className="row">
<div className="col-md-12 mt-3">
<div className="alert alert-light" role="alert">
<div className="table-responsive" style={{ width: "100%" }}>
<h3>Alumnos de empresas</h3>
<table
className="table table-sm mb-0 table-hover"
style={{ fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Tipo
</th>
<th className="text-start" style={{ width: "20%" }}>
Cantidad
</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start" style={{ width: "80%" }}>
Cursos Abierto
</td>
<td className="text-start" style={{ width: "20%" }}>
0
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "80%" }}>
Cursos Cerrado
</td>
<td className="text-start" style={{ width: "20%" }}>
0
</td>
</tr>
<tr>
<th className="text-start" style={{ width: "80%" }}>
Total
</th>
<th className="text-start" style={{ width: "20%" }}>
0
</th>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<h4 className="text-center">
<small>
<u>Sedes con alumnos de empresas</u>
</small>
</h4>
<div className="col-md-8 text-start">
<h1>
<i className="fa-solid fa-school"></i>
</h1>
<span className="fw-bold">
<strong>Sedes</strong>
</span>
</div>
<div className="col-md-4 text-center mt-1">
<div
className="progress"
role="progressbar"
aria-label="Default striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped"
style={{ width: "100%" }}
>
Alumnos sin SENCE
</div>
</div>
<br />
<div
className="progress"
role="progressbar"
aria-label="Warning striped example"
aria-valuenow={100}
aria-valuemin={0}
aria-valuemax={100}
>
<div
className="progress-bar progress-bar-striped bg-warning text-dark"
style={{ width: "100%" }}
>
Alumnos con SENCE
</div>
</div>
</div>
<div className="col-md-12 text-center mt-3">
<h5>
<strong>Moneda</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Segment one"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="mone"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "50%" }}
></div>
<div
id="moneSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "50%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Providencia</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="prov"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "60%" }}
></div>
<div
id="provSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "40%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>La Florida</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="flor"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "70%" }}
></div>
<div
id="florSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "30%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Online</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="onli"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "80%" }}
></div>
<div
id="onliSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "20%" }}
></div>
</div>
</div>
<hr />
<h5>
<strong>Empresas</strong>
</h5>
<div className="progress-stacked">
<div
className="progress"
role="progressbar"
aria-label="Info example"
aria-valuenow={50}
aria-valuemin={0}
aria-valuemax={100}
>
<div
id="corp"
className="progress-bar progress-bar-striped progress-bar-animated"
style={{ width: "40%" }}
></div>
<div
id="corpSNC"
className="progress-bar progress-bar-striped progress-bar-animated bg-warning text-dark"
style={{ width: "60%" }}
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Canvas de Gráfico Tipos de Ventas */}
<div className="col-md-5 align-middle mt-5">
<div className="row">
<div className="col-md-12" id="TipoDeVentas">
<div
className="alert alert-light text-dark offcanvas-lg offcanvas-sm container-md container-sm"
role="alert"
>
<h3>
<span>
<b>
<u>Tipos de ventas</u>
</b>
</span>
</h3>
<canvas id="ventaPie" className="w-100 h-100"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
{/* MODAL ALERTA / ERRORES */}
{showAlertModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>Módulo Académico - Empresas</strong>
</h5>
<button
type="button"
className="btn-close"
onClick={() => setShowAlertModal(false)}
></button>
</div>
<div className="modal-body text-center py-3">
<h5>
<strong>{mensajeAlerta}</strong>
</h5>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowAlertModal(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{showLoadingModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="modal-title">
<strong>SAM - Académico Empresas</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5>
<strong>Procesando, espere un momento...</strong>
</h5>
<div className="mt-3">
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+4 -4
View File
@@ -15,25 +15,25 @@ export default function Page() {
icon: <File className="bx-sm bx-border" />,
color: "text-warning",
label: "Informe cursos iniciados por fecha",
href: "/Informes/Index?boton=periodo",
href: "/Informes/CursosInicio",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-warning",
label: "Informe cursos activos por mes",
href: "/Informes/Index?boton=activos",
href: "/Informes/CursosActivos",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-info",
label: "Cursos por iniciar",
href: "/Informes/CursosInicios?search=CURSOSINICIAN",
href: "/Informes/CursosIniTer",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-info",
label: "Cursos por finalizar",
href: "/Informes/CursosInicios?search=CURSOSFINALIZAN",
href: "/Informes/CursosIniTer",
},
];
+386
View File
@@ -0,0 +1,386 @@
"use client";
import React, { useState } from "react";
import {
// TransferAlt,
Check,
X,
// Error as ErrorIcon,
// ErrorCircle,
CheckCircle,
} from "@boxicons/react";
// Interfaz para los datos del reemplazo
interface ReemplazoItem {
idCursoAbierto: string;
Curso: string;
FechaAsistencia: string;
HoraInicio: string;
HoraSalida: string;
rutProfesor: string;
Profesor: string;
Estado: string;
idAsistenciaProfesor: string;
Email?: string;
}
// Interfaz para la configuración de la confirmación
interface ModalConfirmacionState {
show: boolean;
accion: "autorizar" | "rechazar" | null;
item: ReemplazoItem | null;
}
export default function ReemplazosPendientesPage() {
// Estado con datos de ejemplo
const [reemplazos, setReemplazos] = useState<ReemplazoItem[]>([
{
idCursoAbierto: "CUR-101",
Curso: "Inglés Básico A1",
FechaAsistencia: "15-02-2026",
HoraInicio: "09:00",
HoraSalida: "10:30",
rutProfesor: "12.345.678-9",
Profesor: "Juan Pérez",
Estado: "Pendiente",
idAsistenciaProfesor: "SES-001",
Email: "jperez@correo.cl",
},
{
idCursoAbierto: "CUR-102",
Curso: "Inglés Intermedio B2",
FechaAsistencia: "16-02-2026",
HoraInicio: "11:00",
HoraSalida: "12:30",
rutProfesor: "15.987.654-3",
Profesor: "María González",
Estado: "Pendiente",
idAsistenciaProfesor: "SES-002",
Email: "mgonzalez@correo.cl",
},
]);
// Estados para diálogos y procesamientos
const [modalConfirm, setModalConfirm] = useState<ModalConfirmacionState>({
show: false,
accion: null,
item: null,
});
const [isLoading, setIsLoading] = useState(false);
const [modalRespuesta, setModalRespuesta] = useState<{
show: boolean;
errorMsg: string;
okMsg: string;
}>({ show: false, errorMsg: "", okMsg: "" });
// Abrir modal customizado de confirmación
const abrirConfirmacion = (item: ReemplazoItem, accion: "autorizar" | "rechazar") => {
setModalConfirm({
show: true,
accion,
item,
});
};
// Procesar la autorización / rechazo
const handleConfirmar = () => {
if (!modalConfirm.item || !modalConfirm.accion) return;
const { idAsistenciaProfesor } = modalConfirm.item;
const accion = modalConfirm.accion;
// Cerrar modal de confirmación y mostrar loader
setModalConfirm({ show: false, accion: null, item: null });
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
// Eliminar el ítem procesado de la lista
setReemplazos((prev) => prev.filter((r) => r.idAsistenciaProfesor !== idAsistenciaProfesor));
setModalRespuesta({
show: true,
errorMsg: "",
okMsg: `El reemplazo se ha ${
accion === "autorizar" ? "autorizado" : "rechazado"
} correctamente.`,
});
}, 1000);
};
return (
<>
<div className="row">
{/* ENCABEZADO */}
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-1 text-center">
{/* <TransferAlt className="text-warning fs-3 border rounded p-1" /> */}
</div>
<div className="col-md-9">
<span className="text-muted">
<strong>Autorización</strong>
</span>
<h5 className="mb-0">
<strong>Reemplazos Pendientes</strong>
</h5>
</div>
</div>
</div>
</div>
{/* TABLA O ALERTA */}
{reemplazos.length > 0 ? (
<div className="col-md-12" id="divTablaReemplazos">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "18%" }}>Curso</th>
<th className="text-center" style={{ width: "10%" }}>Sesión</th>
<th className="text-center" style={{ width: "8%" }}>Inicio</th>
<th className="text-center" style={{ width: "8%" }}>Salida</th>
<th className="text-center" style={{ width: "14%" }}>Run</th>
<th className="text-center" style={{ width: "14%" }}>Reemplazante</th>
<th className="text-center" style={{ width: "10%" }}>Estado Sesion</th>
<th className="text-center" style={{ width: "18%" }}>Acción</th>
</tr>
</thead>
<tbody>
{reemplazos.map((item) => (
<tr key={item.idAsistenciaProfesor}>
<td className="text-start" style={{ width: "18%" }}>
<strong>{item.Curso}</strong>
<span className="badge bg-secondary ms-1">
{item.idCursoAbierto}
</span>
</td>
<td className="text-center" style={{ width: "10%" }}>
{item.FechaAsistencia}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.HoraInicio}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.HoraSalida}
</td>
<td className="text-center" style={{ width: "14%" }}>
{item.rutProfesor}
</td>
<td className="text-center" style={{ width: "14%" }}>
{item.Profesor}
</td>
<td className="text-center" style={{ width: "10%" }}>
<span className="badge bg-warning text-dark">
{item.Estado}
</span>
</td>
<td className="text-center" style={{ width: "18%" }}>
<button
type="button"
className="btn btn-success btn-sm me-1"
onClick={() => abrirConfirmacion(item, "autorizar")}
>
<Check className="me-1" /> Autorizar
</button>
<button
type="button"
className="btn btn-danger btn-sm"
onClick={() => abrirConfirmacion(item, "rechazar")}
>
<X className="me-1" /> Rechazar
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
) : (
<div className="col-md-12" id="divSinReemplazos">
<div className="alert alert-light text-dark shadow text-center py-4" role="alert">
<div className="row">
<div className="col-md-3"></div>
<div className="col-md-6 text-center">
<div className="alert alert-light text-dark mt-5" role="alert">
<strong>
{/* <ErrorIcon className="text-primary" style={{ fontSize: "90px" }} /> */}
</strong>
<br />
<br />
<h5>
<strong>No hay reemplazos pendientes de autorización</strong>
</h5>
<hr />
<strong className="text-muted">
Si cree que esto es un error, contáctenos.{" "}
<a
target="_blank"
href="https://norteamericano.freshdesk.com/support/tickets/new"
rel="noreferrer"
>
Generar Ticket
</a>
</strong>
</div>
</div>
</div>
</div>
</div>
)}
</div>
{/* MODAL PERSONALIZADO DE CONFIRMACIÓN (REEMPLAZO DE SWEETALERT2) */}
{modalConfirm.show && modalConfirm.item && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content rounded-4 p-3">
<div className="modal-body text-center">
{modalConfirm.accion === "autorizar" ? (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#198754" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#dc3545" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="15" y1="9" x2="9" y2="15" />
<line x1="9" y1="9" x2="15" y2="15" />
</svg>
)}
<h4 className="mt-2 mb-1 fw-bold" style={{ color: "#1f2937" }}>
{modalConfirm.accion === "autorizar" ? "Autorizar Reemplazo" : "Rechazar Reemplazo"}
</h4>
<p className="text-muted mb-3" style={{ fontSize: "14px" }}>
{modalConfirm.accion === "autorizar"
? "Se asignará al profesor reemplazante"
: "Se rechazará al profesor reemplazante"}
</p>
<div
className="p-3 text-start rounded-3"
style={{
backgroundColor: modalConfirm.accion === "autorizar" ? "#f0fdf4" : "#fef2f2",
border: `1px solid ${modalConfirm.accion === "autorizar" ? "#a3cfbb" : "#f1aeb5"}`,
fontSize: "13px",
color: "#374151",
}}
>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Curso</span>
<span>
{modalConfirm.item.Curso}{" "}
<span className="badge bg-secondary ms-1">
{modalConfirm.item.idCursoAbierto}
</span>
</span>
</div>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Sesión</span>
<span>
{modalConfirm.item.FechaAsistencia} | {modalConfirm.item.HoraInicio} - {modalConfirm.item.HoraSalida}
</span>
</div>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Profesor</span>
<span>{modalConfirm.item.rutProfesor}</span>
</div>
<div className="d-flex justify-content-between">
<span className="fw-bold">Reemplazante</span>
<span
className="fw-bold"
style={{
color: modalConfirm.accion === "autorizar" ? "#198754" : "#dc3545",
}}
>
{modalConfirm.item.Profesor}
</span>
</div>
</div>
<div className="d-flex justify-content-end gap-2 mt-4">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalConfirm({ show: false, accion: null, item: null })}
>
Cancelar
</button>
<button
type="button"
className={`btn ${modalConfirm.accion === "autorizar" ? "btn-success" : "btn-danger"}`}
onClick={handleConfirmar}
>
{modalConfirm.accion === "autorizar" ? "Sí, autorizar" : "Sí, rechazar"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
{/* MODAL RESPUESTA */}
{modalRespuesta.show && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content">
<div className="modal-header text-white text-center" style={{ backgroundColor: "#373193" }}>
<h5 className="modal-title">Reemplazos</h5>
</div>
<div className="modal-body">
{modalRespuesta.errorMsg && (
<div>
<strong style={{ color: "#e22523" }}>
{/* <ErrorCircle className="me-1" /> */}
<span>{modalRespuesta.errorMsg}</span>
</strong>
</div>
)}
{modalRespuesta.okMsg && (
<div>
<strong style={{ color: "#00285d" }}>
<CheckCircle className="me-1" />
<span>{modalRespuesta.okMsg}</span>
</strong>
</div>
)}
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalRespuesta({ show: false, errorMsg: "", okMsg: "" })}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="col-md-12 text-center py-3">
<div className="spinner-border text-info" role="status">
<span className="visually-hidden">Procesando...</span>
</div>
<p className="mt-2 mb-0">Procesando la información...</p>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
+533
View File
@@ -0,0 +1,533 @@
"use client";
import React, { useState } from "react";
import Link from "next/link";
import { User, Save, Receipt } from "@boxicons/react";
export default function EvaluacionAlumnosPage() {
// Estados para visibilidad de secciones (equivalente a Visible="false")
const [showCreateAlm, setShowCreateAlm] = useState(false);
const [showUpdatePlacement, setShowUpdatePlacement] = useState(false);
// Estados para modales
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("Mensaje de prueba");
// Estados para botones con estado de carga
const [isSearching, setIsSearching] = useState(false);
const [isSavingAlumno, setIsSavingAlumno] = useState(false);
const [isSavingEvaluacion, setIsSavingEvaluacion] = useState(false);
// Handlers para simular acciones
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setIsSearching(true);
setShowLoadingModal(true);
setTimeout(() => {
setIsSearching(false);
setShowLoadingModal(false);
// Muestra la sección deseada al terminar la búsqueda
setShowUpdatePlacement(true);
}, 1500);
};
const handleGuardarAlumno = (e: React.FormEvent) => {
e.preventDefault();
setIsSavingAlumno(true);
setTimeout(() => {
setIsSavingAlumno(false);
setMensajeAlerta("Alumno guardado correctamente.");
setShowAlertModal(true);
}, 1500);
};
const handleGuardarEvaluacion = (e: React.FormEvent) => {
e.preventDefault();
setIsSavingEvaluacion(true);
setTimeout(() => {
setIsSavingEvaluacion(false);
setMensajeAlerta("Evaluación guardada correctamente.");
setShowAlertModal(true);
}, 1500);
};
return (
<div className="container-fluid py-3">
<div className="row">
{/* Búsqueda del alumno */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Evaluación alumnos</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Academico/Index"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</Link>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col">
<span className="fw-bold">RUN del alumno</span>
</div>
<div className="col">
<input
type="text"
id="TextBoxIDRun"
className="form-control form-control-sm"
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
disabled={isSearching}
>
<div className="contenedor-boton">
{isSearching ? (
<div className="col-12 text-center py-1">
<span
className="spinner-border spinner-border-sm me-2"
role="status"
aria-hidden="true"
></span>
<strong>Buscando alumno...</strong>
</div>
) : (
"Buscar"
)}
</div>
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{/* Carta de ingreso alumno nuevo */}
{showCreateAlm && (
<div className="col-md-6 mx-auto" id="create_alm">
<div className="alert alert-light text-dark" role="alert">
<table className="table w-100">
<tbody>
<tr>
<td className="text-start" style={{ width: "10%" }}>
R.U.N.
</td>
<td className="text-start" style={{ width: "15%" }}>
<input type="text" id="TextBoxId" className="form-control" />
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Nombre
</td>
<td className="text-start" style={{ width: "15%" }}>
<input type="text" id="TextBoxName" className="form-control" />
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Apellido Paterno
</td>
<td className="text-start" style={{ width: "15%" }}>
<input
type="text"
id="TextBoxApPaterno"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Apellido Materno
</td>
<td className="text-start" style={{ width: "15%" }}>
<input
type="text"
id="TextBoxApMaterno"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Dirección
</td>
<td className="text-start" style={{ width: "15%" }}>
<input
type="text"
id="TextBoxDirAlm"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Región
</td>
<td className="text-start" style={{ width: "15%" }}>
<select id="ListRegion" className="form-select">
<option value="0">Seleccionar</option>
</select>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "10%" }}>
Comuna
</td>
<td className="text-start" style={{ width: "15%" }}>
<select id="ListComuna" className="form-select">
<option value="0">Seleccionar</option>
</select>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "20%" }}>
Telefono
</td>
<td className="text-start" style={{ width: "35%" }}>
<input
type="tel"
id="TextBoxFono"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "20%" }}>
Email
</td>
<td className="text-start" style={{ width: "35%" }}>
<input
type="email"
id="TextBoxEmail"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "20%" }}>
Fecha de nacimiento
</td>
<td className="text-start" style={{ width: "35%" }}>
<input
type="date"
id="TextBoxNacimiento"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "20%" }}>
Profesion
</td>
<td className="text-start" style={{ width: "35%" }}>
<input
type="text"
id="TextBoxProfesion"
className="form-control"
/>
</td>
</tr>
<tr>
<td className="text-start" style={{ width: "20%" }}></td>
<td className="text-start" style={{ width: "35%" }}>
<button
type="button"
onClick={handleGuardarAlumno}
className="btn p-0 border-0 text-start w-100"
disabled={isSavingAlumno}
>
<div className="alert alert-success shadow mb-0" role="alert">
<div className="row contenedor-boton">
{isSavingAlumno ? (
<div className="col-12 text-center py-2">
<span
className="spinner-border spinner-border-sm me-2"
role="status"
aria-hidden="true"
></span>
<strong>Guardando alumno...</strong>
</div>
) : (
<>
<div className="col text-end">
<h2>
<Save />
</h2>
</div>
<div className="col text-start">
<span className="text-muted">
<strong>Guardar</strong>
</span>
<h5>
<strong>Evaluacion</strong>
</h5>
</div>
</>
)}
</div>
</div>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{/* Carta del alumno y selección de nivel */}
{showUpdatePlacement && (
<div className="col-md-12" id="update_placement">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-4 text-end">
<table className="table table-sm table-borderless shadow mb-0 text-center">
<tbody>
<tr>
<td colSpan={2}>
<User
className="text-primary bx-border mb-2 bx-burst-hover"
style={{ fontSize: "50px" }}
/>
</td>
</tr>
<tr>
<td colSpan={2}>
<span className="fs-5">Juan Pérez</span>
</td>
</tr>
<tr>
<td colSpan={2}>
<strong>
<span className="fs-5">12.345.678-9</span>
</strong>
</td>
</tr>
<tr>
<td colSpan={2}>
<strong>
<span className="fs-5">Nivel Inicial</span>
</strong>
</td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-4 text-center">
<div className="row">
<div className="col-md-12">
<h3>Evaluacion</h3>
<div className="form-check form-check-inline">
<input
className="form-check-input"
type="checkbox"
id="CheckBox1"
/>
<label className="form-check-label" htmlFor="CheckBox1">
Presencial/Online
</label>
</div>
<div className="form-check form-check-inline">
<input
className="form-check-input"
type="checkbox"
id="CheckBox2"
/>
<label className="form-check-label" htmlFor="CheckBox2">
Placement Test
</label>
</div>
</div>
<div className="col-md-12 mt-3">
<span>Nivel</span>
<select id="listNiveles" className="form-select">
<option value="0">Seleccionar Nivel</option>
</select>
</div>
</div>
</div>
<div className="col-md-4 text-start">
<button
type="button"
onClick={handleGuardarEvaluacion}
className="btn p-0 border-0 text-decoration-none w-100"
disabled={isSavingEvaluacion}
>
<div
className="alert alert-success shadow mb-0"
role="alert"
id="ContenedorBoton"
>
<div className="row contenedor-boton align-items-center">
{isSavingEvaluacion ? (
<div className="col-12 text-center py-2">
<span
className="spinner-border spinner-border-sm me-2"
role="status"
aria-hidden="true"
></span>
<strong>Guardando evaluación...</strong>
</div>
) : (
<>
<div className="col-md-3">
<h2>
<Receipt />
</h2>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Guardar</strong>
</span>
<h5>
<strong>Evaluacion</strong>
</h5>
</div>
</>
)}
</div>
</div>
</button>
</div>
</div>
</div>
</div>
)}
</div>
{/* POPUPS Y MODALES */}
{/* Modal Alerta */}
{showAlertModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="float-start mt-2">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button
type="button"
className="btn-close float-end"
onClick={() => setShowAlertModal(false)}
aria-label="Close"
></button>
</div>
<div className="modal-body alert text-justify">
<div className="row">
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{mensajeAlerta}</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setShowAlertModal(false)}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* Modal Cargando */}
{showLoadingModal && (
<div
className="modal fade show d-block"
style={{ backgroundColor: "rgba(0,0,0,0.5)" }}
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="float-start mt-2">
<strong>SAM - Académico Empresas </strong>
</h5>
</div>
<div className="modal-body alert text-justify">
<div className="row">
<div className="row mb-2">
<div className="col-md-12 text-center"></div>
<div className="col-md-12 text-center">
<h5>
<strong>Procesando, espere un momento</strong>
</h5>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary me-1"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger me-1"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+846
View File
@@ -0,0 +1,846 @@
'use client';
import React, { useState } from 'react';
import Link from 'next/link';
import {
//Transfer,
User,
// PhoneCall,
// MailSend,
Envelope,
// CurrentLocation,
// Cake,
Edit,
Pencil,
File,
UserPlus,
Certification,
// Comment,
// Error as ErrorIcon,
RefreshCwDot,
// Download,
// FilePdf,
Save
} from '@boxicons/react';
export default function FichaAlumnoPage() {
// --- ESTADOS DE PESTAÑAS ---
const [activeTab, setActiveTab] = useState<'cursos' | 'contratos' | 'apoderados' | 'certificados' | 'comentarios'>('cursos');
// --- ESTADOS DE VISTAS INTERNAS ---
const [subViewCursos, setSubViewCursos] = useState<'reporte' | 'error' | 'detalle' | 'confirma_cambio'>('reporte');
const [hasCursosError, setHasCursosError] = useState(false);
// --- ESTADOS DE MODALS ---
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showErrorModal, setShowErrorModal] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [showModalNotas, setShowModalNotas] = useState(false);
const [showModalAsistencia, setShowModalAsistencia] = useState(false);
const [showModalCursosDisp, setShowModalCursosDisp] = useState(false);
const [showModalEditarAlumno, setShowModalEditarAlumno] = useState(false);
// --- ESTADOS DE FORMULARIOS ---
const [comentarioInput, setComentarioInput] = useState('');
const [confirmCambioCheck, setConfirmCambioCheck] = useState(false);
const [editForm, setEditForm] = useState({
nombre: '',
paterno: '',
materno: '',
nacimiento: '',
fono: '',
mail: '',
direccion: '',
region: '',
comuna: '',
ocupacion: '',
profesion: ''
});
// --- DISPARADORES DE EJEMPLO PARA ACCIONES Y CARGAS ---
const handleSimulateLoading = (action: () => void) => {
setShowLoadingModal(true);
setTimeout(() => {
setShowLoadingModal(false);
action();
}, 1200);
};
const triggerError = (msg: string) => {
setErrorMessage(msg);
setShowErrorModal(true);
};
return (
<div className="container-fluid py-3">
{/* BARRA SUPERIOR */}
<div className="row">
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-6">
<h5 className="mb-0">
<strong className="text-muted">Ficha</strong> <strong>Alumno</strong>
</h5>
</div>
<div className="col-md-6 text-end">
<Link href="/index" className="btn btn-primary btn-sm">
{/* <Transfer className="me-2" /> */}
Cambiar Alumno
</Link>
</div>
</div>
</div>
</div>
{/* PANEL IZQUIERDO: INFORMACIÓN DE CONTACTO */}
<div className="col-md-3">
<div className="alert alert-light text-dark shadow" role="alert">
<table className="table table-sm table-borderless mb-0 text-center">
<tbody>
<tr>
<td colSpan={2}>
<User className="text-primary mb-2" style={{ fontSize: '50px' }} />
</td>
</tr>
<tr>
<td colSpan={2}>
<span className="fs-5 fw-bold">Juan Pérez González</span>
</td>
</tr>
<tr>
<td colSpan={2}>
<strong>12.345.678-9</strong>
</td>
</tr>
<tr>
<td>
<div className="d-grid gap-2">
<button
type="button"
className="btn btn-primary btn-sm"
// onClick={() => handleTokyPopup('+56912345678')}
>
{/* <PhoneCall className="me-1" /> */}
Llamar
</button>
</div>
</td>
<td>
<div className="d-grid gap-2">
<button
type="button"
className="btn btn-light btn-sm border"
// onClick={() => handleGmailPopup('alumno@email.com')}
>
{/* <MailSend className="me-1" /> */}
Mensaje
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table table-sm table-borderless mb-0" style={{ fontSize: '14px' }}>
<tbody>
<tr>
<td colSpan={2}>
<span className="text-dark" style={{ fontSize: '18px' }}>Contacto</span>
<hr className="my-2" />
</td>
</tr>
<tr>
<td style={{ width: '25px' }}>
{/* <PhoneCall /> */}
</td>
<td>+56 9 1234 5678</td>
</tr>
<tr>
<td><Envelope /></td>
<td>alumno@email.com</td>
</tr>
<tr>
<td>
{/* <CurrentLocation /> */}
</td>
<td>Av. Providencia 1234</td>
</tr>
<tr>
<td>
{/* <CurrentLocation /> */}
</td>
<td>Providencia, Región Metropolitana</td>
</tr>
<tr>
<td>
{/* <Cake /> */}
</td>
<td>15/08/1995</td>
</tr>
<tr>
<td colSpan={2}>
<div className="d-grid gap-2 mt-2">
<button
className="btn btn-warning btn-sm"
onClick={() => setShowModalEditarAlumno(true)}
>
<strong><Edit className="me-1" /> Editar</strong>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/* PANEL DERECHO: PESTAÑAS Y CONTENIDOS */}
<div className="col-md-9">
<div className="row">
<div className="col-md-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
{/* NAVEGACIÓN TAB */}
<div className="d-grid gap-2 mb-3">
<div className="btn-group" role="group">
<button
className={`btn btn-light border-top-0 border-end-0 border-start-0 border-3 ${activeTab === 'cursos' ? 'border-primary active' : ''}`}
onClick={() => setActiveTab('cursos')}
>
<Pencil className="me-2" style={{ fontSize: '18px' }} /> Cursos
</button>
<button
className={`btn btn-light border-top-0 border-end-0 border-start-0 border-3 ${activeTab === 'contratos' ? 'border-primary active' : ''}`}
onClick={() => setActiveTab('contratos')}
>
<File className="me-2" style={{ fontSize: '18px' }} /> Contratos
</button>
<button
className={`btn btn-light border-top-0 border-end-0 border-start-0 border-3 ${activeTab === 'apoderados' ? 'border-primary active' : ''}`}
onClick={() => setActiveTab('apoderados')}
>
<UserPlus className="me-2" style={{ fontSize: '18px' }} /> Apoderado
</button>
<button
className={`btn btn-light border-top-0 border-end-0 border-start-0 border-3 ${activeTab === 'certificados' ? 'border-primary active' : ''}`}
onClick={() => setActiveTab('certificados')}
>
<Certification className="me-2" style={{ fontSize: '18px' }} /> Certificados
</button>
<button
className={`btn btn-light border-top-0 border-end-0 border-start-0 border-3 ${activeTab === 'comentarios' ? 'border-primary active' : ''}`}
onClick={() => setActiveTab('comentarios')}
>
{/* <Comment className="me-2" style={{ fontSize: '18px' }} /> */}
Comentarios
</button>
</div>
</div>
{/* --- PESTAÑA: CURSOS --- */}
{activeTab === 'cursos' && (
<div>
{subViewCursos === 'reporte' && !hasCursosError && (
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive mt-3">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th scope="col" style={{ width: '10%' }}></th>
<th scope="col" className="text-center" style={{ width: '5%' }}><strong>Year</strong></th>
<th scope="col" className="text-center" style={{ width: '6%' }}><strong>ID</strong></th>
<th scope="col" className="text-start" style={{ width: '32%' }}><strong>Curso</strong></th>
<th scope="col" className="text-center" style={{ width: '20%' }}><strong>Contrato</strong></th>
<th scope="col" className="text-center" style={{ width: '17%' }}><strong>Fecha</strong></th>
<th scope="col" className="text-center" style={{ width: '10%' }}><strong>Estado</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start">
<button
className="btn btn-link p-0 text-decoration-none"
onClick={() => setSubViewCursos('detalle')}
>
<h6><span className="badge bg-secondary style-normal">Ingresar</span></h6>
</button>
</td>
<td className="text-center">2026</td>
<td className="text-center">1024</td>
<td className="text-start">2026-1 - Inglés Avanzado C1</td>
<td className="text-center">
<strong className="text-primary">PARTICULAR</strong>
</td>
<td className="text-center">01/03/2026 | 30/06/2026</td>
<td className="text-center">
<span className="badge bg-primary style-normal" style={{ fontSize: '12px' }}>
<span className="me-2 ms-2">Cursando</span>
</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{hasCursosError && (
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3"></div>
<div className="col-md-6 text-center">
<div className="alert alert-light text-dark mt-5" role="alert">
{/* <ErrorIcon className="text-primary" style={{ fontSize: '90px' }} /> */}
<br /><br />
<h5><strong>El alumno no tiene Cursos disponibles</strong></h5>
<hr />
<strong className="text-muted">
Si cree que esto es un error, contáctenos.{' '}
<a target="_blank" rel="noreferrer" href="https://norteamericano.freshdesk.com/support/tickets/new">Generar Ticket</a>
</strong>
</div>
</div>
</div>
</div>
)}
{subViewCursos === 'detalle' && (
<div className="alert alert-light text-dark" role="alert">
<div className="row mt-4">
<div className="col-md-7">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td>Curso</td>
<td style={{ fontSize: '16px' }}><strong>Inglés Avanzado C1</strong></td>
</tr>
<tr>
<td>Código</td>
<td><strong>1024</strong></td>
</tr>
<tr>
<td>Estado</td>
<td><strong>Cursando</strong></td>
</tr>
<tr>
<td>Sede</td>
<td><strong>Providencia</strong></td>
</tr>
<tr>
<td>Profesor</td>
<td><strong>John Doe</strong></td>
</tr>
<tr>
<td>Sala</td>
<td><strong>Lab 402</strong></td>
</tr>
<tr>
<td>Horario</td>
<td><strong>Lu-Mi-Vi 19:00 - 21:00</strong></td>
</tr>
<tr>
<td>Inicio</td>
<td><strong>01/03/2026</strong></td>
</tr>
<tr>
<td>Término</td>
<td><strong>30/06/2026</strong></td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-5">
<table className="table table-sm mb-4">
<tbody>
<tr className="table-secondary text-dark">
<td colSpan={3}><strong>Opciones</strong></td>
</tr>
<tr>
<td colSpan={3}>
<button
className="btn btn-link p-0 fw-bold text-decoration-none"
onClick={() => setSubViewCursos('confirma_cambio')}
>
Cambiar de Curso
</button>
</td>
</tr>
</tbody>
</table>
<div>
<div className="row">
<div className="col-md-12">
<table className="table table-sm mb-0">
<tbody>
<tr className="table-secondary text-dark">
<td colSpan={3}><strong>RollBook</strong></td>
</tr>
<tr>
<td>Nota</td>
<td colSpan={2}>
<button
className="btn btn-link p-0 fw-bold text-decoration-none"
onClick={() => setShowModalNotas(true)}
>
Ver
</button>
</td>
</tr>
<tr>
<td>Asistencia</td>
<td colSpan={2}>
<button
className="btn btn-link p-0 fw-bold text-decoration-none"
onClick={() => setShowModalAsistencia(true)}
>
Ver
</button>
</td>
</tr>
<tr>
<td>Estado</td>
<td colSpan={2}><strong>En proceso</strong></td>
</tr>
<tr>
<td>Certificado</td>
<td>
<button className="btn btn-link p-0 text-decoration-none">
<RefreshCwDot /> Refrescar certificado
</button>
</td>
<td><strong>---</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{subViewCursos === 'confirma_cambio' && (
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-5">
<table className="table table-sm mb-0 caption-top">
<caption><strong><u>Actual Curso</u></strong></caption>
<tbody>
<tr>
<td>Curso</td>
<td style={{ fontSize: '16px' }}><strong>Inglés Avanzado C1</strong></td>
</tr>
<tr>
<td>Código</td>
<td><strong>1024</strong></td>
</tr>
<tr>
<td>Sede</td>
<td><strong>Providencia</strong></td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-2 style-center-vh">
<h2 className="text-center">
{/* <Transfer /> */}
</h2>
</div>
<div className="col-md-5">
<table className="table table-sm mb-0 caption-top">
<caption><strong><u>Nuevo Curso</u></strong></caption>
<tbody>
<tr>
<td>Curso</td>
<td style={{ fontSize: '16px' }}><strong>Inglés Intensivo C1</strong></td>
</tr>
<tr>
<td>Código</td>
<td><strong>2048</strong></td>
</tr>
<tr>
<td>Sede</td>
<td><strong>Santiago Centro</strong></td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-12 text-center mb-0 mt-3">
<div className="form-check d-inline-block">
<input
className="form-check-input me-2"
type="checkbox"
id="chkConfirm"
checked={confirmCambioCheck}
onChange={(e) => setConfirmCambioCheck(e.target.checked)}
/>
<label className="form-check-label" htmlFor="chkConfirm">
Confirmo y autorizo el cambio de curso con la información mostrada en pantalla.
</label>
</div>
</div>
<div className="col-md-12 text-center mt-2">
<button
className="btn btn-success"
onClick={() => handleSimulateLoading(() => setSubViewCursos('detalle'))}
disabled={!confirmCambioCheck}
>
Actualizar Curso
</button>
</div>
</div>
</div>
)}
</div>
)}
{/* --- PESTAÑA: CONTRATOS --- */}
{activeTab === 'contratos' && (
<div>
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive mt-3">
<table className="table table-sm mb-0" style={{ fontSize: '11px' }}>
<thead>
<tr>
<th scope="col" style={{ width: '10%' }}></th>
<th scope="col" style={{ width: '7%' }}><strong>Fecha</strong></th>
<th scope="col" style={{ width: '7%' }}><strong>Contrato</strong></th>
<th scope="col" className="text-center" style={{ width: '8%' }}><strong>Tipo</strong></th>
<th scope="col" className="text-center" style={{ width: '12%' }}><strong>RUT Empresa</strong></th>
<th scope="col" className="text-center" style={{ width: '25%' }}><strong>Empresa</strong></th>
<th scope="col" className="text-center" style={{ width: '15%' }}><strong>Curso</strong></th>
<th scope="col" className="text-center" style={{ width: '10%' }}><strong>Registro</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<button className="btn btn-secondary btn-sm p-0 px-2" style={{ fontSize: '10px' }}>
Ver
</button>
</td>
<td>01/01/2026</td>
<td><strong>CNT-991</strong></td>
<td className="text-center">Empresa</td>
<td className="text-center">76.123.456-7</td>
<td className="text-center"><strong>Corporación X</strong></td>
<td className="text-center">Inglés C1</td>
<td className="text-center">SENCE</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
)}
{/* --- PESTAÑA: APODERADOS --- */}
{activeTab === 'apoderados' && (
<div>
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive mt-3">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th scope="col" style={{ width: '10%' }}></th>
<th scope="col" style={{ width: '12%' }}><strong>Fecha</strong></th>
<th scope="col" className="text-center" style={{ width: '12%' }}><strong>RUT Empresa</strong></th>
<th scope="col" className="text-center" style={{ width: '30%' }}><strong>Empresa</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td></td>
<td>10/02/2026</td>
<td className="text-center"><strong>76.123.456-7</strong></td>
<td className="text-center"><strong>Corporación X</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
)}
{/* --- PESTAÑA: CERTIFICADOS --- */}
{activeTab === 'certificados' && (
<div>
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive mt-3">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th scope="col" style={{ width: '10%' }}></th>
<th scope="col" style={{ width: '20%' }}><strong>Cursos</strong></th>
<th scope="col" className="text-center" style={{ width: '10%' }}><strong>Estado</strong></th>
<th scope="col" className="text-center" style={{ width: '15%' }}><strong>Fecha</strong></th>
<th scope="col" className="text-center" style={{ width: '10%' }}><strong>Nota</strong></th>
<th scope="col" className="text-center" style={{ width: '10%' }}><strong>Asistencia</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<a href="#" target="_blank" rel="noreferrer" className="text-decoration-none">
{/* <FilePdf className="me-1" style={{ fontSize: '12px' }} /> */}
Ver Certificado
</a>
</td>
<td>Inglés B2 Finalizado</td>
<td className="text-center">
<span className="badge bg-success" style={{ fontWeight: 100, fontSize: '12px' }}>Aprobado</span>
</td>
<td className="text-center"><strong>20/12/2025</strong></td>
<td className="text-center"><strong>6.5</strong></td>
<td className="text-center"><strong>95%</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
)}
{/* --- PESTAÑA: COMENTARIOS --- */}
{activeTab === 'comentarios' && (
<div>
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-12 mt-3">
<div className="table-responsive mt-3">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th scope="col" style={{ width: '10%' }}><strong>Fecha</strong></th>
<th scope="col" style={{ width: '10%' }}><strong>Hora</strong></th>
<th scope="col" style={{ width: '60%' }}><strong>Comentario</strong></th>
<th scope="col" style={{ width: '20%' }}><strong>Usuario</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>14/09/2026</td>
<td>10:30</td>
<td>Alumno solicita cambio de horario.</td>
<td>Admin_User</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-12 mt-5">
<div className="row">
<div className="col-md-1"></div>
<div className="col-md-9">
<input
type="text"
placeholder="Escribe un comentario"
className="form-control"
value={comentarioInput}
onChange={(e) => setComentarioInput(e.target.value)}
/>
</div>
<div className="col-md-2">
<button
className="btn btn-primary btn-sm w-100"
onClick={() => handleSimulateLoading(() => setComentarioInput(''))}
>
Agregar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
{/* --- MODAL NOTAS --- */}
{showModalNotas && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-lg modal-dialog-scrollable">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Notas</h5>
<button type="button" className="btn-close" onClick={() => setShowModalNotas(false)}></button>
</div>
<div className="modal-body">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th className="text-center" style={{ width: '20%' }}><strong>Fecha</strong></th>
<th className="text-center" style={{ width: '60%' }}><strong>Test</strong></th>
<th className="text-center" style={{ width: '20%' }}><strong>Grade</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start" style={{ width: '20%' }}><strong>05/04/2026</strong></td>
<td className="text-start" style={{ width: '60%' }}><strong>Midterm Exam</strong></td>
<td className="text-center" style={{ width: '20%' }}><strong>92%</strong></td>
</tr>
</tbody>
</table>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setShowModalNotas(false)}>Close</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL ASISTENCIA --- */}
{showModalAsistencia && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-lg modal-dialog-scrollable">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Asistencia</h5>
<button type="button" className="btn-close" onClick={() => setShowModalAsistencia(false)}></button>
</div>
<div className="modal-body">
<table className="table table-sm mb-0" style={{ fontSize: '18px' }}>
<thead>
<tr>
<th className="text-center" style={{ width: '50%' }}><strong>Fecha</strong></th>
<th className="text-center" style={{ width: '50%' }}><strong>Marcaciones</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center"><strong>01/03/2026</strong></td>
<td className="text-center"><strong className="text-success">Present</strong></td>
</tr>
</tbody>
</table>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setShowModalAsistencia(false)}>Close</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL EDITAR ALUMNO --- */}
{showModalEditarAlumno && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Editar Alumno</h5>
<button type="button" className="btn-close" onClick={() => setShowModalEditarAlumno(false)}></button>
</div>
<div className="modal-body">
<table className="table table-sm">
<tbody>
<tr>
<td><strong>Nombre</strong></td>
<td>
<input
type="text"
className="form-control"
value={editForm.nombre}
onChange={(e) => setEditForm({ ...editForm, nombre: e.target.value })}
/>
</td>
</tr>
<tr>
<td><strong>Paterno</strong></td>
<td>
<input
type="text"
className="form-control"
value={editForm.paterno}
onChange={(e) => setEditForm({ ...editForm, paterno: e.target.value })}
/>
</td>
</tr>
<tr>
<td></td>
<td>
<div className="d-grid gap-2">
<button
className="btn btn-warning text-dark"
onClick={() => handleSimulateLoading(() => setShowModalEditarAlumno(false))}
>
<strong><Save className="me-2" /> Guardar</strong>
</button>
<button type="button" className="btn btn-secondary" onClick={() => setShowModalEditarAlumno(false)}>Cancelar</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CARGANDO (LOADING) --- */}
{showLoadingModal && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="mt-2"><strong>SAM - Empresas</strong></h5>
</div>
<div className="modal-body alert text-center" style={{ textAlign: 'justify' }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5 className="mb-3"><strong>Procesando, espere un momento</strong></h5>
<div className="spinner-grow spinner-grow-sm text-primary mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger mx-1" role="status"></div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL ERROR / ALERTA --- */}
{showErrorModal && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="float-start mt-2"><strong>Módulo Academico - Empresa</strong></h5>
<button type="button" className="btn-close" onClick={() => setShowErrorModal(false)}></button>
</div>
<div className="modal-body alert" style={{ textAlign: 'justify' }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5><strong>{errorMessage || 'Ocurrió un error en la operación.'}</strong></h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" onClick={() => setShowErrorModal(false)}>Close</button>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+703
View File
@@ -0,0 +1,703 @@
"use client";
import React, { useState } from "react";
import {
// UserDetail,
Plus,
Save,
User,
// MailSend,
// PhoneCall,
Envelope,
// CurrentLocation,
// Cake,
Flag,
Edit,
UserCheck,
Pencil,
File,
Book,
// Error as ErrorIcon,
CheckCircle,
XCircle,
} from "@boxicons/react";
export default function ProfesorPage() {
// Estados para controlar vistas del flujo ASP.NET
const [vistas, setVistas] = useState({
divBuscar: true,
divBuscarResultado: false,
agregarProfe: false,
fichaProfe: false,
profeCursosActivos: true,
profeCursosActivosOk: false,
profeCursosActivosError: false,
profeCursosFinalizados: false,
profeCursosFinalizadosOk: false,
profeCursosFinalizadosError: false,
profePerfil: false,
});
// Estados para Modales
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showAlertModal, setShowAlertModal] = useState(false);
const [showEditModal, setShowEditModal] = useState(false);
const [mensajeAlerta, setMensajeAlerta] = useState("Mensaje de prueba");
// Función equivalente a GmailPopup
const handleGmailPopup = (mail: string, name: string) => {
const title = "Contacto";
const w = 800;
const h = 600;
const options = "scrollbars=no,resizable=no";
const url = `https://mail.google.com/mail/u/0/?view=cm&fs=1&to=${mail.toLowerCase()}&su=Contacto%20Ichn`;
const dualScreenLeft = window.screenLeft !== undefined ? window.screenLeft : window.screenX;
const dualScreenTop = window.screenTop !== undefined ? window.screenTop : window.screenY;
const width = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
const height = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
const left = width / 2 - w / 2 + dualScreenLeft;
const top = height / 2 - h / 2 + dualScreenTop;
window.open(url, title, `${options}, width=${w}, height=${h}, top=${top}, left=${left}`);
};
// Solo números para teléfono
const handleOnlyNumbers = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (!/[0-9]/.test(e.key) && e.key !== "Backspace" && e.key !== "Tab") {
e.preventDefault();
}
};
return (
<div className="container-fluid py-3">
{/* SECCIÓN DE BÚSQUEDA */}
{vistas.divBuscar && (
<div className="row" id="div_buscar">
<div className="col-md-1"></div>
<div className="col-md-10">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-1 mt-2 text-end">
<div className="mt-2">
<strong>Profesor</strong>
</div>
</div>
<div className="col-md-3 mt-2">
<select className="form-select" id="ListaTipoBusqueda">
<option value="">Seleccione filtro...</option>
</select>
</div>
<div className="col-md-2 mt-2">
<input
type="text"
className="form-control"
id="TextBoxProfe"
autoComplete="off"
/>
</div>
<div className="col-md-1 mt-2">
<button
type="button"
className="btn btn-sm btn-primary"
onClick={() => setVistas({ ...vistas, divBuscarResultado: true })}
>
Buscar
</button>
</div>
<div className="col-md-3 text-end mt-2">
<button
type="button"
className="btn btn-success text-dark"
>
{/* <UserDetail className="me-1" /> */}
<strong>Listado Profesores</strong>
</button>
</div>
<div className="col-md-2 text-end mt-2">
<button
type="button"
className="btn btn-warning text-dark me-4"
onClick={() => setVistas({ ...vistas, agregarProfe: true })}
>
<Plus className="me-1" /> <strong>Agregar</strong>
</button>
</div>
</div>
{/* RESULTADOS BÚSQUEDA */}
{vistas.divBuscarResultado && (
<div className="row" id="div_buscar_resultado">
<div className="col-md-12 mt-4">
<div className="alert alert-light text-dark" role="alert">
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead className="alert-secondary text-dark">
<tr>
<th className="text-start" style={{ width: "10%" }}></th>
<th className="text-start" style={{ width: "10%" }}><strong>Run</strong></th>
<th className="text-start" style={{ width: "28%" }}><strong>Nombre</strong></th>
<th className="text-center" style={{ width: "10%" }}><strong>Estado</strong></th>
<th className="text-start" style={{ width: "10%" }}><strong>Fono</strong></th>
<th className="text-start" style={{ width: "29%" }}><strong>Mail</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start" style={{ width: "10%" }}>
<button
type="button"
className="btn btn-link p-0 text-decoration-none"
onClick={() => setVistas({ ...vistas, fichaProfe: true })}
>
<span className="badge bg-primary" style={{ fontWeight: "normal" }}>
Seleccionar
</span>
</button>
</td>
<td className="text-start" style={{ width: "10%" }}><strong>12345678-9</strong></td>
<td className="text-start" style={{ width: "14%" }}><strong>Pérez</strong></td>
<td className="text-start" style={{ width: "14%" }}><strong>Juan</strong></td>
<td className="text-center" style={{ width: "10%" }}>
<span className="badge rounded-pill bg-success">Activo</span>
</td>
<td className="text-start" style={{ width: "10%" }}><strong>912345678</strong></td>
<td className="text-start" style={{ width: "29%" }}><strong>juan.perez@example.com</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-12">
<nav aria-label="...">
<ul className="pagination justify-content-center">
<li className="page-item"><button className="page-link">First</button></li>
<li className="page-item"><button className="page-link">Previous</button></li>
<li className="page-item"><button className="page-link">Next</button></li>
<li className="page-item"><button className="page-link">Last</button></li>
</ul>
</nav>
</div>
</div>
)}
</div>
</div>
</div>
)}
{/* SECCIÓN AGREGAR PROFESOR */}
{vistas.agregarProfe && (
<div className="row" id="agregar_profe">
<div className="col-md-1"></div>
<div className="col-md-10">
<div className="alert alert-light text-dark shadow" role="alert">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td className="text-start" colSpan={4}>
<h5><strong>Información Personal</strong></h5>
</td>
</tr>
<tr>
<td style={{ width: "20%" }}><strong className="text-muted">Run</strong></td>
<td><input type="text" className="form-control" autoComplete="off" /></td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong className="text-muted">Nombre</strong></td>
<td><input type="text" className="form-control" autoComplete="off" /></td>
<td></td>
<td></td>
</tr>
<tr>
<td><strong className="text-muted">Paterno</strong></td>
<td><input type="text" className="form-control" autoComplete="off" /></td>
<td><strong className="text-muted">Materno</strong></td>
<td><input type="text" className="form-control" autoComplete="off" /></td>
</tr>
<tr>
<td><strong className="text-muted">Nacimiento</strong></td>
<td><input type="date" className="form-control datepicker" autoComplete="off" /></td>
<td><strong className="text-muted">Nacionalidad</strong></td>
<td><select className="form-select"><option value="">Seleccione...</option></select></td>
</tr>
</tbody>
</table>
</div>
<div className="alert alert-light text-dark shadow" role="alert">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td className="text-start" colSpan={2}>
<h5><strong>Información de contacto</strong></h5>
</td>
</tr>
<tr>
<td><strong className="text-muted">Fono (+56)</strong></td>
<td colSpan={3}>
<input
type="tel"
maxLength={9}
onKeyDown={handleOnlyNumbers}
className="form-control"
autoComplete="off"
/>
</td>
</tr>
<tr className="needs-validation">
<td><strong className="text-muted">Mail</strong></td>
<td colSpan={3}>
<input type="email" className="form-control" placeholder="name@example.com" autoComplete="off" />
</td>
</tr>
<tr>
<td><strong className="text-muted">Dirección</strong></td>
<td colSpan={3}><input type="text" className="form-control" autoComplete="off" /></td>
</tr>
<tr>
<td><strong className="text-muted">Región</strong></td>
<td style={{ width: "35%" }}><select className="form-select"><option value="">Seleccione...</option></select></td>
<td style={{ width: "10%" }}><strong className="text-muted">Comuna</strong></td>
<td style={{ width: "35%" }}><select className="form-select"><option value="">Seleccione...</option></select></td>
</tr>
</tbody>
</table>
<table className="table table-sm mb-0 mt-3">
<tbody>
<tr>
<td style={{ width: "70%" }}></td>
<td>
<div className="d-grid gap-2">
<button type="button" className="btn btn-primary">
<Save className="me-2" /> Guardar
</button>
</div>
</td>
<td>
<div className="d-grid gap-2">
<button
type="button"
className="btn btn-secondary"
onClick={() => setVistas({ ...vistas, agregarProfe: false })}
>
Cancelar
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
)}
{/* SECCIÓN FICHA PROFESOR */}
{vistas.fichaProfe && (
<div className="row" id="ficha_profe">
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-6">
<h5>
<strong className="text-muted">Ficha</strong> <strong>Profesor</strong>
</h5>
</div>
<div className="col-md-6 text-end">
<button type="button" className="btn btn-primary btn-sm">
<i className="bx bx-transfer me-2"></i> Cambiar Profesor
</button>
</div>
</div>
</div>
</div>
<div className="col-md-3">
<div className="alert alert-light text-dark shadow" role="alert">
<table className="table table-sm table-borderless mb-0 text-center">
<tbody>
<tr>
<td colSpan={2}>
<User className="text-primary mb-2" style={{ fontSize: "50px" }} />
</td>
</tr>
<tr>
<td colSpan={2}>
<span className="fs-5">Juan Pérez</span>
</td>
</tr>
<tr>
<td colSpan={2}>
<strong><span className="fs-5">12.345.678-9</span></strong>
</td>
</tr>
<tr>
<td>
<div className="d-grid gap-2">
<button
type="button"
className="btn btn-light btn-sm border"
onClick={() => handleGmailPopup("juan@example.com", "Juan")}
>
{/* <MailSend className="me-1" /> */}
Mensaje
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div className="alert alert-light text-dark shadow" role="alert">
<table className="table table-sm table-borderless mb-0" style={{ fontSize: "14px" }}>
<tbody>
<tr>
<td colSpan={2}>
<span className="text-dark" style={{ fontSize: "18px" }}>Contacto</span>
<hr />
</td>
</tr>
<tr>
<td>
{/* <PhoneCall /> */}
</td>
<td>+56 9 1234 5678</td>
</tr>
<tr>
<td>
<Envelope />
</td>
<td>juan.perez@example.com</td>
</tr>
<tr>
<td>
{/* <CurrentLocation /> */}
</td>
<td>Av. Siempre Viva 123</td>
</tr>
<tr>
<td>
{/* <CurrentLocation /> */}
</td>
<td>Santiago</td>
</tr>
<tr>
<td>
{/* <Cake /> */}
</td>
<td>01/01/1990</td>
</tr>
<tr>
<td><Flag /></td>
<td>Chilena</td>
</tr>
<tr>
<td colSpan={2}>
<div className="d-grid gap-2">
<button
type="button"
className="btn btn-warning btn-sm"
onClick={() => setShowEditModal(true)}
>
<strong><Edit className="me-1" /> Editar</strong>
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-9">
<div className="row">
<div className="col-md-12">
<div className="alert alert-light text-dark mb-0" role="alert">
<div className="d-grid gap-2">
<div className="btn-group" role="group">
<button
type="button"
className="btn btn-light border-top-0 border-end-0 border-start-0 border border-primary border-3"
onClick={() => setVistas({ ...vistas, profePerfil: true, profeCursosActivos: false, profeCursosFinalizados: false })}
>
<UserCheck className="me-2" style={{ fontSize: "18px" }} />Perfil
</button>
<button
type="button"
className="btn btn-light border-top-0 border-end-0 border-start-0 border border-3"
onClick={() => setVistas({ ...vistas, profePerfil: false, profeCursosActivos: true, profeCursosFinalizados: false })}
>
<Pencil className="me-2" style={{ fontSize: "18px" }} />Cursos Activos
</button>
<button
type="button"
className="btn btn-light border-top-0 border-end-0 border-start-0 border border-3"
onClick={() => setVistas({ ...vistas, profePerfil: false, profeCursosActivos: false, profeCursosFinalizados: true })}
>
<File className="me-2" style={{ fontSize: "18px" }} />Cursos Finalizados
</button>
<button type="button" className="btn btn-light border-top-0 border-end-0 border-start-0 border border-3 disabled"></button>
</div>
</div>
</div>
{/* CURSOS ACTIVOS */}
{vistas.profeCursosActivos && (
<div id="profe_cursos_activos">
{vistas.profeCursosActivosOk ? (
<div className="row mt-3">
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row text-center">
<div className="col-md-3"></div>
<div className="col-md-1">
<Book className="text-primary mt-2" style={{ fontSize: "50px" }} />
</div>
<div className="col-md-2">
<span className="text-muted"><strong>Cursos</strong></span>
<h3><strong>2</strong></h3>
</div>
<div className="col-md-1">
<User className="text-success mt-2" style={{ fontSize: "50px" }} />
</div>
<div className="col-md-2">
<span className="text-muted"><strong>Alumnos</strong></span>
<h3><strong>25</strong></h3>
</div>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "5%" }}></th>
<th className="text-start" style={{ width: "5%" }}>ID</th>
<th className="text-start" style={{ width: "10%" }}>Curso</th>
<th className="text-start" style={{ width: "27%" }}>Curso</th>
<th className="text-center" style={{ width: "7%" }}>Participantes</th>
<th className="text-center" style={{ width: "10%" }}>Dias</th>
<th className="text-center" style={{ width: "18%" }}>Horas</th>
<th className="text-center" style={{ width: "20%" }}>Fechas</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start">
<a href="#"><span className="badge bg-primary" style={{ fontWeight: "normal" }}>Ver</span></a>
</td>
<td className="text-start">101</td>
<td className="text-start">Inglés</td>
<td className="text-start">Inglés Básico</td>
<td className="text-center">12</td>
<td className="text-center">Lu-Mi</td>
<td className="text-center">19:00 - 21:00</td>
<td className="text-center">01/03 / 30/04</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
) : (
<div className="alert alert-light text-dark mt-3" role="alert">
<div className="row">
<div className="col-md-3"></div>
<div className="col-md-6 text-center">
<div className="alert alert-light text-dark" role="alert">
<strong>
{/* <ErrorIcon className="text-primary" style={{ fontSize: "90px" }} /> */}
</strong>
<br /><br />
<h5><strong>El profesor no tiene Cursos Activos</strong></h5>
<hr />
<strong className="text-muted">
Si cree que esto es un error, contáctenos.{" "}
<a target="_blank" rel="noreferrer" href="https://norteamericano.freshdesk.com/support/tickets/new">
Generar Ticket
</a>
</strong>
</div>
</div>
</div>
</div>
)}
</div>
)}
{/* CURSOS FINALIZADOS */}
{vistas.profeCursosFinalizados && (
<div id="profe_cursos_finalizados">
<div className="alert alert-light text-dark mt-3" role="alert">
<div className="row">
<div className="col-md-3"></div>
<div className="col-md-6">
<table className="table table-sm table-borderless mb-0">
<tbody>
<tr>
<td><span className="text-muted"><strong>Año</strong></span></td>
<td><input type="text" className="form-control form-control-sm" /></td>
<td>
<div className="d-grid gap-2">
<button type="button" className="btn btn-primary btn-sm">Buscar</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
{/* PERFIL */}
{vistas.profePerfil && (
<div id="profe_perfil" className="mt-3">
<div className="alert alert-light text-dark">
<div className="row">
<div className="col-md-4">
<div className="progress text-start mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;DIURNO</strong></div>
</div>
<div className="progress text-center mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;VESPERTINO</strong></div>
</div>
</div>
<div className="col-md-2">
<div className="progress mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;0</strong></div>
</div>
<div className="progress mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;0</strong></div>
</div>
</div>
<div className="col-md-4">
<div className="progress text-start mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;PRESENCIAL</strong></div>
</div>
<div className="progress text-center mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;ONLINE</strong></div>
</div>
</div>
<div className="col-md-2">
<div className="progress mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;0</strong></div>
</div>
<div className="progress mb-2" style={{ height: "61px" }}>
<div style={{ fontSize: "20px", marginTop: "17px" }}><strong>&nbsp;&nbsp;0</strong></div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{showLoadingModal && (
<div className="modal fade show d-block" style={{ backgroundColor: "rgba(0,0,0,0.5)" }} tabIndex={-1}>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="float-start mt-2"><strong>SAM - Empresas</strong></h5>
</div>
<div className="modal-body alert text-center">
<h5><strong>Procesando, espere un momento</strong></h5>
<div className="spinner-grow spinner-grow-sm text-primary me-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger me-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary me-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger me-1" role="status"></div>
</div>
</div>
</div>
</div>
)}
{/* MODAL ALERTA / MENSAJES */}
{showAlertModal && (
<div className="modal fade show d-block" style={{ backgroundColor: "rgba(0,0,0,0.5)" }} tabIndex={-1}>
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary">
<h5 className="float-start mt-2"><strong>Módulo Academico - Empresa</strong></h5>
<button type="button" className="btn-close float-end" onClick={() => setShowAlertModal(false)}></button>
</div>
<div className="modal-body alert text-center">
<h5><strong>{mensajeAlerta}</strong></h5>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" onClick={() => setShowAlertModal(false)}>Close</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL EDITAR PROFESOR */}
{showEditModal && (
<div className="modal fade show d-block" style={{ backgroundColor: "rgba(0,0,0,0.5)" }} tabIndex={-1}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Editar Profe</h5>
<button type="button" className="btn-close" onClick={() => setShowEditModal(false)}></button>
</div>
<div className="modal-body">
<table className="table table-sm">
<tbody>
<tr>
<td><strong>Nombre</strong></td>
<td><input type="text" className="form-control" /></td>
</tr>
<tr>
<td><strong>Paterno</strong></td>
<td><input type="text" className="form-control" /></td>
</tr>
<tr>
<td><strong>Materno</strong></td>
<td><input type="text" className="form-control" /></td>
</tr>
<tr>
<td><strong>Fono (+56)</strong></td>
<td><input type="text" maxLength={9} className="form-control" /></td>
</tr>
<tr>
<td><strong>Mail</strong></td>
<td><input type="email" className="form-control" /></td>
</tr>
<tr>
<td></td>
<td>
<div className="d-grid gap-2">
<button type="button" className="btn btn-warning text-dark">
<strong><Save className="me-2" /> Guardar</strong>
</button>
<button type="button" className="btn btn-secondary" onClick={() => setShowEditModal(false)}>Cancelar</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+401 -2
View File
@@ -1,3 +1,402 @@
'use client';
import React, { useState } from 'react';
import Link from 'next/link';
import {
User,
//Graduation,
File,
//IdCard,
ContactBook,
Book,
AddressBook,
//ErrorAlt
} from '@boxicons/react';
interface Alumno {
idAlumno: string;
AP_Paterno: string;
AP_Materno: string;
Nombres: string;
}
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
// --- ESTADOS DE VISTA ---
const [currentView, setCurrentView] = useState<'menu' | 'buscar'>('menu');
const [errorData, setErrorData] = useState(false);
// --- ESTADOS DE FORMULARIO DE BÚSQUEDA ---
const [tipoBusqueda, setTipoBusqueda] = useState('run');
const [textoBusqueda, setTextoBusqueda] = useState('');
// --- ESTADOS DE MODALES ---
const [showModalResultados, setShowModalResultados] = useState(false);
const [showLoadingModal, setShowLoadingModal] = useState(false);
const [showErrorModal, setShowErrorModal] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
// --- DATOS DE EJEMPLO PARA RESULTADOS ---
const [alumnosEncontrados, setAlumnosEncontrados] = useState<Alumno[]>([]);
// --- MANEJADORES DE EVENTOS ---
const handleOpenBuscarAlumno = () => {
setCurrentView('buscar');
setErrorData(false);
};
const handleBuscarAlumno = (e: React.FormEvent) => {
e.preventDefault();
if (!textoBusqueda.trim()) {
setErrorData(true);
return;
}
setErrorData(false);
setShowLoadingModal(true);
// Simulación de búsqueda
setTimeout(() => {
setShowLoadingModal(false);
const mockResultados: Alumno[] = [
{ idAlumno: '12.345.678-9', AP_Paterno: 'Pérez', AP_Materno: 'González', Nombres: 'Juan Carlos' },
{ idAlumno: '98.765.432-1', AP_Paterno: 'Pérez', AP_Materno: 'Muñoz', Nombres: 'María José' }
];
setAlumnosEncontrados(mockResultados);
setShowModalResultados(true);
}, 1000);
};
const handleSeleccionarAlumno = (alumno: Alumno) => {
setShowModalResultados(false);
setShowLoadingModal(true);
// Redirección o acción con el alumno seleccionado
setTimeout(() => {
setShowLoadingModal(false);
alert(`Alumno seleccionado: ${alumno.Nombres} ${alumno.AP_Paterno}`);
}, 800);
};
return (
<div className="container-fluid py-4">
{/* VISTA: MENÚ PRINCIPAL */}
{currentView === 'menu' && (
<div id="menu">
<div className="row">
<div className="col-md-2" />
{/* SECCIÓN SECRETARÍA */}
<div className="col-md-4">
<div className="alert alert-light text-dark shadow-sm">
<h5><strong>Secretaria</strong></h5>
<hr />
<table className="table table-hover mb-0">
<tbody>
<tr>
<td style={{ width: '5%' }}>
<User className="text-primary border rounded p-1" style={{ fontSize: '32px' }} />
</td>
<td>
<div className="d-grid gap-2 mt-2">
<button
type="button"
onClick={handleOpenBuscarAlumno}
className="btn btn-link text-start p-0 text-decoration-none alert-link"
>
Ficha del Alumno
</button>
</div>
</td>
</tr>
<tr>
<td>
{/* <Graduation className="text-primary border rounded p-1" style={{ fontSize: '32px' }} /> */}
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/secretaria/FichaProfesor" className="text-decoration-none alert-link">
Ficha del Profesor
</Link>
</div>
</td>
</tr>
<tr>
<td>
<File className="text-success border rounded p-1" style={{ fontSize: '32px' }} />
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/secretaria/EvaluacionPO" className="text-decoration-none alert-link">
Ingreso de evaluación
</Link>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
{/* SECCIÓN INFORMES */}
<div className="col-md-4">
<div className="alert alert-light text-dark shadow-sm">
<h5><strong>Informes</strong></h5>
<hr />
<table className="table table-hover mb-0">
<tbody>
<tr>
<td style={{ width: '5%' }}>
{/* <IdCard className="text-danger border rounded p-1" style={{ fontSize: '32px' }} /> */}
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/Informes/SEAlumnos" className="text-decoration-none alert-link">
Informes de Alumnos
</Link>
</div>
</td>
</tr>
<tr>
<td>
<ContactBook className="text-warning border rounded p-1" style={{ fontSize: '32px' }} />
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/Informes/SEAlumnosCursosCC" className="text-decoration-none alert-link">
Informes de Alumnos por cursos
</Link>
</div>
</td>
</tr>
<tr>
<td>
<Book className="text-warning border rounded p-1" style={{ fontSize: '32px' }} />
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/Informes/SEAlumnosCursosPC" className="text-decoration-none alert-link">
Informes de Alumnos por cursos (Plan central)
</Link>
</div>
</td>
</tr>
<tr>
<td>
<AddressBook className="text-danger-emphasis border rounded p-1" style={{ fontSize: '32px' }} />
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link href="/Informes/SEAlumnosEmpresas" className="text-decoration-none alert-link">
Informes de Alumnos por empresas
</Link>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-2" />
</div>
</div>
)}
{/* VISTA: BUSCAR ALUMNO */}
{currentView === 'buscar' && (
<div id="buscar_alumno">
<div className="row" style={{ marginTop: '5%' }}>
<div className="col-md-4" />
<div className="col-md-4 text-center">
<strong>
<User className="text-primary border rounded p-2 mb-2" style={{ fontSize: '60px' }} />
</strong>
<div className="alert alert-light text-dark shadow-sm" role="alert">
<form onSubmit={handleBuscarAlumno}>
<table className="table table-borderless mb-0">
<tbody>
<tr>
<td className="text-start">
<h5><strong>Ficha del Alumno</strong></h5>
</td>
<td className="text-end">
<button
type="button"
className="btn btn-link p-0 text-decoration-none"
onClick={() => setCurrentView('menu')}
>
Volver
</button>
</td>
</tr>
<tr>
<td colSpan={2}>
<br />
<select
className="form-select"
value={tipoBusqueda}
onChange={(e) => setTipoBusqueda(e.target.value)}
>
<option value="run">Búsqueda por RUN</option>
<option value="nombre">Búsqueda por Nombre</option>
</select>
</td>
</tr>
<tr>
<td colSpan={2}>
<input
type="text"
className="form-control form-control-sm"
autoComplete="off"
placeholder="Ingrese término de búsqueda..."
value={textoBusqueda}
onChange={(e) => setTextoBusqueda(e.target.value)}
/>
</td>
</tr>
{errorData && (
<tr>
<td colSpan={2}>
<div className="alert alert-danger text-center mb-0 mt-2">
<h5 className="mb-0 d-flex align-items-center justify-center gap-2">
{/* <ErrorAlt /> */}
Error en el RUN seleccionado
</h5>
</div>
</td>
</tr>
)}
<tr>
<td colSpan={2}>
<div className="d-grid gap-2 mt-2">
<button type="submit" className="btn btn-primary">
Buscar
</button>
</div>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
<div className="col-md-4" />
</div>
</div>
)}
{/* MODAL: RESULTADOS ALUMNOS */}
{showModalResultados && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">Ficha Alumno</h5>
<button
type="button"
className="btn-close"
onClick={() => setShowModalResultados(false)}
></button>
</div>
<div className="modal-body text-center">
<table className="table table-sm mb-0" style={{ fontSize: '14px' }}>
<thead>
<tr>
<th className="text-start" scope="col" style={{ width: '11%' }}></th>
<th className="text-start" scope="col" style={{ width: '12%' }}><strong>Run</strong></th>
<th className="text-start" scope="col" style={{ width: '25%' }}><strong>Paterno</strong></th>
<th className="text-start" scope="col" style={{ width: '25%' }}><strong>Materno</strong></th>
<th className="text-start" scope="col" style={{ width: '27%' }}><strong>Nombre</strong></th>
</tr>
</thead>
<tbody>
{alumnosEncontrados.map((alumno, index) => (
<tr key={index}>
<td className="text-start" style={{ width: '11%' }}>
<button
type="button"
className="btn p-0 border-0 background-transparent"
onClick={() => handleSeleccionarAlumno(alumno)}
>
<span className="badge bg-warning text-dark">Seleccionar</span>
</button>
</td>
<td className="text-start" style={{ width: '12%' }}>
<strong>{alumno.idAlumno}</strong>
</td>
<td className="text-start" style={{ width: '25%' }}>
<span>{alumno.AP_Paterno}</span>
</td>
<td className="text-start" style={{ width: '25%' }}>
<span>{alumno.AP_Materno}</span>
</td>
<td className="text-start" style={{ width: '27%' }}>
<span>{alumno.Nombres}</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={() => setShowModalResultados(false)}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL: CARGANDO (LOADING) */}
{showLoadingModal && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="mt-2 mb-0"><strong>Secretaría</strong></h5>
</div>
<div className="modal-body text-center py-4">
<h5 className="mb-3"><strong>Procesando, espere un momento</strong></h5>
<div className="spinner-grow spinner-grow-sm text-primary mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary mx-1" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger mx-1" role="status"></div>
</div>
</div>
</div>
</div>
)}
{/* MODAL: ERROR */}
{showErrorModal && (
<div className="modal fade show d-block" tabIndex={-1} style={{ backgroundColor: 'rgba(0,0,0,0.5)' }}>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="mt-2 mb-0"><strong>Error</strong></h5>
<button type="button" className="btn-close" onClick={() => setShowErrorModal(false)}></button>
</div>
<div className="modal-body text-center py-4">
<h5><strong>{errorMessage || 'Ocurrió un error en la operación.'}</strong></h5>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setShowErrorModal(false)}>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
}