Alejandro Rosales 1 year ago
parent
commit
0ef9e2a1f4

+ 2 - 0
action/action_auditoria.php

@@ -2,6 +2,8 @@
 #input $_GET['id_espacio_sgu']
 #output rutas: [ ...ruta, salones: [{...salon}] ]
 header('Content-Type: application/json charset=utf-8');
+ini_set('memory_limit', '256M');
+ini_set('post_max_size', '256M');
 ini_set('display_errors', 1);
 ini_set('display_startup_errors', 1);
 error_reporting(E_ALL);

+ 9 - 7
action/action_carreras.php

@@ -12,13 +12,15 @@ $user = unserialize($_SESSION['user']);
 
 $ruta = "../";
 require_once "../include/bd_pdo.php";
+$facultad_id = $user->facultad['facultad_id'];
+$carreras = $db->query(
+    "SELECT * FROM carrera
+    WHERE
+        (facultad_id = :facultad_id OR :facultad_id IS NULL)
+    ORDER BY carrera_nombre DESC",
+    array('facultad_id' => $facultad_id)
+);
 
-$nivel = $db->where("id", $_POST['periodo'])->getOne("fs_periodo", "nivel_id");
-$carreras = $db
-    ->where("nivel", $nivel)
-    ->where("facultad", $_POST['facultad'])
-    ->get("fs_carrera", null, "id, carrera");
-
-$user->print_to_log("Crea carrera", old: $_POST);
+// $user->print_to_log("Crea carrera", old: $_POST);
 
 die(json_encode($carreras));

+ 293 - 0
action/avisos.php

@@ -0,0 +1,293 @@
+<?
+require_once "{$_SERVER['DOCUMENT_ROOT']}/class/c_login.php";
+header('Content-Type: application/json');
+
+if (!Login::is_logged()) {
+    header('HTTP/1.1 401 Unauthorized');
+    echo json_encode(array('error' => 'No se ha iniciado sesión'));
+    exit();
+}
+$user = Login::get_user();
+try {
+
+    switch ($_SERVER['REQUEST_METHOD']) {
+        case 'GET':
+            $facultad_id = $user->facultad['facultad_id'];
+            $avisos = $db->query(
+                "SELECT * FROM aviso
+                WHERE
+                    (CURRENT_DATE BETWEEN aviso_fecha_inicial AND aviso_fecha_final) AND
+                    (facultad_id = :facultad_id OR :facultad_id IS NULL) AND
+                    aviso_estado
+                ORDER BY aviso_id DESC",
+                array('facultad_id' => $facultad_id)
+            );
+
+            /*
+            if (empty($avisos)) {
+                header('HTTP/1.1 404 Not Found');
+                echo json_encode(array('error' => 'No hay avisos disponibles'));
+                exit();
+            }
+            */
+
+            $avisos = array_map(fn($aviso) => array(
+                ...$aviso,
+                'carreras' => $db->query(
+                    "SELECT carrera_id, carrera_nombre FROM aviso_carrera
+                    JOIN carrera USING (carrera_id)
+                    WHERE aviso_id = :aviso_id",
+                    array('aviso_id' => $aviso['aviso_id'])
+                ),
+                'profesores' => $db->query(
+                    "SELECT profesor_id, profesor_clave, profesor_nombre FROM aviso_profesor
+                    JOIN profesor USING (profesor_id)
+                    WHERE aviso_id = :aviso_id",
+                    array('aviso_id' => $aviso['aviso_id'])
+                ),
+            ), $avisos);
+            echo json_encode($avisos);
+            break;
+        case 'POST':
+            $raw_input = file_get_contents('php://input');
+            if (empty($raw_input)) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'No se recibieron parámetros'));
+                exit();
+            }
+
+            $input_data = json_decode($raw_input);
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'Invalid JSON format'));
+                exit();
+            }
+
+
+            $schema = <<<JSON
+                {
+                    "\$schema": "http://json-schema.org/draft-07/schema#",
+                    "type": "object",
+                    "required": ["aviso_fecha_inicial", "aviso_fecha_final", "aviso_titulo", "aviso_texto"],
+                    "properties": {
+                        "aviso_fecha_inicial": {
+                        "type": "string",
+                        "format": "date"
+                        },
+                        "aviso_fecha_final": {
+                        "type": "string",
+                        "format": "date"
+                        },
+                        "aviso_texto": {
+                        "type": "string"
+                        },
+                        "aviso_titulo": {
+                        "type": "string"
+                        },
+                        "carreras": {
+                        "type": "array",
+                        "items": {
+                            "type": "integer",
+                            "minimum": 1
+                        },
+                        "minItems": 0,
+                        "uniqueItems": true
+                        },
+                        "profesores": {
+                        "type": "array",
+                        "items": {
+                            "type": "integer",
+                            "minimum": 1
+                        },
+                        "minItems": 0,
+                        "uniqueItems": true
+                        }
+                    },
+                    "anyOf": [
+                        {"required": ["carreras"]},
+                        {"required": ["profesores"]}
+                    ]
+                }
+                JSON;
+            // VALIDATE JSON SCHEMA
+            $validate = new JsonSchema\Validator();
+            $validate->validate($input_data, json_decode($schema));
+
+            if (!$validate->isValid()) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(
+                    array(
+                        'error' => 'El formato de la solicitud es incorrecto',
+                        'success' => false,
+                        'errors' => $validate->getErrors()
+                    )
+                );
+                exit();
+            }
+
+            $aviso_id = $db->insert(
+                'aviso',
+                array(
+                    'aviso_fecha_inicial' => $input_data->aviso_fecha_inicial,
+                    'aviso_fecha_final' => $input_data->aviso_fecha_final,
+                    'aviso_texto' => $input_data->aviso_texto,
+                    'facultad_id' => $user->facultad['facultad_id'],
+                ),
+                'aviso_id'
+            );
+
+            if (isset($input_data->carreras)) {
+                array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $aviso_id, 'carrera_id' => $carrera_id)));
+            }
+            if (isset($input_data->profesores)) {
+                array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $aviso_id, 'profesor_id' => $profesor_id)));
+            }
+
+            echo json_encode(
+                array(
+                    'aviso_id' => $aviso_id,
+                    'msg' => 'Aviso creado exitosamente',
+                    'success' => true
+                )
+            );
+            break;
+        case 'PUT':
+            $raw_input = file_get_contents('php://input');
+            if (empty($raw_input)) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'No se recibieron parámetros'));
+                exit();
+            }
+
+            $input_data = json_decode($raw_input);
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'Invalid JSON format'));
+                exit();
+            }
+
+            $schema = <<<JSON
+                {
+                    "\$schema": "http://json-schema.org/draft-07/schema#",
+                    "type": "object",
+                    "required": ["aviso_id", "aviso_fecha_final"],
+                    "properties": {
+                        "aviso_id": {
+                        "type": "integer",
+                        "minimum": 1
+                        },
+                        "aviso_fecha_final": {
+                        "type": "string",
+                        "format": "date"
+                        }
+                    }
+                }
+                JSON;
+
+            // VALIDATE JSON SCHEMA
+            $validate = new JsonSchema\Validator();
+            $validate->validate($input_data, json_decode($schema));
+
+            if (!$validate->isValid()) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(
+                    array(
+                        'error' => 'El formato de la solicitud es incorrecto',
+                        'errors' => $validate->getErrors(),
+                        'success' => false,
+                    )
+                );
+                exit();
+            }
+
+            $db->where('aviso_id', $input_data->aviso_id)
+                ->update(
+                    'aviso',
+                    array(
+                        'aviso_fecha_final' => $input_data->aviso_fecha_final,
+                    ),
+                );
+
+            if (isset($input_data->carreras)) {
+                $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_carrera');
+                array_walk($input_data->carreras, fn($carrera_id) => $db->insert('aviso_carrera', array('aviso_id' => $input_data->aviso_id, 'carrera_id' => $carrera_id)));
+            }
+
+            if (isset($input_data->profesores)) {
+                $db->where('aviso_id', $input_data->aviso_id)->delete('aviso_profesor');
+                array_walk($input_data->profesores, fn($profesor_id) => $db->insert('aviso_profesor', array('aviso_id' => $input_data->aviso_id, 'profesor_id' => $profesor_id)));
+            }
+
+            echo json_encode(
+                array(
+                    'msg' => 'Aviso actualizado exitosamente',
+                    'success' => true
+                )
+            );
+            break;
+
+        case 'DELETE':
+            $raw_input = file_get_contents('php://input');
+            if (empty($raw_input)) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'No se recibieron parámetros'));
+                exit();
+            }
+
+            $input_data = json_decode($raw_input);
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(array('error' => 'Invalid JSON format'));
+                exit();
+            }
+
+            $schema = <<<JSON
+                {
+                    "\$schema": "http://json-schema.org/draft-07/schema#",
+                    "type": "object",
+                    "required": ["aviso_id"],
+                    "properties": {
+                        "aviso_id": {
+                        "type": "integer",
+                        "minimum": 1
+                        }
+                    }
+                }
+                JSON;
+
+            // VALIDATE JSON SCHEMA
+            $validate = new JsonSchema\Validator();
+            $validate->validate($input_data, json_decode($schema));
+
+            if (!$validate->isValid()) {
+                header('HTTP/1.1 400 Bad Request');
+                echo json_encode(
+                    array(
+                        'error' => 'El formato de la solicitud es incorrecto',
+                        'errors' => $validate->getErrors(),
+                        'success' => false,
+                    )
+                );
+                exit();
+            }
+
+            $result = $db->where('aviso_id', $input_data->aviso_id)->update('aviso', array('aviso_estado' => false));
+            echo json_encode(
+                array(
+                    'msg' => 'Aviso eliminado exitosamente',
+                    'success' => true,
+                    'result' => $result
+                )
+            );
+
+            break;
+    }
+} catch (PDOException $e) {
+    echo json_encode(
+        array(
+            'error' => $e->getMessage(),
+            'query' => $db->getLastQuery(),
+            'exception' => $e->getTraceAsString()
+        )
+    );
+}

