فهرست منبع

Merge branch 'devAldrick' of ITTEC/PlataformaEducativaWeb2 into develop

AldrickChavarria 1 هفته پیش
والد
کامیت
f64d3052ea

+ 11 - 3
Back/backendP-Educativa/app/Http/Controllers/Api/TareasController.php

@@ -27,15 +27,23 @@ class TareasController extends Controller
     public function getAllTareas()
     {
         try {
-            $tareas = DB::table('tareas as t')
+            $tareas = DB::table('tareas_usuarios_colegioabc as tu')
+                ->join('tareas as t', 'tu.idTarea', '=', 't.idTarea')
                 ->join('materias as m', 't.idMateriaTarea', '=', 'm.idMateria')
                 ->join('tareas_tipos as tt', 't.idTipoTarea', '=', 'tt.idTareasTipos')
+                ->join('usuarios as u', 't.idUsuario', '=', 'u.idUsuario')
                 ->select(
+                    'u.primerNombre',
+                    'u.segundoNombre',
+                    'u.apellidoPaterno',
+                    'u.apellidoMaterno',
+                    'u.alias',
                     'm.nombreMateria as materia',
                     'tt.nombreTareasTipos as tipo_tarea',
-                    't.*'
+                    't.*', // todos los campos de tareas
+                    'tu.idUsuario as usuario_asignado', // opcional, por si quieres saber a qué usuario está asignada
+                    'tu.completa'
                 )
-                ->distinct()
                 ->orderBy('t.fechaPublicacion', 'desc')
                 ->get();
 

+ 7 - 5
Front/src/app/modules/Administrador/admin-routing.module.ts

@@ -22,6 +22,7 @@ import { AdminFormComponent } from './pages/admin-form/admin-form.component';
 import { FormSelectorComponent } from './pages/admin-form/form-selector/form-selector.component';
 import { DynamicFormComponentComponent } from './pages/admin-form/dynamic-form-component/dynamic-form-component.component';
 import { PeriodosComponent } from './pages/periodos/periodos.component';
+import { TareasComponent } from './pages/tareas/tareas.component';
 
 
 const routes: Routes = [
@@ -44,20 +45,21 @@ const routes: Routes = [
             { path: 'alumnos-padres', component: AlumnosPadresComponent },
             { path: 'profesores-materias', component: ProfesorMateriasComponent },
             { path: 'tipoTarea', component: TiposTareasComponent },
+            { path: 'tareas', component: TareasComponent },
             { path: 'periodos', component: PeriodosComponent },
 
             { path: 'personalizar', component: PersonalizarComponent },
-            {path:'seguimiento', component: SeguimientoComponent},
+            { path: 'seguimiento', component: SeguimientoComponent },
 
             //módulo adminitración escolar
             { path: 'circulares', component: CircularesComponent },
-            {path: 'formularios', component: AdminFormComponent},
-            {path: 'verFormulario', component: FormSelectorComponent},
-            {path: 'visualizarForm/:id', component: DynamicFormComponentComponent},
+            { path: 'formularios', component: AdminFormComponent },
+            { path: 'verFormulario', component: FormSelectorComponent },
+            { path: 'visualizarForm/:id', component: DynamicFormComponentComponent },
 
 
 
-            {path:'consularRegistro', component : ConsultarRegistroAcayAdmiComponent},
+            { path: 'consularRegistro', component: ConsultarRegistroAcayAdmiComponent },
             { path: '', redirectTo: 'main', pathMatch: 'full' },
             { path: '**', redirectTo: '404' },
 

+ 2 - 0
Front/src/app/modules/Administrador/administrador.module.ts

@@ -37,6 +37,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
 import { DynamicFormComponentComponent } from './pages/admin-form/dynamic-form-component/dynamic-form-component.component';
 import { FormSelectorComponent } from './pages/admin-form/form-selector/form-selector.component';
 import { PeriodosComponent } from './pages/periodos/periodos.component';
+import { TareasComponent } from './pages/tareas/tareas.component';
 
 
 @NgModule({
@@ -94,6 +95,7 @@ import { PeriodosComponent } from './pages/periodos/periodos.component';
     DynamicFormComponentComponent,
     FormSelectorComponent,
     PeriodosComponent,
+    TareasComponent,
 
   ],
   imports: [

+ 3 - 2
Front/src/app/modules/Administrador/components/cards/cards.component.ts

@@ -64,11 +64,12 @@ export class CardsComponent implements OnInit {
   public cardsModulos = [
     { title: 'Tipos de Tareas', icono: 'Tipo_Tarea', url: 'tipoTarea' },
     { title: 'Gestión de Periodos', icono: 'Tipo_Tarea', url: 'periodos' },
+    { title: 'Visualizar Tareas', icono: 'Tipo_Tarea', url: 'tareas' },
   ];
   public cardsPersonalizar = [
     { title: 'Personalizar', icono: 'personalizar', url: 'personalizar' },
-    {title : 'Formularios', icono:'Materia', url : 'formularios' },
-  {title : 'Publicar Formulario', icono:'Materia', url : 'verFormulario' }
+    { title: 'Formularios', icono: 'Materia', url: 'formularios' },
+    { title: 'Publicar Formulario', icono: 'Materia', url: 'verFormulario' }
 
   ];
   public variable1: string = "";

+ 13 - 0
Front/src/app/modules/Administrador/pages/tareas/modalTarea.component.html

@@ -0,0 +1,13 @@
+<div style="display: flex; justify-content: space-between; padding-left: 20px; padding-right: 20px; padding-top: 20;">
+    <h2 mat-dialog-title>{{data.titulo}}</h2>
+    <mat-icon class="cursor-pointer" mat-dialog-close style="margin-top: 20px;">close</mat-icon>
+</div>
+<mat-dialog-content class="mat-typography" style="min-width: 300px;">
+    <div [innerHTML]="data.contenido"></div>
+
+</mat-dialog-content>
+<div style="width: 100; display: flex; align-items: center; justify-content: center; margin-bottom: 20px;">
+    <button class="red" mat-dialog-close style="display: flex; align-items: center; justify-content: center;">
+        Cerrar <mat-icon class="icon" matSuffix>cancel</mat-icon>
+    </button>
+</div>

+ 354 - 0
Front/src/app/modules/Administrador/pages/tareas/tareas.component.css

@@ -0,0 +1,354 @@
+.centrar {
+    margin-top: 4%;
+    line-height: auto;
+    text-align: center;
+}
+
+.cerrar-b {
+  background-color: #fff;
+  border: none;
+}
+
+.fondo {
+    border-radius: 10px;
+    line-height: 1;
+    display: inline-block;
+    vertical-align: middle;
+}
+
+.content {
+    margin-bottom: 0;
+    margin-top: 0;
+    padding-top: 10px;
+    padding-bottom: 10px;
+    padding-left: 70px;
+    padding-right: 70px;
+    font-weight: 500;
+    font-size: 32px;
+    color: white;
+    font-family: "Serenity Medium";
+}
+
+.form-container {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr); /* 4 columnas iguales */
+  gap: 10px; /* espacio entre columnas y filas */
+}
+
+.item {
+  box-sizing: border-box;
+  padding: 10px;
+}
+
+.item.two-columns {
+  grid-column: span 2;
+}
+
+.w-responsive {
+    width: 160px;
+}
+
+.input {
+    width: 500px;
+    color: rgb(0, 140, 255);
+}
+
+.file-input {
+  display: none;
+}
+
+.btnDelete {
+  display: flex;              
+  align-items: center;        
+  justify-content: center;
+  cursor: pointer;
+  border: none;
+  background-color: transparent;
+  height: 30px;
+  width: 30px;
+  color: #ccc;
+  border-radius: 5px;
+  padding: 0;
+}
+
+
+.btnDelete:hover {
+  color: #dd131a;
+  background-color: #f7e3e4;
+}
+
+.container-col {
+    display: flex;
+    flex-direction: column;
+    padding-top: 100px;
+    padding-left: 30px;
+    padding-right: 65px;
+    width: 100%;
+    box-sizing: border-box;
+}
+
+.yellow {
+    border: none;
+    border-radius: 5px;
+    padding: 5px 15px;
+    font-size: 1rem;
+    color: white;
+    margin-left: 10px;
+    background-color: #ebac3f;
+}
+
+.yellow:hover {
+    background-color: #be8b32;
+
+}
+
+.orange {
+    border: none;
+    border-radius: 5px;
+    padding: 5px 15px;
+    font-size: 1rem;
+    color: white;
+    margin-left: 10px;
+    background-color: #f56227;
+
+}
+
+.orange:hover {
+    background-color: #d15321;
+
+}
+
+.red {
+    border: none;
+    border-radius: 5px;
+    padding: 5px 15px;
+    font-size: 1rem;
+    color: white;
+    margin-left: 10px;
+    background-color: red;
+
+}
+
+.red:hover {
+    background-color: rgb(177, 0, 0);
+
+}
+
+.action-edit {
+    margin-left: 5px;
+    background-color: #1d156e;
+    color: white;
+    height: 30px;
+    width: 30px;
+}
+
+.action-delete {
+    margin-left: 5px;
+    background-color: #e43b3d;
+    color: white;
+    height: 30px;
+    width: 30px;
+}
+
+.inline {
+    display: flex;
+    align-items: center;
+    color: red;
+    cursor: pointer;
+}
+
+.icon {
+    transform: scale(0.8);
+    vertical-align: middle;
+}
+
+.check-icon:hover {
+    color: #2a6c42;
+}
+
+.green {
+    background-color: #2a6c42;
+    border: none;
+    color: white !important;
+    cursor: pointer;
+    border-radius: 6px;
+    height: 35px;
+}
+
+.green:hover {
+    background-color: #205232;
+}
+
+.buttons {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    margin-bottom: 15px;
+    padding-left: 20px;
+}
+
+.badge-active {
+    color: #026AA2;
+    font-weight: 500;
+    padding: 3px 7px;
+    background-color: #E0F2FE;
+    border-radius: 15px;
+}
+
+.badge-inactive {
+    color: #AC2722;
+    font-weight: 500;
+    padding: 3px 7px;
+    background-color: #FEE4E2;
+    border-radius: 15px;
+}
+
+/* --------------- Table and responsive styles ---------------- */
+.table-container {
+    width: 100%;
+    overflow: auto;
+}
+
+.table-responsive {
+
+    overflow: auto;
+}
+
+/* --------------- Special button styles for Circulares ---------------- */
+.btn-grande {
+    display: inline-flex;
+    align-items: center;
+    background-color: rgb(184, 221, 247);
+    border-radius: 4px;
+    padding: 0 12px;
+    height: 36px;
+}
+
+.btn-movil {
+    display: none;
+    background: none;
+    border: none;
+    padding: 0;
+    margin: 0;
+}
+
+/* --------------- Modal and form styles ---------------- */
+.close {
+    padding-top: 20px;
+    padding-right: 20px;
+    display: flex;
+    justify-content: end;
+}
+
+.center {
+    text-align: center;
+    font-size: 32px;
+    font-weight: 600;
+}
+
+.responsive {
+    display: flex;
+    flex-direction: row;
+}
+
+.align {
+    margin-top: 30px;
+    display: flex;
+    justify-content: center;
+}
+
+/* --------------- Media Queries ---------------- */
+@media only screen and (max-width: 600px) {
+    .centrar {
+        margin-top: 8%;
+    }
+
+    .fondo {
+        width: 90%;
+    }
+
+    .content {
+        font-size: 24px;
+        padding: 10px 20px;
+    }
+
+    .container-col {
+        padding-top: 50px;
+        padding-left: 15px;
+        padding-right: 15px;
+    }
+
+    .input {
+        width: 100%;
+    }
+
+    .container-search {
+        flex-direction: column;
+    }
+
+    .buttons {
+        flex-direction: column;
+        align-items: stretch;
+        gap: 10px;
+        padding-left: 0;
+    }
+
+    .table-container {
+        width: 100%;
+    }
+
+    /* Special mobile styles for Circulares buttons */
+    .btn-grande {
+        display: none;
+    }
+
+    .btn-movil {
+        display: inline-flex;
+    }
+
+    .btn-movil img {
+        width: 24px;
+        height: 24px;
+    }
+
+    /* Adjust action buttons container */
+    .flex-row.items-center {
+        justify-content: center;
+    }
+}
+
+@media (max-width: 768px) {
+    .w-responsive {
+        width: 100%;
+    }
+
+    .content {
+        font-size: 22px;
+        padding: 10px 15px;
+    }
+
+    .item {
+        flex: 1 0 100%;
+    }
+
+    .table-responsive {
+
+        overflow-x: auto;
+    }
+
+    /* Ensure table cells have proper spacing */
+    .mat-cell,
+    .mat-header-cell {
+        padding: 4px 8px;
+    }
+
+    /* Adjust column widths for mobile */
+    .mat-column-acciones {
+        min-width: 80px;
+    }
+
+    .mat-column-adjuntos {
+        min-width: 100px;
+    }
+}

+ 153 - 0
Front/src/app/modules/Administrador/pages/tareas/tareas.component.html

@@ -0,0 +1,153 @@
+<div class="centrar fadeIn">
+    <div class="fondo" [style.background-color]="color">
+        <p class="content" [style.color]="textColor">Tareas</p>
+    </div>
+</div>
+
+<div class="container-col fadeIn">
+    <div class="flex-row container-search">
+        <div class="">
+            <mat-form-field class="input">
+                <input class="input" (keyup)="applyFilter($event)" matInput placeholder="Buscar" #input>
+                <mat-icon matSuffix>search</mat-icon>
+            </mat-form-field>
+            <mat-form-field style="width: 200px; margin-left: 20px; margin-right: 20px; margin-top: 5px;">
+                <mat-label>Filtrar por:</mat-label>
+                <mat-select (selectionChange)="onFiltroChange($event.value)">
+                    <mat-option value="FE">Fecha de entrega</mat-option>
+                    <mat-option value="FA">Fecha de asignación</mat-option>
+                    <mat-option value="MAT">Materia</mat-option>
+                </mat-select>
+            </mat-form-field>
+
+            <!-- Si se elige "Fecha de entrega" o "Fecha de asignación" -->
+            <mat-form-field *ngIf="filtroSeleccionado === 'FE' || filtroSeleccionado === 'FA'" class="input"
+                style="width: 200px; margin-left: 20px; margin-right: 20px; margin-top: 5px;">
+                <mat-label>Seleccionar fecha</mat-label>
+                <input matInput [matDatepicker]="picker" (dateChange)="onFechaSeleccionada($event)">
+                <mat-datepicker-toggle matIconSuffix [for]="picker"></mat-datepicker-toggle>
+                <mat-datepicker #picker></mat-datepicker>
+            </mat-form-field>
+
+            <!-- Si se elige "Materia" -->
+            <mat-form-field *ngIf="filtroSeleccionado === 'MAT'"
+                style="width: 200px; margin-left: 20px; margin-right: 20px; margin-top: 5px;">
+                <mat-label>Seleccionar materia</mat-label>
+                <mat-select (selectionChange)="onMateriaSeleccionada($event.value)">
+                    <mat-option *ngFor="let materia of materias" [value]="materia.idMateria">
+                        {{ materia.nombreMateria }}
+                    </mat-option>
+                </mat-select>
+            </mat-form-field>
+        </div>
+
+    </div>
+    <div class="table-container mat-elevation-z8">
+        <div class="table-responsive" #TABLE>
+            <table mat-table [dataSource]="dataSource" #table class="mat-elevation-z8">
+
+                <ng-container matColumnDef="materia">
+                    <th mat-header-cell *matHeaderCellDef> Materia</th>
+                    <td mat-cell *matCellDef="let tarea"> {{tarea.materia}}</td>
+                </ng-container>
+
+                <ng-container matColumnDef="titulo">
+                    <th mat-header-cell *matHeaderCellDef> Título </th>
+                    <td mat-cell *matCellDef="let tarea"> {{tarea.tituloTarea}} </td>
+                </ng-container>
+
+
+                <ng-container matColumnDef="tipoTarea">
+                    <th mat-header-cell *matHeaderCellDef> Tipo de Tarea </th>
+                    <td mat-cell *matCellDef="let tarea"> {{tarea.tipo_tarea}} </td>
+                </ng-container>
+
+                <ng-container matColumnDef="fechaPub">
+                    <th mat-header-cell *matHeaderCellDef> Fecha de Asignación </th>
+                    <td mat-cell *matCellDef="let tarea"> {{tarea.fechaPublicacion| date: 'dd/MM/yyyy hh:mm:ss'}}
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="fechaEntrega">
+                    <th mat-header-cell *matHeaderCellDef> Fecha de Entrega </th>
+                    <td mat-cell *matCellDef="let tarea"> {{tarea.fechaEntrega| date: 'dd/MM/yyyy hh:mm:ss'}}
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="enlaces">
+                    <th mat-header-cell *matHeaderCellDef style="text-align: center;"> Vinculos </th>
+                    <td mat-cell *matCellDef="let tarea" style="text-align: center;">
+                        <button *ngIf="tarea.vinculoTareaArray.length>0" mat-button [matMenuTriggerFor]="menuVin"
+                            class="btn-grande" style="background-color: rgb(184, 221, 247);">Vinculos <mat-icon
+                                matSuffix>keyboard_arrow_down</mat-icon></button>
+                        <button *ngIf="tarea.vinculoTareaArray.length>0" mat-button [matMenuTriggerFor]="menuVin"
+                            class="btn-movil">
+                            <img src="../../../../../assets/icons/carpeta.png" alt="icono carpeta" width="30"
+                                height="30">
+                        </button>
+                        <span *ngIf="tarea.vinculoTareaArray.length==0">No aplica</span>
+                        <mat-menu #menuVin="matMenu">
+                            <button mat-menu-item *ngFor="let option of tarea.vinculoTareaArray"
+                                (click)="buscarArchivo(option.url)">
+                                <span style="font-size: 13px;">
+                                    {{ option.nombre }}
+                                </span>
+                            </button>
+                        </mat-menu>
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="adjuntos">
+                    <th mat-header-cell *matHeaderCellDef style="text-align: center;"> Adjuntos </th>
+                    <td mat-cell *matCellDef="let tarea" style="text-align: center;">
+                        <button *ngIf="tarea.adjuntoTarea.length>0" mat-button [matMenuTriggerFor]="menuAd"
+                            class="btn-grande" style="background-color: rgb(184, 221, 247);">Adjuntos <mat-icon
+                                matSuffix>keyboard_arrow_down</mat-icon></button>
+                        <button *ngIf="tarea.adjuntoTarea.length>0" mat-button [matMenuTriggerFor]="menuAd"
+                            class="btn-movil">
+                            <img src="../../../../../assets/icons/carpeta.png" alt="icono carpeta" width="30"
+                                height="30">
+                        </button>
+                        <span *ngIf="tarea.adjuntoTarea.length==0">No aplica</span>
+                        <mat-menu #menuAd="matMenu">
+                            <button mat-menu-item *ngFor="let option of tarea.adjuntoTarea"
+                                (click)="buscarArchivo(option.ruta)">
+                                <span style="font-size: 13px;">
+                                    {{ option.nombre }}
+                                </span>
+                            </button>
+                        </mat-menu>
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="asignado_por">
+                    <th mat-header-cell *matHeaderCellDef> Asignado Por</th>
+                    <td mat-cell *matCellDef="let tarea"> {{ tarea.alias ? tarea.alias : tarea.primerNombre+ ' ' +
+                        tarea.apellidoPaterno + ' ' + tarea.apellidoMaterno}}
+                    </td>
+                </ng-container>
+
+                <ng-container matColumnDef="acciones">
+                    <th mat-header-cell *matHeaderCellDef> Acciones</th>
+                    <td mat-cell *matCellDef="let tarea">
+                        <div class="flex-row items-center">
+                            <button mat-menu-item (click)="openDialog(tarea)" style="width: fit-content;">
+                                <mat-icon>preview</mat-icon>
+                                <span>Visualizar</span>
+                            </button>
+
+                        </div>
+                    </td>
+                </ng-container>
+
+                <tr mat-header-row *matHeaderRowDef="columnas"></tr>
+                <tr mat-row *matRowDef="let row; columns: columnas;"></tr>
+                <tr class="mat-row" *matNoDataRow>
+                    <td class="mat-cell" colspan="7">No hay resultados para "{{input.value}}"</td>
+                </tr>
+            </table>
+            <mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
+        </div>
+        <mat-paginator [pageSizeOptions]="[5, 10, 15]" showFirstLastButtons class="mat-elevation-z8"></mat-paginator>
+    </div>
+</div>

+ 318 - 0
Front/src/app/modules/Administrador/pages/tareas/tareas.component.ts

@@ -0,0 +1,318 @@
+import { Component, ElementRef, Inject, ViewChild } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { MatPaginator, MatPaginatorIntl } from '@angular/material/paginator';
+import { MatTableDataSource } from '@angular/material/table';
+import { CircularService } from '../../../Administrador/services/circular.service';
+import { MatIconModule, MatIconRegistry } from '@angular/material/icon';
+import { DomSanitizer } from '@angular/platform-browser';
+import { EnviarInfoService } from '../../../Administrador/services/enviar-info.service';
+import { MAT_DIALOG_DATA, MatDialog, MatDialogActions, MatDialogClose, MatDialogContent } from '@angular/material/dialog';
+import { ModalTarea } from '../../../Profesor/pages/tareas/tareas.component';
+
+import * as XLSX from 'xlsx';
+
+import { MAT_DATE_LOCALE, provideNativeDateAdapter } from '@angular/material/core';
+import Swal from 'sweetalert2';
+import { TareasService } from '../../../Alumno/services/tareas.service';
+
+@Component({
+  selector: 'app-tareas',
+  templateUrl: './tareas.component.html',
+  styleUrl: './tareas.component.css',
+  providers: [provideNativeDateAdapter(),
+  { provide: MAT_DATE_LOCALE, useValue: 'en-GB' }
+  ]
+})
+export class TareasComponent {
+  public checked = false;
+  public isLoading: boolean = true;
+  public searchInput = new FormControl('');
+  public color: string = '';
+  public textColor: string = '';
+  public columnas: string[] = ['titulo', 'materia', 'tipoTarea', 'fechaPub', 'fechaEntrega', 'enlaces', 'adjuntos', 'asignado_por', 'acciones'];
+  public dataSource = new MatTableDataSource<any>();
+  private userData = JSON.parse(localStorage.getItem('userData') || '[]');
+  private userDataS = JSON.parse(localStorage.getItem('userDataS') || '[]');
+  @ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
+  @ViewChild('TABLE') table!: ElementRef;
+
+  constructor(
+    private circularService: CircularService,
+    private sanitizer: DomSanitizer,
+    private tareasService: TareasService,
+    private _MatIconRegister: MatIconRegistry,
+    private _DomSanitizer: DomSanitizer,
+    private paginatorIntl: MatPaginatorIntl,
+    private _enviarInfo: EnviarInfoService,
+    public dialog: MatDialog
+  ) {
+    this._MatIconRegister.addSvgIcon('excel', this._DomSanitizer.bypassSecurityTrustResourceUrl('assets/icons/excel.svg'));
+    //paginador de tabla a español
+    const spanishRangeLabel = (page: number, pageSize: number, length: number): string => {
+      if (length === 0 || pageSize === 0) {
+        return `0 de ${length}`;
+      }
+      length = Math.max(length, 0);
+      const startIndex = page * pageSize;
+      const endIndex = startIndex < length ?
+        Math.min(startIndex + pageSize, length) :
+        startIndex + pageSize;
+      return `${startIndex + 1} - ${endIndex} de ${length}`;
+    };
+    this.paginatorIntl.nextPageLabel = "Siguiente";
+    this.paginatorIntl.previousPageLabel = "Anterior";
+    this.paginatorIntl.firstPageLabel = "Ir a la primer página";
+    this.paginatorIntl.lastPageLabel = "Ir a la última página";
+    this.paginatorIntl.itemsPerPageLabel = "Registros por página";
+    this.paginatorIntl.getRangeLabel = spanishRangeLabel;
+  }
+
+  ngOnInit(): void {
+    this._enviarInfo.currentTextColor.subscribe(textColor => {
+      this.textColor = textColor;
+    });
+    this._enviarInfo.currentColor.subscribe(color => {
+      this.color = color;
+    });
+
+    //suscribirse al subject que manda al servicio
+    this._enviarInfo.tabla$.subscribe(() => {
+      this.getTareas();
+    });
+
+    this.getTareas()
+
+  }
+
+  openDialog(circular: any) {
+    this.dialog.open(TareaAlumComponent, {
+      data: { titulo: circular.tituloTarea, contenido: this.sanitizer.bypassSecurityTrustHtml(circular.descripcionTarea) }
+    });
+  }
+
+  completarTarea(idTarea: any) {
+    const data = {
+      idTarea: idTarea,
+      idUsuario: this.userDataS[0] ? this.userDataS[0] : this.userData[0]
+    };
+
+    Swal.fire({
+      title: '¿Quieres cambiar el estado de la tarea?',
+      text: 'Se marcará o desmarcará como completada.',
+      icon: 'question',
+      showCancelButton: true,
+      confirmButtonText: 'Sí, cambiar estado',
+      cancelButtonText: 'Cancelar',
+      confirmButtonColor: '#3085d6',
+      cancelButtonColor: '#d33'
+    }).then((result) => {
+      if (result.isConfirmed) {
+        this.tareasService.completarTarea(data).subscribe({
+          next: (response: any) => {
+            Swal.fire({
+              title: '¡Hecho!',
+              text: response.mensaje,
+              icon: 'success',
+              timer: 1500,
+              showConfirmButton: false
+            });
+            this.getTareas(); // Actualiza la lista
+          },
+          error: (err) => {
+            Swal.fire({
+              title: 'Error',
+              text: 'No se pudo cambiar el estado de la tarea.',
+              icon: 'error'
+            });
+          }
+        });
+      }
+    });
+  }
+
+  public allInfo: any;
+  public files: any;
+  public urls: any = [];
+  //Traer la información y mostrarla en la tabla
+  getTareas() {
+    this.tareasService.getAllTareas().subscribe((response: any) => {
+      this.isLoading = false;
+
+      this.allInfo = response.map((tarea: any) => {
+        // separar los vinculos en un arreglo de objetos con nombre
+        if (tarea.vinculoTarea) {
+          tarea.vinculoTareaArray = tarea.vinculoTarea.split("||").map((url: string, index: number) => {
+            return { nombre: url, url: url };
+          });
+        } else {
+          tarea.vinculoTareaArray = [];
+        }
+
+        if (tarea.adjuntoTarea) {
+          tarea.adjuntoTarea = JSON.parse(tarea.adjuntoTarea);
+        } else {
+          tarea.adjuntoTarea = [];
+        }
+
+        return tarea;
+      });
+
+
+      this.dataSource = new MatTableDataSource<any>(this.allInfo);
+      this.dataSource.paginator = this.paginator;
+    });
+  }
+
+  buscarArchivo(ruta: string) {
+    // console.log("🚀 ~ TareasComponent ~ buscarArchivo ~ ruta:", ruta)
+    window.open(ruta, '_blank');
+  }
+
+  //filtro de búsqueda
+  applyFilter(event: Event) {
+    const filterValue = (event.target as HTMLInputElement).value;
+    this.dataSource.filter = filterValue.trim().toLowerCase();
+  }
+
+  filtroSeleccionado: string = '';
+  materias: any[] = [];
+  fechaSeleccionada: Date | null = null;
+  materiaSeleccionada: any = null;
+
+  onFiltroChange(valor: string): void {
+    // Actualiza el filtro seleccionado
+    this.filtroSeleccionado = valor;
+
+    // Limpia valores previos
+    this.fechaSeleccionada = null;
+    this.materiaSeleccionada = null;
+
+    // Limpia tabla (opcional)
+    this.dataSource.data = this.allInfo;
+
+    // Si se selecciona MAT, carga materias recientes
+    if (valor === 'MAT') {
+      this.cargarMaterias();
+    }
+  }
+
+  cargarMaterias(): void {
+    const userId = this.userDataS[0] ? this.userDataS[0] : this.userData[0];
+
+    this.tareasService.getMaterias30Dias(userId).subscribe(
+      (response: any) => {
+        this.materias = response;
+        console.log('Materias de últimos 30 días:', this.materias);
+      },
+      (error) => {
+        console.error('Error al cargar materias:', error);
+        this.materias = []; // fallback
+      }
+    );
+  }
+
+  onFechaSeleccionada(event: any): void {
+
+    this.fechaSeleccionada = event.value;
+    if (!this.fechaSeleccionada) return;
+    const fechaFormateada = this.formatFecha(this.fechaSeleccionada);
+    console.log('📅 Fecha seleccionada:', fechaFormateada);
+
+    if (!this.filtroSeleccionado) return;
+
+    // Mostrar loader
+    this.isLoading = true;
+
+    // Llamar al servicio correspondiente
+    if (this.filtroSeleccionado === 'FE') {
+      // Fecha de entrega
+      this.tareasService.getByFechaEntrega(fechaFormateada, this.userDataS[0] ? this.userDataS[0] : this.userData[0]).subscribe((response: any) => {
+        this.actualizarTabla(response);
+      });
+    } else if (this.filtroSeleccionado === 'FA') {
+      // Fecha de asignación
+      this.tareasService.getByFechaAsignacion(fechaFormateada, this.userDataS[0] ? this.userDataS[0] : this.userData[0]).subscribe((response: any) => {
+        this.actualizarTabla(response);
+      });
+    }
+  }
+
+  onMateriaSeleccionada(idMateria: any): void {
+    this.materiaSeleccionada = idMateria;
+    console.log('📘 Materia seleccionada:', idMateria);
+
+    if (!idMateria) return;
+
+    this.isLoading = true;
+    this.tareasService.getByMateria(idMateria).subscribe((response: any) => {
+      this.actualizarTabla(response);
+    });
+  }
+
+  private actualizarTabla(response: any): void {
+    this.isLoading = false;
+
+    this.dataSource = new MatTableDataSource<any>(
+      response.map((tarea: any) => {
+        tarea.vinculoTareaArray = tarea.vinculoTarea
+          ? tarea.vinculoTarea.split("||").map((url: string) => ({ nombre: url, url }))
+          : [];
+        tarea.adjuntoTarea = tarea.adjuntoTarea ? JSON.parse(tarea.adjuntoTarea) : [];
+        return tarea;
+      })
+    );
+    this.dataSource.paginator = this.paginator;
+  }
+
+  private formatFecha(fecha: Date): string {
+    // Devuelve formato YYYY-MM-DD
+    const year = fecha.getFullYear();
+    const month = String(fecha.getMonth() + 1).padStart(2, '0');
+    const day = String(fecha.getDate()).padStart(2, '0');
+    return `${year}-${month}-${day}`;
+  }
+
+
+
+
+  // openDialog1(id: string) {
+  //   const dialogRef = this.dialog.open(ModalCircular, {
+  //     autoFocus: false
+  //   });
+
+
+  //   dialogRef.componentInstance.setData(id);
+  // }
+
+
+
+  // openDialogEdit(circular: any) {
+  //   console.log("🚀 ~ CircularesComponent ~ openDialogEdit ~ circular:", circular)
+  //   const dialogRef = this.dialog.open(ModalCircularesEdit, {
+  //     autoFocus: false,
+  //     data: circular
+  //   });
+
+  //   dialogRef.componentInstance.circularActualizada.subscribe(() => {
+  //     this.getCirculares();
+  //   });
+
+
+  // }
+
+
+
+
+}
+
+@Component({
+  selector: 'App-circularAlumno-component',
+  templateUrl: './modalTarea.component.html',
+  styleUrls: ['./tareas.component.css'],
+  standalone: true,
+  imports: [MatIconModule, MatDialogContent, MatDialogActions, MatDialogClose]
+})
+export class TareaAlumComponent {
+  constructor(@Inject(MAT_DIALOG_DATA) public data: any) {
+  }
+}

+ 2 - 2
Front/src/app/modules/Alumno/pages/tareas/tareas.component.ts

@@ -174,8 +174,8 @@ export class TareasComponent {
   }
 
   buscarArchivo(ruta: string) {
-    console.log("🚀 ~ TareasComponent ~ buscarArchivo ~ ruta:", ruta)
-    // window.open(ruta, '_blank');
+    // console.log("🚀 ~ TareasComponent ~ buscarArchivo ~ ruta:", ruta)
+    window.open(ruta, '_blank');
   }
 
   //filtro de búsqueda

+ 4 - 0
Front/src/app/modules/Alumno/services/tareas.service.ts

@@ -23,6 +23,10 @@ export class TareasService {
     return this.http.get(`${this.URL}/tareas/usuario/${idAlumno}`, { headers: this.getHeaders() });
   }
 
+  getAllTareas() {
+    return this.http.get(`${this.URL}/getAllTareas`, { headers: this.getHeaders() });
+  }
+
   getByFechaEntrega(fechaEntrega: string, idUsuario: string) {
     return this.http.get(`${this.URL}/tareas/fecha-entrega/${fechaEntrega}/${idUsuario}`, { headers: this.getHeaders() });
   }

+ 1 - 1
Front/src/environments/environments.ts

@@ -1,6 +1,6 @@
 export const environments = {
     // baseUrl:'http://192.168.200.2:8000/api'
     // baseUrl:'http://127.0.0.1:8000/api'
-    baseUrl:'https://dv.plataforma-educativa.com.mx/back/public/api'
+    baseUrl:'https://qa.plataforma-educativa.com.mx/back/public/api'
 
 }