Added new tab search in groups
parent
e90316161c
commit
70c6ea59b1
|
@ -56,7 +56,7 @@ import { DeleteGroupsModalComponent } from './components/groups/delete-groups-mo
|
|||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { ToastrModule } from 'ngx-toastr';
|
||||
import { ShowOrganizationalUnitComponent } from './components/groups/organizational-units/show-organizational-unit/show-organizational-unit.component';
|
||||
import { MatGridList } from "@angular/material/grid-list";
|
||||
import {MatGridList, MatGridTile} from "@angular/material/grid-list";
|
||||
import { TreeViewComponent } from './components/groups/tree-view/tree-view.component';
|
||||
import {
|
||||
MatNestedTreeNode,
|
||||
|
@ -68,6 +68,7 @@ import {
|
|||
} from "@angular/material/tree";
|
||||
import { LegendComponent } from './components/groups/legend/legend.component';
|
||||
import { ClassroomViewDialogComponent } from './components/groups/classroom-view/classroom-view-modal';
|
||||
import {MatPaginator} from "@angular/material/paginator";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -132,7 +133,7 @@ import { ClassroomViewDialogComponent } from './components/groups/classroom-view
|
|||
progressAnimation: 'increasing',
|
||||
closeButton: true
|
||||
}
|
||||
), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet
|
||||
), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet, MatPaginator, MatGridTile
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import {HttpClient, HttpParams} from '@angular/common/http';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import { UnidadOrganizativa } from './model';
|
||||
|
@ -10,7 +10,7 @@ import { UnidadOrganizativa } from './model';
|
|||
export class DataService {
|
||||
|
||||
private apiUrl = 'http://127.0.0.1:8080/organizational-units?page=1&itemsPerPage=1000';
|
||||
private clientsUrl = 'http://127.0.0.1:8080/clients?page=1&itemsPerPage=30';
|
||||
private clientsUrl = 'http://127.0.0.1:8080/clients?page=1&itemsPerPage=1000';
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
|
@ -107,5 +107,36 @@ export class DataService {
|
|||
);
|
||||
}
|
||||
|
||||
getFilteredResults(filter1: string, filter2: string, filterName: string, page: number, pageSize: number): Observable<any> {
|
||||
let params = new HttpParams();
|
||||
|
||||
if (filter2 && filter2 !== 'none') {
|
||||
params = params.set('type', filter2);
|
||||
}
|
||||
if (filterName) {
|
||||
params = params.set('name', filterName);
|
||||
}
|
||||
|
||||
params = params.set('page', page.toString());
|
||||
params = params.set('itemsPerPage', pageSize.toString());
|
||||
|
||||
const url = filter1 === 'client' ? this.clientsUrl : this.apiUrl;
|
||||
|
||||
return this.http.get<any>(url, { params }).pipe(
|
||||
map(response => {
|
||||
if (response['hydra:member'] && Array.isArray(response['hydra:member'])) {
|
||||
return {
|
||||
results: response['hydra:member'],
|
||||
total: response['hydra:totalItems'] || response['hydra:member'].length
|
||||
};
|
||||
} else {
|
||||
throw new Error('Unexpected response format');
|
||||
}
|
||||
}),
|
||||
catchError(error => {
|
||||
console.error('Error fetching data', error);
|
||||
return throwError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,3 +131,68 @@ mat-spinner {
|
|||
.roomMap-btn {
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.header mat-form-field {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.filters {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.saved-filter {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 300px;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.results {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.results-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
height: 250px; /* Fijo para mantener la forma cuadrada */
|
||||
}
|
||||
|
||||
.paginator-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
mat-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
<div class="header-container">
|
||||
<h2 class="title">Administrar grupos</h2>
|
||||
<div class="groups-button-row">
|
||||
<button mat-flat-button color="primary" (click)="addOU($event)">Nueva Unidad Organizativa</button>
|
||||
<button mat-flat-button color="primary" (click)="addClient($event)">Nuevo Cliente</button>
|
||||
<button mat-raised-button (click)="openBottomSheet()">Leyenda</button>
|
||||
|
||||
|
||||
</div>
|
||||
<div class="container">
|
||||
<button mat-flat-button class="roomMap-btn" color="accent" (click)="roomMap()" *ngIf="selectedDetail && selectedDetail.type === 'classroom'">Plano de aula</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Búsqueda</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>Pulsar 'enter' para buscar entre las unidades organizativas</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="groupLists-container">
|
||||
<mat-card class="card unidad-card">
|
||||
<mat-card-title>Unidad organizativa</mat-card-title>
|
||||
<mat-card-content>
|
||||
<mat-spinner *ngIf="loading"></mat-spinner>
|
||||
<mat-list *ngIf="!loading">
|
||||
<mat-list-item *ngFor="let unidad of organizationalUnits"
|
||||
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
|
||||
<div class="item-content">
|
||||
<mat-icon>apartment</mat-icon>
|
||||
{{ unidad.name }}
|
||||
<span class="actions">
|
||||
<mat-tab-group>
|
||||
<mat-tab label="General">
|
||||
<div class="header-container">
|
||||
<h2 class="title">Administrar grupos</h2>
|
||||
<div class="groups-button-row">
|
||||
<button mat-flat-button color="primary" (click)="addOU($event)">Nueva Unidad Organizativa</button>
|
||||
<button mat-flat-button color="primary" (click)="addClient($event)">Nuevo Cliente</button>
|
||||
<button mat-raised-button (click)="openBottomSheet()">Leyenda</button>
|
||||
</div>
|
||||
<div class="container">
|
||||
<button mat-flat-button class="roomMap-btn" color="accent" (click)="roomMap()" *ngIf="selectedDetail && selectedDetail.type === 'classroom'">Plano de aula</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-container">
|
||||
<mat-form-field appearance="fill">
|
||||
<mat-label>Búsqueda</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint>Pulsar 'enter' para buscar entre las unidades organizativas</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="groupLists-container">
|
||||
<mat-card class="card unidad-card">
|
||||
<mat-card-title>Unidad organizativa</mat-card-title>
|
||||
<mat-card-content>
|
||||
<mat-spinner *ngIf="loading"></mat-spinner>
|
||||
<mat-list *ngIf="!loading">
|
||||
<mat-list-item *ngFor="let unidad of organizationalUnits"
|
||||
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
|
||||
<div class="item-content">
|
||||
<mat-icon>apartment</mat-icon>
|
||||
{{ unidad.name }}
|
||||
<span class="actions">
|
||||
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="onTreeClick($event, unidad)">
|
||||
|
@ -80,43 +80,42 @@
|
|||
</button>
|
||||
</mat-menu>
|
||||
</span>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="card elements-card">
|
||||
<mat-card-title>
|
||||
<div class="title-with-breadcrumb">
|
||||
<span>Elementos internos</span>
|
||||
<mat-card-subtitle>
|
||||
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
|
||||
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
|
||||
<span *ngIf="i < breadcrumb.length - 1"> > </span>
|
||||
</ng-container>
|
||||
</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<mat-card class="card elements-card">
|
||||
<mat-card-title>
|
||||
<div class="title-with-breadcrumb">
|
||||
<span>Elementos internos</span>
|
||||
<mat-card-subtitle>
|
||||
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
|
||||
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
|
||||
<span *ngIf="i < breadcrumb.length - 1"> > </span>
|
||||
</ng-container>
|
||||
</mat-card-subtitle>
|
||||
</div>
|
||||
</mat-card-title>
|
||||
<mat-card-content class="element-content">
|
||||
<mat-spinner *ngIf="loadingChildren"></mat-spinner>
|
||||
<mat-list *ngIf="!loadingChildren">
|
||||
<div *ngIf="children.length === 0" class="empty-list">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>No hay elementos internos</span>
|
||||
</div>
|
||||
<mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)">
|
||||
<div class="item-content">
|
||||
<mat-icon [ngSwitch]="child.type">
|
||||
<ng-container *ngSwitchCase="'organizational-unit'">apartment</ng-container>
|
||||
<ng-container *ngSwitchCase="'classrooms-group'">meeting_room</ng-container>
|
||||
<ng-container *ngSwitchCase="'classroom'">school</ng-container>
|
||||
<ng-container *ngSwitchCase="'client'">computer</ng-container>
|
||||
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container>
|
||||
<ng-container *ngSwitchDefault>help_outline</ng-container>
|
||||
</mat-icon>
|
||||
{{child.name}}
|
||||
<span class="actions">
|
||||
</mat-card-title>
|
||||
<mat-card-content class="element-content">
|
||||
<mat-spinner *ngIf="loadingChildren"></mat-spinner>
|
||||
<mat-list *ngIf="!loadingChildren">
|
||||
<div *ngIf="children.length === 0" class="empty-list">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>No hay elementos internos</span>
|
||||
</div>
|
||||
<mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)">
|
||||
<div class="item-content">
|
||||
<mat-icon [ngSwitch]="child.type">
|
||||
<ng-container *ngSwitchCase="'organizational-unit'">apartment</ng-container>
|
||||
<ng-container *ngSwitchCase="'classrooms-group'">meeting_room</ng-container>
|
||||
<ng-container *ngSwitchCase="'classroom'">school</ng-container>
|
||||
<ng-container *ngSwitchCase="'client'">computer</ng-container>
|
||||
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container>
|
||||
<ng-container *ngSwitchDefault>help_outline</ng-container>
|
||||
</mat-icon>
|
||||
{{child.name}}
|
||||
<span class="actions">
|
||||
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)">
|
||||
|
@ -141,11 +140,89 @@
|
|||
</button>
|
||||
</mat-menu>
|
||||
</span>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<!-- <app-classroom-view class="card classroom-view" [clients]="clientsData" [pcInTable]="5"></app-classroom-view> -->
|
||||
</div>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<!-- <app-classroom-view class="card classroom-view" [clients]="clientsData" [pcInTable]="5"></app-classroom-view> -->
|
||||
</div>
|
||||
</mat-tab>
|
||||
<mat-tab label="Búsqueda avanzada">
|
||||
<h2 class="title">Búsqueda</h2>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<mat-form-field>
|
||||
<mat-label>Seleccione filtro</mat-label>
|
||||
<mat-select (selectionChange)="loadSelectedFilter($event.value)">
|
||||
<mat-option *ngFor="let savedFilter of savedFilters" [value]="savedFilter">
|
||||
{{ savedFilter.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider class="divider"></mat-divider>
|
||||
<div class="main-content">
|
||||
<div class="filters">
|
||||
<mat-form-field>
|
||||
<mat-label>Selecciona una opción</mat-label>
|
||||
<mat-select [(value)]="selectedFilter1" (selectionChange)="applyFilter()">
|
||||
<mat-option value="ou">Unidades organizativas</mat-option>
|
||||
<mat-option value="client">Clientes</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput placeholder="Unidad organizativa" (input)="applyFilter()" [(ngModel)]="filterName" >
|
||||
</mat-form-field>
|
||||
<mat-form-field disabled="selectedFilter1 === 'ou'">
|
||||
<mat-label>Tipo de unidad </mat-label>
|
||||
<mat-select [(value)]="selectedFilter2" (selectionChange)="applyFilter()">
|
||||
<mat-option value="organizational-unit">Unidad organizativa</mat-option>
|
||||
<mat-option value="classroom-group">Grupos de aulas</mat-option>
|
||||
<mat-option value="classroom">Aulas</mat-option>
|
||||
<mat-option value="client-group">Grupos de clientes</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Select an option</mat-label>
|
||||
<mat-select [(value)]="selectedFilter1" (selectionChange)="applyFilter()">
|
||||
<mat-option value="none">None</mat-option>
|
||||
<mat-option value="option1">Option 1</mat-option>
|
||||
<mat-option value="option2">Option 2</mat-option>
|
||||
<mat-option value="option3">Option 3</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button mat-raised-button color="primary" (click)="saveFilters()">Guardar Filtros</button>
|
||||
</div>
|
||||
<div class="results">
|
||||
<ng-container *ngIf="filteredResults && filteredResults.length > 0; else noResults">
|
||||
<mat-grid-list cols="4" rowHeight="1:1">
|
||||
<mat-grid-tile *ngFor="let result of filteredResults" >
|
||||
<mat-card class="result-card">
|
||||
<mat-card-title>{{ result.name }}</mat-card-title>
|
||||
<mat-card-content>
|
||||
<p>{{ result.type }}</p>
|
||||
<p *ngIf="result.type !== 'client'">Unidades internas: {{ result.type !== 'client' ? result.children.length : 0}}</p>
|
||||
<p *ngIf="result.type !== 'client'">Clientes: {{ result.type !== 'client' ? result.clients.length : 0}}</p>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
<div class="paginator-container">
|
||||
<mat-paginator [length]="length"
|
||||
[pageSize]="itemsPerPage"
|
||||
[pageIndex]="page"
|
||||
[pageSizeOptions]="pageSizeOptions"
|
||||
(page)="onPageChange($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #noResults>
|
||||
<p>No hay resultados para mostrar.</p>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
|
|
|
@ -15,6 +15,9 @@ import {MatBottomSheet} from "@angular/material/bottom-sheet";
|
|||
import {LegendComponent} from "./legend/legend.component";
|
||||
import { ClassroomViewComponent } from './classroom-view/classroom-view.component';
|
||||
import { ClassroomViewDialogComponent } from './classroom-view/classroom-view-modal';
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {Observable} from "rxjs";
|
||||
import {PageEvent} from "@angular/material/paginator";
|
||||
|
||||
@Component({
|
||||
selector: 'app-groups',
|
||||
|
@ -32,11 +35,22 @@ export class GroupsComponent implements OnInit {
|
|||
loading:boolean = false;
|
||||
loadingChildren:boolean = false;
|
||||
searchTerm: string = '';
|
||||
constructor(
|
||||
selectedFilter1: string = 'none';
|
||||
selectedFilter2: string = 'none';
|
||||
filterName: string = '';
|
||||
filteredResults: any[] = [];
|
||||
savedFilters: any[] = [];
|
||||
length: number = 0;
|
||||
itemsPerPage: number = 10;
|
||||
page: number = 1;
|
||||
pageSizeOptions: number[] = [5, 10, 25, 100];
|
||||
|
||||
constructor(
|
||||
private dataService: DataService,
|
||||
public dialog: MatDialog,
|
||||
private toastService: ToastrService,
|
||||
private _bottomSheet: MatBottomSheet
|
||||
private _bottomSheet: MatBottomSheet,
|
||||
private http: HttpClient
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -267,4 +281,35 @@ constructor(
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
applyFilter() {
|
||||
this.dataService.getFilteredResults(this.selectedFilter1, this.selectedFilter2, this.filterName, this.page, this.itemsPerPage)
|
||||
.subscribe(
|
||||
response => {
|
||||
this.filteredResults = response.results;
|
||||
this.length = response.total;
|
||||
},
|
||||
error => {
|
||||
console.error('Error al obtener los resultados filtrados', error);
|
||||
this.filteredResults = [];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onPageChange(event: PageEvent) {
|
||||
this.page = event.pageIndex;
|
||||
this.itemsPerPage = event.pageSize;
|
||||
this.applyFilter();
|
||||
}
|
||||
saveFilters() {
|
||||
const filters = {
|
||||
name: `Filter ${new Date().toISOString()}`,
|
||||
filter1: this.selectedFilter1,
|
||||
filter2: this.selectedFilter2
|
||||
};
|
||||
}
|
||||
|
||||
loadSelectedFilter(savedFilter: any) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue