Se agregarn vistas faltantes al proyecto. Queda pendiente funcionaildades de API
This commit is contained in:
1 parent
eed3b45de3
commit
a2fbd4b675
17 files changed
+7223
-101
No files matched your search
@@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user