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

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

No files matched your search

+386
View File
@@ -0,0 +1,386 @@
"use client";
import React, { useState } from "react";
import {
// TransferAlt,
Check,
X,
// Error as ErrorIcon,
// ErrorCircle,
CheckCircle,
} from "@boxicons/react";
// Interfaz para los datos del reemplazo
interface ReemplazoItem {
idCursoAbierto: string;
Curso: string;
FechaAsistencia: string;
HoraInicio: string;
HoraSalida: string;
rutProfesor: string;
Profesor: string;
Estado: string;
idAsistenciaProfesor: string;
Email?: string;
}
// Interfaz para la configuración de la confirmación
interface ModalConfirmacionState {
show: boolean;
accion: "autorizar" | "rechazar" | null;
item: ReemplazoItem | null;
}
export default function ReemplazosPendientesPage() {
// Estado con datos de ejemplo
const [reemplazos, setReemplazos] = useState<ReemplazoItem[]>([
{
idCursoAbierto: "CUR-101",
Curso: "Inglés Básico A1",
FechaAsistencia: "15-02-2026",
HoraInicio: "09:00",
HoraSalida: "10:30",
rutProfesor: "12.345.678-9",
Profesor: "Juan Pérez",
Estado: "Pendiente",
idAsistenciaProfesor: "SES-001",
Email: "jperez@correo.cl",
},
{
idCursoAbierto: "CUR-102",
Curso: "Inglés Intermedio B2",
FechaAsistencia: "16-02-2026",
HoraInicio: "11:00",
HoraSalida: "12:30",
rutProfesor: "15.987.654-3",
Profesor: "María González",
Estado: "Pendiente",
idAsistenciaProfesor: "SES-002",
Email: "mgonzalez@correo.cl",
},
]);
// Estados para diálogos y procesamientos
const [modalConfirm, setModalConfirm] = useState<ModalConfirmacionState>({
show: false,
accion: null,
item: null,
});
const [isLoading, setIsLoading] = useState(false);
const [modalRespuesta, setModalRespuesta] = useState<{
show: boolean;
errorMsg: string;
okMsg: string;
}>({ show: false, errorMsg: "", okMsg: "" });
// Abrir modal customizado de confirmación
const abrirConfirmacion = (item: ReemplazoItem, accion: "autorizar" | "rechazar") => {
setModalConfirm({
show: true,
accion,
item,
});
};
// Procesar la autorización / rechazo
const handleConfirmar = () => {
if (!modalConfirm.item || !modalConfirm.accion) return;
const { idAsistenciaProfesor } = modalConfirm.item;
const accion = modalConfirm.accion;
// Cerrar modal de confirmación y mostrar loader
setModalConfirm({ show: false, accion: null, item: null });
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
// Eliminar el ítem procesado de la lista
setReemplazos((prev) => prev.filter((r) => r.idAsistenciaProfesor !== idAsistenciaProfesor));
setModalRespuesta({
show: true,
errorMsg: "",
okMsg: `El reemplazo se ha ${
accion === "autorizar" ? "autorizado" : "rechazado"
} correctamente.`,
});
}, 1000);
};
return (
<>
<div className="row">
{/* ENCABEZADO */}
<div className="col-md-12">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="row align-items-center">
<div className="col-md-1 text-center">
{/* <TransferAlt className="text-warning fs-3 border rounded p-1" /> */}
</div>
<div className="col-md-9">
<span className="text-muted">
<strong>Autorización</strong>
</span>
<h5 className="mb-0">
<strong>Reemplazos Pendientes</strong>
</h5>
</div>
</div>
</div>
</div>
{/* TABLA O ALERTA */}
{reemplazos.length > 0 ? (
<div className="col-md-12" id="divTablaReemplazos">
<div className="alert alert-light text-dark shadow" role="alert">
<div className="table-responsive">
<table className="table table-sm mb-0" style={{ fontSize: "14px" }}>
<thead>
<tr>
<th className="text-start" style={{ width: "18%" }}>Curso</th>
<th className="text-center" style={{ width: "10%" }}>Sesión</th>
<th className="text-center" style={{ width: "8%" }}>Inicio</th>
<th className="text-center" style={{ width: "8%" }}>Salida</th>
<th className="text-center" style={{ width: "14%" }}>Run</th>
<th className="text-center" style={{ width: "14%" }}>Reemplazante</th>
<th className="text-center" style={{ width: "10%" }}>Estado Sesion</th>
<th className="text-center" style={{ width: "18%" }}>Acción</th>
</tr>
</thead>
<tbody>
{reemplazos.map((item) => (
<tr key={item.idAsistenciaProfesor}>
<td className="text-start" style={{ width: "18%" }}>
<strong>{item.Curso}</strong>
<span className="badge bg-secondary ms-1">
{item.idCursoAbierto}
</span>
</td>
<td className="text-center" style={{ width: "10%" }}>
{item.FechaAsistencia}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.HoraInicio}
</td>
<td className="text-center" style={{ width: "8%" }}>
{item.HoraSalida}
</td>
<td className="text-center" style={{ width: "14%" }}>
{item.rutProfesor}
</td>
<td className="text-center" style={{ width: "14%" }}>
{item.Profesor}
</td>
<td className="text-center" style={{ width: "10%" }}>
<span className="badge bg-warning text-dark">
{item.Estado}
</span>
</td>
<td className="text-center" style={{ width: "18%" }}>
<button
type="button"
className="btn btn-success btn-sm me-1"
onClick={() => abrirConfirmacion(item, "autorizar")}
>
<Check className="me-1" /> Autorizar
</button>
<button
type="button"
className="btn btn-danger btn-sm"
onClick={() => abrirConfirmacion(item, "rechazar")}
>
<X className="me-1" /> Rechazar
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
) : (
<div className="col-md-12" id="divSinReemplazos">
<div className="alert alert-light text-dark shadow text-center py-4" role="alert">
<div className="row">
<div className="col-md-3"></div>
<div className="col-md-6 text-center">
<div className="alert alert-light text-dark mt-5" role="alert">
<strong>
{/* <ErrorIcon className="text-primary" style={{ fontSize: "90px" }} /> */}
</strong>
<br />
<br />
<h5>
<strong>No hay reemplazos pendientes de autorización</strong>
</h5>
<hr />
<strong className="text-muted">
Si cree que esto es un error, contáctenos.{" "}
<a
target="_blank"
href="https://norteamericano.freshdesk.com/support/tickets/new"
rel="noreferrer"
>
Generar Ticket
</a>
</strong>
</div>
</div>
</div>
</div>
</div>
)}
</div>
{/* MODAL PERSONALIZADO DE CONFIRMACIÓN (REEMPLAZO DE SWEETALERT2) */}
{modalConfirm.show && modalConfirm.item && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content rounded-4 p-3">
<div className="modal-body text-center">
{modalConfirm.accion === "autorizar" ? (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#198754" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" />
<polyline points="22 4 12 14.01 9 11.01" />
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#dc3545" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="10" />
<line x1="15" y1="9" x2="9" y2="15" />
<line x1="9" y1="9" x2="15" y2="15" />
</svg>
)}
<h4 className="mt-2 mb-1 fw-bold" style={{ color: "#1f2937" }}>
{modalConfirm.accion === "autorizar" ? "Autorizar Reemplazo" : "Rechazar Reemplazo"}
</h4>
<p className="text-muted mb-3" style={{ fontSize: "14px" }}>
{modalConfirm.accion === "autorizar"
? "Se asignará al profesor reemplazante"
: "Se rechazará al profesor reemplazante"}
</p>
<div
className="p-3 text-start rounded-3"
style={{
backgroundColor: modalConfirm.accion === "autorizar" ? "#f0fdf4" : "#fef2f2",
border: `1px solid ${modalConfirm.accion === "autorizar" ? "#a3cfbb" : "#f1aeb5"}`,
fontSize: "13px",
color: "#374151",
}}
>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Curso</span>
<span>
{modalConfirm.item.Curso}{" "}
<span className="badge bg-secondary ms-1">
{modalConfirm.item.idCursoAbierto}
</span>
</span>
</div>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Sesión</span>
<span>
{modalConfirm.item.FechaAsistencia} | {modalConfirm.item.HoraInicio} - {modalConfirm.item.HoraSalida}
</span>
</div>
<div className="d-flex justify-content-between mb-2">
<span className="fw-bold">Profesor</span>
<span>{modalConfirm.item.rutProfesor}</span>
</div>
<div className="d-flex justify-content-between">
<span className="fw-bold">Reemplazante</span>
<span
className="fw-bold"
style={{
color: modalConfirm.accion === "autorizar" ? "#198754" : "#dc3545",
}}
>
{modalConfirm.item.Profesor}
</span>
</div>
</div>
<div className="d-flex justify-content-end gap-2 mt-4">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalConfirm({ show: false, accion: null, item: null })}
>
Cancelar
</button>
<button
type="button"
className={`btn ${modalConfirm.accion === "autorizar" ? "btn-success" : "btn-danger"}`}
onClick={handleConfirmar}
>
{modalConfirm.accion === "autorizar" ? "Sí, autorizar" : "Sí, rechazar"}
</button>
</div>
</div>
</div>
</div>
</div>
)}
{/* MODAL RESPUESTA */}
{modalRespuesta.show && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered" role="document">
<div className="modal-content">
<div className="modal-header text-white text-center" style={{ backgroundColor: "#373193" }}>
<h5 className="modal-title">Reemplazos</h5>
</div>
<div className="modal-body">
{modalRespuesta.errorMsg && (
<div>
<strong style={{ color: "#e22523" }}>
{/* <ErrorCircle className="me-1" /> */}
<span>{modalRespuesta.errorMsg}</span>
</strong>
</div>
)}
{modalRespuesta.okMsg && (
<div>
<strong style={{ color: "#00285d" }}>
<CheckCircle className="me-1" />
<span>{modalRespuesta.okMsg}</span>
</strong>
</div>
)}
</div>
<div className="modal-footer">
<button
type="button"
className="btn btn-secondary"
onClick={() => setModalRespuesta({ show: false, errorMsg: "", okMsg: "" })}
>
Cerrar
</button>
</div>
</div>
</div>
</div>
)}
{/* MODAL CARGANDO */}
{isLoading && (
<div className="modal fade show d-block bg-dark bg-opacity-50" tabIndex={-1} role="dialog">
<div className="modal-dialog modal-dialog-centered">
<div className="modal-content">
<div className="modal-body">
<div className="col-md-12 text-center py-3">
<div className="spinner-border text-info" role="status">
<span className="visually-hidden">Procesando...</span>
</div>
<p className="mt-2 mb-0">Procesando la información...</p>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}