+ 3 - 4
action/reposicion_insert.php

@@ -13,10 +13,9 @@ if (!isset($_SESSION['user']))
 $user = unserialize($_SESSION['user']);
 //$user->access();
 
-$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
-$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
-$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
-$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//limpia texto
+$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion
+$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);//
+$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);//
 $fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//limpia texto
 $fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//limpia texto
 $fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//limpia texto

+ 13 - 4
action/reposicion_select.php

@@ -7,7 +7,12 @@ $ruta = "../";
 require_once "../class/c_login.php";
 
 // check if the session is started
-$user = Login::get_user();
+if (!isset($_SESSION['user']))
+    die('No se ha iniciado sesión');
+
+$user = unserialize($_SESSION['user']);
+
+
 //--- Objeto para validar usuario. El id de usuario lo lee desde sesión
 /*if(!$objSesion->tieneAcceso()){
     $return["error"] = "Error! No tienes permisos para realizar esta acción.";
@@ -25,6 +30,7 @@ $user = Login::get_user();
     }catch(Exception $e){
         $return["error"] = "Ocurrió un error al leer los datos de la reposición.";
         echo json_encode($return);
+        exit();
     }
     
     
@@ -36,15 +42,16 @@ $user = Login::get_user();
     $hora_nueva_fin = explode(":",$rs["hora_nueva_fin"]);
     $return["hora_fin"] = $hora_nueva_fin[0];
     $return["min_fin"] = $hora_nueva_fin[1];
-    $return["duracion"] = $rs["duracion_total"];
+    $return["duracion"] = $rs["duracion_interval"];
 
 //    $return["carrera"] = $rs["PlanEstudio_desc"];
     $return["horario"] = $rs["horario_id"];
     $return["materia"] = $rs["materia_id"];
     $return["materia_desc"] = $rs["materia_nombre"];
     $return["salon"] = $rs["salon_id"];
-    $return["salon_desc"] = $rs["Salon_desc"]=="" ? "-Pendiente-": $rs["Salon_desc"];
-    $return["grupo"] = $rs["horario_grupo"];
+    $return["salon_desc"] = $rs["salon"]=="" ? "-Pendiente-": $rs["salon"];
+    $return["ciclo"] = $rs["ciclo"];
+    $return["bloque"] = $rs["bloque"];
     $return["profesor"] = $rs["profesor_id"];
     $return["profesor_nombre"] = $rs["profesor_nombre"];
     $return["comentario"] = $rs["descripcion"];
@@ -54,6 +61,8 @@ $user = Login::get_user();
     $return["aula_desc"] = $rs["tipoaula_nombre"];
     $return["aula_supervisor"] = $rs["tipoaula_supervisor"];
     $return["dia"] = date('w', strtotime($rs["fecha_clase"]));
+    $return["motivo_cancelacion"] = $rs["motivo_cancelacion"];
+    $return["estado"] = $rs["estado_reposicion_id"];
 }
 echo json_encode($return);
 ?>

+ 49 - 41
action/reposicion_update.php

@@ -8,46 +8,58 @@ $ruta = "../";
 require_once "../class/c_login.php";
 
 // check if the session is started
-$user = Login::get_user();
+if (!isset($_SESSION['user']))
+    die('No se ha iniciado sesión');
+
+$user = unserialize($_SESSION['user']);
+
+
 /*if(!isset($_POST["id"]) || !isset($_POST["fecha_falta"]) || !isset($_POST["fecha_inicial"]) || !isset($_POST["hora_ini"]) || !isset($_POST["min_ini"]) || !isset($_POST["materia"]) || !isset($_POST["grupo"])){
     header("Location: ".$pag."?error=0");
     exit();
 }*/
 
 $id = filter_input(INPUT_POST, "id", FILTER_SANITIZE_NUMBER_INT);//limpia texto
