Arreglo de node_modules

This commit is contained in:
Fimm committed 2026-09-07 15:17:43 +00:00
commit eed3b45de3
40 files changed
+13127

No files matched your search

Executable
+41
View File
@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
Vendored Executable
+1
View File
@@ -0,0 +1 @@
{}
Executable
+36
View File
@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
+18
View File
@@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
".next/**",
"out/**",
"build/**",
"next-env.d.ts",
]),
]);
export default eslintConfig;
Executable
+8
View File
@@ -0,0 +1,8 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
reactCompiler: true,
};
export default nextConfig;
Executable
+29
View File
@@ -0,0 +1,29 @@
{
"name": "academicoempresas",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
},
"dependencies": {
"@boxicons/react": "^1.0.3",
"bootstrap": "5.3.8",
"next": "16.2.12",
"react": "19.2.4",
"react-dom": "19.2.4",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/bootstrap": "^5.2.11",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"babel-plugin-react-compiler": "1.0.0",
"eslint": "^9",
"eslint-config-next": "16.2.12",
"typescript": "^5"
}
}
Generated Executable
+3920
View File
File diff suppressed because it is too large. Load diff
+6
View File
@@ -0,0 +1,6 @@
allowBuilds:
sharp: true
unrs-resolver: true
ignoredBuiltDependencies:
- sharp
- unrs-resolver
+1
View File
@@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

+1
View File
@@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

