Arreglo de node_modules
This commit is contained in:
commit
eed3b45de3
40 files changed
+13127
No files matched your search
Executable
+41
@@ -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
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -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.
|
||||
Executable
+18
@@ -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
@@ -0,0 +1,8 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
reactCompiler: true,
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
Executable
+29
@@ -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"
|
||||
}
|
||||
}
|
||||
+3920
File diff suppressed because it is too large.
Load diff
Executable
+6
@@ -0,0 +1,6 @@
|
||||
allowBuilds:
|
||||
sharp: true
|
||||
unrs-resolver: true
|
||||
ignoredBuiltDependencies:
|
||||
- sharp
|
||||
- unrs-resolver
|
||||
Executable
+1
@@ -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 |
Executable
+1
@@ -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 |
Executable
+1
@@ -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 |
Executable
+1
@@ -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 |
Executable
+1
@@ -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 |
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+349
@@ -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
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+634
@@ -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>
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
Executable
+304
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+357
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+414
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <h1>Hello, Next.js!</h1>;
|
||||
}
|
||||
Executable
+312
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+355
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+360
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+341
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+341
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+47
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+784
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+81
@@ -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>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
Executable
+643
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+535
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+1281
File diff suppressed because it is too large.
Load diff
Executable
+128
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+36
@@ -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`);
|
||||
};
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
Executable
+147
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+197
@@ -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>
|
||||
);
|
||||
}
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
export default function Page() {
|
||||
return <h1>Hello, Next.js!</h1>;
|
||||
}
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
declare module "bootstrap/dist/js/bootstrap.bundle.min.js";
|
||||
Executable
+34
@@ -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"]
|
||||
}
|
||||
Reference in new issue
Block a user