-$fecha_falta = trim(filter_input(INPUT_POST, "fecha_falta", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
-$fecha = trim(filter_input(INPUT_POST, "fecha_inicial", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
-$fecha_cambio = trim(filter_input(INPUT_POST, "fecha_cambio", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
+$duracion_id = filter_input(INPUT_POST, "duracion", FILTER_SANITIZE_NUMBER_INT);//Id reposicion
+$bloque = filter_input(INPUT_POST, "bloque", FILTER_SANITIZE_NUMBER_INT);//
+$ciclo = filter_input(INPUT_POST, "ciclo", FILTER_SANITIZE_NUMBER_INT);//
+$fecha_falta = trim(htmlspecialchars($_POST["fecha_falta"], ENT_QUOTES, "UTF-8"));//limpia texto
+$fecha = trim(htmlspecialchars($_POST["fecha_inicial"], ENT_QUOTES, "UTF-8"));//limpia texto
+$fecha_cambio = trim(htmlspecialchars($_POST["fecha_cambio"], ENT_QUOTES, "UTF-8"));//limpia texto
 $hora_ini = filter_input(INPUT_POST, "hora_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 $min_ini = filter_input(INPUT_POST, "min_ini", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 $hor = filter_input(INPUT_POST, "horario", FILTER_SANITIZE_NUMBER_INT);//limpia texto
-$prof = $_SESSION["usuario_id"];
-//if(isset($_POST["salon"]) && $_POST["salon"] != "")
-//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
-$comentario = trim(filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
-
 $alumnos = filter_input(INPUT_POST, "alumnos", FILTER_SANITIZE_NUMBER_INT);//limpia texto
 $tipo = filter_input(INPUT_POST, "tipo", FILTER_SANITIZE_NUMBER_INT);//1 Repo , 0 Cambio
 $aula = filter_input(INPUT_POST, "aula", FILTER_SANITIZE_NUMBER_INT);//1 regular , 2 sala computo, 3 otro facultad
-$comentario = trim(filter_input(INPUT_POST, "comentario", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
 
-$horario_rs = $db->querySingle('SELECT * from fs_horario_basic where id = :hor',
+if(empty($_POST["prof"]))
+    $prof = $user["id"];
+else
+    $prof = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto
+
+//if(isset($_POST["salon"]) && $_POST["salon"] != "")
+//$salon = trim(filter_input(INPUT_POST, "salon", FILTER_SANITIZE_STRING,array('flags' => FILTER_FLAG_STRIP_LOW)));//limpia texto
+$comentario = trim(htmlspecialchars($_POST["comentario"], ENT_QUOTES, "UTF-8"));//limpia texto
+
+$duracion_rs = $db->querySingle("select * from duracion where duracion_id = :id", [":id"=>$duracion_id]);
+$duracion_tiempo = $duracion_rs["duracion_interval"];
+
+$horario_rs = $db->querySingle('SELECT * from horario_view where horario_id = :hor',
         [':hor' => $hor]
     );
 
 $materia = $horario_rs["materia_id"];
-$gpo = $horario_rs["grupo"];
-$duracion = $horario_rs["duracion_total"];
-$dia = $horario_rs["dia"];
+$dia = $horario_rs["horario_dia"];
 
 
 $hora = $hora_ini.":".$min_ini.":00";
 $fecha_new =  DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d')." ".$hora;
-$fecha_fin_new = date("Y-m-d H:i:00", strtotime($fecha_new.' + '.$duracion.' minute'));
+$fecha_fin_new = date("Y-m-d", strtotime($fecha_new))." ".$duracion_tiempo;
 $dia_new = date('w', strtotime($fecha_new));
 
-echo $fecha_new."<br>";
-echo $fecha_fin_new."<br>";
+//echo $fecha_new."<br>";
+//echo $fecha_fin_new."<br>";
 if($tipo == 1){//Reposición
     $fecha_falta = DateTime::createFromFormat('d/m/Y', $fecha_falta)->format('Y-m-d');
     $dia_falta = date('w', strtotime($fecha_falta));
@@ -76,40 +88,36 @@ if($tipo == 1){//Reposición
     //Valida que profesor no este en 2 reposiciones al mismo tiempo
     */
     $traslape = $db->querySingle('SELECT * from traslape_profesor_reposicion(:prof, :fecha, :hora, :dur)',
-        [':prof' => $prof, ':fecha'=>$fecha_falta, ':hora'=>$hora, ':dur'=>$duracion]
+    [':prof' => $prof, ':fecha'=>DateTime::createFromFormat('d/m/Y', $fecha)->format('Y-m-d'), ':hora'=>$hora, ':dur'=>$duracion_tiempo]
     )["traslape_profesor_reposicion"];
     if($traslape){
-        header("Location:".$pag."?error=9");
+        //header("Location:".$pag."?error=9");
+        echo "traslape";
         exit();
     }
 
-    try{
-        $db->query('SELECT * from fu_reposicion(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, true, :aula)',
-            [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
-            ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula
-            ]
-        );
-    }catch(Exception $e){
-        header("Location: ".$pag."?error=2");
-        exit();
-    }
+   
     /*
     $log = new LogActividad();
     $desc_log = "Actualiza reposición ID[".$id."] Fechas[".$fecha_ini."][".$fecha_fin."] Periodo[".$_SESSION["periodo_id"]."] Materia[".$materia."] Profesor[".$prof."] Salon[".$salon."] Horario[".$hor."]";
     $log->appendLog($_SESSION["usuario_id"], $_SESSION["usuario_nombre"]." ".$_SESSION["usuario_apellidos"], $desc_log);*/
-}else{
+}
 
-    try{
-        $db->query('SELECT * from fu_reposicion(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, true, :aula)',
-            [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
-            ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula
-            ]
-        );
-    }catch(Exception $e){
-        header("Location: ".$pag."?error=2");
-        exit();
-    }
-    
+try{
+    $db->query('SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, :aula, :duracion_id, NULL)',
+        [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
+        ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion_id' => $duracion_id
+        ]
+    );
+}catch(Exception $e){
+    //header("Location: ".$pag."?error=2");
+    print_r($e->getMessage());
+    echo "SELECT * from fu_reposicion_solicitud(:id, :f_falta, :f_nueva, :hora_nueva, NULL, 1, :desc, :alumnos, :aula, :duracion_id, NULL)'";
+    print_r(
+        [':id'=> $id, ':f_falta' => $fecha_falta, ':f_nueva' => $fecha_new, ':hora_nueva' => $hora,
+        ':desc' => $comentario, ':alumnos' => $alumnos, ':aula' => $aula, ':duracion_id' => $duracion_id
+    ]);
+    exit();
 }
 header("Location: ".$pag);
 exit();

+ 1 - 2
auditoria.php

@@ -313,8 +313,7 @@
                                             <span class="mr-2" :class="`text-${registro.estado_color}`">
                                                 <i :class="`${registro.estado_icon} ing-2x`"></i>
                                             </span>
-                                            <strong v-if="registro.usuario_nombre">{{ registro.usuario_nombre
-                                                }}</strong>
+                                            <strong v-if="registro.usuario_nombre">{{ registro.usuario_nombre }}</strong>
                                         </div>
                                         <div class="col-12" v-if="registro.registro_fecha_supervisor">
                                             Hora

+ 296 - 6
avisos.php

@@ -8,6 +8,7 @@
     <?php
     include 'import/html_css_files.php';
     ?>
+    <link rel="stylesheet" type="text/css" href="https://unpkg.com/trix@2.0.0/dist/trix.css">
     <style>
         [v-cloak] {
             display: none;
@@ -31,20 +32,303 @@
     ?>
 
     <main class="container-fluid px-4 mt-4" id="app" v-cloak @vue:mounted="mounted" style="min-height: 70vh;">
-        <div class="table-responsive">
+        <!-- btn open modal -->
+        <? include_once 'import/periodo.php' ?>
+        <div class="row mb-4">
+            <div class="col-4">
+                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#avisos-modal">
+                    <div class="ing-mas"></div>
+                    Nuevo aviso
+                </button>
+            </div>
+        </div>
+        <div class="table-responsive row" v-if="avisos.length">
             <table class="table table-hover table-striped table-bordered table-sm">
                 <thead class="thead-dark">
                     <tr>
-                        <th class="text-center">Fecha</th>
-                        <th class="text-center">Aviso</th>
-                        <th class="text-center">Estado</th>
+                        <th class="text-center" style="width: 20%;">Fecha</th>
+                        <th class="text-center" style="width: 70%;">Aviso</th>
+                        <th class="text-center" style="width: 10%;">Eliminar</th>
                     </tr>
                 </thead>
-
                 <tbody>
+                    <tr v-for="aviso in avisos" :key="aviso.aviso_id" @click="aviso_shown = aviso">
+                        <td class="text-center" data-toggle="modal" data-target="#aviso-extender">{{
+                            aviso.aviso_fecha_inicial }} - {{ aviso.aviso_fecha_final }}</td>
+                        <td class="text-center" data-toggle="modal" data-target="#aviso-mostrar">{{ aviso.aviso_titulo
+                            }}</td>
+                        <td class="text-center" data-toggle="modal" data-target="#aviso-suspender-modal"
+                            @click="aviso_suspendido = aviso.aviso_id">
+                            <span class="badge badge-pill badge-danger">
+                                <div class="ing-borrar"></div>
+                            </span>
+                        </td>
+                    </tr>
                 </tbody>
             </table>
         </div>
+        <div v-else class="alert alert-info" role="alert">
+            No hay avisos registrados
+        </div>
+
+        <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="avisos-modal">
+            <div class="modal-dialog modal-xl" role="document">
+                <div class="modal-content">
+                    <div class="modal-header text-white">
+                        <h5 class="modal-title">Crear nuevo aviso</h5>
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true" class="text-white">&times;</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <div class="container">
+                            <div class="form-box">
+
+                                <div class="form-group row">
+                                    <label for="fechaInicio" class="col-4 col-form-label">Fecha de inicio</label>
+                                    <div class="col-6">
+                                        <input type="text" class="form-control date-picker" id="fechaInicio"
+                                            name="fecha" v-model="new_aviso.fechaInicio" readonly
+                                            placeholder="aaaa-mm-dd">
+                                    </div>
+                                </div>
+
+                                <div class="form-group row">
+                                    <label for="fechaFin" class="col-4 col-form-label">Fecha fin</label>
+                                    <div class="col-6">
+                                        <input type="text" class="form-control date-picker" id="fechaFin" name="fecha"
+                                            v-model="new_aviso.fechaFin" readonly placeholder="aaaa-mm-dd">
+                                    </div>
+                                </div>
+                                <div class="form-group row">
+                                    <div class="col-6">
+                                        <label for="dlCarreras" class="col-4 col-form-label">Carreras</label>
+                                        <hr>
+
+                                        <div class="col-12 my-2" v-if="relevant_carreras.length">
+                                            <div id="dlCarreras" class="datalist datalist-select mb-1 w-100">
+                                                <div class="datalist-input">
+                                                    Selecciona una carrera
+                                                </div>
+                                                <span class="icono ing-buscar"></span>
+                                                <ul style="display:none">
+                                                    <!--
+                                                    <li class="datalist-option" data-id="0"
+                                                        @click="new_aviso.carreras = carreras">
+                                                        Todas las carreras
+                                                    </li>
+                                                -->
+                                                    <li class="datalist-option" v-for="carrera in relevant_carreras"
+                                                        :key="carrera.carrera_id" :data-id="carrera.carrera_id"
+                                                        @click="new_aviso.carreras.push(carrera)"
+                                                        style=" white-space: nowrap;">
+                                                        (<small> {{carrera.clave_carrera}} </small>) {{
+                                                        carrera.carrera_nombre }}
+                                                    </li>
+                                                </ul>
+                                                <input type="hidden" id="carrera_id" name="id">
+                                            </div>
+                                        </div>
+                                        <ul class="list-group overflow-auto col-12" style="max-height: 200px;">
+                                            <li class="list-group-item list-group-item-action"
+                                                v-for="(carrera, index) in new_aviso.carreras" :key="carrera.carrera_id"
+                                                @click="new_aviso.carreras.splice(index, 1)">
+                                                <span class="icono ing-borrar text-danger"></span>
+                                                (<small> {{carrera.clave_carrera}} </small>) {{ carrera.carrera_nombre
+                                                }}
+                                            </li>
+                                        </ul>
+                                        <div class="col-4 my-2">
+                                            <button type="button" class="btn btn-danger btn-block"
+                                                @click="new_aviso.carreras = []">
+                                                <span class="icono ing-borrar"></span>
+                                                Limpiar
+                                            </button>
+                                        </div>
+                                    </div>
+                                    <div class="col-6">
+                                        <label for="profesor" class="col-4 col-form-label">Profesores</label>
+                                        <hr>
+                                        <div class="col-12" v-if="relevant_profesores.length">
+                                            <div class="form-row justify-content-around align-items-center">
+                                                <input id="profesor" name="profesor"
+                                                    class="form-control col-11 mr-1 px-2"
+                                                    placeholder="Seleccione una profesor" list="dlProfesor"
+                                                    v-model="profesor" @input="addProfesor">
+                                                <button type="button"
+                                                    class="btn btn-outline-danger btn-sm form-control col ml-auto"
+                                                    @click="profesor = null">
+                                                    <i class="ing-borrar"></i>
+                                                </button>
+                                            </div>
+                                            <datalist id="dlProfesor">
+                                                <option v-for="profesor in relevant_profesores"
+                                                    :key="profesor.profesor_id" :value="formatProfesor(profesor)">
+                                            </datalist>
+                                        </div>
+                                        <ul class="list-group overflow-auto my-2 col-12" style="max-height: 200px;">
+                                            <li class="list-group-item list-group-item-action"
+                                                v-for="(profesor, index) in new_aviso.profesores"
+                                                :key="profesor.profesor_id"
+                                                @click="new_aviso.profesores.splice(index, 1)">
+                                                <span class="icono ing-borrar text-danger"></span>
+                                                (<small> {{profesor.profesor_clave}} </small>) {{
+                                                profesor.profesor_nombre }}
+                                            </li>
+                                        </ul>
+                                        <div class="col-4 my-2">
+                                            <button type="button" class="btn btn-danger btn-block"
+                                                @click="new_aviso.profesores = []">
+                                                <span class="icono ing-borrar"></span>
+                                                Limpiar
+                                            </button>
+                                        </div>
+                                    </div>
+                                </div>
+
+                                <div class="form-group row">
+                                    <label for="aviso" class="col-4 col-form-label">Etiqueta</label>
+                                    <div class="col-6">
+                                        <input type="text" class="form-control" id="aviso" name="aviso"
+                                            v-model="new_aviso.titulo" placeholder="Etiqueta del aviso">
+                                    </div>
+                                </div>
+
+                                <div class="form-group row">
+                                    <label for="aviso" class="col-4 col-form-label">Aviso</label>
+                                    <!-- always use relative units -->
+                                    <div class="col-6">
+                                        <input id="x" type="hidden" name="content">
+                                        <trix-editor input="x" class="form-control" id="descripcion" name="descripcion"
+                                            v-model="new_aviso.descripcion"
+                                            placeholder="Aviso que se mostrará en el checador"
+                                            style="min-height: 7em; max-height: 10em; overflow-y: auto;"></trix-editor>
+                                    </div>
+                                </div>
+
+                            </div>
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-outline-danger" data-dismiss="modal"
+                            @click="new_aviso.reset()">Cancelar</button>
+                        <button type="button" class="btn btn-primary" @click="createAviso()"
+                            :disabled="!new_aviso.isValid" :class="{'disabled': !new_aviso.isValid}">
+                            Guardar cambios
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="aviso-suspender-modal">
+            <div class="modal-dialog modal-dialog-centered" role="document">
+                <div class="modal-content">
+                    <div class="modal-header text-white">
+                        <h5 class="modal-title">Eliminar aviso</h5>
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true" class="text-white">&times;</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <div class="container">
+                            <h1>¿Está seguro que desea eliminar el aviso?</h1>
+                            <em class="text-center">
+                                <p>Esta acción no se puede deshacer</p>
+                            </em>
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-outline-danger" data-dismiss="modal">Cancelar</button>
+                        <button type="button" class="btn btn-danger" data-dismiss="modal"
+                            @click="suspenderAviso()">Eliminar</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="aviso-mostrar">
+            <div class="modal-dialog modal-dialog-centered" role="document" v-if="aviso_shown">
+                <div class="modal-content">
+                    <div class="modal-header text-white">
+                        <h5 class="modal-title">{{ aviso_shown.aviso_titulo }}</h5>
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true" class="text-white">&times;</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <div class="container">
+                            <div class="row mb-2">
+                                <div class="col-12">
+                                    <fieldset>
+                                        <legend>Fecha</legend>
+                                        <p class="text-center">{{ aviso_shown.aviso_fecha_inicial }} - {{
+                                            aviso_shown.aviso_fecha_final }}</p>
+                                    </fieldset>
+                                    <fieldset>
+                                        <legend>Aviso</legend>
+                                        <p class="text-center text-justify border rounded p-2 border-primary"
+                                            v-html="aviso_shown.aviso_texto"></p>
+                                    </fieldset>
+
+                                    <fieldset v-if="aviso_shown.profesores.length">
+                                        <legend>Profesores</legend>
+                                        <ul v-if="aviso_shown.profesores.length" class="list-group">
+                                            <li v-for="profesor in aviso_shown.profesores" :key="profesor.profesor_id"
+                                                class="list-group-item list-group-item-light">
+                                                {{ profesor.profesor_nombre }}
+                                            </li>
+                                        </ul>
+                                    </fieldset>
+
+                                    <fieldset v-if="aviso_shown.carreras.length">
+                                        <legend>Carreras</legend>
+                                        <ul class="list-group" v-if="aviso_shown.carreras.length">
+                                            <li v-for="carrera in aviso_shown.carreras" :key="carrera.carrera_id"
+                                                class="list-group-item list-group-item-light">
+                                                {{ carrera.carrera_nombre }}
+                                            </li>
+                                        </ul>
+                                    </fieldset>
+
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="modal" tabindex="-1" role="dialog" accesskey="a" id="aviso-extender">
+            <div class="modal-dialog modal-dialog-centered" role="document">
+                <div class="modal-content">
+                    <div class="modal-header text-white">
+                        <h5 class="modal-title">Extender aviso</h5>
+                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
+                            <span aria-hidden="true" class="text-white">&times;</span>
+                        </button>
+                    </div>
+                    <div class="modal-body">
+                        <div class="container" v-if="aviso_shown">
+                            <fieldset>
+                                <legend>{{ aviso_shown.aviso_titulo}}</legend>
+                                <div class="form-group row">
+                                    <label for="uFechaFin" class="col-4 col-form-label">Fecha fin</label>
+                                    <div class="col-6">
+                                        <input v-effect="initializeDatepickers($el)" type="text"
+                                            class="form-control date-picker" id="uFechaFin" name="fecha" readonly
+                                            placeholder="aaaa-mm-dd" v-model="aviso_shown.aviso_fecha_final">
+                                    </div>
+                                </div>
+                            </fieldset>
+
+                        </div>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-outline-danger" data-dismiss="modal">Cancelar</button>
+                        <button type="button" class="btn btn-primary" data-dismiss="modal"
+                            @click="updateAviso(aviso_shown)">Extender</button>
+                    </div>
+                </div>
+            </div>
+        </div>
     </main>
 
     <? include "import/html_footer.php"; ?>
@@ -52,10 +336,16 @@
     <script src="js/jquery.min.js"></script>
     <script src="js/jquery-ui.js"></script>
     <script src="js/bootstrap/bootstrap.min.js"></script>
-    <script src="js/datalist.js"></script>
     <script src="js/datepicker-es.js"></script>
     <script src="js/avisos.js?<?= rand(0, 2) ?>" type="module"></script>
     <script src="js/scrollables.js"></script>
+    <script type="text/javascript" src="https://unpkg.com/trix@2.0.0/dist/trix.umd.min.js"></script>
+    <script>
+        document.addEventListener("trix-file-accept", function (event) {
+            event.preventDefault()
+        })
+    </script>
+
 </body>
 
 </html>

+ 7 - 7
class/c_login.php

@@ -11,9 +11,9 @@ $remainingTime = $endOfDay - $currentTime;
 session_set_cookie_params($remainingTime, '/', $_SERVER['HTTP_HOST'], false, true);
 session_start();
 
-require_once($ruta ?? '') . "include/bd_pdo.php";
-require_once($ruta ?? '') . "class/c_logasistencia.php";
-require_once($ruta ?? '') . "vendor/autoload.php";
+require_once "{$_SERVER['DOCUMENT_ROOT']}/include/bd_pdo.php";
+require_once "{$_SERVER['DOCUMENT_ROOT']}/class/c_logasistencia.php";
+require_once "{$_SERVER['DOCUMENT_ROOT']}/vendor/autoload.php";
 
 /*
 $user->acceso        // Devuelve el tipo de acceso del usuario. Si es administrador, retorna "w". De lo contrario, verifica el tipo de acceso a una página específica y retorna ese valor.
@@ -102,7 +102,7 @@ class Login
     {
         global $db;
 
-        if (!Login::validaUsuario($user, $pass))
+        if (!self::validaUsuario($user, $pass))
             return ['error' => true, 'msg' => 'Error al autenticar usuario'];
 
         if ($db->has("FS_VALIDACLAVEULSA('$user')")) {
@@ -126,16 +126,16 @@ class Login
         session_destroy();
     }
 
-    public static function get_user(): Login
+    public static function get_user(): ?Login
     {
-        if (Login::is_logged()) {
+        if (self::is_logged()) {
             $user = unserialize($_SESSION["user"]);
             return $user;
         }
         header("Location: /");
         exit();
     }
-    private static function is_logged(): bool
+    public static function is_logged(): bool
     {
         return isset($_SESSION["user"]);
     }

+ 3 - 3
include/bd_pdo.php

@@ -1,5 +1,5 @@
 <?php
-require_once ($ruta ?? "./") . "vendor/autoload.php";
+require_once "{$_SERVER['DOCUMENT_ROOT']}/vendor/autoload.php";
 $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
 $dotenv->load();
 use \SeinopSys\PostgresDb;
@@ -40,7 +40,7 @@ function query(string $sql, array $params = null, bool $single = true)
     try {
         $stmt = $pdo->prepare($sql);
         $stmt->execute($params);
-        $response = $single ?  $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC);
+        $response = $single ? $stmt->fetch(PDO::FETCH_ASSOC) : $stmt->fetchAll(PDO::FETCH_ASSOC);
 
         return $response;
     } catch (PDOException $e) {
@@ -60,4 +60,4 @@ function queryAll(string $sql, array $params = null)
 function toSQLArray(array $array): string
 {
     return sprintf("{%s}", implode(", ", $array));
-}
+}

+ 145 - 2
js/avisos.js

@@ -1,5 +1,148 @@
-import { createApp } from 'https://unpkg.com/petite-vue?module';
+import { createApp, reactive } from 'https://unpkg.com/petite-vue?module';
+const new_aviso = reactive({
+    titulo: '',
+    descripcion: '',
+    fechaInicio: '',
+    fechaFin: '',
+    profesores: [],
+    carreras: [],
+    reset() {
+        this.titulo = '';
+        this.descripcion = '';
+        this.fechaInicio = '';
+        this.fechaFin = '';
+        this.profesores = [];
+        this.carreras = [];
+    },
+    get isValid() {
+        return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null;
+    },
+});
+// define datepicker method
 const app = createApp({
-    mounted() {
+    new_aviso,
+    profesores: [],
+    carreras: [],
+    avisos: [],
+    profesor: null,
+    formatProfesor(profesor) {
+        return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}`;
+    },
+    addProfesor() {
+        const profesorObj = this.profesores.find((profesor) => this.profesor === this.formatProfesor(profesor));
+        if (profesorObj) {
+            this.new_aviso.profesores.push(profesorObj);
+            this.profesor = null;
+        }
+    },
+    aviso_shown: null,
+    // int?
+    aviso_suspendido: null,
+    suspenderAviso() {
+        if (this.aviso_suspendido) {
+            const aviso = this.avisos.find((aviso) => aviso.aviso_id === this.aviso_suspendido);
+            if (aviso) {
+                this.deleteAviso(aviso);
+            }
+        }
+    },
+    get relevant_profesores() {
+        // not in array new_aviso.profesores
+        const relevant = this.profesores.filter((profesor) => !this.new_aviso.profesores.map((profesor) => profesor.profesor_id).includes(profesor.profesor_id));
+        // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre))
+        return relevant;
+    },
+    get relevant_carreras() {
+        // not in array new_aviso.carreras
+        return this.carreras.filter((carrera) => !this.new_aviso.carreras.includes(carrera));
+    },
+    createAviso() {
+        const data = {
+            aviso_titulo: this.new_aviso.titulo,
+            aviso_texto: this.new_aviso.descripcion,
+            aviso_fecha_inicial: this.new_aviso.fechaInicio,
+            aviso_fecha_final: this.new_aviso.fechaFin,
+            profesores: this.new_aviso.profesores.map((profesor) => profesor.profesor_id),
+            carreras: this.new_aviso.carreras.map((carrera) => carrera.carrera_id),
+        };
+        fetch('/action/avisos.php', {
+            method: 'POST',
+            body: JSON.stringify(data)
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+                // hydrate with carreras and profesores
+                this.avisos.push({
+                    ...data,
+                    carreras: this.carreras.filter((carrera) => data.carreras.includes(carrera.carrera_id)),
+                    profesores: this.profesores.filter((profesor) => data.profesores.includes(profesor.profesor_id)),
+                    aviso_estado: true,
+                    aviso_id: res.aviso_id,
+                });
+                this.new_aviso.reset();
+            }
+            else {
+                alert(res.error);
+                console.log(res.errors);
+            }
+        });
+    },
+    deleteAviso(aviso) {
+        fetch(`/action/avisos.php`, {
+            method: 'DELETE',
+            body: JSON.stringify({ aviso_id: aviso.aviso_id })
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+                this.avisos = this.avisos.filter((aviso) => aviso.aviso_id !== this.aviso_suspendido);
+                this.aviso_suspendido = null;
+            }
+            else {
+                alert(res.error);
+                console.log(res.errors);
+            }
+        });
+    },
+    updateAviso() {
+        fetch(`/action/avisos.php`, {
+            method: 'PUT',
+            body: JSON.stringify({
+                aviso_id: this.aviso_shown.aviso_id,
+                aviso_fecha_final: this.aviso_shown.aviso_fecha_final,
+            })
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+            }
+            else {
+                alert(res.error);
+                console.log(res.errors);
+            }
+        });
+    },
+    async initializeDatepickers($el) {
+        const periodo = await fetch('action/periodo_datos.php');
+        const periodo_data = await periodo.json();
+        $('.date-picker').datepicker({
+            dateFormat: 'yy-mm-dd',
+            maxDate: periodo_data.periodo_fecha_fin,
+            minDate: 0,
+        });
+        $($el).on('change', () => {
+            this.aviso_shown.aviso_fecha_final = $($el).val();
+        });
+    },
+    async mounted() {
+        this.avisos = await fetch("/action/avisos.php").then(res => res.json());
+        this.profesores = await fetch('/action/action_profesor.php').then(res => res.json());
+        this.carreras = await fetch('/action/action_carreras.php').then(res => res.json());
+        await this.initializeDatepickers();
+        const fechaInicio = $('#fechaInicio.date-picker');
+        const fechaFin = $('#fechaFin.date-picker');
+        fechaInicio.on("change", function () {
+            new_aviso.fechaInicio = fechaInicio.val();
+            fechaFin.datepicker("option", "minDate", fechaInicio.val());
+        });
+        fechaFin.on("change", function () {
+            new_aviso.fechaFin = fechaFin.val();
+            fechaInicio.datepicker("option", "maxDate", fechaFin.val());
+        });
     }
 }).mount('#app');

+ 3 - 0
js/datalist.js

@@ -38,6 +38,7 @@ const setDatalist = (selector, value = -1) => {
         $(selector).val(value);
         $('.datalist li').removeClass("selected");
         $(this).addClass("selected");
+        $(this).click();
     });
 }
 const makeRequiredDatalist = (selector, required = true) => $(selector).closest('.datalist').toggleClass("required", required);
@@ -60,6 +61,7 @@ function setDatalistFirst(selector) {
     }
 }
 
+
 function disableDatalist(selector, disabled = true) {
     var elementRoot = $(selector).parents('.datalist');
     if (disabled) {
@@ -78,6 +80,7 @@ function invalidDatalist(selector, invalid = true) {
         elementRoot.removeClass("datalist-invalid");
 }
 
+//¿Se usa?
 function buscaDatalist(selector, valor) {
     selector.find('ul li').each(function () {
         var elem = $(this);

+ 20 - 26
package-lock.json

@@ -1,18 +1,18 @@
 {
-  "name": "admin_checador (pruebas)",
+  "name": "paad",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "dependencies": {
         "@popperjs/core": "^2.11.7",
+        "@types/jqueryui": "^1.12.18",
         "axios": "^1.4.0",
         "es6-promise": "^4.2.8",
         "moment": "^2.29.4",
         "petite-vue": "^0.4.1"
       },
       "devDependencies": {
-        "@types/bootstrap": "^5.2.6",
         "@types/file-saver": "^2.0.5",
         "@types/jquery": "^3.5.14",
         "@types/node": "^20.2.1"
@@ -27,15 +27,6 @@
         "url": "https://opencollective.com/popperjs"
       }
     },
-    "node_modules/@types/bootstrap": {
-      "version": "5.2.6",
-      "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.6.tgz",
-      "integrity": "sha512-BlAc3YATdasbHoxMoBWODrSF6qwQO/E9X8wVxCCSa6rWjnaZfpkr2N6pUMCY6jj2+wf0muUtLySbvU9etX6YqA==",
-      "dev": true,
-      "dependencies": {
-        "@popperjs/core": "^2.9.2"
-      }
-    },
     "node_modules/@types/file-saver": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
@@ -46,11 +37,18 @@
       "version": "3.5.14",
       "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
       "integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==",
-      "dev": true,
       "dependencies": {
         "@types/sizzle": "*"
       }
     },
+    "node_modules/@types/jqueryui": {
+      "version": "1.12.18",
+      "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.18.tgz",
+      "integrity": "sha512-crlmH8kFzIiU+4aBFgvYUjykSaOTP5RDw7NqkFkcSNWFAF/SMPrr7sY1uNXDEhite/2pEwUoZlufQoy87A22LA==",
+      "dependencies": {
+        "@types/jquery": "*"
+      }
+    },
     "node_modules/@types/node": {
       "version": "20.2.1",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz",
@@ -60,8 +58,7 @@
     "node_modules/@types/sizzle": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
-      "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
-      "dev": true
+      "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ=="
     },
     "node_modules/asynckit": {
       "version": "0.4.0",
@@ -178,15 +175,6 @@
       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
       "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw=="
     },
-    "@types/bootstrap": {
-      "version": "5.2.6",
-      "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.6.tgz",
-      "integrity": "sha512-BlAc3YATdasbHoxMoBWODrSF6qwQO/E9X8wVxCCSa6rWjnaZfpkr2N6pUMCY6jj2+wf0muUtLySbvU9etX6YqA==",
-      "dev": true,
-      "requires": {
-        "@popperjs/core": "^2.9.2"
-      }
-    },
     "@types/file-saver": {
       "version": "2.0.5",
       "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.5.tgz",
@@ -197,11 +185,18 @@
       "version": "3.5.14",
       "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz",
       "integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==",
-      "dev": true,
       "requires": {
         "@types/sizzle": "*"
       }
     },
+    "@types/jqueryui": {
+      "version": "1.12.18",
+      "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.18.tgz",
+      "integrity": "sha512-crlmH8kFzIiU+4aBFgvYUjykSaOTP5RDw7NqkFkcSNWFAF/SMPrr7sY1uNXDEhite/2pEwUoZlufQoy87A22LA==",
+      "requires": {
+        "@types/jquery": "*"
+      }
+    },
     "@types/node": {
       "version": "20.2.1",
       "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.1.tgz",
@@ -211,8 +206,7 @@
     "@types/sizzle": {
       "version": "2.3.3",
       "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
-      "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
-      "dev": true
+      "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ=="
     },
     "asynckit": {
       "version": "0.4.0",

+ 1 - 1
package.json

@@ -1,12 +1,12 @@
 {
   "devDependencies": {
-    "@types/bootstrap": "^5.2.6",
     "@types/file-saver": "^2.0.5",
     "@types/jquery": "^3.5.14",
     "@types/node": "^20.2.1"
   },
   "dependencies": {
     "@popperjs/core": "^2.11.7",
+    "@types/jqueryui": "^1.12.18",
     "axios": "^1.4.0",
     "es6-promise": "^4.2.8",
     "moment": "^2.29.4",

+ 109 - 60
reposiciones_autorizar.php

@@ -1,47 +1,62 @@
 <?php
 
 require_once 'class/c_login.php';
-$user = Login::get_user();
+if (!isset($_SESSION['user'])){
+    die(header('Location: index.php'));
+}
 
+//$user = unserialize($_SESSION['user']);
+$user = Login::get_user();
 
 $user->access();
-//if (!$user->admin && in_array($user->acceso, ['n']))
-    //die(header('Location: main.php?error=1'));
+echo $user;
+/*print_r($user);
+print_r($user->user["id"]);
+echo "****|";
+print_r($user->acceso);//null sin permisos, w o r
+echo "|****|";
+print_r($user->profesor);
+echo "|****|";
+print_r($user->facultad["facultad_id"]);
+exit();*/
+//profesor, admin, rol, facultad
+if ($user->acceso === null && !$user->admin){
+    die(header('Location: index.php'));
+    exit();
+}
+
+$supervisor = false;
+$coordinador = false;
+if($user->rol["rol_id"]==7){
+    $supervisor = true;
+}
+if($user->rol["rol_id"]==9){
+    $coordinador = true;
+}
 
-$user->print_to_log('Reposiciones');
+//$user->print_to_log('Reposiciones');
 //$write = $user->admin || in_array($user->acceso, ['w']);
 $write = true; //
 
 function duracionMinutos($fechahora_i, $fechahora_f){
     return round((strtotime($fechahora_f) - strtotime($fechahora_i)) / 60,2);
 }
-
-if(!empty($user->periodo)){
-    $en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo])['esta_en_periodo'];
-
+if($user->periodo_id!= ""){
+    $en_fecha = $db->querySingle("SELECT ESTA_EN_PERIODO(NOW()::DATE, :periodo_id)", [':periodo_id' => $user->periodo_id])['esta_en_periodo'];
 
     $profesores_rs = array();
     $tab_inicial = 1;
-    if($user->jefe_carrera){
-        $carrera_rs = $db->query('SELECT * FROM fs_usuario_carrera(:usr, NULL)', [':usr'=>$user->user["id"]]);
-        foreach($carrera_rs as $carr){
-            $rs = $db->query('SELECT * FROM fs_profesor_carrera(:carr, :periodo)', [':carr' => $carr['carrera_id'], ':periodo' => $user->periodo]);
-            $profesores_rs = array_merge($profesores_rs, $rs);
-        }
-        
-    }else if($write){// $user->supervisor || $user->admin
-        $profesores_rs = $db->query('SELECT * FROM fs_profesor_carrera(NULL, :periodo)', [':periodo' => $user->periodo]);
-        $tab_inicial = 2;
+    if(!$supervisor){
+        $fac_id = $user->facultad["facultad_id"];
+        $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(:fac, :periodo)', [':fac'=>$fac_id, ':periodo' => $user->periodo_id]);
     }else{
-        die(header('Location: index.php'));
+        $carrera_rs = $db->query('SELECT * FROM fs_profesor_facultad(NULL, :periodo)', [ ':periodo' => $user->periodo_id]);
     }
 
-
     $salones_rs = $db->query('SELECT * FROM salon_view WHERE tiene_salones IS true');
 
-
     //Periodo
-    $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo]);
+    $periodo_rs = $db->querySingle('SELECT periodo_fecha_inicio, periodo_fecha_fin FROM periodo WHERE periodo_id = :periodo_id', [':periodo_id' => $user->periodo_id]);
     $periodo_fin = $periodo_rs["periodo_fecha_fin"];
     if(strtotime($periodo_rs["periodo_fecha_inicio"])>strtotime(date("Y-m-d")) )
         $fecha_man = date("d/m/Y", strtotime($periodo_rs["periodo_fecha_inicio"]));
@@ -73,13 +88,13 @@ if(!empty($user->periodo)){
     $repEdo_rs = $db->query('SELECT * FROM fs_estado_reposicion' );
 
     $repoParams = array();
-    $query = "";//carrera, prof
-    if($user->jefe_carrera){
+    $query = "NULL,";//carrera, prof
+    /*if($user->jefe_carrera){
         $query .= ":jefe, ";
         $repoParams[":jefe"] = $user->user["id"];
     }else{
         $query .= "NULL, ";
-    }
+    }*/
     if((isset($_POST["prof"]) && is_numeric($_POST["prof"])) ){
         $query .= ":prof,";
         $repoParams[":prof"] = filter_input(INPUT_POST, "prof", FILTER_SANITIZE_NUMBER_INT);//limpia texto
@@ -87,8 +102,15 @@ if(!empty($user->periodo)){
         $query .= "NULL,";
     }
     $query .= ":f_ini, :f_fin, :edo, ";
-    $repoParams[":f_ini"] = $fecha_ini;
-    $repoParams[":f_fin"] = $fecha_fin;
+
+
+    $date = DateTime::createFromFormat('d/m/Y', $fecha_ini);
+    $fecha_ini_db = $date->format('Y-m-d');
+
+    $date = DateTime::createFromFormat('d/m/Y', $fecha_fin);
+    $fecha_fin_db = $date->format('Y-m-d');
+    $repoParams[":f_ini"] = $fecha_ini_db;
+    $repoParams[":f_fin"] = $fecha_fin_db;
     $repoParams[":edo"] = 1;//se sobreescribe
 }
 ?>
@@ -101,24 +123,26 @@ if(!empty($user->periodo)){
     <meta charset="utf-8">
     <meta http-equiv="content-type" content="text/plain; charset=UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <?php include_once "import/html_css_files.php"; ?>
-    <link rel="stylesheet" href="css/jquery-ui.css">
-    <link rel="stylesheet" href="css/richtext.css" type="text/css">
-    <link rel="stylesheet" href="css/clockpicker.css">
-    <link rel="stylesheet" href="css/calendar.css">
-    <link rel="stylesheet" href="css/fa_all.css" type="text/css">
+    <?php
+    include 'import/html_css_files.php';
+    ?>
 
     <script src="js/scrollables.js" defer></script>
     <script>
         const write = <?= $write ? 'true' : 'false' ?>;
     </script>
-    <script src="js/moment.js" defer></script>
     <style>
         .wizard { height: 20px; width: 80%; background: #D0D0D0; }
         .wizard.full { background: #D0D0D0; }
         .wizard.active > div:first-child { background: #00A6CE;  }
         .wizard.active > div:last-child { width: 0px; height: 0px; border-style: solid; border-width: 10px 0 10px 6px; border-color: transparent transparent transparent #00a6ce; transform: rotate(0deg); }
     </style>
+    <script src="js/jquery.min.js"></script>
+    <script src="js/bootstrap/popper.min.js"></script>
+    <script src="js/bootstrap/bootstrap.min.js"></script>
+    <script src="js/jquery-ui.js"></script>
+    <script src="js/datepicker-es.js"></script>
+    <script src="js/messages.js"></script>
 
 
 </head>
@@ -136,7 +160,7 @@ if(!empty($user->periodo)){
         <section id="message"></section>
         <?php require('import/periodo.php') ?>
         
-        <?php if(!empty($user->periodo)){ ?>
+        <?php if($user->periodo_id!= ""){  ?>
         <form id="asistencia" method="post" onsubmit="return validaFechas()">
             <div class="form-box">
                 <input type="hidden" name="facultad" value="5">
@@ -191,10 +215,10 @@ if(!empty($user->periodo)){
                 <a class="nav-link" id="tab1-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="calendario" aria-selected="true">Nuevas reposiciones</a>
             </li>
             <li class="nav-item">
-                <a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="lista" aria-selected="false">Aprobadas por jefe</a>
+                <a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="lista" aria-selected="false">Aprobadas por Facultad</a>
             </li>
             <li class="nav-item">
-                <a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="lista" aria-selected="false">Autorizadas</a>
+                <a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="lista" aria-selected="false">Autorizadas por Vicerrectoría</a>
             </li>
             <li class="nav-item">
                 <a class="nav-link" id="tab4-tab" data-toggle="tab" href="#tab4" role="tab" aria-controls="lista" aria-selected="false">Rechazadas</a>
@@ -208,6 +232,7 @@ if(!empty($user->periodo)){
                 <?php
                 $repoParams[":edo"]=$redo["estado_reposicion_id"];
                 $reposiciones_rs = $db->query('SELECT * FROM fs_reposicion(NULL, '.$query.'0, NULL) ', $repoParams );
+                
                 ?>
                 
                 <h4 class="mb-4" <?php echo "style='color:".$redo["estado_color"]."'>".$redo["estado_nombre"]; ?> </h4>
@@ -229,7 +254,7 @@ if(!empty($user->periodo)){
                     if(isset($reposiciones_rs)){
                         foreach($reposiciones_rs as $reposicion){
                         ?>
-                        <tr data-id="<?php echo $reposicion["reposicion_id"]; ?>" data-edo="<?php echo $reposicion["estado_reposicion_id"];?>" id="id<?php echo $reposicion["reposicion_id"]; ?>">
+                        <tr data-id="<?php echo $reposicion["reposicion_solicitud_id"]; ?>" data-edo="<?php echo $reposicion["estado_reposicion_id"];?>" id="id<?php echo $reposicion["reposicion_solicitud_id"]; ?>">
                             <td class="align-middle">
                                 <?php if($reposicion["estado_reposicion_id"]<3){ ?>
                                 <div class="wizard <?php if(intval($reposicion["estado_reposicion_id"])==2) echo "active";?> d-flex mx-auto">
@@ -298,11 +323,12 @@ if(!empty($user->periodo)){
                                 <?php
                                     if($reposicion["estado_reposicion_id"]<4){
                                         if(
-                                            (($user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] <= 2)
-                                            || ((!$user->jefe_carrera || $user->admin) && $reposicion["estado_reposicion_id"] >= 2 )){
+                                            (($user->jefe_carrera || $user->admin || $coordinador) && $reposicion["estado_reposicion_id"] == 1)/* nueva */
+                                            || (($user->admin || $coordinador || $supervisor) && $reposicion["estado_reposicion_id"] == 2)/* aprobado facultad */
+                                        ){
                                 ?>
                                 <a href="#" data-toggle="modal" data-target="#modal_confirm" title="Cancelar"><span class="text-danger"><?php echo $ICO["cancelar"];?></span></a>
-                                <?php }
+                                <?php   }
                                     } //estado
                                 ?>
                             </td>
@@ -351,6 +377,18 @@ if(!empty($user->periodo)){
                                     <p class="rep-mat"></p>
                                 </div>
                             </div>
+                            <div class="row">
+                                <div class="col-6 col-sm-4 barra-right text-right">
+                                    <p class="font-weight-bold">Ciclo y bloque</p>
+                                </div>
+                                <div class="col-3">
+                                    <p><strong>Ciclo:</strong><span class="rep-ciclo ml-3"></span></p>
+                                </div>
+                                <div class="col-3">
+                                    <p><strong>Bloque:</strong><span class="rep-bloque ml-3"></span></p>
+                                </div>
+                            </div>
+                            
                             <div class="row">
                                 <div class="col-6 col-sm-4 barra-right text-right">
                                     <p class="font-weight-bold">Tipo</p>
@@ -438,6 +476,14 @@ if(!empty($user->periodo)){
                                 </div>
                             </div>
                             
+                            <div class="row mt-4" id="cancelada-block">
+                                <div class="col-6 col-sm-4 barra-right text-right">
+                                    <p class="font-weight-bold text-danger">Motivo de cancelación</p>
+                                </div>
+                                <div class="col-6 bg-light">
+                                    <p class="rep-motivo"></p>
+                                </div>
+                            </div>
 
                             <div class="form-group row mt-3">
                                 <div class="col-12 text-center">
@@ -495,12 +541,7 @@ if(!empty($user->periodo)){
         ?>
     </main>
 </body>
-<script src="js/jquery.min.js"></script>
-<script src="js/bootstrap/popper.min.js"></script>
-<script src="js/bootstrap/bootstrap.min.js"></script>
-<script src="js/jquery-ui.js"></script>
-<script src="js/datepicker-es.js"></script>
-<script src="js/messages.js"></script>
+
     <?php
     //--Manejo de errores y mensajes de exito
     if(isset($_GET["error"]) && is_numeric($_GET["error"])){
@@ -537,11 +578,6 @@ if(!empty($user->periodo)){
     var _periodo_fecha_final = "<?php echo date("d/m/Y", strtotime($periodo_rs["periodo_fecha_fin"])); ?>";
     var datepickerOptions = { dateFormat: "dd/mm/yy", minDate:_periodo_fecha_inicial, maxDate:_periodo_fecha_final };
 
-    $(document).ready(function(){
-        $(".date-picker-filtro" ).datepicker(datepickerOptions);
-        $(".date-picker-filtro" ).datepicker( $.datepicker.regional[ "es" ] );
-        $('#tab<?php echo $tab_inicial;?>-tab').tab('show');
-    });
 
     function valida(){
         <?php
@@ -556,7 +592,10 @@ if(!empty($user->periodo)){
     }
     
     $(document).ready(function(){
-        
+        $(".date-picker-filtro" ).datepicker(datepickerOptions);
+        $(".date-picker-filtro" ).datepicker( $.datepicker.regional[ "es" ] );
+        $('#tab<?php echo $tab_inicial;?>-tab').tab('show');
+
         $('#modal_confirm').on('show.bs.modal', function (event) {
             var button = $(event.relatedTarget); // Button that triggered the modal
             var id = button.parents("tr").data("id");
@@ -566,10 +605,11 @@ if(!empty($user->periodo)){
 
         $('#modal_aprobar').on('show.bs.modal', function (event) {
             var button = $(event.relatedTarget); // Button that triggered the modal
-            //console.log(button.data("tipo"));
+            console.log("Abre:"+button.data("tipo"));
             var id = button.parents("tr").data("id");
             var edo = button.data('tipo');
 
+            //1 ver, 2 aprobar, 3 autorizar
             $("#edo").val(edo);
             $("#id").val(id);
             
@@ -587,7 +627,9 @@ if(!empty($user->periodo)){
                     }else{
 
                         $("#modal_aprobar .rep-prof").text(result["profesor_nombre"]);
-                        $("#modal_aprobar .rep-mat").text(result["materia_desc"]+" ["+result["grupo"]+"]" );
+                        $("#modal_aprobar .rep-mat").text(result["materia_desc"]);
+                        $("#modal_aprobar .rep-ciclo").text(result["ciclo"]);
+                        $("#modal_aprobar .rep-bloque").text(result["bloque"]);
                         if(result["tipo"])
                             $("#modal_aprobar .rep-tipo").text("Reposición");
                         else
@@ -605,14 +647,21 @@ if(!empty($user->periodo)){
                         $("#modal_aprobar .rep-comentarios").text(result["comentario"]);
                         $('#modal_aprobar .rep-alumnos').text(result["alumnos"]);
 
-                        if(button.data("tipo") == 1){//ver
+                        if(result["estado"] == 4){//cancelada
+                            $('#modal_aprobar .rep-motivo').text(result["motivo_cancelacion"]);
+                            $("#cancelada-block").show();
+                        }else{
+                            $("#cancelada-block").hide();
+                        }
+
+                        if(edo == 1){// 1  ver
                             $("#modalLabel").text("Detalle de reposición");
                             $(".aprobar-block").hide();
                             $("#salon-ver").show();
                             $("#salon-editar").hide();
                             
                         }else{
-                            if(parseInt($("#modal_aprobar .rep-aula").data("aula")) == 1){//ver
+                            if(parseInt($("#modal_aprobar .rep-aula").data("aula")) == 1){//tipo aula 1 (salon normal)  - ver
                                 $("#modalLabel").text("Detalle de reposición");
                                 $(".aprobar-block").hide();
                                 $("#salon-ver").show();
@@ -620,7 +669,7 @@ if(!empty($user->periodo)){
                             }else{
                                 $("#modalLabel").text("Aprobar reposición");
                                 $(".aprobar-block").show();
-                                if(button.data("tipo") == 3){//aprobar (con salón)
+                                if(edo == 3){//aprobar (con salón)
                                     $("#salon-ver").hide();
                                     $("#salon-editar").show();
                                     
@@ -629,13 +678,13 @@ if(!empty($user->periodo)){
                         }
 
                         if(result["aula_supervisor"]){//Solo supervisor
-                            <?php if($user->supervisor){ ?>
+                            <?php if($supervisor){ ?>
                                 $("#salon-editar").attr("disabled", false);
                             <?php }else{?>
                                 $("#salon-editar").attr("disabled", true);
                             <?php } ?>
                         }else{// Facultad
-                            <?php if(!$user->supervisor){ ?>
+                            <?php if(!$supervisor){ ?>
                                 $("#salon-editar").attr("disabled", false);
                             <?php }else{?>
                                 $("#salon-editar").attr("disabled", true);

+ 14 - 10
reposiciones_crear.php

@@ -19,10 +19,10 @@ echo "|****|";
 print_r($user->facultad["facultad_id"]);
 exit();*/
 //profesor, admin, rol, facultad
-/*if ($user->acceso === null || !$user->admin){
-    die(header('Location: index.php'));
+if ($user->acceso === null && !$user->admin){
+    //die(header('Location: index.php'));
     exit();
-}*/
+}
 
 
 //if (!$user->admin && in_array($user->acceso, ['n']))
@@ -161,7 +161,7 @@ $fecha_fin_db = $date->format('Y-m-d');
         <?php
         
         $reposiciones_rs = $db->query('SELECT * FROM fs_reposiciones_solicitud(:f_ini, :f_fin, :usr ,NULL, NULL)', [':f_ini' => $fecha_ini_db, ':f_fin' => $fecha_fin_db, ':usr' => $user->user["id"]]);
-        echo "SELECT * FROM fs_reposiciones_solicitud('$fecha_ini_db', '$fecha_fin_db', ".$user->user["id"]." ,NULL, NULL)".date("Y-m-d",strtotime($fecha_fin));
+        
         ?>
 
         <div class="row">
@@ -755,6 +755,7 @@ $fecha_fin_db = $date->format('Y-m-d');
                 type: 'POST', 
                 dataType: 'json',
                 data: { id: pid, },
+                async: false,
                 success: function(result) {
                     if(result["error"]!= "" &&  result["error"] !== undefined){
                         triggerMessage(result["error"], "Error");
@@ -813,6 +814,7 @@ $fecha_fin_db = $date->format('Y-m-d');
                                 $(this).prop('selected', true);
                             }
                         });
+                        console.log("fin materia click");
                     }
 
                 },
@@ -870,8 +872,6 @@ $fecha_fin_db = $date->format('Y-m-d');
             $("#modal .is-invalid").removeClass("is-invalid");
             //$(this).find(".form-control:first-child").focus();
             
-           
-
 
             $("#errorBox").collapse('hide');
             $("#errorBox_text").html("");
@@ -903,6 +903,7 @@ $fecha_fin_db = $date->format('Y-m-d');
                 //$("#materia").attr("readonly", true);
                 disableDatalist("#horario");
                 disableDatalist("#tipo");
+                disableDatalist("#prof");
                 /*if($("#prof").length>0)
                     disableDatalist("#prof");
                 $("#prof").attr("readonly", true);*/
@@ -919,14 +920,16 @@ $fecha_fin_db = $date->format('Y-m-d');
                             $("#modal").modal('hide');
                         }else{
                             //setDatalist("#prof", result["profesor"]);
-                            $('#salon').val(result["salon"]);
+                            setDatalist("#prof", result["profesor"])
+                            //$('#salon').val(result["salon"]);
                             $("#fecha_falta").val(result["fecha_clase"]);
                             $('#hora_ini').val(result["hora_ini"]);
                             $('#min_ini').val(result["min_ini"]);
                             $('#comentario').val(result["comentario"]);
                             $('#alumnos').val(result["alumnos"]);
-                            setDatalist("#horario", result["horario"]);
-                            setDatalist("#profesor", result["profesor"]);
+                            $('#ciclo').val(result["ciclo"]);
+                            $('#bloque').val(result["bloque"]);
+                            
                             if(result["tipo"]){
                                 setDatalist("#tipo", 1);
                                 cambiaTipo(1);
@@ -939,6 +942,8 @@ $fecha_fin_db = $date->format('Y-m-d');
                             _dia_valido = parseInt(result["dia"]);
                             $(".date-picker" ).datepicker(datepickerOptions);
                             $("#dlTipo ul li:selected").click();
+                            console.log("llega a cambio horario"+result["horario"]);
+                            setTimeout(setDatalist("#horario", result["horario"]), 20);// No se actualiza TODO
                             setDatalist("#aula", result["aula"]);
                             modal.modal('show');
                         }
@@ -950,7 +955,6 @@ $fecha_fin_db = $date->format('Y-m-d');
                     }
                 });//ajax
             }
-            
         });//show
         
     });

+ 202 - 1
ts/avisos.ts

@@ -1,6 +1,207 @@
 import { createApp, reactive } from 'https://unpkg.com/petite-vue?module'
 
+type Profesor = {
+    profesor_clave: string;
+    profesor_correo: null | string;
+    profesor_grado: null | string;
+    profesor_id: number;
+    profesor_nombre: string;
+}
+
+type Carrera = {
+    carrera_activa: boolean;
+    carrera_comun: boolean;
+    carrera_id: number;
+    carrera_nombre: string;
+    clave_carrera: string;
+    facultad_id: number | null;
+    nivel_id: number;
+}
+
+type Periodo = {
+    created_at: Date;
+    estado_id: number;
+    fecha_final: Date;
+    id_periodo_sgu: number;
+    nivel_id: number;
+    periodo_clave: string;
+    periodo_fecha_fin: Date;
+    periodo_fecha_inicio: Date;
+    periodo_id: number;
+    periodo_nombre: string;
+}
+
+type Aviso = {
+    aviso_estado: boolean;
+    aviso_titulo: string;
+    aviso_fecha_final: Date;
+    aviso_fecha_inicial: Date;
+    aviso_id: number;
+    aviso_texto: string;
+    carreras: Carrera[];
+    facultad_id: null;
+    profesores: Profesor[];
+}
+
+const new_aviso = reactive({
+    titulo: '',
+    descripcion: '',
+    fechaInicio: '',
+    fechaFin: '',
+    profesores: [] as Array<Profesor>,
+    carreras: [] as Array<Carrera>,
+    reset() {
+        this.titulo = ''
+        this.descripcion = ''
+        this.fechaInicio = ''
+        this.fechaFin = ''
+        this.profesores = []
+        this.carreras = []
+    },
+    get isValid() {
+        return this.titulo !== '' && this.descripcion !== '' && this.fechaInicio !== '' && this.fechaFin !== '' && (this.profesores.length > 0 || this.carreras.length > 0) && this.facultad_id !== null
+    },
+})
+// define datepicker method
+
 const app = createApp({
-    mounted() {
+    new_aviso,
+    profesores: [] as Array<Profesor>,
+    carreras: [] as Array<Carrera>,
+    avisos: [] as Array<Aviso>,
+
+    profesor: null as String | null,
+    formatProfesor(profesor: Profesor) {
+        return `(${profesor.profesor_clave}) ${profesor.profesor_nombre}`
+    },
+    addProfesor() {
+        const profesorObj = this.profesores.find((profesor: Profesor) => this.profesor === this.formatProfesor(profesor))
+        if (profesorObj) {
+            this.new_aviso.profesores.push(profesorObj)
+            this.profesor = null
+        }
+    },
+
+    aviso_shown: null as Aviso | null,
+    // int?
+    aviso_suspendido: null as number | null,
+    suspenderAviso() {
+        if (this.aviso_suspendido) {
+            const aviso = this.avisos.find((aviso: Aviso) => aviso.aviso_id === this.aviso_suspendido)
+            if (aviso) {
+                this.deleteAviso(aviso)
+            }
+        }
+    },
+
+    get relevant_profesores() {
+        // not in array new_aviso.profesores
+        const relevant = this.profesores.filter((profesor: Profesor) => !this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id).includes(profesor.profesor_id))
+        // console.log('profesores:', this.profesores.map((profesor: Profesor) => profesor.profesor_nombre), 'relevant:', relevant.map((profesor: Profesor) => profesor.profesor_nombre), 'new_aviso:', this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_nombre))
+        return relevant
+    },
+
+    get relevant_carreras() {
+        // not in array new_aviso.carreras
+        return this.carreras.filter((carrera: Carrera) => !this.new_aviso.carreras.includes(carrera))
+    },
+
+    createAviso() {
+        const data = {
+            aviso_titulo: this.new_aviso.titulo,
+            aviso_texto: this.new_aviso.descripcion,
+            aviso_fecha_inicial: this.new_aviso.fechaInicio,
+            aviso_fecha_final: this.new_aviso.fechaFin,
+            profesores: this.new_aviso.profesores.map((profesor: Profesor) => profesor.profesor_id),
+            carreras: this.new_aviso.carreras.map((carrera: Carrera) => carrera.carrera_id),
+        }
+        fetch('/action/avisos.php', {
+            method: 'POST',
+            body: JSON.stringify(data)
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+                // hydrate with carreras and profesores
+                this.avisos.push({
+                    ...data,
+                    carreras: this.carreras.filter((carrera: Carrera) => data.carreras.includes(carrera.carrera_id)),
+                    profesores: this.profesores.filter((profesor: Profesor) => data.profesores.includes(profesor.profesor_id)),
+                    aviso_estado: true,
+                    aviso_id: res.aviso_id,
+                })
+                this.new_aviso.reset()
+            }
+            else {
+                alert(res.error)
+                console.log(res.errors)
+            }
+        })
+    },
+
+    deleteAviso(aviso: Aviso) {
+        fetch(`/action/avisos.php`, {
+            method: 'DELETE',
+            body: JSON.stringify({ aviso_id: aviso.aviso_id })
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+                this.avisos = this.avisos.filter((aviso: Aviso) => aviso.aviso_id !== this.aviso_suspendido)
+                this.aviso_suspendido = null
+            }
+            else {
+                alert(res.error)
+                console.log(res.errors)
+            }
+        })
+    },
+
+    updateAviso() {
+        fetch(`/action/avisos.php`, {
+            method: 'PUT',
+            body: JSON.stringify({
+                aviso_id: this.aviso_shown.aviso_id,
+                aviso_fecha_final: this.aviso_shown.aviso_fecha_final,
+            })
+        }).then(res => res.json()).then(res => {
+            if (res.success) {
+            }
+            else {
+                alert(res.error)
+                console.log(res.errors)
+            }
+        })
+    },
+
+    async initializeDatepickers($el: HTMLElement) {
+        const periodo = await fetch('action/periodo_datos.php');
+        const periodo_data = await periodo.json() as Periodo;
+
+        $('.date-picker').datepicker({
+            dateFormat: 'yy-mm-dd',
+            maxDate: periodo_data.periodo_fecha_fin,
+            minDate: 0,
+        });
+
+        $($el).on('change', () => {
+            this.aviso_shown.aviso_fecha_final = $($el).val() as string;
+        });
+    },
+
+    async mounted() {
+        this.avisos = await fetch("/action/avisos.php").then(res => res.json()) as Array<Aviso>
+        this.profesores = await fetch('/action/action_profesor.php').then(res => res.json()) as Array<Profesor>
+        this.carreras = await fetch('/action/action_carreras.php').then(res => res.json()) as Array<Carrera>
+
+        await this.initializeDatepickers()
+
+        const fechaInicio = $('#fechaInicio.date-picker')
+        const fechaFin = $('#fechaFin.date-picker')
+        fechaInicio.on("change", function () {
+            new_aviso.fechaInicio = fechaInicio.val() as string
+            fechaFin.datepicker("option", "minDate", fechaInicio.val());
+        });
+
+        fechaFin.on("change", function () {
+            new_aviso.fechaFin = fechaFin.val() as string
+            fechaInicio.datepicker("option", "maxDate", fechaFin.val());
+        });
     }
 }).mount('#app')

+ 1 - 1
ts/declaration.ts

@@ -1 +1 @@
-declare module 'https://*'
+declare module 'https://*'

+ 1 - 1
tsconfig.json

@@ -8,7 +8,7 @@
         "rootDir": "ts",
         "target": "ES2022",
         "moduleResolution": "node",
-        "module": "ESNext"
+        "module": "ESNext",
         // ts/auditoría.ts:1:37 - error TS2307: Cannot find module 'https://unpkg.com/petite-vue?module' or its corresponding type declarations.
     }
 }