Executable
+511
View File
@@ -0,0 +1,511 @@
layout
________
"use client";
import { Geist, Geist_Mono } from "next/font/google";
import "bootstrap/dist/css/bootstrap.min.css";
import { useState } from "react";
import {
Menu, MenuRight, Grid, School, Buildings, Book, Group, SwapHorizontal, DoorOpen
} from "@boxicons/react";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const [open, setOpen] = useState(true);
return (
<html lang="en" className={`${geistSans.variable} ${geistMono.variable}`}>
<body className="d-flex m-0 vh-100" style={{ fontFamily: "system-ui, sans-serif" }}>
<div
className={`sidebar d-flex flex-column flex-shrink-0 ${open ? "open" : ""}`}
style={{
width: open ? 220 : 60,
background: "#3C3B6E",
transition: "width 0.3s ease",
overflow: "hidden",
}}
>
<div className="logo-details d-flex align-items-center justify-content-between p-3" style={{ height: 60, whiteSpace: "nowrap" }}>
{open && <div className="logo_name fw-bold fs-4 text-white">SAM</div>}
<button
onClick={() => setOpen(!open)}
className="btn border-0 text-white p-0 d-flex align-items-center"
style={{ background: "none", fontSize: 24 }}
>
{open ? <MenuRight width={24} height={24} /> : <Menu width={24} height={24} />}
</button>
</div>
<ul className="nav-list list-unstyled m-0 flex-grow-1 d-flex flex-column px-0 py-2">
<li className="position-relative">
<a href="/" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Grid width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Dashboard</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Dashboard</span>
</li>
<li className="position-relative">
<a href="/academico" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<School width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Academico</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Academico</span>
</li>
<li className="position-relative">
<a href="/empresas" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Buildings width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Gestion Empresas</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Gestion Empresas</span>
</li>
<li className="position-relative">
<a href="/cursos" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Book width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Curso</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Curso</span>
</li>
<li className="position-relative">
<a href="/secretaria" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Group width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Secretaría</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Secretaría</span>
</li>
<li className="position-relative">
<a href="https://sam.norteamericano.cl/academico/index.aspx" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<SwapHorizontal width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Plan Central</span>
</a>
<span className="tooltip badge rounded-pill bg-dark" style={{ display: open ? "none" : "block", position: "absolute", left: 65, top: 12, zIndex: 10, whiteSpace: "nowrap" }}>Plan Central</span>
</li>
</ul>
<div className="profile border-top" style={{ borderColor: "rgba(255,255,255,0.2)" }}>
<div className="profile-details d-flex align-items-center justify-content-between p-3" style={{ whiteSpace: "nowrap" }}>
{open && (
<div className="name_job text-white" style={{ fontSize: 13, lineHeight: 1.3 }}>
<div className="name fw-bold" style={{ fontSize: 14 }}>Usuario</div>
<div className="job" style={{ opacity: 0.8 }}>Sede</div>
</div>
)}
<a href="/logout" className="text-white text-decoration-none d-flex align-items-center" style={{ flexShrink: 0 }}>
<DoorOpen width={20} height={20} />
</a>
</div>
</div>
</div>
<section className="home-section flex-grow-1 overflow-auto bg-light">
<main className="container-fluid p-3">{children}</main>
</section>
</body>
</html>
);
}
_________
page
________
'use client'
import { useState, useEffect } from "react"; // 1. Agregado useEffect
import {
Sun,Moon
} from "@boxicons/react";
export default function Home() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
return setLoading(false);
}, []);
const alumnos = [
{ id: 101, tipo: "Regular", curso: "Inglés Básico Intensivo", profesor: "John Doe", sede: "Sede Central", sala: "Sala A", horario: "09:00 / 10:30", inicio: "09:00", inicioBadge: "bg-warning text-dark", termino: "10:30", sesion: "En proceso", sesionBadge: "bg-light text-dark" },
{ id: 102, tipo: "Intensivo", curso: "Francés Avanzado", profesor: "Maria Perez", sede: "Sede Norte", sala: "Sala B", horario: "10:30 / 12:00", inicio: "10:30", inicioBadge: "bg-success text-white", termino: "12:00", sesion: "Completada", sesionBadge: "bg-success text-white" },
{ id: 103, tipo: "Regular", curso: "Alemán Intermedio", profesor: "Carlos López", sede: "Sede Sur", sala: "Sala C", horario: "14:00 / 15:30", inicio: "14:00", inicioBadge: "bg-warning text-dark", termino: "15:30", sesion: "En proceso", sesionBadge: "bg-light text-dark" },
{ id: 104, tipo: "Intensivo", curso: "Inglés Avanzado", profesor: "Ana Torres", sede: "Sede Central", sala: "Sala A", horario: "16:00 / 17:30", inicio: "16:00", inicioBadge: "bg-danger text-white", termino: "17:30", sesion: "Pendiente", sesionBadge: "bg-danger text-white" },
{ id: 105, tipo: "Regular", curso: "Japonés Básico", profesor: "Takashi Tanaka", sede: "Sede Norte", sala: "Sala D", horario: "18:00 / 19:30", inicio: "18:00", inicioBadge: "bg-warning text-dark", termino: "19:30", sesion: "En proceso", sesionBadge: "bg-light text-dark" },
];
if (loading) return <div className="text-center py-5">Cargando...</div>;
if (error) return <div className="alert alert-danger my-3">{error}</div>;
return (
<div className="row">
<div className="col-md-12 mx-auto">
<div className="row">
{/* <!-- Buscador y Filtros --> */}
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
{/* CORREGIDO: margin-bottom cambiado a marginBottom */}
<div className="row" style={{ marginBottom: '-10px' }}>
<div className="col-12">
<div className="row">
<div className="col-md-4 mt-2">
<h1><i className="bx bx-time me-1 float-start"></i></h1>
<strong>Mostrando cursos del día</strong>
</div>
<div className="col-md-8"></div>
</div>
</div>
<div className="col-md-6">
<div className="row">
<div className="col-md-4 mt-2">
<input type="date" id="TextBoxFecha" className="form-control" />
</div>
<div className="col-md-4 mt-2">
<select id="ListaSedes" className="form-control">
<option value="">Seleccione Sede</option>
<option value="">TODAS</option>
<option value="">MONEDA</option>
<option value="">PROVIDENCIA</option>
<option value="">LA FLORIDA</option>
<option value="">ONLINE</option>
<option value="">EMPRESAS</option>
</select>
</div>
<div className="col-md-4 mt-2 d-grid gap-2">
<button type="button" id="ButtonSearchMod" className="btn btn-primary">Buscar</button>
</div>
</div>
</div>
<div className="col-md-6">
<div className="row">
<div className="col-md-6 d-grid">
<button type="button" id="LinkButtonJornada01" className="alert-link text-decoration-none btn p-0 text-start">
<div className="alert alert-light text-dark mb-4" id="div_jornada_01" role="alert">
<div className="mb-4">
<h3 className="float-start me-1"><Sun /></h3>
<h5 className="float-start">
<strong><span id="LabelNombreJornada">Diurno</span></strong>
</h5>
</div>
</div>
</button>
</div>
<div className="col-md-6 d-grid">
<button type="button" id="LinkButtonJornada02" className="alert-link text-decoration-none btn p-0 text-start">
<div className="alert alert-secondary text-dark mb-4" id="div_jornada_02" role="alert">
<div className="mb-4">
<h3 className="float-start me-1"><Moon /></h3>
<h5 className="float-start">
<strong><span id="LabelNombreJornada02">Vespertino</span></strong>
</h5>
</div>
</div>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{/* <!-- Tarjetas de Contadores / Indicadores --> */}
<div className="col-md-12">
<div className="row">
<div className="col-md-2" id="Div1">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1><i className="bx bxs-buildings"></i></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><span id="LabelEmpTotal">0 %</span></strong></h5>
</div>
</div>
</div>
</div>
<div className="col-md-2" id="promedio_cursos">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1><i className="bx bxs-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><span id="LabelCursosTotal">0 %</span></strong></h5>
</div>
</div>
</div>
</div>
<div className="col-md-6" id="promedio_alumnos">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-3 text-center">
<h1><i className="bx bxs-user-circle"></i></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><span id="LabelAlmConSNC">0</span></strong></h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted"><strong>Sin SENCE</strong></span>
<h5><strong><span id="LabelAlmSinSNC">0</span></strong></h5>
</div>
<div className="col-md-4 text-center">
<span className="text-muted"><strong>Total</strong></span>
<h5><strong><span id="LabelAlumnosTotal">0</span></strong></h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-2 mt-2" id="excel_primary">
<button type="button" id="LinkButtonExcel" className="text-decoration-none btn p-0 text-start w-100">
<div className="alert alert-success" role="alert">
<div className="row">
<div className="col-md-3">
<h1><i className="bx bx-export"></i></h1>
</div>
<div className="col text-center">
<span className="text-muted"><strong>Excel</strong></span>
<h5><strong><span id="Label1">Exportar</span></strong></h5>
</div>
</div>
</div>
</button>
</div>
</div>
</div>
{/* Listado de alumnos*/}
<div className="col-md-12">
<div className="row">
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive" id="listado_cursos_dia">
<table className="table table-sm mb-0" style={{ fontSize: '12px' }}>
<thead>
<tr>
{/* CORREGIDO: Anchos de columnas pasados a objetos style */}
<th className="text-center" scope="col" style={{ width: '5%' }}>ID</th>
<th className="text-center" scope="col" style={{ width: '5%' }}>Tipo</th>
<th scope="col" style={{ width: '20%' }}>Curso</th>
<th scope="col" style={{ width: '19%' }}>Profesor</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sede</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sala</th>
<th className="text-center" scope="col" style={{ width: '14%' }}>Horario</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Inicio</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Termino</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sesion</th>
</tr>
</thead>
<tbody>
{alumnos.map((a) => (
<tr key={a.id}>
<td className="text-center">{a.id}</td>
<td className="text-center">{a.tipo}</td>
<td className="text-start">{a.curso}</td>
<td className="text-start">{a.profesor}</td>
<td className="text-center">{a.sede}</td>
<td className="text-center">{a.sala}</td>
<td className="text-center">{a.horario}</td>
<td className="text-center">
<span className={`badge rounded-pill ${a.inicioBadge}`}>{a.inicio}</span>
</td>
<td className="text-center">{a.termino}</td>
<td className="text-center">
<span className={`badge rounded-pill ${a.sesionBadge}`}>{a.sesion}</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Vista alternativa: Sin clases */}
<div className="text-center d-none" id="listado_cursos_no_clases">
<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">
{/* CORREGIDO: style cambiado a objeto */}
<strong><i className="bx bx-error text-primary" style={{ fontSize: '90px' }}></i></strong>
<br /><br />
<h5><strong>Jornada sin clases</strong></h5>
<hr />
<strong className="text-muted">Si cree que esto es un error, contáctenos. <a target="_blank" rel="noopener noreferrer" href="https://norteamericano.freshdesk.com/support/tickets/new">Generar Ticket</a></strong>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
________
layout v2
_________
"use client";
import { Geist, Geist_Mono } from "next/font/google";
import "bootstrap/dist/css/bootstrap.min.css";
import { useState, useEffect } from "react";
import {
Menu, MenuRight, Grid, School, Buildings, Book, Group, SwapHorizontal, DoorOpen, Sun, Moon
} from "@boxicons/react";
const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
const [open, setOpen] = useState(true);
const [theme, setTheme] = useState<"light" | "dark">("light");
// Cargar tema guardado o preferencia del sistema al iniciar
useEffect(() => {
const savedTheme = localStorage.getItem("theme") as "light" | "dark" | null;
const systemDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const currentTheme = savedTheme || (systemDark ? "dark" : "light");
setTheme(currentTheme);
document.documentElement.setAttribute("data-bs-theme", currentTheme);
}, []);
// Alternar entre Claro y Oscuro
const toggleTheme = () => {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
document.documentElement.setAttribute("data-bs-theme", newTheme);
localStorage.setItem("theme", newTheme);
};
return (
<html lang="es" className={`${geistSans.variable} ${geistMono.variable}`} data-bs-theme={theme}>
<body className="d-flex m-0 vh-100" style={{ fontFamily: "system-ui, sans-serif" }}>
<div
className={`sidebar d-flex flex-column flex-shrink-0 ${open ? "open" : ""}`}
style={{
width: open ? 220 : 60,
background: "#3C3B6E",
transition: "width 0.3s ease",
overflow: "hidden",
}}
>
<div className="logo-details d-flex align-items-center justify-content-between p-3" style={{ height: 60, whiteSpace: "nowrap" }}>
{open && <div className="logo_name fw-bold fs-4 text-white">SAM</div>}
<button
onClick={() => setOpen(!open)}
className="btn border-0 text-white p-0 d-flex align-items-center"
style={{ background: "none", fontSize: 24 }}
>
{open ? <MenuRight width={24} height={24} /> : <Menu width={24} height={24} />}
</button>
</div>
<ul className="nav-list list-unstyled m-0 flex-grow-1 d-flex flex-column px-0 py-2">
<li className="position-relative">
<a href="/" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Grid width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Dashboard</span>
</a>
</li>
<li className="position-relative">
<a href="/academico" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<School width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Academico</span>
</a>
</li>
<li className="position-relative">
<a href="/empresas" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Buildings width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Gestion Empresas</span>
</a>
</li>
<li className="position-relative">
<a href="/cursos" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Book width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Curso</span>
</a>
</li>
<li className="position-relative">
<a href="/secretaria" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Group width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Secretaría</span>
</a>
</li>
<li className="position-relative">
<a href="https://sam.norteamericano.cl/academico/index.aspx" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<SwapHorizontal width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Plan Central</span>
</a>
</li>
</ul>
{/* Botón para cambiar tema */}
<div className="px-2 py-2 border-top" style={{ borderColor: "rgba(255,255,255,0.2)" }}>
<button
onClick={toggleTheme}
className="btn text-white d-flex align-items-center gap-3 w-100 py-2 px-2 border-0"
style={{ background: "rgba(255,255,255,0.1)", borderRadius: 6, whiteSpace: "nowrap" }}
title="Cambiar tema"
>
{theme === "light" ? <Moon width={20} height={20} /> : <Sun width={20} height={20} />}
{open && <span>{theme === "light" ? "Modo Oscuro" : "Modo Claro"}</span>}
</button>
</div>
<div className="profile border-top" style={{ borderColor: "rgba(255,255,255,0.2)" }}>
<div className="profile-details d-flex align-items-center justify-content-between p-3" style={{ whiteSpace: "nowrap" }}>
{open && (
<div className="name_job text-white" style={{ fontSize: 13, lineHeight: 1.3 }}>
<div className="name fw-bold" style={{ fontSize: 14 }}>Usuario</div>
<div className="job" style={{ opacity: 0.8 }}>Sede</div>
</div>
)}
<a href="/logout" className="text-white text-decoration-none d-flex align-items-center" style={{ flexShrink: 0 }}>
<DoorOpen width={20} height={20} />
</a>
</div>
</div>
</div>
<section className="home-section flex-grow-1 overflow-auto bg-body-tertiary">
<main className="container-fluid p-3">{children}</main>
</section>
</body>
</html>
);
}
+349
View File
@@ -0,0 +1,349 @@
"use client";
import React, { useState } from "react";
import Link from "next/link";
import { User } from "@boxicons/react";
// Interface para mapear la estructura de la lista de contratos anulados
interface ContratoAnuladoItem {
idEmpresas: string;
empresa: string;
Contrato: string;
Fecha: string;
DescripcionActividad: string;
usuarioResponsable: string;
}
export default function ContratosHistorialPage() {
// --- ESTADOS DE CONTROLES Y SECCIONES ---
const [mes, setMes] = useState("");
const [agno, setAgno] = useState("");
const [showSearch, setShowSearch] = useState(false);
const [mensajeLabel, setMensajeLabel] = useState("");
// --- ESTADOS DE MODALES Y CARGA ---
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({ show: false, message: "" });
// --- DATOS SIMULADOS (DataList / Grid) ---
const [contratosAnulados, setContratosAnulados] = useState<ContratoAnuladoItem[]>([
{
idEmpresas: "76.123.456-7",
empresa: "Empresa Ejemplo S.A.",
Contrato: "1002",
Fecha: "2026-02-10",
DescripcionActividad: "Anulación solicitada por el cliente por cambio de presupuesto",
usuarioResponsable: "AdminUser",
},
]);
// --- MANEJADORES DE EVENTOS ---
const handleBuscar = (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
// Simulación de respuesta de backend
setTimeout(() => {
setIsLoading(false);
if (!mes || !agno) {
setModalAlerta({
show: true,
message: "Por favor seleccione un mes e ingrese un año válido.",
});
return;
}
setShowSearch(true);
setMensajeLabel("");
}, 800);
};
const handleExportarExcel = (e: React.MouseEvent) => {
e.preventDefault();
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({
show: true,
message: "Informe mensual exportado correctamente a Excel.",
});
}, 1000);
};
return (
<div className="container-fluid py-3">
<div className="row">
<div className="col-md-12">
<div className="row">
{/* CABECERA IZQUIERDA */}
<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-8 d-flex align-items-center">
<strong>
<User style={{ fontSize: "24px" }} />
</strong>
<strong>
<span className="ms-2">Contratos anulados por mes</span>
</strong>
</div>
<div className="col text-end">
<Link
href="/Clientes/Index"
className="btn btn-warning text-dark btn-sm fw-bold"
>
Volver
</Link>
</div>
</div>
</div>
</div>
{/* CABECERA DERECHA / FILTROS DE BÚSQUEDA */}
<div className="col-md-7">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<form onSubmit={handleBuscar} className="row align-items-center">
<div className="col text-end">
<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="">-- Seleccione --</option>
<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 text-end">
<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)}
placeholder="AAAA"
/>
</div>
<div className="col">
<button
type="submit"
className="btn btn-primary btn-sm d-grid w-100"
>
Buscar
</button>
</div>
</form>
</div>
</div>
{/* BOTÓN EXPORTAR EXCEL */}
<div className="col-md-12 mx-auto">
<button
type="button"
className="btn p-0 text-start w-100 text-decoration-none border-0 bg-transparent"
onClick={handleExportarExcel}
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1 className="mb-0">
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5 className="mb-0">
<strong>Exportar Mensual</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
{/* TABLA DE RESULTADOS */}
{showSearch && (
<div className="col-md-12 mt-3" id="div_search">
<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-start" style={{ width: "7%" }}>
RUT Empresa
</th>
<th className="text-start" style={{ width: "20%" }}>
Empresa
</th>
<th className="text-start" style={{ width: "7%" }}>
Contrato
</th>
<th className="text-start" style={{ width: "12%" }}>
Fecha
</th>
<th className="text-start" style={{ width: "40%" }}>
Observacion
</th>
<th className="text-start" style={{ width: "11%" }}>
Responsable
</th>
</tr>
</thead>
<tbody>
{contratosAnulados.map((item, index) => (
<tr key={index}>
<td className="text-start" style={{ width: "3%" }}></td>
<td className="text-start" style={{ width: "7%" }}>
{item.idEmpresas}
</td>
<td className="text-start" style={{ width: "20%" }}>
{item.empresa}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.Contrato}
</td>
<td className="text-start" style={{ width: "12%" }}>
{item.Fecha}
</td>
<td className="text-start" style={{ width: "40%" }}>
{item.DescripcionActividad}
</td>
<td className="text-start" style={{ width: "11%" }}>
{item.usuarioResponsable}
</td>
</tr>
))}
</tbody>
</table>
{mensajeLabel && (
<h4 className="mt-2">
<span>{mensajeLabel}</span>
</h4>
)}
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* --- MODAL ALERTA / ERRORES --- */}
{modalAlerta.show && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
>
<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 - Empresa</strong>
</h5>
<button
type="button"
className="btn-close float-end mt-1"
onClick={() => setModalAlerta({ show: false, message: "" })}
aria-label="Close"
></button>
</div>
<div
className="modal-body alert mb-0"
style={{ textAlign: "justify" }}
>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.message}</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, message: "" })}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CARGANDO (LOADING SPINNER) --- */}
{isLoading && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
>
<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>Procesando</strong>
</h5>
</div>
<div
className="modal-body alert mb-0"
style={{ textAlign: "justify" }}
>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>Espere un momento, por favor...</strong>
</h5>
<div className="d-flex justify-content-center gap-1 mt-3">
<div
className="spinner-grow spinner-grow-sm text-primary"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+865
View File
@@ -0,0 +1,865 @@
"use client";
import React, { useState } from "react";
import Link from "next/link";
import {
User,
// Transfer,
// Export,
// BxsFilePdf,
SearchPlus,
} from "@boxicons/react";
// Types para los datos de las tablas
interface ArchivoItem {
contrato: string;
cotizacion: string;
tipoVenta: string;
empresa: string;
tipoContrato: string;
Responsable: string;
observacion: string;
fechaobservacion: string;
}
interface ContratoDetalleItem {
Url: string;
Contrato: string;
"Firma Estado": number;
"CURSO ID": string;
CURSO: string;
JORNADA: string;
DIREMP: string;
Fecha: string;
Valor: string;
}
interface OCItem {
Detalle: string;
"Numero interno": string;
"Fecha de subida pago": string;
"Tipo documento": string;
Responsable: string;
}
interface SNCItem {
Detalle: string;
codInscripcion: string;
"Fecha de subida": string;
Responsable: string;
}
interface AlumnoItem {
run: string;
nombreCompleto: string;
tipoRegistro: string;
empresaApoderada: string;
}
export default function AutorizadosPage() {
// --- ESTADOS DE SECCIONES (Visibilidad) ---
const [showSearch, setShowSearch] = useState(true);
const [showBusqueda, setShowBusqueda] = useState(false);
const [showDetalle, setShowDetalle] = useState(false);
// --- ESTADOS DE CONTROLES ---
const [estado, setEstado] = useState("");
const [mes, setMes] = useState("");
const [agno, setAgno] = useState("");
// --- ESTADOS DE VALORES DE DETALLE ---
const [neto, setNeto] = useState("0");
const [descuento, setDescuento] = useState("0");
const [total, setTotal] = useState("0");
// --- ESTADOS DE MODALES ---
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({ show: false, message: "" });
const [modalAlumnos, setModalAlumnos] = useState(false);
// --- DATOS SIMULADOS ---
const [filesList, setFilesList] = useState<ArchivoItem[]>([
{
contrato: "1001",
cotizacion: "5001",
tipoVenta: "Cerrado",
empresa: "Empresa Ejemplo S.A.",
tipoContrato: "Anual",
Responsable: "Juan Pérez",
observacion: "Contrato Aprobado",
fechaobservacion: "2026-02-15",
},
]);
const [contratosDetalleList, setContratosDetalleList] = useState<
ContratoDetalleItem[]
>([
{
Url: "https://empresas.norteamericano.cl/documento.pdf",
Contrato: "1001",
"Firma Estado": 1,
"CURSO ID": "ENG-01",
CURSO: "Inglés Avanzado",
JORNADA: "Vespertina",
DIREMP: "Providencia",
Fecha: "2026-02-01",
Valor: "$500.000",
},
]);
const [ocList, setOcList] = useState<OCItem[]>([
{
Detalle: "comprobante_1.pdf",
"Numero interno": "OC-9982",
"Fecha de subida pago": "2026-02-10",
"Tipo documento": "Orden de Compra",
Responsable: "Maria Lopez",
},
]);
const [sncList, setSncList] = useState<SNCItem[]>([
{
Detalle: "sence_1.pdf",
codInscripcion: "SNC-2026-A",
"Fecha de subida": "2026-02-12",
Responsable: "Pedro Gomez",
},
]);
const [alumnosList, setAlumnosList] = useState<AlumnoItem[]>([
{
run: "12.345.678-9",
nombreCompleto: "Carlos Mendoza",
tipoRegistro: "Regular",
empresaApoderada: "Empresa Ejemplo S.A.",
},
]);
// --- MANEJADORES DE EVENTOS ---
const handleEstadoChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const value = e.target.value;
setEstado(value);
if (value) {
setShowSearch(false);
setShowBusqueda(true);
}
};
const handleBuscar = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
}, 1000);
};
const handleVerDetalle = (cont: string, cotz: string, type: string) => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setShowBusqueda(false);
setShowDetalle(true);
}, 800);
};
const handleVerParticipantes = (contratoId: string) => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlumnos(true);
}, 600);
};
const handleExportarExcel = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({
show: true,
message: "Informe generado correctamente.",
});
}, 1000);
};
return (
<div className="container-fluid py-3">
<div className="row">
<div className="col-md-12" id="contratos_autorizados">
<div className="row">
{/* CABECERA IZQUIERDA */}
<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 d-flex align-items-center">
<User style={{ fontSize: "24px" }} />
<strong className="ms-2">Contratos Autorizados</strong>
</div>
<div className="col text-end">
<Link
href="../Clientes/Index"
className="btn btn-warning text-dark btn-sm fw-bold"
>
Volver
</Link>
</div>
</div>
</div>
</div>
{/* CABECERA DERECHA / SELECCIÓN DE ESTADO */}
<div className="col-md-7">
<div className="alert alert-light text-dark shadow-sm" role="alert">
{showSearch && (
<div className="row align-items-center" id="div_search">
<div className="col">
<span className="fw-bold">Estado</span>
</div>
<div className="col">
<select
className="form-select"
value={estado}
onChange={handleEstadoChange}
>
<option value="">-- Seleccione --</option>
<option value="1">Autorizados</option>
<option value="2">Pendientes</option>
</select>
</div>
</div>
)}
{!showSearch && (
<div className="row" id="div_back">
<div className="col">
<button
type="button"
className="btn btn-warning text-dark btn-sm fw-bold d-inline-flex align-items-center gap-1"
onClick={() => {
setShowSearch(true);
setShowBusqueda(false);
setShowDetalle(false);
}}
>
{/* <Transfer /> */}
Volver
</button>
</div>
</div>
)}
</div>
</div>
{/* SECCIÓN DE BÚSQUEDA Y LISTADO PRINCIPAL */}
{showBusqueda && (
<div className="col-md-12" id="div_busqueda">
<div className="row">
<div className="col-md-9">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col-1">
<span className="fw-bold">Month</span>
</div>
<div className="col">
<select
className="form-select"
value={mes}
onChange={(e) => setMes(e.target.value)}
>
<option value="">Seleccione Mes</option>
<option value="01">Enero</option>
<option value="02">Febrero</option>
<option value="03">Marzo</option>
</select>
</div>
<div className="col-1">
<span className="fw-bold">Year</span>
</div>
<div className="col">
<input
type="text"
className="form-control"
value={agno}
onChange={(e) => setAgno(e.target.value)}
/>
</div>
<div className="col-2">
<button
type="button"
className="btn btn-primary btn-sm w-100"
onClick={handleBuscar}
>
Buscar
</button>
</div>
</div>
</div>
</div>
<div className="col-md-3 mx-auto">
<button
type="button"
className="btn p-0 text-start w-100 text-decoration-none border-0 bg-transparent"
onClick={handleExportarExcel}
>
<div className="alert alert-success shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<h1 className="mb-0">
{/* <Export /> */}
</h1>
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Excel</strong>
</span>
<h5 className="mb-0">
<strong>Exportar Mensual</strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<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-start" style={{ width: "5%" }}>
Contrato
</th>
<th className="text-start" style={{ width: "7%" }}>
Tipo
</th>
<th className="text-start" style={{ width: "18%" }}>
Empresa
</th>
<th className="text-start" style={{ width: "7%" }}>
Tipo Curso
</th>
<th className="text-start" style={{ width: "12%" }}>
Observacion
</th>
<th className="text-start" style={{ width: "10%" }}>
Fecha
</th>
</tr>
</thead>
<tbody>
{filesList.map((item, index) => (
<tr key={index}>
<td className="text-start" style={{ width: "3%" }}>
<button
type="button"
className="btn p-0 border-0 bg-transparent"
onClick={() =>
handleVerDetalle(
item.contrato,
item.cotizacion,
item.tipoVenta === "Cerrado" ? "C" : "A"
)
}
>
<span
className="badge bg-primary"
style={{ fontWeight: "normal" }}
>
Ver
</span>
</button>
</td>
<td className="text-start" style={{ width: "5%" }}>
{item.contrato}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.tipoVenta}
</td>
<td className="text-start" style={{ width: "18%" }}>
{item.empresa}
</td>
<td className="text-start" style={{ width: "7%" }}>
{item.tipoContrato === ""
? item.Responsable
: item.tipoContrato}
</td>
<td className="text-start" style={{ width: "12%" }}>
{item.observacion}
</td>
<td className="text-start" style={{ width: "10%" }}>
{item.fechaobservacion}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
{/* SECCIÓN DE DETALLE DE EMPRESA Y TABLAS SECUNDARIAS */}
{showDetalle && (
<div className="col-md-12" id="div_detalle">
<div className="row">
<div className="col-md-3">
<div className="col-md-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="table-responsive">
<table className="table" style={{ fontSize: "13px" }}>
<tbody className="table-group-divider">
<tr>
<td>
<h5 className="fs-6 mb-0">R.U.T.</h5>
</td>
<td>76.123.456-7</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Razon Social</h5>
</td>
<td className="text-wrap">Empresa Ejemplo S.A.</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Giro</h5>
</td>
<td className="text-wrap">Capacitaciones e Instrucción</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Direccion</h5>
</td>
<td className="text-wrap">Av. Providencia 1234, Santiago</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Fono</h5>
</td>
<td>+56 2 2222 3333</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Email</h5>
</td>
<td className="text-wrap">contacto@empresa.cl</td>
</tr>
<tr>
<td>
<h5 className="fs-6 mb-0">Contacto</h5>
</td>
<td className="text-wrap">Juan Pérez</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark shadow table-responsive">
<table className="table table-sm mb-0 caption-top">
<caption>
<h4>
<strong>Valores</strong>
</h4>
</caption>
<tbody>
<tr>
<th className="text-end align-middle">
<h4 className="mb-0">SubTotal</h4>
</th>
<td className="text-start">
<input
type="text"
className="form-control"
value={neto}
onChange={(e) => setNeto(e.target.value)}
/>
</td>
</tr>
<tr>
<th className="text-end align-middle mt-1">
<h4 className="mb-0">Descuento</h4>
</th>
<td className="text-start">
<input
type="text"
className="form-control"
value={descuento}
onChange={(e) => setDescuento(e.target.value)}
/>
</td>
</tr>
<tr>
<th className="text-end align-middle mt-1">
<h4 className="mb-0">Total</h4>
</th>
<td className="text-start">
<input
type="text"
className="form-control"
value={total}
onChange={(e) => setTotal(e.target.value)}
/>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="col-md-9 col-sm-12">
<div className="row">
{/* TABLA CONTRATOS DETALLE */}
<div className="col-12">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<table className="table table-sm caption-top mb-0">
<thead>
<tr>
<th className="text-center" style={{ width: "5%" }}>
Ver contrato
</th>
<th className="text-center" style={{ width: "10%" }}>
Contrato
</th>
<td className="text-center" style={{ width: "10%" }}>
Estado
</td>
<td className="text-center" style={{ width: "20%" }}>
Curso
</td>
<td className="text-center" style={{ width: "5%" }}>
Participantes
</td>
<td className="text-center" style={{ width: "15%" }}>
Valor
</td>
</tr>
</thead>
<tbody>
{contratosDetalleList.map((item, idx) => (
<tr key={idx}>
<td className="text-center" style={{ width: "5%" }}>
<a
target="_blank"
href={item.Url}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
{/* <BxsFilePdf /> */}
</a>
</td>
<th className="text-center" style={{ width: "10%" }}>
{item.Contrato}
</th>
<th
className="text-center mx-auto"
style={{ width: "10%" }}
>
{item["Firma Estado"] === 1
? "CONTRATO FIRMADO"
: "CONTRATO SIN FIRMAR"}
</th>
<td className="text-center" style={{ width: "20%" }}>
{`${item["CURSO ID"]} ${item.CURSO} ${item.JORNADA} ${item.DIREMP} ${item.Fecha}`}
</td>
<td className="text-center" style={{ width: "5%" }}>
<button
type="button"
className="btn btn-link p-0 text-decoration-none d-inline-flex align-items-center gap-1"
onClick={() =>
handleVerParticipantes(item.Contrato)
}
>
<SearchPlus /> Ver Participantes
</button>
</td>
<td className="text-center" style={{ width: "15%" }}>
{item.Valor}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* TABLA COMPROBANTES / OC */}
<div className="col-md-6">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<table className="table table-sm caption-top mb-0">
<caption>Comprobantes de Pagos u Orden de Compras</caption>
<thead>
<tr>
<th className="text-start" style={{ width: "5%" }}></th>
<th className="text-start small" style={{ width: "10%" }}>
Número Interno
</th>
<th className="text-center small" style={{ width: "10%" }}>
Fecha de Subida
</th>
<th className="text-center small" style={{ width: "10%" }}>
Tipo Documento
</th>
<th className="text-center small" style={{ width: "10%" }}>
Responsable
</th>
</tr>
</thead>
<tbody>
{ocList.map((oc, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "5%" }}>
<a
target="_blank"
href={`https://empresas.norteamericano.cl/ComprobantesPagos/${oc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</td>
<td
className="text-start small text-wrap"
style={{ width: "10%" }}
>
{oc["Numero interno"]}
</td>
<td className="text-center small" style={{ width: "10%" }}>
{oc["Fecha de subida pago"]}
</td>
<td className="text-center small" style={{ width: "10%" }}>
{oc["Tipo documento"]}
</td>
<td className="text-center small" style={{ width: "10%" }}>
{oc.Responsable}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* TABLA INSCRIPCIÓN SENCE */}
<div className="col-md-6">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<table className="table table-sm caption-top mb-0">
<caption>Inscripcion SENCE</caption>
<thead>
<tr>
<th className="text-center" style={{ width: "10%" }}></th>
<th className="text-center" style={{ width: "40%" }}>
Inscripción sence
</th>
<th className="text-center" style={{ width: "20%" }}>
Fecha de subida
</th>
<th className="text-center" style={{ width: "30%" }}>
Responsable
</th>
</tr>
</thead>
<tbody>
{sncList.map((snc, idx) => (
<tr key={idx}>
<th className="text-center" style={{ width: "10%" }}>
<a
target="_blank"
href={`https://empresas.norteamericano.cl/DocumentosSence/${snc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</th>
<td className="text-center small" style={{ width: "40%" }}>
{snc.codInscripcion}
</td>
<td className="text-center small" style={{ width: "20%" }}>
{snc["Fecha de subida"]}
</td>
<td className="text-center small" style={{ width: "30%" }}>
{snc.Responsable}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
</div>
</div>
{/* --- MODAL PARTICIPANTES (ALUMNOS) --- */}
{modalAlumnos && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
>
<div className="modal-dialog modal-dialog-centered modal-xl" role="document">
<div className="modal-content">
<div
className="modal-header text-white text-center"
style={{ backgroundColor: "#373193" }}
>
<h5 className="modal-title">Alumnos</h5>
<button
type="button"
className="btn-close btn-close-white"
onClick={() => setModalAlumnos(false)}
></button>
</div>
<div className="modal-body">
<table
className="table table-bordered table-hover table-sm mb-0"
style={{ backgroundColor: "white", fontSize: "12px" }}
>
<thead>
<tr>
<th className="text-start" style={{ width: "10%" }}>
RUN
</th>
<th className="text-center" style={{ width: "30%" }}>
Nombre Alumno
</th>
<th className="text-center" style={{ width: "20%" }}>
Tipo Registro
</th>
<th className="text-center" style={{ width: "40%" }}>
Empresa Apoderada
</th>
</tr>
</thead>
<tbody>
{alumnosList.map((alm, index) => (
<tr key={index}>
<td className="text-start">{alm.run}</td>
<td className="text-center">{alm.nombreCompleto}</td>
<td className="text-center">{alm.tipoRegistro}</td>
<td className="text-center">{alm.empresaApoderada}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalAlumnos(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL ALERTA DE MENSAJES --- */}
{modalAlerta.show && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
>
<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"
onClick={() => setModalAlerta({ show: false, message: "" })}
aria-label="Close"
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.message}</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, message: "" })}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CARGANDO (SPINNER) --- */}
{isLoading && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
tabIndex={-1}
role="dialog"
>
<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>Procesando</strong>
</h5>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>Espere un momento, por favor...</strong>
</h5>
<div className="d-flex justify-content-center gap-1 mt-2">
<div
className="spinner-grow spinner-grow-sm text-primary"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-primary"
role="status"
></div>
<div
className="spinner-grow spinner-grow-sm text-danger"
role="status"
></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+634
View File
@@ -0,0 +1,634 @@
'use client'
import { ArrowToBottomStroke, MessageCaptions, TrendingUp, UserCheck, Star, StarHalf } from "@boxicons/react";
import { useEffect, useState } from "react";
const mapaSedes: Record<string, string> = {
"0": "TODAS",
"1": "MONEDA",
"2": "PROVIDENCIA",
"3": "LA FLORIDA",
"4": "ONLINE",
"5": "EMPRESAS",
};
const mapaEncuesta: Record<string, string> = {
"0": "ALL",
"1": "OPINION",
"2": "CERTIFICADO",
"3": "OBSERVACION",
};
export default function Page() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [activeTab, setActiveTab] = useState('');
const [tabMetrica, setMetricTab] = useState(false);
const [tabDetalle, setDetalle] = useState(false);
const [SelectF, setFiltro] = useState('');
const [sedeSelect, setSedeSelect] = useState('0');
const [encuestaSelect, setEncuestaSelect] = useState('0');
const handleActionFiltro = (tipo: number) => {
if (tipo === 1) {
setFiltro('1')
setActiveTab('todos');
}
else if (tipo === 2) {
setFiltro('2')
setActiveTab('cerrados');
}
else if (tipo === 3) {
setFiltro('3')
setActiveTab('abiertos');
}
};
useEffect(() => {
try {
handleActionFiltro(1);
} catch (err) {
console.error("Error al ejecutar filtro inicial:", err);
} finally {
// 2. 'finally' garantiza que setLoading(false) se ejecute SIEMPRE, haya o no error
setLoading(false);
}
}, []);
if (loading) return <div className="text-center py-5">Cargando...</div>;
if (error) return <div className="alert alert-danger my-3">{error}</div>;
//Metricas
const dataMetric = [
{
idKey: 0,
representatividad: 25,
promedioTotal: "43 %",
cursos: 10,
alumnos: 18,
respondieron: 6,
},
{
idKey: 1,
representatividad: 10,
promedioTotal: "19 %",
cursos: 9,
alumnos: 1,
respondieron: 0,
}
];
const dataSummary = [
{
docenteID: "18172636-9",
docente: "FELIPE MENA",
tipo: "Cerrado",
cursoID: "6203",
curso: "PRE-INTERMEDIATE 1",
sede: "EMPRESAS",
almTotal: "25",
Answ: "9",
},
{
docenteID: "18636172-9",
docente: "IGNACIO MUNOZ",
tipo: "ABIERTO",
cursoID: "6318",
curso: "BEGINNER 1",
sede: "MONEDA",
almTotal: "12",
Answ: "0",
},
];
const datosFiltrados = dataSummary.filter((item) => {
if (sedeSelect === "0") return true;
const sedeNombre = mapaSedes[sedeSelect];
return item.sede.toUpperCase() === sedeNombre.toUpperCase();
});
const metricaActual = dataMetric.find((m) => m.idKey === Number(sedeSelect)) || {
representatividad: 0,
promedioTotal: "0 %",
cursos: 0,
alumnos: 0,
respondieron: 0,
};
const dataDetalle = [
{id: "6203",
nombre: "PRE-INTERMEDIATE 1",
tipo: "Cerrado",
horario: "19:00 - 21:00",
fechaInicio: "01/03/2026",
alumnos: 0,
respuestas: 0,
detractores: 0,
pasivos: 0,
promotores: 0},
];
const dataAlumnos =[
{
id:1,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "OPINION",
question: "Recomendarias el norteamericano?",
answer: 0,
},
{ id:2,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "OPINION",
question: "Recomendarias el norteamericano?",
answer: 1,
},
{ id:3,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "CERTIFICADO",
question: "Recomendarias el norteamericano?",
answer: 2,
},
{ id:4,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "CERTIFICADO",
question: "Recomendarias el norteamericano?",
answer: 3,
},
{ id:5,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "OBSERVACION",
question: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ut explicabo nostrum blanditiis quisquam quos deleniti voluptate.",
answer: 4,
},
{ id:6,
run: "11726398-3",
ap_p: "Lillo",
nombre: "Juan",
tipoQ: "OBSERVACION",
question: "Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ut explicabo nostrum blanditiis quisquam quos deleniti voluptate, ipsam voluptates repellendus odio nam accusamus error nihil, porro quae, illum dolore consequuntur vel.",
answer: 5,
}
];
const datosFiltradosAlumno = dataAlumnos.filter((item) => {
if (encuestaSelect === "0") return true;
const tipoNombre = mapaEncuesta[encuestaSelect];
return item.tipoQ.toUpperCase() === tipoNombre.toUpperCase();
});
const renderEstrellas = (rating: number) => {
const estrellas = [];
const max = 5;
for (let i = 1; i <= max; i++) {
if (rating >= i) {
// Estrella llena
estrellas.push(<Star key={i} size="sm" type="solid" className="text-warning" />);
} else if (rating >= i - 0.75 && rating < i) {
// Media estrella (para decimales como 4.3, 4.5, 4.7)
estrellas.push(<StarHalf key={i} size="sm" type="solid" className="text-warning" />);
} else {
// Estrella vacía
estrellas.push(<Star key={i} size="sm" className="text-muted" />);
}
}
return estrellas;
};
return (
<div className="row">
{/* Seccion de Filtros y Rango de Fechas */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col">
<strong>
<i className="bx bx-user" style={{ fontSize: '24px' }}></i>
</strong>
<strong>
<span className="ms-2">Encuesta de alumnos</span>
</strong>
</div>
<div className="col-3 text-end">
<button type="button" id="LinkButtonVolver"
className="btn btn-warning btn-sm">
<strong>Volver</strong>
</button>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<span className="fw-bold">Rango de búsqueda</span>
</div>
<div className="col-md-9">
<select id="ListaSedes"
className="form-control"
value={SelectF}
onChange={(e) => handleActionFiltro(Number(e.target.value))}>
<option value="1">TODAS</option>
<option value="2">Cursos Cerrados</option>
<option value="3">Cursos Plan Central</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Filtro de Todos*/}
{activeTab === 'todos' && (
<div className="col-md-12">
<div className="row justify-content-center">
<div className="col-md-8 text-center">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<span className="fw-bold">Rango de búsqueda</span>
</div>
<div className="col-md-3">
<input type="date"
id="allIni"
className="form-control form-control-sm"
value="2026-01-01"
// onChange={(e) => setFechaAgno(e.target.value)}
/>
</div>
<div className="col-md-3">
<input type="date"
id="allTer"
className="form-control form-control-sm"
value="2026-12-31"
// onChange={(e) => setFechaAgno(e.target.value)}
/>
</div>
<div className="col-md-3">
<button
type="button"
className="btn btn-primary btn-sm w-100"
onClick={() => { setMetricTab(true) }}
>
Buscar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* Filtro de Cerrados*/}
{activeTab === 'cerrados' && (<div> Cerrados</div>)}
{/* Filtro de Abiertos*/}
{activeTab === 'abiertos' && (<div> Plan Central</div>)}
{/* Metricas de representatividad, cursos y alumnos */}
{tabMetrica && (
<div className="row align-items-center">
<div className="col-md-4 col-sm-12">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-3 col-sm-12 text-center">
<UserCheck removePadding size="xl" />
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Representatividad de alumnos que respondieron</strong>
</span>
<h3>
{metricaActual.representatividad}
</h3>
</div>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12 text-center">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-3 col-sm-12">
<TrendingUp removePadding size="xl" />
</div>
<div className="col text-center">
<span className="text-muted">
<strong>Promedio de cursos que respondieron</strong>
</span>
<h3>{metricaActual.promedioTotal}</h3>
</div>
</div>
</div>
</div>
<div className="col-md-4 col-sm-12">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-2 col-sm-12 text-center">
<MessageCaptions removePadding size="lg" />
</div>
<div className="col-md-10 text-center col-sm-12">
<table className="table table-sm mb-0 table-borderless">
<thead>
<tr>
<td><span className="text-muted"><strong>Cursos</strong></span></td>
<td><span className="text-muted"><strong>Alumnos</strong></span></td>
<td><span className="text-muted"><strong>Respondieron</strong></span></td>
</tr>
</thead>
<tbody>
<tr>
<td><strong>{metricaActual.cursos}</strong></td>
<td><strong>{metricaActual.alumnos}</strong></td>
<td><strong>{metricaActual.respondieron}</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div className="col-md-6">
<button type="button"
id="LinkButton1"
className="btn p-0 border-0 w-100 text-center text-decoration-none"
//onClick={handleDescargar}
>
<div className="alert alert-success" role="alert">
<div className="row align-items-center text-center">
<div className="col-md-6 text-end col-sm-6">
<h1 className="m-0"><ArrowToBottomStroke /></h1>
</div>
<div className="col text-start">
<span className="text-muted"><strong>Exportar</strong></span>
<h5 className="m-0">
<strong><span id="Label1">NPS Empresas</span></strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-6">
<button type="button"
id="LinkButton1"
className="btn p-0 border-0 w-100 text-center text-decoration-none"
//onClick={handleDescargar}
>
<div className="alert alert-success" role="alert">
<div className="row align-items-center text-center">
<div className="col-md-6 text-end col-sm-6">
<h1 className="m-0"><ArrowToBottomStroke /></h1>
</div>
<div className="col text-start">
<span className="text-muted"><strong>Exportar</strong></span>
<h5 className="m-0">
<strong><span id="Label1">Opinion Empresas</span></strong>
</h5>
</div>
</div>
</div>
</button>
</div>
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive">
<table className="table table-sm table-hover mb-0 caption-top" style={{ fontSize: '12px' }}>
<caption className="text-center">
<h6>SEDE:</h6>
<select id="ListaSedes"
className="form-control text-center"
value={sedeSelect}
onChange={(e) => setSedeSelect(e.target.value)}
>{Object.entries(mapaSedes).map(([value, label]) => (
<option key={value} value={value}>
{label}
</option>
))}
</select>
</caption>
<thead>
<tr>
<th className="text-start" style={{ width: '8%' }}> </th>
<th className="text-start" style={{ width: '15%' }}>Docente</th>
<th className="text-start" style={{ width: '8%' }}>Tipo Curso</th>
<th className="text-start" style={{ width: '5%' }}>ID Curso</th>
<th className="text-start" style={{ width: '15%' }}>Curso</th>
<th className="text-start" style={{ width: '12%' }}>Sede</th>
<th className="text-start" style={{ width: '7%' }}>Total de Alumnos</th>
<th className="text-start" style={{ width: '7%' }}>Respuestas</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para mapear con data dynamic (.map) */}
{datosFiltrados.length === 0 ? (
<tr>
<td colSpan={8} className="text-center py-4 text-muted fw-bold">
Sin datos asociados a la sede
</td>
</tr>
) : (
datosFiltrados.map((a) => (
<tr key={`${a.docenteID}-${a.cursoID}`}>
<td className="text-start fs-6" style={{ width: '8%' }}>
<button className="btn btn-primary btn-sm" onClick={() => { setDetalle(true), setMetricTab(false) } }>Ver detalle</button>
</td>
<td className="text-start" style={{ width: '15%' }}>{a.docente}</td>
<td className="text-start" style={{ width: '8%' }}>{a.tipo}</td>
<td className="text-start" style={{ width: '5%' }}>{a.cursoID}</td>
<td className="text-start" style={{ width: '15%' }}>{a.curso}</td>
<td className="text-start" style={{ width: '12%' }}>{a.sede}</td>
<td className="text-start" style={{ width: '7%' }}>{a.almTotal}</td>
<td className="text-start" style={{ width: '7%' }}>{a.Answ}</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
{tabDetalle && (
<div className="row align-items-center">
<div className="col-md-4">
<div className="alert alert-light text-dark" role="alert">
<table className="table table-sm mb-1" style={{ fontSize: "14px" }}>
<tbody>
<tr>
<td style={{ width: "15%" }}>
<strong className="text-muted">Curso</strong>
</td>
<td colSpan={2}>
<strong>{dataDetalle[0].nombre}</strong>
</td>
</tr>
<tr>
<td style={{ width: "15%" }}>
<strong className="text-muted">Horario</strong>
</td>
<td colSpan={2}>
<strong>{dataDetalle[0].horario}</strong>
</td>
</tr>
<tr>
<td style={{ width: "15%" }}>
<strong className="text-muted">Fecha</strong>
</td>
<td colSpan={2}>
<strong>{dataDetalle[0].fechaInicio}</strong>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-3">
<div className="alert alert-light text-dark" role="alert">
<table className="table mb-0" style={{ fontSize: "14px" }}>
<tbody>
<tr>
<td>
<strong className="text-muted">Alumnos</strong>
</td>
<td>
<strong>{dataDetalle[0].alumnos}</strong>
</td>
</tr>
<tr>
<td>
<strong className="text-muted">Respondieron</strong>
</td>
<td>
<strong>{dataDetalle[0].respuestas}</strong>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<table className="table text-center mb-0" style={{ fontSize: "14px" }}>
<tbody>
<tr>
<td>
<strong className="text-muted">Detractores</strong>
</td>
<td>
<strong className="text-muted">Pasivos</strong>
</td>
<td>
<strong className="text-muted">Promotores</strong>
</td>
</tr>
<tr>
<td>
<strong>{dataDetalle[0].detractores}</strong>
</td>
<td>
<strong>{dataDetalle[0].pasivos}</strong>
</td>
<td>
<strong>{dataDetalle[0].promotores}</strong>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-12">
<button type="button"
className="btn p-0 border-0 w-100 text-center text-decoration-none"
//onClick={handleDescargar}
>
<div className="alert alert-success" role="alert">
<div className="row align-items-center text-center">
<div className="col-md-6 text-end col-sm-6">
<h1 className="m-0"><ArrowToBottomStroke /></h1>
</div>
<div className="col text-start">
<span className="text-muted"><strong>Exportar</strong></span>
<h5 className="m-0">
<strong><span id="Label1">Encuesta curso</span></strong>
</h5>
</div>
</div>
</div>
</button>
</div>
{/* Cambiar profe por alumnos detalle del curso y respuestas en numeros por estrellas representativas */}
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive">
<table className="table table-sm table-hover mb-0 caption-top" style={{ fontSize: '12px' }}>
<caption className="text-center">
<h6>SEDE:</h6>
<select
className="form-control text-center"
value={encuestaSelect}
onChange={(e) => setEncuestaSelect(e.target.value)}
>{Object.entries(mapaEncuesta).map(([value, label]) => (
<option key={value} value={value}>
{label}
</option>
))}
</select>
</caption>
<thead>
<tr>
<th className="text-start" style={{ width: '8%' }}>Ficha</th>
<th className="text-start" style={{ width: '15%' }}>R.U.N.</th>
<th className="text-start" style={{ width: '8%' }}>Apellido</th>
<th className="text-start" style={{ width: '5%' }}>Nombre</th>
<th className="text-start" style={{ width: '15%' }}>Tipo Encuesta</th>
<th className="text-start" style={{ width: '12%' }}>Pregunta</th>
<th className="text-start" style={{ width: '7%' }}>Respuesta</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para mapear con data dynamic (.map) */}
{datosFiltradosAlumno.length === 0 ? (
<tr>
<td colSpan={8} className="text-center py-4 text-muted fw-bold">
Sin datos asociados a la sede
</td>
</tr>
) : (
datosFiltradosAlumno.map((a) => (
<tr key={`${a.id}-${a.run}`}>
<td className="text-start fs-6" style={{ width: '8%' }}>
<button className="btn btn-primary btn-sm" >Ver</button>
</td>
<td className="text-start" style={{ width: '15%' }}>{a.run}</td>
<td className="text-start" style={{ width: '8%' }}>{a.ap_p}</td>
<td className="text-start" style={{ width: '5%' }}>{a.nombre}</td>
<td className="text-start" style={{ width: '15%' }}>{a.tipoQ}</td>
<td className="text-start" style={{ width: '12%' }}>{a.question}</td>
{/* Muestra las estrellas dinámicamente */}
<td className="text-start" style={{ width: '7%' }}>{renderEstrellas(a.answer)}</td>
</tr>
))
)}
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+304
View File
@@ -0,0 +1,304 @@
'use client';
import { ArrowToBottomStroke } from "@boxicons/react";
import { useState, useEffect } from "react";
import { descargarExcelProfesor } from '../../excel'; // O donde guardes la función
// bx-export
export default function SesionesEstipuladasPage() {
/* constantes de validaciones cargas, errores y visibles*/
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [mostrarSesiones,setSesiones] = useState(false);
const dataSesionesProfesor = [
{ TitularID: "18172636-9",
paterno: "MENA",
materno: "MUNOZ",
nombre: "FELIPE",
CursoID: "6203",
Curso: "PRE-INTERMEDIATE 1",
AsignacionDocente: "TITULAR",
FechaInicio: "01-06-2026",
FechaFin: "05-09-2026",
Schedule:"LU MI 10:00:00 - 12:00:00 / MA JU 15:00:00 - 16:00:00",
DuracionEstipulada:"01:00:00",
Sesion:"12-08-2026",
},
{ TitularID: "18172636-9",
paterno: "MENA",
materno: "MUNOZ",
nombre: "FELIPE",
CursoID: "6213",
Curso: "PRE-INTERMEDIATE 2",
AsignacionDocente: "TITULAR",
FechaInicio: "01-06-2026",
FechaFin: "05-09-2026",
Schedule:"LU MI 10:00:00 - 12:00:00 / MA JU 15:00:00 - 16:00:00",
DuracionEstipulada:"01:00:00",
Sesion:"12-08-2026",
},
];
useEffect(() => {
setIni();
return setLoading(false);
}, []);
const handleDescargar = () => {
descargarExcelProfesor(dataSesionesProfesor, 'Reporte_Sesiones');
};
const [fechaAgno, setFechaAgno] = useState('');
const [mesSelect, setFechaMes] = useState('');
const [fechaIni, setFechaIni] = useState('');
const [fechaTer, setFechaTer] = useState('');
function setIni(){
const hoy = new Date();
const anio = hoy.getFullYear();
const mes = String(hoy.getMonth() + 1);
const varA = `${anio}`;
setFechaAgno(varA);
setFechaMes(mes);
}
function CargaSesiones(){
setFechasSearch();
setSesiones(true);
}
function setFechasSearch(){
const anioNum = Number(fechaAgno);
const mesNum = Number(mesSelect); // Valor de 1 a 12
const anioA = fechaAgno;
const mesA = String(mesNum).padStart(2, '0');
const diaA = "21";
const varA = `${anioA}-${mesA}-${diaA}`;
const fechaAnterior = new Date(anioNum, mesNum - 2, 20);
const anioB = fechaAnterior.getFullYear();
const mesB = String(fechaAnterior.getMonth() + 1).padStart(2, '0');
const diaB = "20";
const varB = `${anioB}-${mesB}-${diaB}`;
setFechaIni(varA);
setFechaTer(varB);
}
if (loading) return <div className="text-center py-5">Cargando...</div>;
if (error) return <div className="alert alert-danger my-3">{error}</div>;
return (
<>
<div className="row">
{/* Seccion de Filtros y Rango de Fechas */}
<div className="col-md-12">
<div className="row">
<div className="col-md-5">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col">
<strong>
<i className="bx bx-user" style={{ fontSize: '24px' }}></i>
</strong>
<strong>
<span className="ms-2">Sesiones estipuladas del profesores</span>
</strong>
</div>
<div className="col-3 text-end">
<button type="button" id="LinkButtonVolver"
className="btn btn-warning text-dark btn-sm"
>
<strong>Volver</strong>
</button>
</div>
</div>
</div>
</div>
<div className="col-md-7">
<div className="alert alert-light" role="alert">
<div className="row align-items-center">
<div className="col-md-3">
<span className="fw-bold">Rango de búsqueda</span>
</div>
<div className="col-md-3">
<input type="number"
id="fechaIni"
className="form-control form-control-sm"
value={fechaAgno}
onChange={(e) => setFechaAgno(e.target.value)}
/>
</div>
<div className="col-md-3">
<select id="ListaSedes"
className="form-control"
value={mesSelect}
onChange={(e) => setFechaMes(e.target.value)}
>
<option value="1">January</option>
<option value="2">February</option>
<option value="3">March</option>
<option value="4">April</option>
<option value="5">May</option>
<option value="6">June</option>
<option value="7">July</option>
<option value="8">August</option>
<option value="9">September</option>
<option value="10">October</option>
<option value="11">November</option>
<option value="12">December</option>
</select>
</div>
<div className="col-md-3">
<button
type="button"
id="LinkButtonBuscar"
className="btn btn-primary btn-sm w-100"
onClick={() => CargaSesiones()}>
Buscar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Sección de Resultados */}
{mostrarSesiones && (
<div className="col-md-12">
<div className="row">
{/* Botón Exportar a Excel */}
<div className="col-md-12 mt-2">
<button type="button"
id="LinkButton1"
className="btn p-0 border-0 w-100 text-center text-decoration-none"
onClick={handleDescargar}
>
<div className="alert alert-success" role="alert">
<div className="row align-items-center text-center">
<div className="col-md-6 text-end col-sm-6">
<h1 className="m-0"><ArrowToBottomStroke /></h1>
</div>
<div className="col text-start">
<span className="text-muted"><strong>Excel</strong></span>
<h5 className="m-0">
<strong><span id="Label1">Exportar</span></strong>
</h5>
</div>
</div>
</div>
</button>
</div>
{/* Tabla de Informe Docente */}
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive">
<table className="table table-sm table-hover mb-0 caption-top" style={{ fontSize: '12px' }}>
<caption><h6>Rango de Fecha: {fechaTer} ~ {fechaIni} </h6></caption>
<thead>
<tr>
<th className="text-start" style={{ width: '7%' }}>ID</th>
<th className="text-start" style={{ width: '8%' }}>Apellido Paterno</th>
<th className="text-start" style={{ width: '8%' }}>Apellido Materno</th>
<th className="text-start" style={{ width: '8%' }}>Nombre</th>
<th className="text-start" style={{ width: '5%' }}>ID Curso</th>
<th className="text-start" style={{ width: '15%' }}>Curso</th>
<th className="text-start" style={{ width: '7%' }}>Asignación</th>
<th className="text-start" style={{ width: '7%' }}>Inicio Curso</th>
<th className="text-start" style={{ width: '7%' }}>Término Curso</th>
<th className="text-start" style={{ width: '16%' }}>Schedule</th>
<th className="text-start" style={{ width: '5%' }}>Duración</th>
<th className="text-start" style={{ width: '7%' }}>Sesión</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para mapear con data dynamic (.map) */}
{dataSesionesProfesor.map((a) =>(
<tr key={`${a.TitularID}-${a.CursoID}-${a.Sesion}`}>
<td className="text-start" style={{ width: '7%' }}>{a.TitularID}</td>
<td className="text-start" style={{ width: '8%' }}>{a.paterno}</td>
<td className="text-start" style={{ width: '8%' }}>{a.materno}</td>
<td className="text-start" style={{ width: '8%' }}>{a.nombre}</td>
<td className="text-start" style={{ width: '5%' }}>{a.CursoID}</td>
<td className="text-start" style={{ width: '15%' }}>{a.Curso}</td>
<td className="text-start" style={{ width: '7%' }}>{a.AsignacionDocente}</td>
<td className="text-start" style={{ width: '7%' }}>{a.FechaInicio}</td>
<td className="text-start" style={{ width: '7%' }}>{a.FechaFin}</td>
<td className="text-start" style={{ width: '16%' }}>{a.Schedule}</td>
<td className="text-start" style={{ width: '5%' }}>{a.DuracionEstipulada}</td>
<td className="text-start" style={{ width: '7%' }}>{a.Sesion}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)
}
</div>
{/* MODAL DE CARGA (LOADING) */}
<div className="modal fade" id="modalCargando" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title">
<strong><i className="bx bx-loader-alt bx-spin me-2"></i>Procesando</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5 className="mb-3"><strong>Por favor espere un momento...</strong></h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status"><span className="visually-hidden">Cargando...</span></div>
<div className="spinner-grow spinner-grow-sm text-secondary" role="status"><span className="visually-hidden">Cargando...</span></div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status"><span className="visually-hidden">Cargando...</span></div>
<div className="spinner-grow spinner-grow-sm text-secondary" role="status"><span className="visually-hidden">Cargando...</span></div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
<i className="bx bx-error-circle me-2 fs-4"></i>
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un problema al procesar la solicitud. Por favor intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cerrar</button>
</div>
</div>
</div>
</div>
</>
);
}
+357
View File
@@ -0,0 +1,357 @@
'use client';
import Link from 'next/link';
export default function CursosPlanCentralPage() {
return (
<>
<div className="row">
{/* ENCABEZADO Y BUSCADOR */}
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col">
<div className="mt-1 mb-1">
<h5>
<strong>Cursos Plan Central</strong>
</h5>
</div>
</div>
<div className="col text-end">
<Link href="/academico" 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">
<div className="row align-items-center">
<div className="col-md-2">
<div className="mt-2">
<strong>Programa</strong>
</div>
</div>
<div className="col-md-8">
<select id="ListaPrograma" className="form-select">
<option value="">Seleccione programa...</option>
</select>
</div>
<div className="col-md-2">
<button type="button" id="LinkButtonBuscar" className="btn btn-primary w-100">
Buscar
</button>
</div>
</div>
</div>
</div>
{/* DETALLE Y TABLA DE REPORTES */}
<div className="col-md-12" id="div_reporte_ok">
{/* Tarjeta de Resumen */}
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-1 text-center">
<h1 className="m-0"><i className="bx bx-user"></i></h1>
</div>
<div className="col-md-2">
<span className="text-muted"><strong>Tipo de Alumnos</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelTipo">0</span>
</strong>
</h5>
</div>
<div className="col-md-1 text-center">
<h1 className="m-0"><i className="bx bx-message-detail"></i></h1>
</div>
<div className="col-md-4">
<span className="text-muted"><strong>Descripción</strong></span>
<h5 className="m-0">
<strong>
<small><span id="LabelObs">0</span></small>
</strong>
</h5>
</div>
<div className="col-md-1 text-end">
<h1 className="m-0"><i className="bx bx-list-plus"></i></h1>
</div>
<div className="col-md-1">
<span className="text-muted"><strong>Niveles</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelNiveles">0</span>
</strong>
</h5>
</div>
<div className="col-md-2"></div>
</div>
</div>
{/* Tabla de Resultados */}
<div className="alert alert-light text-dark" role="alert" id="search_ok">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '4%' }}></th>
<th className="text-start" style={{ width: '6%' }}>Nivel</th>
<th className="text-start" style={{ width: '25%' }}>Curso</th>
<th className="text-center" style={{ width: '10%' }}>Horas Cronológicas</th>
<th className="text-center" style={{ width: '10%' }}>CEFR Level</th>
<th className="text-center" style={{ width: '20%' }}>Libros</th>
<th className="text-center" style={{ width: '7%' }}>SENCE<br />Online</th>
<th className="text-center" style={{ width: '7%' }}>SENCE<br />Presencial</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática */}
<tr>
<td className="text-start" style={{ width: '4%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '6%' }}>Nivel 1</td>
<td className="text-start" style={{ width: '25%' }}>Curso Demo</td>
<td className="text-center" style={{ width: '10%' }}>40 hrs.</td>
<td className="text-center" style={{ width: '10%' }}>A1</td>
<td className="text-center" style={{ width: '20%', fontSize: '14px' }}>Libro Demo</td>
<td className="text-center" style={{ width: '7%' }}>Si</td>
<td className="text-center" style={{ width: '7%' }}>No</td>
</tr>
</tbody>
</table>
<span id="LabelMsjCursos" className="d-none">Sin cursos asociados</span>
</div>
</div>
{/* Mensaje Sin Cursos */}
<div className="alert alert-light text-dark d-none" role="alert" id="search_error">
<h5 className="text-center mb-0" style={{ fontSize: '16px' }}>
<strong><small>No existen cursos asociados a este programa.</small></strong>
</h5>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR CURSO */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
<span id="lblRE">Editar</span> <strong>CURSO</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '35%' }}>
<strong>Nivel</strong>
</td>
<td>
<input type="text" id="TextBoxNivel" className="form-control" disabled />
</td>
</tr>
<tr>
<td>
<strong>Curso</strong>
</td>
<td>
<input type="text" id="TextBoxNombre" className="form-control" disabled />
</td>
</tr>
<tr>
<td>
<strong>Tiempo (Hrs.)</strong>
</td>
<td>
<input type="text" id="TextBoxTiempo" className="form-control" disabled />
</td>
</tr>
<tr>
<td>
<strong>CEFR Level</strong>
</td>
<td>
<input type="text" id="ListCefr" className="form-control" disabled />
</td>
</tr>
<tr>
<td>
<strong>Libro</strong>
</td>
<td>
<select id="ListLibros" className="form-select">
<option value="">Seleccione libro...</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Código SENCE Presencial</strong>
</td>
<td>
<select id="ListaSENCEPresnecial" className="form-select">
<option value="">Seleccione código...</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Código SENCE Online</strong>
</td>
<td>
<select id="ListaSENCEOnline" className="form-select">
<option value="">Seleccione código...</option>
</select>
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresarCurso" className="btn btn-primary">
Agregar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE ALERTAS Y MENSAJES */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title float-start mt-1">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de notificación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="mensajeCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title">
<strong>
<i className="bx bx-loader-alt bx-spin me-2"></i>Módulo Academico - Empresas
</strong>
</h5>
</div>
<div className="modal-body text-center py-4 mb-0">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
<i className="bx bx-error-circle me-2 fs-4"></i>
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un error inesperado. Por favor, reintente más tarde.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+414
View File
@@ -0,0 +1,414 @@
'use client';
import Link from 'next/link';
import { useState } from "react";
export default function CursosCerrados() {
return (
<>
<div className="row">
{/* ENCABEZADO Y FILTROS DE BÚSQUEDA */}
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col">
<div className="mt-1 mb-1">
<h5>
<strong>Cursos por Programa</strong>
</h5>
</div>
</div>
<div className="col text-end">
<Link href="/Academico" 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">
<div className="row align-items-center">
<div className="col-md-2">
<div className="mt-2">
<strong>Programa</strong>
</div>
</div>
<div className="col-md-8">
<select id="ListaPrograma" className="form-select">
<option value="">Seleccione un programa...</option>
<option value="1">Programa Demo 1</option>
<option value="2">Programa Demo 2</option>
</select>
</div>
<div className="col-md-2">
<button type="button" id="LinkButtonBuscar" className="btn btn-primary w-100">
Buscar
</button>
</div>
</div>
</div>
</div>
{/* CONTENIDO DEL REPORTE / RESULTADOS */}
<div className="col-md-12" id="div_reporte_ok">
{/* RESUMEN DEL PROGRAMA */}
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-1 text-center">
<h1 className="m-0"><i className="bx bx-user"></i></h1>
</div>
<div className="col-md-2">
<span className="text-muted"><strong>Tipo de Alumnos</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelTipo">Corporativo</span>
</strong>
</h5>
</div>
<div className="col-md-1 text-center">
<h1 className="m-0"><i className="bx bx-message-detail"></i></h1>
</div>
<div className="col-md-4">
<span className="text-muted"><strong>Descripción</strong></span>
<h5 className="m-0">
<strong>
<small><span id="LabelObs">Sin observaciones registradas</span></small>
</strong>
</h5>
</div>
<div className="col-md-1 text-end">
<h1 className="m-0"><i className="bx bx-list-plus"></i></h1>
</div>
<div className="col-md-1">
<span className="text-muted"><strong>Niveles</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelNiveles">6</span>
</strong>
</h5>
</div>
<div className="col-md-2">
<div className="d-grid gap-2">
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<i className="bx bx-plus me-1"></i>
<strong>Agregar curso</strong>
</button>
<button
type="button"
id="LinkButton1"
className="btn btn-warning text-dark mt-1"
data-bs-toggle="modal"
data-bs-target="#modalSincronizar"
>
<i className="bx bx-book-add me-1"></i>
<strong>Asociar libros</strong>
</button>
</div>
</div>
</div>
</div>
{/* TABLA DE CURSOS */}
<div className="alert alert-light text-dark" role="alert" id="search_ok">
<div className="table-responsive">
<table className="table table-sm table-hover mb-0" style={{ fontSize: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '4%' }}></th>
<th className="text-start" style={{ width: '6%' }}>Nivel</th>
<th className="text-start" style={{ width: '25%' }}>Curso</th>
<th className="text-center" style={{ width: '10%' }}>Horas Cronológicas</th>
<th className="text-center" style={{ width: '10%' }}>CEFR Level</th>
<th className="text-center" style={{ width: '10%' }}>Ponderación</th>
<th className="text-center" style={{ width: '20%' }}>Libros</th>
<th className="text-center" style={{ width: '7%' }}>SENCE<br />Online</th>
<th className="text-center" style={{ width: '7%' }}>SENCE<br />Presencial</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para mapear (.map) posteriormente */}
<tr>
<td className="text-start" style={{ width: '4%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '6%' }}>Nivel 1</td>
<td className="text-start" style={{ width: '25%' }}>Inglés Inicial A1</td>
<td className="text-center" style={{ width: '10%' }}>40 hrs.</td>
<td className="text-center" style={{ width: '10%' }}>A1</td>
<td className="text-center" style={{ width: '10%' }}>100%</td>
<td className="text-center" style={{ width: '20%', fontSize: '14px' }}>Book 1 - Starter</td>
<td className="text-center" style={{ width: '7%' }}>Si</td>
<td className="text-center" style={{ width: '7%' }}>No</td>
</tr>
</tbody>
</table>
<span id="LabelMsjCursos" className="d-none">Sin cursos asociados</span>
</div>
</div>
{/* MENSAJE CUANDO NO HAY CURSOS (Oculto por defecto mediante d-none) */}
<div className="alert alert-light text-dark d-none" role="alert" id="search_error">
<h5 className="text-center mb-0" style={{ fontSize: '16px' }}>
<strong><small>No existen cursos asociados a este programa.</small></strong>
</h5>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR CURSO */}
<div className="modal fade" id="modalAgregar" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
<span id="lblRE">Agregar</span> <strong>CURSO</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '30%' }}>
<strong>Nivel</strong>
</td>
<td>
<input type="text" id="TextBoxNivel" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Curso</strong>
</td>
<td>
<input type="text" id="TextBoxNombre" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Tiempo (Hrs.)</strong>
</td>
<td>
<input type="text" id="TextBoxTiempo" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>CEFR Level</strong>
</td>
<td>
<select id="ListCefr" className="form-select">
<option value="">Seleccione...</option>
<option value="A1">A1</option>
<option value="A2">A2</option>
<option value="B1">B1</option>
<option value="B2">B2</option>
<option value="C1">C1</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Libro</strong>
</td>
<td>
<select id="ListLibros" className="form-select">
<option value="">Seleccione...</option>
</select>
</td>
</tr>
{/* Filas condicionales para SENCE (Ocultas por defecto con d-none) */}
<tr id="SNP" className="d-none">
<td>
<strong>Código SENCE Presencial</strong>
</td>
<td>
<select id="ListaSENCEPresnecial" className="form-select"></select>
</td>
</tr>
<tr id="SNO" className="d-none">
<td>
<strong>Código SENCE Online</strong>
</td>
<td>
<select id="ListaSENCEOnline" className="form-select"></select>
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresarCurso" className="btn btn-primary">
Agregar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL ASOCIAR LIBROS (SINCRONIZAR) */}
<div className="modal fade" id="modalSincronizar" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
Asocia <strong>libros</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '30%' }}>
<strong>Curso</strong>
</td>
<td>
<select id="ListCursosSync" className="form-select">
<option value="">Seleccione curso...</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Libro</strong>
</td>
<td>
<select id="ListLibrosSync" className="form-select">
<option value="">Seleccione libro...</option>
</select>
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonAsociar" className="btn btn-primary">
Asociar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE ALERTAS Y MENSAJES DE SISTEMA */}
<div className="modal fade" id="mensajeAlerta" data-bs-backdrop="static" data-bs-keyboard="false" 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 mb-0">
<h5 className="modal-title float-start mt-2">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end mt-1" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de confirmación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div className="modal fade" id="mensajeCargando" data-bs-backdrop="static" data-bs-keyboard="false" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title">
<strong>
<i className="bx bx-loader-alt bx-spin me-2"></i>Módulo Academico - Empresas
</strong>
</h5>
</div>
<div className="modal-body alert text-center py-4 mb-0">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
<i className="bx bx-error-circle me-2 fs-4"></i>
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un problema al procesar la solicitud. Por favor intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+3
View File
@@ -0,0 +1,3 @@
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
+312
View File
@@ -0,0 +1,312 @@
'use client';
// Importación de iconos nativos según tu estructura de Boxicons
import { BookBookmark, Plus } from "@boxicons/react";; // Ajusta la ruta/librería de tus iconos según corresponda
export default function ListadoLibrosPage() {
return (
<>
<div className="row">
{/* ENCABEZADO */}
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-2 text-center">
<BookBookmark style={{ fontSize: '57px' }} />
</div>
<div className="col">
<div className="mt-1 mb-1">
<h4>
<strong>Listado de libros</strong>
</h4>
</div>
</div>
</div>
</div>
</div>
{/* FILTROS */}
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-12">
<strong className="text-muted">Libros</strong>
</div>
<div className="col-md-9">
<select id="ListaTipo" className="form-select">
<option value="">Seleccione tipo...</option>
</select>
</div>
<div className="col-md-3">
<button type="button" id="ButtonFiltro" className="btn btn-primary w-100">
Buscar
</button>
</div>
</div>
</div>
</div>
{/* BOTÓN AGREGAR */}
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row">
<div className="col-md-12 text-end">
<div className="d-grid gap-2">
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<Plus className="me-1" />
<strong>Agregar nuevo libro</strong>
</button>
</div>
</div>
</div>
</div>
</div>
{/* TABLA DE LIBROS */}
<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: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '5%' }}></th>
<th className="text-start" style={{ width: '35%' }}>Libro</th>
<th className="text-start" style={{ width: '7%' }}>Codigo</th>
<th className="text-start" style={{ width: '20%' }}>URL</th>
<th className="text-start" style={{ width: '15%' }}>Tipo de libro</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para iteración con .map */}
<tr>
<td className="text-start" style={{ width: '5%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '35%' }}>
<span id="lblId" className="d-none">1</span>
English File Elementary
</td>
<td className="text-start" style={{ width: '7%' }}>EF-01</td>
<td className="text-start" style={{ width: '20%' }}>https://www.libreriainglesa.cl</td>
<td className="text-start" style={{ width: '15%' }}>General English</td>
</tr>
</tbody>
</table>
<span id="LabelMsjBook" className="d-none">No existen registros.</span>
</div>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR LIBRO */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
Agregar <strong>PROGRAMA</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '35%' }}>
<strong>ID libreria</strong>
</td>
<td>
<span id="LabelIdEdit" className="d-none">0</span>
<input type="text" id="TextBoxIDLibreria" className="form-control" />
<span id="LabelID" className="d-none">0</span>
</td>
</tr>
<tr>
<td>
<strong>Libro</strong>
</td>
<td>
<input type="text" id="TextBoxDescripcion" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Codigo interno libro</strong>
</td>
<td>
<input type="text" id="TextBoxSKU" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>URL</strong>
</td>
<td>
<input
type="text"
id="TextBoxUrl"
className="form-control"
defaultValue="https://www.libreriainglesa.cl"
/>
</td>
</tr>
<tr>
<td>
<strong>Tipo libro</strong>
</td>
<td>
<select id="tipoLibroAdd" className="form-select">
<option value="">Seleccione tipo...</option>
</select>
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresar" className="btn btn-primary cargando">
Registrar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE ALERTAS Y NOTIFICACIONES */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title float-start mt-1">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de confirmación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="mensajeCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title d-flex align-items-center">
{/* <LoaderAlt className="bx-spin me-2" /> */}
<strong>Módulo Academico - Empresas</strong>
</h5>
</div>
<div className="modal-body text-center py-4 mb-0">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
{/* <ErrorCircle className="me-2 fs-4" /> */}
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un error inesperado al procesar los libros. Por favor intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+355
View File
@@ -0,0 +1,355 @@
// //8'use client'
// export default function Page() {
// return (
// <h1>asdasdasd</h1>
// );
// }
'use client';
import { BookBookmark } from "@boxicons/react";
import { useState } from "react";
export default function PlanDeEstudio() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
return (
<>
<div className="row">
{/* PANEL DASHBOARD DE PROGRAMAS */}
<div className="col-md-12">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-2 text-center">
<BookBookmark removePadding size="xl" />
</div>
<div className="col-md-2">
<strong className="text-muted">Programas</strong>
<h1>
<strong>
<span id="LabelPrograma">0</span>
</strong>
</h1>
</div>
<div className="col-md-5 text-center">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td style={{ width: '25%' }}>
<strong className="text-muted">Corp</strong>
</td>
<td>
<h5>
<strong>
<span id="LabelCorp">0</span>
</strong>
</h5>
</td>
<td style={{ width: '25%' }}>
<strong className="text-muted">Adults</strong>
</td>
<td>
<h5>
<strong>
<span id="LabelAdults">0</span>
</strong>
</h5>
</td>
</tr>
<tr>
<td>
<strong className="text-muted">Teens</strong>
</td>
<td>
<h5>
<strong>
<span id="LabelTeens">0</span>
</strong>
</h5>
</td>
<td>
<strong className="text-muted">Kid</strong>
</td>
<td>
<h5>
<strong>
<span id="LabelKids">0</span>
</strong>
</h5>
</td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-1"></div>
<div className="col-md-2">
<div className="d-grid gap-2 mt-3">
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<i className="bx bx-plus me-1"></i>
<strong>Agregar nuevo programa</strong>
</button>
</div>
</div>
</div>
</div>
</div>
{/* TABLA DE PROGRAMAS */}
<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: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '5%' }}></th>
<th className="text-start" style={{ width: '75%' }}>Programa</th>
<th className="text-start" style={{ width: '20%' }}>Tipo de programa</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática lista para iterar datos (.map) */}
<tr>
<td className="text-start" style={{ width: '5%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '75%' }}>
Programa de Ejemplo
</td>
<td className="text-start" style={{ width: '20%' }}>
Corp
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR PROGRAMA */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="modalAgregarLabel"
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">
Agregar <strong>PROGRAMA</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '30%' }}>
<strong>Nombre</strong>
</td>
<td>
<input type="text" id="TextBoxNombre" className="form-control" />
</td>
</tr>
{/* Fila Error Nombre (Oculta por defecto, manejar con React State si aplica) */}
<tr id="row_error1" className="d-none">
<td colSpan={2} className="text-center">
<strong>
<span id="LabelMnsErr1" className="text-danger small">
Debe ingresar un nombre para el programa.
</span>
</strong>
</td>
</tr>
<tr>
<td>
<strong>Descripción</strong>
</td>
<td>
<input type="text" id="TextBoxDescripcion" className="form-control" />
</td>
</tr>
{/* Fila Error Descripción (Oculta por defecto) */}
<tr id="row_error2" className="d-none">
<td colSpan={2} className="text-center">
<strong>
<span id="LabelMnsErr2" className="text-danger small">
La descripción debe contener un mínimo de 45 caracteres.
</span>
</strong>
</td>
</tr>
<tr>
<td>
<strong>Tipo Alumno</strong>
</td>
<td>
<select className="form-select" id="ListaTipoAlumno">
<option value="">Seleccione...</option>
<option value="1">Corp</option>
<option value="2">Adults</option>
<option value="3">Teens</option>
<option value="4">Kids</option>
</select>
</td>
</tr>
{/* Fila Error Tipo Alumno (Oculta por defecto) */}
<tr id="row_error3" className="d-none">
<td colSpan={2} className="text-center">
<strong>
<span id="LabelMnsErr3" className="text-danger small">
Selecciona el tipo de alumno.
</span>
</strong>
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresar" className="btn btn-primary">
Registrar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE MENSAJE / ALERTA DE SISTEMA */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-labelledby="mensajeAlertaLabel"
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="modal-title">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje del sistema</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="modalCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title">
<strong>
<i className="bx bx-loader-alt bx-spin me-2"></i>Procesando
</strong>
</h5>
</div>
<div className="modal-body text-center py-4">
<h5 className="mb-3">
<strong>Por favor espere un momento...</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-secondary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-secondary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
<i className="bx bx-error-circle me-2 fs-4"></i>
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un problema al procesar la solicitud. Por favor intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+360
View File
@@ -0,0 +1,360 @@
'use client';
export default function PonderacionesPage() {
return (
<>
<div className="row">
{/* ENCABEZADO Y FILTROS */}
<div className="col-md-4">
<div className="alert alert-light text-dark" role="alert">
<h5 className="mb-0">
<strong>
<i className="bx bx-user mt-2" style={{ fontSize: '24px' }}></i>
</strong>
<strong>
<span className="ms-2">Ponderaciones</span>
</strong>
</h5>
</div>
</div>
<div className="col-md-8">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col">
<select id="ListaPrograma" className="form-select">
<option value="">Seleccione programa...</option>
</select>
<span id="LabelProgID" className="d-none">0</span>
</div>
<div className="col">
<select id="ListaCursos" className="form-select">
<option value="">Seleccione curso...</option>
</select>
<span id="LabelCurID" className="d-none">0</span>
</div>
<div className="col-md-2">
<button type="button" id="LinkButtonBuscar" className="btn btn-primary w-100">
Buscar
</button>
</div>
</div>
</div>
</div>
{/* DETALLE Y TABLA DE REPORTE */}
<div className="col-md-12" id="reporte">
{/* RESUMEN DE CURSO Y TEST */}
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-1 text-end">
<div className="mt-1">
<h1 className="m-0"><i className="bx bx-user"></i></h1>
</div>
</div>
<div className="col-md-6">
<span className="text-muted"><strong>Curso</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelCurso">Curso Demo</span>
</strong>
</h5>
</div>
<div className="col-md-1 text-end">
<h1 className="m-0"><i className="bx bx-pencil"></i></h1>
</div>
<div className="col-md-2">
<span className="text-muted"><strong>Test</strong></span>
<h5 className="m-0">
<strong>
<span id="LabelTestSummary">0</span>
</strong>
</h5>
</div>
<div className="col-md-2">
<div className="d-grid gap-2">
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<i className="bx bx-plus me-1"></i>
<strong>Agregar</strong>
</button>
</div>
</div>
</div>
</div>
{/* TABLA DE PONDERACIONES */}
<div className="alert alert-light text-dark" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '10%' }}></th>
<th className="text-start" style={{ width: '80%' }}>Test</th>
<th className="text-start" style={{ width: '10%' }}>Grade</th>
</tr>
</thead>
<tbody>
{/* Fila de ejemplo estática para iterar con .map */}
<tr>
<td className="text-start" style={{ width: '10%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalEditar"
>
<span className="badge bg-warning text-dark">Editar</span>
</button>
</td>
<td className="text-start" style={{ width: '80%' }}>
<span id="LabelTest">Midterm Exam</span>
<span id="LabelPonderacionID" className="d-none">1</span>
</td>
<td className="text-start" style={{ width: '10%' }}>
<span id="LabelPonderacion">30%</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL AGREGAR TEST */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">Agregar</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '25%' }}>
<strong>Test</strong>
</td>
<td colSpan={2}>
<select id="ListaNota" className="form-select">
<option value="">Seleccione test...</option>
</select>
</td>
</tr>
{/* Fila de error condicional (Oculta por defecto con d-none) */}
<tr id="error_test" className="d-none">
<td></td>
<td colSpan={2}>
<span id="Label1" className="text-danger">
Tiene que seleccionar el test
</span>
</td>
</tr>
<tr>
<td>
<strong>Grade</strong>
</td>
<td style={{ width: '30%' }}>
<input type="text" id="TextBoxGradeTest" className="form-control" />
</td>
<td></td>
</tr>
<tr>
<td></td>
<td colSpan={2} className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresarCurso" className="btn btn-primary">
Agregar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL EDITAR TEST */}
<div
className="modal fade"
id="modalEditar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
Editar <strong></strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '25%' }}>
<strong>Test</strong>
</td>
<td colSpan={2}>
<span id="LabelNota">Midterm Exam</span>
<span id="LabelPonderacionID_Edit" className="d-none">1</span>
</td>
</tr>
<tr>
<td>
<strong>Grade</strong>
</td>
<td style={{ width: '30%' }}>
<input type="text" id="TextBoxGrade" className="form-control" />
</td>
<td></td>
</tr>
<tr>
<td></td>
<td colSpan={2} className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonEditar" className="btn btn-primary">
Editar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE ALERTAS Y MENSAJES */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title float-start mt-1">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de notificación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="mensajeCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title">
<strong>
<i className="bx bx-loader-alt bx-spin me-2"></i>Módulo Academico - Empresas
</strong>
</h5>
</div>
<div className="modal-body text-center py-4 mb-0">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
<i className="bx bx-error-circle me-2 fs-4"></i>
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un error al procesar los datos de las ponderaciones. Intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+341
View File
@@ -0,0 +1,341 @@
'use client';
// Importación directa desde la librería nativa @boxicons/react
import { BookBookmark, Plus } from '@boxicons/react';
export default function CodigosSencePage() {
return (
<>
<div className="row">
{/* ENCABEZADO */}
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-2 text-center mt-2">
<h3>
<BookBookmark style={{ fontSize: '57px' }} />
</h3>
</div>
<div className="col">
<div className="mt-2 mb-1">
<h4>
<strong>Listado de Códigos SENCE</strong>
</h4>
</div>
</div>
</div>
</div>
</div>
{/* FILTROS Y ACCIÓN */}
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-4">
<div className="row">
<div className="col-md-12">
<strong className="text-muted">Duracion</strong>
</div>
<div className="col-md-12">
<select id="ListaDuracion" className="form-select">
<option value="">Seleccione duración...</option>
</select>
</div>
</div>
</div>
<div className="col-4">
<div className="row">
<div className="col-md-12">
<strong className="text-muted">Modalidad</strong>
</div>
<div className="col-md-12">
<select id="ListaModalidad" className="form-select">
<option value="">Seleccione modalidad...</option>
</select>
</div>
</div>
</div>
<div className="col-md-4">
<div className="d-grid gap-1">
<button type="button" id="ButtonFiltro" className="btn btn-primary">
Buscar
</button>
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1 d-flex align-items-center justify-content-center"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<Plus className="me-1" />
<strong>Agregar nuevo código</strong>
</button>
</div>
</div>
</div>
</div>
</div>
{/* TABLA DE CONTENIDO */}
<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: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '3%' }}></th>
<th className="text-start" style={{ width: '60%' }}>Nombre</th>
<th className="text-start" style={{ width: '7%' }}>SENCE ID</th>
<th className="text-start" style={{ width: '7%' }}>Modalidad</th>
<th className="text-center" style={{ width: '7%' }}>Duración</th>
<th className="text-start" style={{ width: '7%' }}>Vigencia</th>
</tr>
</thead>
<tbody>
{/* Ejemplo de registro habilitado */}
<tr>
<td className="text-start" style={{ width: '3%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '60%' }}>
<span id="lblId" className="d-none">1234567890</span>
Capacitación en Liderazgo y Gestión
</td>
<td className="text-start" style={{ width: '7%' }}>1234567890</td>
<td className="text-start" style={{ width: '7%' }}>Presencial</td>
<td className="text-center" style={{ width: '7%' }}>40 hrs</td>
<td className="text-start" style={{ width: '7%' }}>31/12/2026</td>
</tr>
{/* Ejemplo de registro deshabilitado (Código 0000000000) */}
<tr>
<td className="text-start" style={{ width: '3%' }}>
<button type="button" className="btn p-0 border-0" disabled>
<span className="badge bg-secondary text-white" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '60%' }}>
<span id="lblId" className="d-none">0000000000</span>
Curso Básico Sin Código
</td>
<td className="text-start" style={{ width: '7%' }}>0000000000</td>
<td className="text-start" style={{ width: '7%' }}>E-Learning</td>
<td className="text-center" style={{ width: '7%' }}>10 hrs</td>
<td className="text-start" style={{ width: '7%' }}>01/01/2026</td>
</tr>
</tbody>
</table>
<span id="LabelMsjBook" className="d-none">No existen registros.</span>
</div>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR CÓDIGO SENCE */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
Agregar <strong>código SENCE</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '30%' }}>
<strong>Codigo</strong>
</td>
<td>
<input type="text" id="TextBoxCodigo" className="form-control" />
<span id="LabelEdit" className="d-none">0</span>
</td>
</tr>
<tr>
<td>
<strong>Descripcion</strong>
</td>
<td>
<input type="text" id="TextBoxObservacion" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Modalidad</strong>
</td>
<td>
<select id="ListaModalidadCreate" className="form-select">
<option value="">Seleccione modalidad...</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Duracion</strong>
</td>
<td>
<input type="text" id="TextBoxDuracion" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Vigencia</strong>
</td>
<td>
<input type="date" id="TextBoxVigencia" className="form-control" />
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresar" className="btn btn-primary cargando">
Registrar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE NOTIFICACIÓN / ALERTA GENERAL */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title float-start mt-1">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de notificación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="mensajeCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title d-flex align-items-center">
{/* <LoaderAlt className="bx-spin me-2" /> */}
<strong>Módulo Academico - Empresas</strong>
</h5>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center py-3">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
{/* <ErrorCircle className="me-2 fs-4" /> */}
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un error inesperado en el servidor al procesar el código SENCE. Intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+341
View File
@@ -0,0 +1,341 @@
'use client';
// Importación de componentes nativos de Boxicons
import { BookBookmark, Plus } from '@boxicons/react';
export default function CodigosSencePage() {
return (
<>
<div className="row">
{/* ENCABEZADO DE LA SECCIÓN */}
<div className="col-md-5">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-md-2 text-center mt-2">
<h3>
<BookBookmark style={{ fontSize: '57px' }} />
</h3>
</div>
<div className="col">
<div className="mt-2 mb-1">
<h4>
<strong>Listado de Códigos SENCE</strong>
</h4>
</div>
</div>
</div>
</div>
</div>
{/* FILTROS Y BOTONES DE ACCIÓN */}
<div className="col-md-7">
<div className="alert alert-light text-dark" role="alert">
<div className="row align-items-center">
<div className="col-4">
<div className="row">
<div className="col-md-12">
<strong className="text-muted">Duracion</strong>
</div>
<div className="col-md-12">
<select id="ListaDuracion" className="form-select">
<option value="">Seleccione duración...</option>
</select>
</div>
</div>
</div>
<div className="col-4">
<div className="row">
<div className="col-md-12">
<strong className="text-muted">Modalidad</strong>
</div>
<div className="col-md-12">
<select id="ListaModalidad" className="form-select">
<option value="">Seleccione modalidad...</option>
</select>
</div>
</div>
</div>
<div className="col-md-4">
<div className="d-grid gap-1">
<button type="button" id="ButtonFiltro" className="btn btn-primary">
Buscar
</button>
<button
type="button"
id="LinkButtonAgregar"
className="btn btn-warning text-dark mt-1 d-flex align-items-center justify-content-center"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<Plus className="me-1" />
<strong>Agregar nuevo código</strong>
</button>
</div>
</div>
</div>
</div>
</div>
{/* TABLA DE RESULTADOS */}
<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: '16px' }}>
<thead>
<tr>
<th className="text-start" style={{ width: '3%' }}></th>
<th className="text-start" style={{ width: '60%' }}>Nombre</th>
<th className="text-start" style={{ width: '7%' }}>SENCE ID</th>
<th className="text-start" style={{ width: '7%' }}>Modalidad</th>
<th className="text-center" style={{ width: '7%' }}>Duración</th>
<th className="text-start" style={{ width: '7%' }}>Vigencia</th>
</tr>
</thead>
<tbody>
{/* Fila de muestra editable */}
<tr>
<td className="text-start" style={{ width: '3%' }}>
<button
type="button"
className="btn p-0 border-0"
data-bs-toggle="modal"
data-bs-target="#modalAgregar"
>
<span className="badge bg-warning text-dark" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '60%' }}>
<span id="lblId" className="d-none">1234567890</span>
Curso de Capacitación Empresarial
</td>
<td className="text-start" style={{ width: '7%' }}>1234567890</td>
<td className="text-start" style={{ width: '7%' }}>Presencial</td>
<td className="text-center" style={{ width: '7%' }}>40 hrs</td>
<td className="text-start" style={{ width: '7%' }}>31/12/2026</td>
</tr>
{/* Fila de muestra deshabilitada (código 0000000000) */}
<tr>
<td className="text-start" style={{ width: '3%' }}>
<button type="button" className="btn p-0 border-0" disabled>
<span className="badge bg-secondary text-white" style={{ fontWeight: 'normal' }}>
Edit
</span>
</button>
</td>
<td className="text-start" style={{ width: '60%' }}>
<span id="lblId" className="d-none">0000000000</span>
Curso sin código SENCE
</td>
<td className="text-start" style={{ width: '7%' }}>0000000000</td>
<td className="text-start" style={{ width: '7%' }}>E-Learning</td>
<td className="text-center" style={{ width: '7%' }}>20 hrs</td>
<td className="text-start" style={{ width: '7%' }}>01/01/2026</td>
</tr>
</tbody>
</table>
<span id="LabelMsjBook" className="d-none">No existen registros.</span>
</div>
</div>
</div>
</div>
{/* MODAL AGREGAR / EDITAR CÓDIGO SENCE */}
<div
className="modal fade"
id="modalAgregar"
data-bs-backdrop="static"
data-bs-keyboard="false"
tabIndex={-1}
aria-hidden="true"
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header">
<h5 className="modal-title">
Agregar <strong>código SENCE</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body">
<table className="table table-borderless align-middle mb-0">
<tbody>
<tr>
<td style={{ width: '30%' }}>
<strong>Codigo</strong>
</td>
<td>
<input type="text" id="TextBoxCodigo" className="form-control" />
<span id="LabelEdit" className="d-none">0</span>
</td>
</tr>
<tr>
<td>
<strong>Descripcion</strong>
</td>
<td>
<input type="text" id="TextBoxObservacion" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Modalidad</strong>
</td>
<td>
<select id="ListaModalidadCreate" className="form-select">
<option value="">Seleccione modalidad...</option>
</select>
</td>
</tr>
<tr>
<td>
<strong>Duracion</strong>
</td>
<td>
<input type="text" id="TextBoxDuracion" className="form-control" />
</td>
</tr>
<tr>
<td>
<strong>Vigencia</strong>
</td>
<td>
<input type="date" id="TextBoxVigencia" className="form-control" />
</td>
</tr>
<tr>
<td></td>
<td className="text-end pt-3">
<button type="button" className="btn btn-secondary me-2" data-bs-dismiss="modal">
Cancelar
</button>
<button type="button" id="LinkButtonIngresar" className="btn btn-primary cargando">
Registrar
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{/* MODAL DE NOTIFICACIÓN / ALERTA */}
<div
className="modal fade"
id="mensajeAlerta"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title float-start mt-1">
<strong>Módulo Academico - Empresa</strong>
</h5>
<button type="button" className="btn-close float-end" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>
<span id="LabelMensaje">Mensaje de notificación</span>
</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-primary" data-bs-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
{/* MODAL DE CARGA (LOADING) */}
<div
className="modal fade"
id="mensajeCargando"
data-bs-backdrop="static"
data-bs-keyboard="false"
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 mb-0">
<h5 className="modal-title d-flex align-items-center">
{/* <LoaderAlt className="bx-spin me-2" /> */}
<strong>Módulo Academico - Empresas</strong>
</h5>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: 'justify' }}>
<div className="row">
<div className="col-md-12 text-center py-3">
<h5 className="mb-3">
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* MODAL DE ERROR DE SISTEMA */}
<div className="modal fade" id="modalError" tabIndex={-1} aria-hidden="true">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-danger mb-0">
<h5 className="modal-title text-danger d-flex align-items-center">
{/* <ErrorCircle className="me-2 fs-4" /> */}
<strong>Error de Sistema</strong>
</h5>
<button type="button" className="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body text-center py-4">
<p className="mb-0 fs-6" id="mensajeErrorText">
Ocurrió un error inesperado al procesar los códigos SENCE. Por favor intente nuevamente.
</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary btn-sm" data-bs-dismiss="modal">
Cerrar
</button>
</div>
</div>
</div>
</div>
</>
);
}
+47
View File
@@ -0,0 +1,47 @@
import { FileSearch,Poll,Folder,FileDetail,Pencil,NoteBook,BarcodeSquare} from "@boxicons/react";
export default function Page() {
const items = [
{ icon: <FileSearch />, color: "text-primary", label: "Sesiones estipuladas del docente", href: "/Informes/SesionesProfesor" },
{ icon: <Poll />, color: "text-success", label: "Encuestas de alumnos", href: "/Informes/PollAnalysis" },
{ icon: <Folder />, color: "text-info", label: "Programas Empresas", href: "/academico/PlanDeEstudio" },
{ icon: <FileDetail />, color: "text-danger", label: "Cursos Cerrados", href: "/academico/CursosCerrados" },
{ icon: <FileDetail />, color: "text-primary", label: "Cursos Plan Central", href: "/academico/CursosAbiertos" },
{ icon: <Pencil />, color: "", label: "Ponderaciones Cursos Cerrados", href: "/academico/Ponderaciones" },
{ icon: <NoteBook />, color: "text-danger", label: "Libros Programas Empresas", href: "/academico/LibrosCC" },
{ icon: <NoteBook />, color: "text-primary", label: "Libros Programas Plan Central", href: "/academico/LibrosCA" },
{ icon: <BarcodeSquare />, color: "text-danger", label: "Codigos SENCE Cursos Cerrados", href: "/academico/SenceCerrados" },
{ icon: <BarcodeSquare />, color: "text-primary", label: "Codigos SENCE Plan Central", href: "/academico/SenceAbiertos" },
];
return (
<div id="menu">
<div className="row">
<div className="col-md-3" />
<div className="col-md-6">
<div className="alert alert-light">
<h5><strong>Académico</strong></h5>
<hr />
<table className="table table-hover mb-0 ">
<tbody>
{items.map((item, i) => (
<tr key={i}>
<td className={item.color} style={{ width: "5%"}} >
<h1>{item.icon}</h1>
</td>
<td>
<div className="d-grid gap-2 mt-3">
<a href={item.href} className="text-decoration-none alert-link">{item.label}</a>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="col-md-1" />
</div>
</div>
);
}
+784
View File
@@ -0,0 +1,784 @@
"use client";
import { useState } from "react";
import {
//Transfer,
UserCheck,
Pencil,
File,
//CommentDetail,
//Upload,
ChevronRight,
UserPlus,
BookBookmark,
EditAlt,
//ErrorAlt,
Edit,
Trash,
//MessageSquareEdit,
CalendarCheck
} from "@boxicons/react";
export default function AdministradorCursoPage() {
// --- ESTADOS DE VISTAS SECCIONALES ---
const [conAlumnos, setConAlumnos] = useState(true);
const [conHorario, setConHorario] = useState(false);
const [conProfesor, setConProfesor] = useState(false);
const [conSesiones, setConSesiones] = useState(false);
const [conNotas, setConNotas] = useState(false);
const [conAsistencias, setConAsistencias] = useState(false);
const [conRollbook, setConRollbook] = useState(false);
// --- SUB-SECCIONES Y TABS ---
const [tabAlumnos, setTabAlumnos] = useState<"asistencia" | "notas" | "contenido" | "observaciones">("asistencia");
const [tabHorario, setTabHorario] = useState<"fechas" | "config">("fechas");
const [subTabHorarioConfig, setSubTabHorarioConfig] = useState<"config" | "confirm">("config");
// Profesores
const [busquedaProfeResultado, setBusquedaProfeResultado] = useState(false);
const [guardarTitular, setGuardarTitular] = useState(false);
const [eliminarTitular, setEliminarTitular] = useState(false);
const [quitarTitular, setQuitarTitular] = useState(false);
const [buscarNuevoTitular, setBuscarNuevoTitular] = useState(false);
const [buscarNuevoTitularResultado, setBuscarNuevoTitularResultado] = useState(false);
const [infoTitularNuevo, setInfoTitularNuevo] = useState(false);
// Sesiones
const [sesionReemplazar, setSesionReemplazar] = useState(false);
const [sesionSuspender, setSesionSuspender] = useState(false);
const [resultadoBusquedaReemplazante, setResultadoBusquedaReemplazante] = useState(false);
const [profeReemplazo, setProfeReemplazo] = useState(false);
// Rollbook
const [rollbookTab, setRollbookTab] = useState<"curso" | "comentarios">("curso");
const [rollbookExistente, setRollbookExistente] = useState(true);
const [rollbookCrear, setRollbookCrear] = useState(false);
// --- MODALES (LOADING Y ALERTAS) ---
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({ show: false, message: "" });
const mostrarError = (msg: string) => {
setModalAlerta({ show: true, message: msg });
};
return (
<div className="container-fluid py-3">
{/* HEADER / BANNER */}
<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-10">
<strong className="text-muted">Administrador</strong> <strong>Curso</strong>
</div>
<div className="col-md-2 text-end">
<button className="btn btn-danger btn-sm d-inline-flex align-items-center gap-1">
{/* <Transfer /> */}
Cambiar Curso
</button>
</div>
</div>
</div>
</div>
{/* COLUMNA IZQUIERDA: INFORMACIÓN DEL CURSO */}
<div className="col-md-4">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td className="w-15">
<strong className="text-muted">Curso</strong>
</td>
<td colSpan={2}>
<strong>
LabelCursoNombre -{" "}
<span className="badge bg-primary cursor-pointer">
LabelCursoPeriodo
</span>
</strong>
</td>
</tr>
<tr>
<td className="w-15"><strong className="text-muted">Código</strong></td>
<td colSpan={2}>
<strong>LabelCursoCodigo</strong>
</td>
</tr>
<tr>
<td className="w-15"><strong className="text-muted">Fecha</strong></td>
<td>
<strong>LabelCursoFechaInicio / LabelCursoFechaTermino</strong>
</td>
<td className="text-end">
<button
className="btn btn-warning btn-sm fw-bolder"
onClick={() => {
setConAlumnos(false);
setConHorario(true);
setTabHorario("fechas");
}}
>
Editar
</button>
</td>
</tr>
<tr>
<td><strong className="text-muted">Sede</strong></td>
<td colSpan={2}>
<strong>LabelCursoSede</strong>
</td>
</tr>
<tr>
<td className="w-15"><strong className="text-muted">Estado</strong></td>
<td><strong>LabelCursoEstado</strong></td>
<td className="text-end">
<button className="btn btn-danger btn-sm me-1">Anular Curso</button>
<button className="btn btn-success btn-sm">Activar Curso</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table">
<tbody>
<tr>
<td className="w-15"><strong className="text-muted">Horario</strong></td>
<td className="text-end">
<button
className="btn btn-warning btn-sm fw-bolder"
onClick={() => {
setConAlumnos(false);
setConHorario(true);
setTabHorario("config");
}}
>
Editar
</button>
</td>
</tr>
<tr>
<td colSpan={2}>
<table className="table table-responsive mb-0">
<thead>
<tr>
<th scope="col" style={{ width: "30%" }} className="text-center">Día</th>
<th scope="col" style={{ width: "70%" }} className="text-start">Hora</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center" style={{ width: "30%" }}>Lun-Mié</td>
<td className="text-start" style={{ width: "70%" }}>19:00 - 21:00</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0">
<tbody>
<tr>
<td className="w-15"><strong className="text-muted">Sala</strong></td>
<td style={{ width: "65%" }}><strong>LabelCursoSala</strong></td>
<td style={{ width: "10%" }}></td>
</tr>
<tr>
<td className="w-15"><strong className="text-muted">Profesor</strong></td>
<td style={{ width: "65%" }}>
<strong>LabelCursoProfesor</strong>
</td>
<td style={{ width: "10%" }}>
<div className="d-grid gap-2">
<button
className="btn btn-warning btn-sm fw-bold"
onClick={() => {
setConAlumnos(false);
setConProfesor(true);
}}
>
Editar
</button>
</div>
</td>
</tr>
<tr>
<td className="w-15"><strong className="text-muted">Sesiones</strong></td>
<td style={{ width: "65%" }}><strong>0</strong></td>
<td style={{ width: "10%" }}>
<div className="d-grid gap-2">
<button
className="btn btn-warning btn-sm fw-bold"
onClick={() => {
setConAlumnos(false);
setConSesiones(true);
}}
>
Editar
</button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
{/* COLUMNA DERECHA: VISTAS DINÁMICAS */}
<div className="col-md-8">
<div className="row">
<div className="col-md-12">
{/* --- VISTA: ALUMNOS / SECCIONES PRINCIPALES --- */}
{conAlumnos && (
<div className="row">
{/* Menú Superior de Botones */}
<div className="col-md-12 mb-3">
<div className="row">
<div className="col-md-3">
<div
className={`alert shadow cursor-pointer ${tabAlumnos === "asistencia" ? "alert-success" : "alert-light"} text-dark`}
onClick={() => setTabAlumnos("asistencia")}
>
<div className="d-flex align-items-center gap-2">
<h5 className="mb-0"><UserCheck /></h5>
<strong>Asistencias</strong>
</div>
</div>
</div>
<div className="col-md-3">
<div
className={`alert shadow cursor-pointer ${tabAlumnos === "notas" ? "alert-success" : "alert-light"} text-dark`}
onClick={() => setTabAlumnos("notas")}
>
<div className="d-flex align-items-center gap-2">
<h5 className="mb-0"><Pencil /></h5>
<strong>Notas</strong>
</div>
</div>
</div>
<div className="col-md-3">
<div
className={`alert shadow cursor-pointer ${tabAlumnos === "contenido" ? "alert-success" : "alert-light"} text-dark`}
onClick={() => setTabAlumnos("contenido")}
>
<div className="d-flex align-items-center gap-2">
<h5 className="mb-0"><File /></h5>
<strong>Contenido</strong>
</div>
</div>
</div>
<div className="col-md-3">
<div
className={`alert shadow cursor-pointer ${tabAlumnos === "observaciones" ? "alert-success" : "alert-light"} text-dark`}
onClick={() => setTabAlumnos("observaciones")}
>
<div className="d-flex align-items-center gap-2">
{/* <h5 className="mb-0"><CommentDetail /></h5> */}
<strong>Comentarios</strong>
</div>
</div>
</div>
</div>
</div>
{/* TAB ASISTENCIAS */}
{tabAlumnos === "asistencia" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-6 mb-4">
<strong>Asistencia</strong>
</div>
<div className="col-md-6 text-end">
<h5><strong className="text-muted">Promedio: </strong><strong>100%</strong></h5>
</div>
<div className="col-md-12 text-end mb-3">
<span className="badge bg-success me-1" style={{ fontSize: "12px", fontWeight: "normal" }}>Present</span>
<span className="badge bg-danger me-1" style={{ fontSize: "12px", fontWeight: "normal" }}>Absent</span>
<span className="badge bg-warning text-dark" style={{ fontSize: "12px", fontWeight: "normal" }}>Late</span>
</div>
<div className="col-md-12">
<div className="table-responsive">
<table className="table table-sm mb-0 table-hover" style={{ fontSize: "12px" }}>
<thead>
<tr>
<th scope="col" className="text-center" style={{ width: "10%" }}>Ficha</th>
<th scope="col" className="text-start" style={{ width: "30%" }}>Name</th>
<th scope="col" className="text-center" style={{ width: "20%" }}>Contrato</th>
<th scope="col" className="text-center" style={{ width: "5%" }}>S1</th>
<th scope="col" className="text-center" style={{ width: "5%" }}>S2</th>
<th scope="col" className="text-center" style={{ width: "5%" }}>S3</th>
<th scope="col" className="text-center" style={{ width: "5%" }}>S4</th>
<th scope="col" className="text-center" style={{ width: "5%" }}>S5</th>
<th scope="col" className="text-center" style={{ width: "8%" }}>%</th>
<th scope="col" className="text-center" style={{ width: "7%" }}>ver</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center">
<span className="badge bg-primary cursor-pointer" style={{ fontWeight: "normal" }}>Ver</span>
</td>
<td className="text-start">Pérez Juan</td>
<td className="text-center"><strong className="text-success">PERSONA 12345</strong></td>
<td className="text-center"><span className="badge bg-success" style={{ fontSize: "12px", fontWeight: "normal" }}>P</span></td>
<td className="text-center"><span className="badge bg-danger" style={{ fontSize: "12px", fontWeight: "normal" }}>A</span></td>
<td className="text-center"><span className="badge bg-warning text-dark" style={{ fontSize: "12px", fontWeight: "normal" }}>L</span></td>
<td className="text-center"><span className="badge bg-success" style={{ fontSize: "12px", fontWeight: "normal" }}>P</span></td>
<td className="text-center"><span className="badge bg-success" style={{ fontSize: "12px", fontWeight: "normal" }}>P</span></td>
<td className="text-center" style={{ fontSize: "14px" }}><strong>80%</strong></td>
<td className="text-center">
<button
className="btn btn-link p-0 text-decoration-none"
onClick={() => {
setConAlumnos(false);
setConAsistencias(true);
}}
>
<span className="badge bg-secondary" style={{ fontWeight: "normal" }}>Ver más</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
{/* TAB NOTAS */}
{tabAlumnos === "notas" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-12 mb-4">
<strong>Notas</strong>
</div>
<div className="col-md-12">
<div className="table-responsive">
<table className="table table-hover table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th scope="col" style={{ width: "30%" }}>Name</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA1</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA2</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA3</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA4</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA5</th>
<th scope="col" style={{ width: "5%" }} className="text-center">CA6</th>
<th scope="col" style={{ width: "7%" }}>Editar</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start">Pérez Juan</td>
<td className="text-center">85</td>
<td className="text-center">90</td>
<td className="text-center">78</td>
<td className="text-center">88</td>
<td className="text-center">92</td>
<td className="text-center">100</td>
<td className="text-start">
<button
className="btn btn-link p-0 text-decoration-none"
onClick={() => {
setConAlumnos(false);
setConNotas(true);
}}
>
<span className="badge bg-warning text-dark" style={{ fontWeight: "normal" }}>Editar</span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
{/* TAB CONTENIDO */}
{tabAlumnos === "contenido" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-12 mb-4">
<strong>Contenido</strong>
</div>
<div className="col-md-12">
<div className="table-responsive" style={{ maxHeight: "500px" }}>
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th scope="col" style={{ width: "10%" }}>Fecha</th>
<th scope="col" style={{ width: "90%" }}>Contenido</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-start">2026-03-01</td>
<td className="text-start">Introducción a la materia y reglas generales.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
)}
{/* TAB OBSERVACIONES / COMENTARIOS */}
{tabAlumnos === "observaciones" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow">
<div className="row">
<div className="col-md-12">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th scope="col" className="text-center" style={{ width: "10%" }}>Fecha</th>
<th scope="col" className="text-center" style={{ width: "10%" }}>Hora</th>
<th scope="col" style={{ width: "60%" }}>Evento</th>
<th scope="col" className="text-center" style={{ width: "20%" }}>Usuario</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center">2026-03-01</td>
<td className="text-center">10:00</td>
<td className="text-start">Inicio de curso registrado.</td>
<td className="text-center">Admin</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="col-md-12 mt-4">
<div className="row">
<div className="col-md-1"></div>
<div className="col-md-9">
<input type="text" placeholder="Escribe un comentario" className="form-control" />
</div>
<div className="col-md-2">
<button className="btn btn-primary btn-sm w-100">Agregar</button>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
)}
{/* --- VISTA: HORARIOS Y FECHAS --- */}
{conHorario && (
<div className="row">
<div className="col-md-12 mb-3">
<button className="btn btn-secondary btn-sm mb-2" onClick={() => { setConHorario(false); setConAlumnos(true); }}>Volver</button>
<div className="row">
<div className="col-md-3">
<div className={`alert shadow cursor-pointer ${tabHorario === "fechas" ? "alert-success" : "alert-light"} text-dark`} onClick={() => setTabHorario("fechas")}>
<strong>Fecha</strong>
</div>
</div>
<div className="col-md-3">
<div className={`alert shadow cursor-pointer ${tabHorario === "config" ? "alert-success" : "alert-light"} text-dark`} onClick={() => setTabHorario("config")}>
<strong>Horario</strong>
</div>
</div>
</div>
</div>
{tabHorario === "fechas" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-12 mb-4 text-start">
<h4><strong>Fecha de Inicio y Término Actual</strong></h4>
</div>
<div className="col-md-12 mb-3">
<table className="table">
<tbody>
<tr>
<td>Inicio Actual</td>
<td><span className="fw-bold">2026-01-01</span></td>
<td>Término Actual</td>
<td><span className="fw-bold">2026-06-01</span></td>
</tr>
<tr>
<td colSpan={4}><h4><strong>Fecha de Inicio y Término Nueva</strong></h4></td>
</tr>
<tr>
<td>Nuevo Inicio</td>
<td><input type="date" className="form-control" /></td>
<td>Nuevo Término</td>
<td><input type="date" className="form-control" disabled /></td>
</tr>
<tr>
<td colSpan={3}></td>
<td className="text-end">
<button className="btn btn-success d-inline-flex align-items-center gap-1" onClick={() => setIsLoading(true)}>
{/* <Upload /> Actualizar Fecha */}
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
{tabHorario === "config" && (
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-12 mb-4 text-start">
<h4><strong>Nueva configuración de horario</strong></h4>
</div>
<div className="col-md-12 mb-2">
<table className="table">
<tbody>
<tr>
<td colSpan={2} className="text-end"><h4 className="text-muted">Jornada</h4></td>
<td colSpan={2}>
<select className="form-select">
<option>Seleccionar</option>
</select>
</td>
</tr>
<tr>
<td><h4 className="text-muted text-end">Días</h4></td>
<td><select className="form-select"><option>Lunes</option></select></td>
<td><h4 className="text-muted text-end">Horas</h4></td>
<td><select className="form-select"><option>18:00 - 20:00</option></select></td>
</tr>
<tr>
<td colSpan={4} className="text-end">
<button className="btn btn-warning">Agregar nuevo horario a la lista</button>
</td>
</tr>
</tbody>
</table>
</div>
<div className="col-md-12 text-end mt-3">
<button className="btn btn-success d-inline-flex align-items-center gap-1">
<ChevronRight /> Siguiente
</button>
</div>
</div>
</div>
</div>
)}
</div>
)}
{/* --- VISTA: PROFESOR --- */}
{conProfesor && (
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-2">
<button className="btn btn-primary btn-sm" onClick={() => { setConProfesor(false); setConAlumnos(true); }}>Volver</button>
</div>
<div className="col text-end">
<h5><strong className="text-muted">Editar </strong><strong>Titular</strong></h5>
</div>
<div className="col-md-12"><hr /></div>
<div className="col-md-12">
<div className="table-responsive">
<table className="table table-borderless">
<tbody>
<tr>
<td><strong className="text-muted">Tipo Búsqueda</strong></td>
<td>
<select className="form-select">
<option>Nombre</option>
<option>Paterno</option>
</select>
</td>
<td><input type="text" className="form-control" placeholder="PROFESOR" /></td>
<td><button className="btn btn-primary btn-sm">Buscar</button></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
)}
{/* --- VISTA: SESIONES --- */}
{conSesiones && (
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row">
<div className="col-md-2">
<button className="btn btn-primary btn-sm" onClick={() => { setConSesiones(false); setConAlumnos(true); }}>Volver</button>
</div>
<div className="col text-end">
<h5><strong className="text-muted">Sesiones </strong><strong>Clases</strong></h5>
</div>
<div className="col-md-12"><hr /></div>
<div className="col-md-12 text-center">
<div className="row align-items-center">
<div className="col-md-4">
<div className="d-flex align-items-center justify-content-center gap-2">
<h3><BookBookmark /></h3>
<h5 className="fw-bold mb-0">Sesiones Iniciales<br />20</h5>
</div>
</div>
<div className="col-md-4">
<div className="d-flex align-items-center justify-content-center gap-2">
<h3><Edit /></h3>
<h5 className="fw-bold mb-0">Sesiones Suspendidas<br />2</h5>
</div>
</div>
<div className="col-md-4">
<div className="d-flex align-items-center justify-content-center gap-2">
{/* <h3><ErrorAlt /></h3> */}
<h5 className="fw-bold mb-0">Porcentaje<br />10%</h5>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* --- VISTA: DETALLE NOTAS ALUMNO --- */}
{conNotas && (
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row mb-3">
<div className="col-md-2">
<button className="btn btn-primary btn-sm" onClick={() => { setConNotas(false); setConAlumnos(true); }}>Volver</button>
</div>
<div className="col text-end">
<h5><strong className="text-muted">Student: </strong><strong>Pérez Juan</strong></h5>
</div>
</div>
<div className="table-responsive">
<table className="table table-sm table-bordered mb-0">
<thead>
<tr>
<th className="text-center">Fecha</th>
<th className="text-center">Test</th>
<th className="text-center">Nota</th>
<th className="text-center">Acción</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center">2026-02-10</td>
<td className="text-center">Examen Parcial</td>
<td className="text-center"><strong>95</strong></td>
<td className="text-center">
<button className="btn btn-link btn-sm text-primary"><EditAlt /> Editar</button>
<button className="btn btn-link btn-sm text-danger"><Trash /> Eliminar</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{/* --- VISTA: DETALLE ASISTENCIA ALUMNO --- */}
{conAsistencias && (
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row mb-3">
<div className="col-md-2">
<button className="btn btn-primary btn-sm" onClick={() => { setConAsistencias(false); setConAlumnos(true); }}>Volver</button>
</div>
<div className="col text-end">
<h5><strong className="text-muted">Student: </strong><strong>Pérez Juan</strong></h5>
</div>
</div>
<div className="table-responsive">
<table className="table table-sm table-bordered mb-0">
<thead>
<tr>
<th className="text-center">Fecha</th>
<th className="text-center">Asistencia</th>
<th className="text-center">Acciones</th>
</tr>
</thead>
<tbody>
<tr>
<td className="text-center">2026-02-01</td>
<td className="text-center"><strong className="text-success">Present</strong></td>
<td className="text-center">
<button className="btn btn-link text-primary p-0 d-inline-flex align-items-center gap-1">
{/* <MessageSquareEdit /> Editar */}
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
</div>
</div>
{/* --- MODAL LOADING --- */}
{isLoading && (
<div className="modal fade show d-block tab-index-1 bg-dark bg-opacity-50" role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-center p-4">
<div className="spinner-border text-primary mx-auto mb-3" role="status">
<span className="visually-hidden">Cargando...</span>
</div>
<h5>Procesando solicitud...</h5>
</div>
</div>
</div>
)}
{/* --- MODAL ALERTA / ERRORES --- */}
{modalAlerta.show && (
<div className="modal fade show d-block tab-index-1 bg-dark bg-opacity-50" role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-dark">
<div className="modal-header alert alert-secondary mb-0">
<h5 className="modal-title"><strong>Módulo Académico - Empresa</strong></h5>
<button type="button" className="btn-close" onClick={() => setModalAlerta({ show: false, message: "" })}></button>
</div>
<div className="modal-body text-center py-4">
<h5><strong>{modalAlerta.message}</strong></h5>
</div>
<div className="modal-footer">
<button className="btn btn-primary" onClick={() => setModalAlerta({ show: false, message: "" })}>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+81
View File
@@ -0,0 +1,81 @@
'use client';
import Link from 'next/link';
import { File } from '@boxicons/react';
export default function Page() {
const items = [
{
icon: <File className="bx-sm bx-border" />,
color: "text-primary",
label: "Administrar Cursos",
href: "/cursos/administrador",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-warning",
label: "Informe cursos iniciados por fecha",
href: "/Informes/Index?boton=periodo",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-warning",
label: "Informe cursos activos por mes",
href: "/Informes/Index?boton=activos",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-info",
label: "Cursos por iniciar",
href: "/Informes/CursosInicios?search=CURSOSINICIAN",
},
{
icon: <File className="bx-sm bx-border" />,
color: "text-info",
label: "Cursos por finalizar",
href: "/Informes/CursosInicios?search=CURSOSFINALIZAN",
},
];
return (
<>
<div id="menu">
<div className="row">
<div className="col-md-3" />
<div className="col-md-6">
<div className="alert alert-light text-dark">
<h5>
<strong>Cursos</strong>
</h5>
<hr />
<table className="table table-hover mb-0">
<tbody>
{items.map((item, i) => (
<tr key={i}>
<td colSpan={2}>
<div className="mt-2 d-grid gap-2">
<Link href={item.href} className="text-decoration-none alert-link">
<div className="row align-items-center">
<div className={`col-2 ${item.color}`}>
{item.icon}
</div>
<div className="col-10">
{item.label}
</div>
</div>
</Link>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="col-md-1" />
</div>
</div>
</>
);
}
+643
View File
@@ -0,0 +1,643 @@
"use client";
import React, { useState } from "react";
import Link from "next/link";
import {
// Transfer,
// Error as ErrorIcon,
Buildings,
// PhoneCall,
Envelope,
// CurrentLocation,
// FilePdf,
UserCircle
} from "@boxicons/react";
// interfaces para TypeScript
interface ContratoPendiente {
idLeadEmpresas: string;
cotizacion: string;
contrato: string;
tipoVenta: string;
tipoContrato: string;
idEmpresas: string;
empresa: string;
fechaFirmado: string;
ejecutivoID: string;
Responsable: string;
}
interface ContratoDetalleItem {
Url: string;
Contrato: string;
FirmaEstado: number;
CURSO_ID: string;
CURSO: string;
JORNADA: string;
DIREMP: string;
Fecha: string;
Valor: string;
}
interface OCItem {
Detalle: string;
NumeroInterno: string;
FechaSubidaPago: string;
TipoDocumento: string;
}
interface SNCItem {
Detalle: string;
codInscripcion: string;
FechaSubida: string;
}
export default function NegociosPorAprobarPage() {
// --- ESTADOS DE VISTAS ---
const [divSelectOk, setDivSelectOk] = useState(true);
const [divGestion, setDivGestion] = useState(false);
const [divGestionMotivo, setDivGestionMotivo] = useState(false);
const [divInfo, setDivInfo] = useState(false);
const [divDetalleContratos, setDivDetalleContratos] = useState(false);
// --- ESTADOS DE GESTIÓN Y SELECCIÓN ---
const [estadoGestion, setEstadoGestion] = useState("");
const [motivoRechazo, setMotivoRechazo] = useState("");
const [empresaSeleccionada, setEmpresaSeleccionada] = useState<{
nombre: string;
id: string;
ejecutivo: string;
telefono: string;
mail: string;
direccion: string;
comuna: string;
}>({
nombre: "",
id: "",
ejecutivo: "",
telefono: "",
mail: "",
direccion: "",
comuna: ""
});
// --- MODALES (LOADING, ALERTA, ALUMNOS) ---
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({ show: false, message: "" });
const [showModalAlumnos, setShowModalAlumnos] = useState(false);
const [alumnosList, setAlumnosList] = useState<any[]>([]);
// --- DATOS SIMULADOS (Reemplazan a los DataLists de ASP.NET) ---
const [listaPendientes, setListaPendientes] = useState<ContratoPendiente[]>([
{
idLeadEmpresas: "101",
cotizacion: "COT-2026-01",
contrato: "CNT-8854",
tipoVenta: "Directa",
tipoContrato: "Anual",
idEmpresas: "EMP-99",
empresa: "Empresa Ejemplo S.A.",
fechaFirmado: "2026-02-15",
ejecutivoID: "EJ-01",
Responsable: "Carlos Mendoza"
}
]);
const [listaContratosDetalle, setListaContratosDetalle] = useState<ContratoDetalleItem[]>([
{
Url: "https://sam.norteamericano.cl/documentos/contrato.pdf",
Contrato: "CNT-8854",
FirmaEstado: 1,
CURSO_ID: "ING-01",
CURSO: "Inglés Corporativo",
JORNADA: "Mañana",
DIREMP: "Av. Providencia 1234",
Fecha: "01/03/2026",
Valor: "$1.500.000"
}
]);
const [listaOC, setListaOC] = useState<OCItem[]>([
{
Detalle: "oc_8854.pdf",
NumeroInterno: "OC-4412",
FechaSubidaPago: "2026-02-16",
TipoDocumento: "Orden de Compra"
}
]);
const [mnsjNoOC, setMnsjNoOC] = useState("");
const [listaSNC, setListaSNC] = useState<SNCItem[]>([
{
Detalle: "sence_8854.pdf",
codInscripcion: "SNC-1200938",
FechaSubida: "2026-02-17"
}
]);
const [mnsjNoSNC, setMnsjNoSNC] = useState("");
// --- MANEJADORES DE EVENTOS ---
const handleVerItem = (item: ContratoPendiente) => {
setEmpresaSeleccionada({
nombre: item.empresa,
id: item.idEmpresas,
ejecutivo: item.Responsable,
telefono: "+56 9 1234 5678",
mail: "contacto@empresa.cl",
direccion: "Av. Providencia 1234",
comuna: "Providencia"
});
setDivGestion(true);
setDivSelectOk(false);
setDivInfo(true);
setDivDetalleContratos(true);
};
const handleListaGestionChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
const val = e.target.value;
setEstadoGestion(val);
if (val === "Rechazado") {
setDivGestionMotivo(true);
} else {
setDivGestionMotivo(false);
}
};
const handleConfirmarGestion = () => {
if (!estadoGestion) {
setModalAlerta({ show: true, message: "Seleccione un estado de gestión." });
return;
}
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setModalAlerta({ show: true, message: "Gestión procesada con éxito." });
}, 1200);
};
const handleVerParticipantes = (contratoId: string) => {
setAlumnosList([
{ RUT: "11.111.111-1", Nombre: "Juan Pérez", Email: "juan@empresa.cl" },
{ RUT: "22.222.222-2", Nombre: "María López", Email: "maria@empresa.cl" }
]);
setShowModalAlumnos(true);
};
return (
<div className="container-fluid py-3">
<div className="row">
{/* BARRA SUPERIOR */}
<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-10">
<strong className="text-muted">Negocios por aprobar</strong>
</div>
<div className="col-md-2 text-end">
<Link href="/Clientes/Index" className="btn btn-danger btn-sm">
{/* <Transfer className="me-1" /> */}
Volver
</Link>
</div>
</div>
</div>
</div>
{/* TABLA O MENSAJE DE NEGOCIOS POR APROBAR */}
<div className="col-md-12" id="div_select">
{divSelectOk && (
<div className="alert alert-light text-dark shadow" id="div_select_ok">
<div className="table-responsive">
{listaPendientes.length > 0 ? (
<table className="table table-sm mb-0" style={{ fontSize: "13px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "3%" }}></th>
<th className="text-start" style={{ width: "5%" }}>Contrato</th>
<th className="text-start" style={{ width: "7%" }}>Tipo Venta</th>
<th className="text-start" style={{ width: "7%" }}>Tipo Contrato</th>
<th className="text-start" style={{ width: "30%" }}>Empresa</th>
<th className="text-start" style={{ width: "7%" }}>Fecha de Subida</th>
<th className="text-center" style={{ width: "11%" }}>Ejecutivo</th>
</tr>
</thead>
<tbody>
{listaPendientes.map((item, idx) => (
<tr key={idx}>
<td className="text-center" style={{ width: "3%" }}>
<button
type="button"
className="btn btn-link p-0 text-decoration-none"
onClick={() => handleVerItem(item)}
>
<span className="badge bg-primary" style={{ fontWeight: "normal" }}>
Ver
</span>
</button>
</td>
<td className="text-start" style={{ width: "5%" }}>{item.contrato}</td>
<td className="text-start" style={{ width: "7%" }}>{item.tipoVenta}</td>
<td className="text-start" style={{ width: "7%" }}>{item.tipoContrato}</td>
<td className="text-start" style={{ width: "30%" }}>{item.empresa}</td>
<td className="text-start" style={{ width: "7%" }}>{item.fechaFirmado}</td>
<td className="text-center" style={{ width: "11%" }}>{item.Responsable}</td>
</tr>
))}
</tbody>
</table>
) : (
<div className="alert alert-light text-dark" id="div_select_error">
<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 existen contratos pendientes por autorizar.</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>
)
}
</div>
{/* PANEL DE GESTIÓN (APROBAR/RECHAZAR) */}
{divGestion && (
<div className="col-md-12" id="div_gestion">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-4 text-end">
<h4 className="mb-0">Estado: </h4>
</div>
<div className="col-md-4">
<select
className="form-select"
value={estadoGestion}
onChange={handleListaGestionChange}
>
<option value="">-- Seleccionar --</option>
<option value="Aprobado">Aprobar</option>
<option value="Rechazado">Rechazar</option>
</select>
</div>
<div className="col-md-4">
<button
type="button"
className="btn btn-primary"
onClick={handleConfirmarGestion}
>
Confirmar
</button>
</div>
</div>
{divGestionMotivo && (
<div className="row mt-2" id="div_gestion_motivo">
<div className="col-md-4 text-end">
<h4>
<strong>Motivo</strong>
</h4>
</div>
<div className="col-md-8">
<input
type="text"
className="form-control"
value={motivoRechazo}
onChange={(e) => setMotivoRechazo(e.target.value)}
/>
</div>
</div>
)}
</div>
</div>
)}
{/* PANEL LATERAL DE INFORMACIÓN DE EMPRESA */}
{divInfo && (
<div className="col-md-3" id="div_info">
<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}>
<Buildings className="text-primary border rounded p-1 mb-2" style={{ fontSize: "50px" }} />
</td>
</tr>
<tr>
<td colSpan={2}>
<span className="fs-5">{empresaSeleccionada.nombre}</span>
</td>
</tr>
<tr>
<td colSpan={2}>
<strong><span className="fs-5">{empresaSeleccionada.id}</span></strong>
</td>
</tr>
<tr>
<td className="text-end">
<strong>Ejecutivo: </strong>
</td>
<td className="text-start">{empresaSeleccionada.ejecutivo}</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 />
</td>
</tr>
<tr>
<td style={{ width: "25px" }}>
{/* <PhoneCall /> */}
</td>
<td>{empresaSeleccionada.telefono}</td>
</tr>
<tr>
<td style={{ width: "25px" }}><Envelope /></td>
<td>{empresaSeleccionada.mail}</td>
</tr>
<tr>
<td style={{ width: "25px" }}>
{/* <CurrentLocation /> */}
</td>
<td>{empresaSeleccionada.direccion}</td>
</tr>
<tr>
<td style={{ width: "25px" }}>
{/* <CurrentLocation /> */}
</td>
<td>{empresaSeleccionada.comuna}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
)}
{/* PANEL DERECHO DE DETALLES DE CONTRATOS, OC Y SENCE */}
{divDetalleContratos && (
<div className="col-md-9" id="div_detalle_contratos">
<div className="row">
{/* LISTADO DE CONTRATOS */}
<div className="col-md-12 mb-3">
<div className="alert alert-light shadow">
<table className="table table-sm mb-0">
<thead>
<tr>
<th className="text-center" style={{ width: "5%" }}>Ver contrato</th>
<th className="text-center" style={{ width: "10%" }}>Contrato</th>
<th className="text-center" style={{ width: "10%" }}>Estado</th>
<th className="text-center" style={{ width: "20%" }}>Curso</th>
<th className="text-center" style={{ width: "5%" }}>Participantes</th>
<th className="text-center" style={{ width: "15%" }}>Valor</th>
</tr>
</thead>
<tbody>
{listaContratosDetalle.map((item, idx) => (
<tr key={idx}>
<td className="text-center" style={{ width: "5%" }}>
<a target="_blank" href={item.Url} className="btn btn-primary btn-sm" rel="noreferrer">
{/* <FilePdf /> */}
</a>
</td>
<th className="text-center" style={{ width: "10%" }}>{item.Contrato}</th>
<th className="text-center mx-auto" style={{ width: "10%" }}>
{item.FirmaEstado === 1 ? "CONTRATO FIRMADO" : "CONTRATO SIN FIRMAR"}
</th>
<td className="text-center" style={{ width: "20%" }}>
{`${item.CURSO_ID} ${item.CURSO} x${item.JORNADA} ${item.DIREMP} ${item.Fecha}`}
</td>
<td className="text-center" style={{ width: "5%" }}>
<button
type="button"
className="btn btn-link p-0 text-decoration-none d-inline-flex align-items-center gap-1"
onClick={() => handleVerParticipantes(item.Contrato)}
>
<UserCircle /> Ver Participantes
</button>
</td>
<td className="text-center" style={{ width: "15%" }}>{item.Valor}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{/* DETALLE ORDEN DE COMPRA */}
<div className="col-md-6" id="detalle_oc">
<div className="alert alert-light shadow">
<table className="table table-sm mb-0">
<thead>
<tr>
<th className="text-start" style={{ width: "5%" }}></th>
<th className="text-center" style={{ width: "10%" }}>Número Interno</th>
<th className="text-center" style={{ width: "10%" }}>Fecha de Subida</th>
<th className="text-center" style={{ width: "15%" }}>Tipo Documento</th>
</tr>
</thead>
<tbody>
{listaOC.map((oc, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "5%" }}>
<a
target="_blank"
href={`https://sam.norteamericano.cl/documentos/Comprobante/${oc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</td>
<td className="text-center text-wrap" style={{ width: "10%" }}>{oc.NumeroInterno}</td>
<td className="text-center" style={{ width: "10%" }}>{oc.FechaSubidaPago}</td>
<td className="text-center" style={{ width: "15%" }}>{oc.TipoDocumento}</td>
</tr>
))}
</tbody>
</table>
{mnsjNoOC && <h4 className="text-center mt-2">{mnsjNoOC}</h4>}
</div>
</div>
{/* DETALLE SENCE */}
<div className="col-md-6" id="detalle_snc">
<div className="alert alert-light shadow">
<table className="table table-sm mb-0">
<thead>
<tr>
<th className="text-center" style={{ width: "10%" }}></th>
<th className="text-center" style={{ width: "40%" }}>Inscripción sence</th>
<th className="text-center" style={{ width: "20%" }}>Fecha de subida</th>
</tr>
</thead>
<tbody>
{listaSNC.map((snc, idx) => (
<tr key={idx}>
<td className="text-center" style={{ width: "10%" }}>
<a
target="_blank"
href={`https://sam.norteamericano.cl/documentos/Sence/${snc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</td>
<td className="text-center" style={{ width: "40%" }}>{snc.codInscripcion}</td>
<td className="text-center" style={{ width: "20%" }}>{snc.FechaSubida}</td>
</tr>
))}
</tbody>
</table>
{mnsjNoSNC && <h4 className="text-center mt-2">{mnsjNoSNC}</h4>}
</div>
</div>
</div>
</div>
)}
</div>
{/* --- MODAL PARTICIPANTES / ALUMNOS --- */}
{showModalAlumnos && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered modal-xl" role="document">
<div className="modal-content">
<div className="modal-header text-white text-center" style={{ backgroundColor: "#373193" }}>
<h5 className="modal-title">Empresas</h5>
<button
type="button"
className="btn-close btn-close-white"
onClick={() => setShowModalAlumnos(false)}
></button>
</div>
<div className="modal-body">
<table className="table table-bordered table-hover table-sm mb-0" style={{ backgroundColor: "white", fontSize: "12px" }}>
<thead>
<tr>
<th>RUT</th>
<th>Nombre</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{alumnosList.map((alm, index) => (
<tr key={index}>
<td>{alm.RUT}</td>
<td>{alm.Nombre}</td>
<td>{alm.Email}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setShowModalAlumnos(false)}>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL ALERTA DE ERRORES / MENSAJES --- */}
{modalAlerta.show && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<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"
onClick={() => setModalAlerta({ show: false, message: "" })}
aria-label="Close"
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.message}</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, message: "" })}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CARGANDO (SPINNER) --- */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<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 - Empresas</strong>
</h5>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row">
<div className="col-md-12 text-center">
<h5>
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-1 mt-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+535
View File
@@ -0,0 +1,535 @@
"use client";
import React, { useState } from "react";
///import { FilePdf, ZoomIn } from "@boxicons/react";
// Interfaces para TypeScript
interface ContratoDetalleItem {
Url: string;
Contrato: string;
FirmaEstado: number;
CURSO_ID: string;
CURSO: string;
JORNADA: string;
DIREMP: string;
Fecha: string;
Valor: string;
}
interface OCItem {
Detalle: string;
NumeroInterno: string;
FechaSubidaPago: string;
TipoDocumento: string;
Responsable: string;
}
interface SNCItem {
Detalle: string;
codInscripcion: string;
FechaSubida: string;
Responsable: string;
}
export default function ContratosEmpresasPage() {
// --- ESTADOS DE FORMULARIO DE BÚSQUEDA ---
const [idContrato, setIdContrato] = useState("");
const [tipoContrato, setTipoContrato] = useState("");
// --- ESTADOS DE SECCIONES DE DETALLES ---
const [mostrarDetalles, setMostrarDetalles] = useState(false);
const [estadoContratoLabel, setEstadoContratoLabel] = useState("Sin información");
const [divDetalleContratos, setDivDetalleContratos] = useState(false);
const [divDetalleOc, setDivDetalleOc] = useState(false);
const [divDetalleSnc, setDivDetalleSnc] = useState(false);
const [observacion, setObservacion] = useState("");
// --- MODALES (LOADING, ALERTA, VERIFICA, ALUMNOS) ---
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({ show: false, message: "" });
const [modalVerificaAnulacion, setModalVerificaAnulacion] = useState(false);
const [modalAlumnos, setModalAlumnos] = useState(false);
// --- DATOS SIMULADOS PARA LAS TABLAS ---
const [contratosDetalleList, setContratosDetalleList] = useState<ContratoDetalleItem[]>([
{
Url: "https://empresas.norteamericano.cl/documento.pdf",
Contrato: "CNT-1020",
FirmaEstado: 1,
CURSO_ID: "ING-01",
CURSO: "Inglés Básico",
JORNADA: "Tarde",
DIREMP: "Casa Matriz",
Fecha: "2026-01-15",
Valor: "$450.000"
}
]);
const [mnsjNoContratos, setMnsjNoContratos] = useState("");
const [ocDetalleList, setOcDetalleList] = useState<OCItem[]>([
{
Detalle: "comprobante_1020.pdf",
NumeroInterno: "OC-5501",
FechaSubidaPago: "2026-01-16",
TipoDocumento: "Comprobante Pago",
Responsable: "María González"
}
]);
const [mnsjNoOC, setMnsjNoOC] = useState("");
const [sncDetalleList, setSncDetalleList] = useState<SNCItem[]>([
{
Detalle: "sence_1020.pdf",
codInscripcion: "SNC-88412",
FechaSubida: "2026-01-17",
Responsable: "Pedro Ramírez"
}
]);
const [mnsjNoSNC, setMnsjNoSNC] = useState("");
const [alumnosList, setAlumnosList] = useState<any[]>([]);
// --- MANEJADORES DE EVENTOS ---
const handleMostrarClick = () => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setEstadoContratoLabel("Vigente");
setMostrarDetalles(true);
setDivDetalleContratos(true);
setDivDetalleOc(true);
setDivDetalleSnc(true);
}, 1000);
};
const handleVerParticipantes = (contratoId: string) => {
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setAlumnosList([
{ RUT: "12.345.678-9", Nombre: "Juan Pérez", Email: "juan.perez@empresa.cl" },
{ RUT: "98.765.432-1", Nombre: "Ana Gómez", Email: "ana.gomez@empresa.cl" }
]);
setModalAlumnos(true);
}, 800);
};
const handleDesactivarVerifica = () => {
if (!observacion.trim()) {
setModalAlerta({
show: true,
message: "Debe ingresar el motivo de por qué se anula el contrato."
});
return;
}
setModalVerificaAnulacion(true);
};
const handleConfirmarAnulacion = () => {
setModalVerificaAnulacion(false);
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setEstadoContratoLabel("Anulado");
setModalAlerta({
show: true,
message: "El contrato se ha anulado exitosamente."
});
}, 1200);
};
return (
<div className="container-fluid py-3">
{/* MENÚ / BÚSQUEDA */}
<div className="row" id="menu">
<div className="col-md-3">
<div className="alert alert-light text-dark shadow-sm">
<div className="row">
<div className="col">
<h5>
<strong>Contratos Empresas</strong>
</h5>
</div>
</div>
</div>
</div>
<div className="col-md-9">
<div className="alert alert-light text-dark shadow-sm" role="alert">
<div className="row align-items-center">
<div className="col">
<h5 className="text-end mb-0">
<strong>Número</strong>
</h5>
</div>
<div className="col">
<input
type="text"
className="form-control form-control-sm"
value={idContrato}
onChange={(e) => setIdContrato(e.target.value)}
/>
</div>
<div className="col">
<select
className="form-select form-select-sm"
value={tipoContrato}
onChange={(e) => setTipoContrato(e.target.value)}
>
<option value="">-- Seleccionar --</option>
<option value="1">Contrato Cerrado</option>
<option value="2">Plan Central</option>
</select>
</div>
<div className="col-md-2">
<button
type="button"
className="btn btn-primary btn-sm w-100"
onClick={handleMostrarClick}
>
Mostrar
</button>
</div>
</div>
</div>
</div>
</div>
{/* DETALLES DEL CONTRATO */}
{mostrarDetalles && (
<div className="row" id="detalles">
<div className="col-md-10 mx-auto">
<div className="row">
<div className="col-md-12">
<div className="row alert alert-warning mx-auto shadow-sm">
<div className="col-md-6 text-end">
<h3>Estado contrato:</h3>
</div>
<div className="col-md-6 text-start">
<h3>{estadoContratoLabel}</h3>
</div>
</div>
</div>
</div>
<div className="row">
{/* TABLA DETALLE CONTRATOS */}
{divDetalleContratos && (
<div className="col-md-12 mb-3" id="div_detalle_contratos">
<div className="alert alert-light shadow-sm">
<table className="table table-sm caption-top mb-0">
<caption className="pt-0">Contrato Empresa</caption>
<thead>
<tr>
<th className="text-center" style={{ width: "5%" }}>Ver contrato</th>
<th className="text-center" style={{ width: "10%" }}>Contrato</th>
<th className="text-center" style={{ width: "10%" }}>Estado</th>
<th className="text-center" style={{ width: "20%" }}>Curso</th>
<th className="text-center" style={{ width: "5%" }}>Participantes</th>
<th className="text-center" style={{ width: "15%" }}>Valor</th>
</tr>
</thead>
<tbody>
{contratosDetalleList.map((item, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "5%" }}>
<a target="_blank" href={item.Url} className="btn btn-primary btn-sm" rel="noreferrer">
{/* <FilePdf /> */}
</a>
</td>
<th className="text-center" style={{ width: "10%" }}>{item.Contrato}</th>
<th className="text-center mx-auto" style={{ width: "10%" }}>
{item.FirmaEstado === 1 ? "CONTRATO FIRMADO" : "CONTRATO SIN FIRMAR"}
</th>
<td className="text-center" style={{ width: "20%" }}>
{`${item.CURSO_ID} ${item.CURSO} ${item.JORNADA} ${item.DIREMP} ${item.Fecha}`}
</td>
<td className="text-center" style={{ width: "5%" }}>
<button
type="button"
className="btn btn-link p-0 text-decoration-none d-inline-flex align-items-center gap-1"
onClick={() => handleVerParticipantes(item.Contrato)}
>
{/* <ZoomIn /> Ver Participantes */}
</button>
</td>
<td className="text-center" style={{ width: "15%" }}>{item.Valor}</td>
</tr>
))}
</tbody>
</table>
{mnsjNoContratos && <h4 className="mt-2">{mnsjNoContratos}</h4>}
</div>
</div>
)}
{/* TABLA COMPROBANTES DE PAGOS (OC) */}
{divDetalleOc && (
<div className="col-md-6" id="div_detalle_oc">
<div className="alert alert-light shadow-sm">
<table className="table table-sm caption-top mb-0">
<caption className="pt-0">Comprobantes de Pagos</caption>
<thead>
<tr>
<th className="text-start" style={{ width: "5%" }}></th>
<th className="text-start small" style={{ width: "10%" }}>Número Interno</th>
<th className="text-center small" style={{ width: "10%" }}>Fecha de Subida</th>
<th className="text-center small" style={{ width: "10%" }}>Tipo Documento</th>
<th className="text-center small" style={{ width: "10%" }}>Responsable</th>
</tr>
</thead>
<tbody>
{ocDetalleList.map((oc, idx) => (
<tr key={idx}>
<td className="text-start" style={{ width: "5%" }}>
<a
target="_blank"
href={`https://empresas.norteamericano.cl/ComprobantesPagos/${oc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</td>
<td className="text-start small text-wrap" style={{ width: "10%" }}>{oc.NumeroInterno}</td>
<td className="text-center small" style={{ width: "10%" }}>{oc.FechaSubidaPago}</td>
<td className="text-center small" style={{ width: "10%" }}>{oc.TipoDocumento}</td>
<td className="text-center small" style={{ width: "10%" }}>{oc.Responsable}</td>
</tr>
))}
</tbody>
</table>
{mnsjNoOC && <h4 className="mt-2">{mnsjNoOC}</h4>}
</div>
</div>
)}
{/* TABLA INSCRIPCIÓN SENCE */}
{divDetalleSnc && (
<div className="col-md-6" id="div_detalle_snc">
<div className="alert alert-light shadow-sm">
<table className="table table-sm caption-top mb-0">
<caption className="pt-0">Inscripcion SENCE</caption>
<thead>
<tr>
<th className="text-center" style={{ width: "10%" }}></th>
<th className="text-center" style={{ width: "40%" }}>Inscripción sence</th>
<th className="text-center" style={{ width: "20%" }}>Fecha de subida</th>
<th className="text-center" style={{ width: "30%" }}>Responsable</th>
</tr>
</thead>
<tbody>
{sncDetalleList.map((snc, idx) => (
<tr key={idx}>
<th className="text-center" style={{ width: "10%" }}>
<a
target="_blank"
href={`https://empresas.norteamericano.cl/DocumentosSence/${snc.Detalle}`}
className="btn btn-primary btn-sm"
rel="noreferrer"
>
Ver
</a>
</th>
<td className="text-center small" style={{ width: "40%" }}>{snc.codInscripcion}</td>
<td className="text-center small" style={{ width: "20%" }}>{snc.FechaSubida}</td>
<td className="text-center small" style={{ width: "30%" }}>{snc.Responsable}</td>
</tr>
))}
</tbody>
</table>
{mnsjNoSNC && <h4 className="mt-2">{mnsjNoSNC}</h4>}
</div>
</div>
)}
</div>
{/* SECCIÓN DESACTIVAR / OBS. */}
<div className="row">
<div className="col-md-12">
<div className="row alert alert-light mx-auto shadow-sm align-items-center">
<div className="col-md-3 text-end">
<h4 className="mb-0">Motivo</h4>
</div>
<div className="col-md-4">
<textarea
id="TextAreaObservacion"
className="form-control"
cols={20}
rows={3}
placeholder="Escribir el motivo de por que se anula el contrato"
value={observacion}
onChange={(e) => setObservacion(e.target.value)}
></textarea>
</div>
<div className="col-md-3 text-start">
<button
type="button"
className="btn btn-warning w-100"
onClick={handleDesactivarVerifica}
>
Desactivar
</button>
</div>
</div>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL PARTICIPANTES (ALUMNOS) --- */}
{modalAlumnos && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered modal-xl" role="document">
<div className="modal-content">
<div className="modal-header text-white text-center" style={{ backgroundColor: "#373193" }}>
<h5 className="modal-title">Empresas</h5>
<button
type="button"
className="btn-close btn-close-white"
onClick={() => setModalAlumnos(false)}
></button>
</div>
<div className="modal-body">
<table className="table table-bordered table-hover table-sm mb-0" style={{ backgroundColor: "white", fontSize: "12px" }}>
<thead>
<tr>
<th>RUT</th>
<th>Nombre</th>
<th>Email</th>
</tr>
</thead>
<tbody>
{alumnosList.map((alm, index) => (
<tr key={index}>
<td>{alm.RUT}</td>
<td>{alm.Nombre}</td>
<td>{alm.Email}</td>
</tr>
))}
</tbody>
</table>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary" onClick={() => setModalAlumnos(false)}>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL ALERTA DE MENSAJES --- */}
{modalAlerta.show && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<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 Venta - Empresa</strong>
</h5>
<button
type="button"
className="btn-close float-end mt-1"
onClick={() => setModalAlerta({ show: false, message: "" })}
aria-label="Close"
></button>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>{modalAlerta.message}</strong>
</h5>
</div>
</div>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-primary"
onClick={() => setModalAlerta({ show: false, message: "" })}
>
Close
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CONFIRMACIÓN DE ANULACIÓN --- */}
{modalVerificaAnulacion && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered modal-xl" role="document">
<div className="modal-content">
<div className="modal-header text-white text-center" style={{ backgroundColor: "#373193" }}>
<h5 className="modal-title">Empresas</h5>
<button
type="button"
className="btn-close btn-close-white"
onClick={() => setModalVerificaAnulacion(false)}
></button>
</div>
<div className="modal-body">
<h4 className="fw-bolder text-center">
¿Desea anular el contrato {idContrato || "0"} junto con su documentación?
</h4>
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-success"
onClick={handleConfirmarAnulacion}
>
Confirmar
</button>
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalVerificaAnulacion(false)}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* --- MODAL CARGANDO (SPINNER) --- */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<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>SAM - Empresas</strong>
</h5>
</div>
<div className="modal-body alert mb-0" style={{ textAlign: "justify" }}>
<div className="row mb-2">
<div className="col-md-12 text-center">
<h5>
<strong>Procesando, espere un momento</strong>
</h5>
<div className="d-flex justify-content-center gap-1 mt-2">
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-primary" role="status"></div>
<div className="spinner-grow spinner-grow-sm text-danger" role="status"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
)}
</div>
);
}
+1281
View File
File diff suppressed because it is too large. Load diff
+128
View File
@@ -0,0 +1,128 @@
"use client";
import React, { useState } from "react";
import Link from "next/link";
import {
InfoSquare,
// CartDownload,
// FileArchive,
File,
// IdCard
} from "@boxicons/react";
export default function Page() {
const [isLoading, setIsLoading] = useState(false);
const [modalAlerta, setModalAlerta] = useState({
show: false,
message: ""
});
const secciones = [
{
titulo: "Administración Empresas",
items: [
{
icon: <InfoSquare />,
color: "text-primary",
label: "Información de Empresas",
href: "/empresas/informacion"
},
{
icon: <InfoSquare />,
color: "text-warning",
label: "Autorizar Negocios",
href: "/empresas/autorizador"
},
{
icon: <InfoSquare />,
color: "text-success",
label: "Anular Contratos",
href: "/empresas/desactivador"
}
]
},
{
titulo: "Informes",
items: [
{
icon: <File />,
color: "text-warning",
label: "Informes de documentos autorizados/rechazados",
href: "/Informes/ContratosAutorizados"
},
{
icon: <InfoSquare />,
color: "text-danger",
label: "Informes de contratos anulados",
href: "/Informes/ContratosAnulados"
}
]
}
];
const handleLinkClick = () => {
setIsLoading(true);
};
return (
<div id="menu" className="container py-3">
{secciones.map((seccion, sIdx) => (
<div className="row" key={sIdx}>
<div className="col-md-2" />
<div className="col-md-8">
<div className="alert alert-light text-dark">
<h5>
<strong>{seccion.titulo}</strong>
</h5>
<hr />
<table className="table table-hover mb-0">
<tbody>
{seccion.items.map((item, i) => (
<tr key={i}>
<td className={item.color} style={{ width: "5%" }}>
<h1>{item.icon}</h1>
</td>
<td>
<div className="d-grid gap-2 mt-2">
<Link
href={item.href}
className="text-decoration-none alert-link"
onClick={handleLinkClick}
>
{item.label}
</Link>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="col-md-2" />
</div>
))}
{/* --- MODAL CARGANDO --- */}
{isLoading && (
<div
className="modal fade show d-block bg-dark bg-opacity-50"
role="dialog"
tabIndex={-1}
>
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content text-center p-4">
<div
className="spinner-border text-primary mx-auto mb-3"
role="status"
>
<span className="visually-hidden">Cargando...</span>
</div>
<h5>Cargando...</h5>
</div>
</div>
</div>
)}
</div>
);
}
+36
View File
@@ -0,0 +1,36 @@
import * as XLSX from 'xlsx';
/**
* Función dinámicas para descargar un arreglo de objetos como Excel
* @param {Array<Object>} dataArreglo - La constante con los datos
* @param {string} nombreArchivo - Nombre opcional para el archivo descargado
*/
export const descargarExcelProfesor = (dataArreglo, nombreArchivo = 'Reporte_Sesiones_Profesor') => {
if (!dataArreglo || dataArreglo.length === 0) {
console.warn("El arreglo de datos está vacío.");
return;
}
// 1. SheetJS extrae automáticamente las claves (xxx:) como columnas
const hojaDeTrabajo = XLSX.utils.json_to_sheet(dataArreglo);
// 2. Crea un libro de trabajo nuevo
const libroDeTrabajo = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(libroDeTrabajo, hojaDeTrabajo, 'Sesiones');
// 3. Ajusta automáticamente el ancho de las columnas según el contenido
const columnasAncho = Object.keys(dataArreglo[0]).map(key => {
// Busca la longitud máxima entre los valores de la columna y el encabezado
const maxLen = dataArreglo.reduce((max, row) => {
const val = row[key] ? String(row[key]) : '';
return Math.max(max, val.length);
}, key.length);
return { wch: maxLen + 3 }; // Margen adicional
});
hojaDeTrabajo['!cols'] = columnasAncho;
// 4. Descarga el archivo Excel .xlsx
XLSX.writeFile(libroDeTrabajo, `${nombreArchivo}.xlsx`);
};
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+147
View File
@@ -0,0 +1,147 @@
'use client';
import { Geist, Geist_Mono } from "next/font/google";
import "bootstrap/dist/css/bootstrap.min.css";
import { useState, useEffect } from "react";
// import "bootstrap/dist/js/bootstrap.bundle.min.js";
// import Bootstrap from "@boxicons/react";
import Link from "next/link";
import {
Menu, MenuRight, Grid, School, Buildings, Book, Group, SwapHorizontal, DoorOpen, Sun, Moon
} from "@boxicons/react";
const geistSans = Geist({ variable: "--font-geist-sans", subsets: ["latin"] });
const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"] });
export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) {
const [open, setOpen] = useState(true);
const [theme, setTheme] = useState<"light" | "dark">("light");
useEffect(() => {
// Sincroniza el estado local con el valor ya inyectado en el DOM por el script
const currentTheme = (document.documentElement.getAttribute("data-bs-theme") as "light" | "dark") || "light";
// import("bootstrap");
import ("bootstrap/dist/js/bootstrap.bundle.min.js");
setTheme(currentTheme);
}, []);
const toggleTheme = () => {
const newTheme = theme === "light" ? "dark" : "light";
setTheme(newTheme);
document.documentElement.setAttribute("data-bs-theme", newTheme);
localStorage.setItem("theme", newTheme);
};
return (
<html lang="es" className={`${geistSans.variable} ${geistMono.variable}`} data-scroll-behavior="smooth" suppressHydrationWarning>
<head>
{/* Script bloqueante: Se ejecuta ANTES del renderizado para evitar el parpadeo */}
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
try {
var savedTheme = localStorage.getItem('theme');
var systemDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
var theme = savedTheme || (systemDark ? 'dark' : 'light');
document.documentElement.setAttribute('data-bs-theme', theme);
} catch (e) {}
})();
`,
}}
/>
</head>
<body className="d-flex m-0 vh-100" style={{ fontFamily: "system-ui, sans-serif" }}>
<div
className={`sidebar d-flex flex-column flex-shrink-0 ${open ? "open" : ""}`}
style={{
width: open ? 220 : 60,
background: "#3C3B6E",
transition: "width 0.3s ease",
overflow: "hidden",
}}
>
<div className="logo-details d-flex align-items-center justify-content-between p-3" style={{ height: 60, whiteSpace: "nowrap" }}>
{open && <div className="logo_name fw-bold fs-4 text-white">SAM</div>}
<button
onClick={() => setOpen(!open)}
className="btn border-0 text-white p-0 d-flex align-items-center"
style={{ background: "none", fontSize: 24 }}
>
{open ? <MenuRight width={24} height={24} /> : <Menu width={24} height={24} />}
</button>
</div>
<ul className="nav-list list-unstyled m-0 flex-grow-1 d-flex flex-column px-0 py-2">
<li className="position-relative">
<Link href="/" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Grid width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Dashboard</span>
</Link>
</li>
<li className="position-relative">
<Link href="/academico" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<School width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Academico</span>
</Link>
</li>
<li className="position-relative">
<Link href="/empresas" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Buildings width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Gestion Empresas</span>
</Link>
</li>
<li className="position-relative">
<Link href="/cursos" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Book width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Curso</span>
</Link>
</li>
<li className="position-relative">
<Link href="/secretaria" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<Group width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Secretaría</span>
</Link>
</li>
<li className="position-relative">
<a href="https://sam.norteamericano.cl/academico/index.aspx" className="text-white text-decoration-none d-flex align-items-center gap-3 py-2 px-3" style={{ whiteSpace: "nowrap", minHeight: 48 }}>
<SwapHorizontal width={22} height={22} style={{ flexShrink: 0 }} />
<span className="links_name" style={{ display: open ? "inline" : "none" }}>Plan Central</span>
</a>
</li>
</ul>
<div className="px-2 py-2 border-top" style={{ borderColor: "rgba(255,255,255,0.2)" }}>
<button
onClick={toggleTheme}
className="btn text-white d-flex align-items-center gap-3 w-100 py-2 px-2 border-0"
style={{ background: "rgba(255,255,255,0.1)", borderRadius: 6, whiteSpace: "nowrap" }}
title="Cambiar tema"
>
{theme === "light" ? <Moon width={20} height={20} /> : <Sun width={20} height={20} />}
{open && <span>{theme === "light" ? "Modo Oscuro" : "Modo Claro"}</span>}
</button>
</div>
<div className="profile border-top" style={{ borderColor: "rgba(255,255,255,0.2)" }}>
<div className="profile-details d-flex align-items-center justify-content-between p-3" style={{ whiteSpace: "nowrap" }}>
{open && (
<div className="name_job text-white" style={{ fontSize: 13, lineHeight: 1.3 }}>
<div className="name fw-bold" style={{ fontSize: 14 }}>Usuario</div>
<div className="job" style={{ opacity: 0.8 }}>Sede</div>
</div>
)}
<Link href="/logout" className="text-white text-decoration-none d-flex align-items-center" style={{ flexShrink: 0 }}>
<DoorOpen width={20} height={20} />
</Link>
</div>
</div>
</div>
<section className="home-section flex-grow-1 overflow-auto bg-body-tertiary">
<main className="container-fluid p-3">{children}</main>
</section>
</body>
</html>
);
}
+197
View File
@@ -0,0 +1,197 @@
'use client'
import { useState, useEffect } from "react";
import { Sun, Moon } from "@boxicons/react";
export default function Home() {
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
useEffect(() => {
setLoading(false);
}, []);
const alumnos = [
{ id: 101, tipo: "Regular", curso: "Inglés Básico Intensivo", profesor: "John Doe", sede: "Sede Central", sala: "Sala A", horario: "09:00 / 10:30", inicio: "09:00", inicioBadge: "bg-warning text-dark", termino: "10:30", sesion: "En proceso", sesionBadge: "bg-body-secondary text-body" },
{ id: 102, tipo: "Intensivo", curso: "Francés Avanzado", profesor: "Maria Perez", sede: "Sede Norte", sala: "Sala B", horario: "10:30 / 12:00", inicio: "10:30", inicioBadge: "bg-success text-white", termino: "12:00", sesion: "Completada", sesionBadge: "bg-success text-white" },
{ id: 103, tipo: "Regular", curso: "Alemán Intermedio", profesor: "Carlos López", sede: "Sede Sur", sala: "Sala C", horario: "14:00 / 15:30", inicio: "14:00", inicioBadge: "bg-warning text-dark", termino: "15:30", sesion: "En proceso", sesionBadge: "bg-body-secondary text-body" },
{ id: 104, tipo: "Intensivo", curso: "Inglés Avanzado", profesor: "Ana Torres", sede: "Sede Central", sala: "Sala A", horario: "16:00 / 17:30", inicio: "16:00", inicioBadge: "bg-danger text-white", termino: "17:30", sesion: "Pendiente", sesionBadge: "bg-danger text-white" },
{ id: 105, tipo: "Regular", curso: "Japonés Básico", profesor: "Takashi Tanaka", sede: "Sede Norte", sala: "Sala D", horario: "18:00 / 19:30", inicio: "18:00", inicioBadge: "bg-warning text-dark", termino: "19:30", sesion: "En proceso", sesionBadge: "bg-body-secondary text-body" },
];
if (loading) return <div className="text-center py-5">Cargando...</div>;
if (error) return <div className="alert alert-danger my-3">{error}</div>;
return (
<div className="row g-3">
{/* Buscador y Filtros */}
<div className="col-md-12">
<div className="card bg-body-tertiary border-0 shadow-sm p-3">
<div className="row align-items-center">
<div className="col-12 mb-2">
<div className="d-flex align-items-center gap-2">
<h1><i className="bx bx-time mb-0"></i></h1>
<strong>Mostrando cursos del día</strong>
</div>
</div>
<div className="col-md-6">
<div className="row g-2">
<div className="col-md-4">
<input type="date" id="TextBoxFecha" className="form-control" />
</div>
<div className="col-md-4">
<select id="ListaSedes" className="form-control">
<option value="">Seleccione Sede</option>
<option value="todas">TODAS</option>
<option value="moneda">MONEDA</option>
<option value="providencia">PROVIDENCIA</option>
<option value="la_florida">LA FLORIDA</option>
<option value="online">ONLINE</option>
<option value="empresas">EMPRESAS</option>
</select>
</div>
<div className="col-md-4 d-grid">
<button type="button" id="ButtonSearchMod" className="btn btn-primary">Buscar</button>
</div>
</div>
</div>
<div className="col-md-6 mt-2 mt-md-0">
<div className="row g-2">
<div className="col-md-6 d-grid">
<button type="button" id="LinkButtonJornada01" className="btn btn-outline-primary text-start p-2">
<div className="d-flex align-items-center gap-2">
<Sun width={24} height={24} />
<strong>Diurno</strong>
</div>
</button>
</div>
<div className="col-md-6 d-grid">
<button type="button" id="LinkButtonJornada02" className="btn btn-outline text-start p-2">
<div className="d-flex align-items-center gap-2">
<Moon width={24} height={24} />
<strong>Vespertino</strong>
</div>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Tarjetas de Indicadores */}
<div className="col-md-12">
<div className="row g-3">
<div className="col-md-2">
<div className="card bg-body-tertiary border-0 shadow-sm p-3 h-100">
<div className="row align-items-center text-center">
<div className="col-12">
<h1><i className="bx bxs-buildings"></i></h1>
<span className="fw-bold">Empresas</span>
</div>
<div className="col-12 mt-2">
<span className="text-secondary small">Total</span>
<h5><strong>0 %</strong></h5>
</div>
</div>
</div>
</div>
<div className="col-md-2">
<div className="card bg-body-tertiary border-0 shadow-sm p-3 h-100">
<div className="row align-items-center text-center">
<div className="col-12">
<h1><i className="bx bxs-book"></i></h1>
<span className="fw-bold">Cursos</span>
</div>
<div className="col-12 mt-2">
<span className="text-secondary small">Total</span>
<h5><strong>0 %</strong></h5>
</div>
</div>
</div>
</div>
<div className="col-md-6">
<div className="card bg-body-tertiary border-0 shadow-sm p-3 h-100">
<div className="row align-items-center text-center">
<div className="col-md-3">
<h1><i className="bx bxs-user-circle"></i></h1>
<span className="fw-bold">Alumnos</span>
</div>
<div className="col-md-9 mt-2 mt-md-0">
<div className="row">
<div className="col-4">
<span className="text-secondary small">Con SENCE</span>
<h5><strong>0</strong></h5>
</div>
<div className="col-4">
<span className="text-secondary small">Sin SENCE</span>
<h5><strong>0</strong></h5>
</div>
<div className="col-4">
<span className="text-secondary small">Total</span>
<h5><strong>0</strong></h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div className="col-md-2">
<button type="button" className="btn btn-success h-100 w-100 p-3 shadow-sm border-0 d-flex flex-column align-items-center justify-content-center">
<h1><i className="bx bx-export mb-0"></i></h1>
<span>Exportar Excel</span>
</button>
</div>
</div>
</div>
{/* Tabla de Alumnos */}
<div className="col-md-12">
<div className="card bg-body-tertiary border-0 shadow-sm p-3">
<div className="table-responsive">
<table className="table table-hover align-middle mb-0" style={{ fontSize: '12px' }}>
<thead>
<tr>
<th className="text-center" scope="col" style={{ width: '5%' }}>ID</th>
<th className="text-center" scope="col" style={{ width: '5%' }}>Tipo</th>
<th scope="col" style={{ width: '20%' }}>Curso</th>
<th scope="col" style={{ width: '19%' }}>Profesor</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sede</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sala</th>
<th className="text-center" scope="col" style={{ width: '14%' }}>Horario</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Inicio</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Termino</th>
<th className="text-center" scope="col" style={{ width: '7%' }}>Sesion</th>
</tr>
</thead>
<tbody>
{alumnos.map((a) => (
<tr key={a.id}>
<td className="text-center">{a.id}</td>
<td className="text-center">{a.tipo}</td>
<td className="text-start">{a.curso}</td>
<td className="text-start">{a.profesor}</td>
<td className="text-center">{a.sede}</td>
<td className="text-center">{a.sala}</td>
<td className="text-center">{a.horario}</td>
<td className="text-center">
<span className={`badge rounded-pill ${a.inicioBadge}`}>{a.inicio}</span>
</td>
<td className="text-center">{a.termino}</td>
<td className="text-center">
<span className={`badge rounded-pill ${a.sesionBadge}`}>{a.sesion}</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}
+3
View File
@@ -0,0 +1,3 @@
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
+1
View File
@@ -0,0 +1 @@
declare module "bootstrap/dist/js/bootstrap.bundle.min.js";
Executable
+34
View File
@@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}