Переглянути джерело

subo el módulo de organigrama funcional

SalemRoman 4 місяців тому
батько
коміт
fc38872b38

+ 2 - 0
src/app/app.module.ts

@@ -426,10 +426,12 @@ import { SelectColorComponent } from './components/system-admin/system-params/se
 import { GridIconsSelectorComponent } from './components/system-admin/system-params/grid-icons-selector/grid-icons-selector.component';
 import { OrganizationComponent } from './components/personal-management/organization/organization.component';
 import { EditOrganizationComponent } from './components/personal-management/organization/edit-organization/edit-organization.component';
+import { BlockUserComponent } from './components/personal-management/organization/block-user/block-user.component';
 /*FIN Componentes SAM*/
 
 @NgModule({
   declarations: [
+    BlockUserComponent,
     EditOrganizationComponent,
     OrganizationComponent,
     AppComponent,

+ 3 - 0
src/app/components/personal-management/organization/block-user/block-user.component.css

@@ -0,0 +1,3 @@
+:host {
+  display: block;
+}

+ 22 - 0
src/app/components/personal-management/organization/block-user/block-user.component.html

@@ -0,0 +1,22 @@
+<h1 mat-dialog-title class="prevent-select" style="text-align: center; margin-top: 15px;">
+    Bloquear Usuario
+</h1>
+
+<div mat-dialog-content class="prevent-select">
+  <div class="is-loading animated fadeIn fast" *ngIf="isLoading" style="text-align: center; padding: 20px;">
+    <mat-spinner></mat-spinner>
+    <h3 style="margin-top: 10px;">Cargando datos...</h3>
+  </div>
+
+<mat-dialog-actions align="end" style="padding: 16px;">
+    <button mat-button style="margin-right: 8px;" [disabled]="isLoading" (click)="cancelar()">
+        <mat-icon>close</mat-icon>
+        Cancelar
+    </button>
+
+    <button mat-button color="primary">
+        <mat-icon>save</mat-icon>
+        <span *ngIf="!isLoading">Guardar</span>
+        <span *ngIf="isLoading">Guardando ...</span>
+    </button>
+</mat-dialog-actions>

+ 48 - 0
src/app/components/personal-management/organization/block-user/block-user.component.ts

@@ -0,0 +1,48 @@
+import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { BlockUser, Usuario } from '../organization.component';
+import { UsersProfilesService } from '../../../../services/users-profiles.service';
+import { EncService } from '../../../../services/enc.service';
+
+@Component({
+  selector: 'block-user',
+  templateUrl: './block-user.component.html',
+  styleUrl: './block-user.component.css',
+  standalone: false
+})
+
+export class BlockUserComponent implements OnInit{
+  
+  usuario: BlockUser;
+  isLoading: boolean = false;
+  hasError: boolean = false;
+  errorMessage: string = '';
+
+
+
+
+  ngOnInit(): void {
+    throw new Error('Method not implemented.');
+  }
+
+  constructor (
+    @Inject(MAT_DIALOG_DATA) public data: {usuarioDATA: BlockUser},
+    private dialogRef: MatDialogRef<BlockUserComponent>,
+    private _usersProfilesService: UsersProfilesService,
+    private _encrypt: EncService
+  ) 
+  
+  {
+    this.usuario = {
+      id: 0, //asi por ahora
+      nombre: '' //asi por ahora
+    }
+  }
+
+
+    cancelar(): void {
+    this.dialogRef.close();
+  }
+  
+
+ }

+ 114 - 45
src/app/components/personal-management/organization/edit-organization/edit-organization.component.html

@@ -1,50 +1,119 @@
-<h1 mat-dialog-title class="prevent-select  text-end">Modificar</h1>
+<h1 mat-dialog-title class="prevent-select" style="text-align: center; margin-top: 15px;">
+  Modificar Organigrama
+</h1>
+
 <div mat-dialog-content class="prevent-select">
-    <div class="is-loading animated fadeIn fast" *ngIf="isLoading">
-        <mat-spinner align="center"></mat-spinner>
-        <h3>Cargando datos ...</h3>
+  <div class="is-loading animated fadeIn fast" *ngIf="isLoading" style="text-align: center; padding: 20px;">
+    <mat-spinner></mat-spinner>
+    <h3 style="margin-top: 10px;">Cargando datos...</h3>
+  </div>
+
+  <div class="has-error animated fadeIn fast" *ngIf="hasError" style="text-align: center; padding: 20px;">
+    <mat-icon class="red_primary_font" style="font-size: 48px; margin-bottom: 10px;">error</mat-icon>
+    <h3 style="font-weight: bold; font-style: italic;">{{ errorMessage }}</h3>
+  </div>
+
+  <div class="form-container mt-10" *ngIf="!isLoading && !hasError">
+    
+    <mat-form-field appearance="outline" style="width: 100%; margin-bottom: 16px;">
+      <mat-label>Usuario a modificar</mat-label>
+      <input matInput
+             [value]="usuario.organigrama?.nombre_completo || usuario.nombre"
+             readonly>
+      <mat-icon matSuffix>person</mat-icon>
+    </mat-form-field>
+
+    <!-- Supervisores dinámicos -->
+    <div style="width: 95%;">
+      <div *ngFor="let supervisor of supervisores; let i = index; trackBy: trackBySupervisor" 
+         style="position: relative; margin-bottom: 16px;">
+      
+      <mat-form-field appearance="outline" style="width: 100%;">
+        <mat-label>
+          Supervisor {{ supervisor.level }}
+          <span *ngIf="supervisor.level === 1" style="color: red;">*</span>
+          <span *ngIf="supervisor.level > 1">(Opcional)</span>
+        </mat-label>
+
+        <mat-select  [value]="supervisor.value"
+                    (selectionChange)="onSupervisorChange(supervisor.id, $event.value)"
+                    [required]="supervisor.level === 1">
+          <mat-option value="No configurado">No configurado</mat-option>
+          <mat-option *ngFor="let supervisorOption of getAvailableSupervisores(supervisor.id)" 
+                      [value]="supervisorOption.value">
+            {{ supervisorOption.display }}
+          </mat-option>
+        </mat-select>
+        <mat-icon matSuffix>
+          {{ supervisor.level === 1 ? 'supervisor_account' : 'manage_accounts' }}
+        </mat-icon>
+        <mat-hint *ngIf="supervisor.level === 1">
+          Seleccione el supervisor principal (obligatorio)
+        </mat-hint>
+        <mat-hint *ngIf="supervisor.level > 1">
+          Seleccione un supervisor adicional (opcional)
+        </mat-hint>
+      </mat-form-field>
+
+      <button *ngIf="supervisores.length > 0 && supervisor.level > 0"
+              mat-icon-button
+              color="warn"
+              (click)="eliminarSupervisor(supervisor.id)"
+              style="position: absolute; right: -48px; top: 40%; transform: translateY(-50%); "
+              matTooltip="Eliminar supervisor"
+              disabled="">
+        <mat-icon>delete</mat-icon>
+      </button>
+      <button *ngIf="supervisores.length > 1 && supervisor.level > 2"
+              mat-icon-button
+              color="warn"
+              (click)="eliminarSupervisor(supervisor.id)"
+              style="position: absolute; right: -48px; top: 40%; transform: translateY(-50%); "
+              matTooltip="Eliminar supervisor">
+        <mat-icon class="red_primary_font">delete</mat-icon>
+      </button>
     </div>
-    <div class="has-error animated fadeIn fast" *ngIf="!isLoading && hasError">
-        <mat-icon class="red_primary_font mb-20" style="transform: scale(5)">error</mat-icon>
-        <h3 style="font-weight: bold; font-style: italic;">{{ errorStr }}</h3>
     </div>
-    
-     <div class="form-row">
-        <div class="w-100 animated fadeIn pt-8">
-            <div mat-dialog-title class="transparent_background w-full" style="height: 60px; border-top-left-radius: 5px; border-top-right-radius: 5px; font-size: 20px;">
-                Juan Pérez
-            <span class="material-icons " style="font-size: 18px; margin-right: 4px;">person</span>
-
-            </div>
-            <br>
-            <mat-label class="ml-20 mb-10">Supervisor 1</mat-label>
-            <br>
-            <mat-form-field appearence="outline" class="w-100 mr-20 " >
-                <mat-label >Supervisor 1<mat-icon>add</mat-icon></mat-label>
-            <mat-select [(ngModel)] = "idsupervisor" required>
-              <mat-option *ngFor="let supervisor of _supervisorList" [value]="supervisor.getUser">
-                {{supervisor.getUser}}
-              </mat-option>
-
-            </mat-select>
-            
-            </mat-form-field>
-            <br>
-            <mat-label class="ml-20 mb-10">Supervisor 2</mat-label>
-            <br>
-            <mat-form-field appearence="outline" class="w-100 mr-20">
-                 <mat-label >Supervisor 2</mat-label>
-            <mat-select [(ngModel)] = "idsupervisor" required>
-              <mat-option *ngFor="let supervisor of _supervisorList" [value]="supervisor.getUser">
-                {{supervisor.getUser}}
-              </mat-option>
-
-            </mat-select>
-            </mat-form-field>
-        </div>
-     </div>
+
+    <div style="text-align: center; margin-left: 450px; margin-bottom: 16px;">
+      <button mat-button 
+              color="primary" 
+              (click)="agregarSupervisor()"
+              [disabled]="listaSupervisores.length === 0">
+        <mat-icon>add</mat-icon>
+        Agregar supervisor
+      </button>
+    </div>
+
+    <div *ngIf="listaSupervisores.length === 0 && !isLoading" 
+         style="padding: 16px; background-color: #fff3cd; border-radius: 4px; margin-bottom: 16px;">
+      <mat-icon style="color: #856404; vertical-align: middle; margin-right: 8px;">warning</mat-icon>
+      <span style="color: #856404;">
+        No hay super usuarios disponibles para asignar como supervisores.
+      </span>
+    </div>
+
+  </div>
 </div>
-<mat-dialog-actions align="end">
-    <button mat-button cdKFocusInitial mat-dialog-close>Cancelar</button>
-    <button mat-button  [disabled]="idsupervisor == ''  ">Guardar</button>
+
+<mat-dialog-actions align="end" style="padding: 16px;">
+  <button mat-button
+          (click)="cancelar()"
+          style="margin-right: 8px;"
+          [disabled]="isLoading">
+    <mat-icon>close</mat-icon>
+    Cancelar
+  </button>
+
+  <button mat-button
+          color="primary"
+          (click)="guardarCambios()"
+          [disabled]="!supervisores[0]?.value || 
+                     supervisores[0]?.value === 'No configurado' || 
+                     isLoading ||
+                     listaSupervisores.length === 0">
+    <mat-icon>save</mat-icon>
+    <span *ngIf="!isLoading">Guardar</span>
+    <span *ngIf="isLoading">Guardando...</span>
+  </button>
 </mat-dialog-actions>

+ 361 - 27
src/app/components/personal-management/organization/edit-organization/edit-organization.component.ts

@@ -1,11 +1,28 @@
 import { MatCardModule } from '@angular/material/card';
-import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
-import { MatDialogRef } from '@angular/material/dialog';
+import { ChangeDetectionStrategy, Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
 import { MatDialog } from '@angular/material/dialog';
 import { MatTableDataSource } from '@angular/material/table';
 import { UsersProfilesService } from '../../../../services/users-profiles.service';
+import { EncService } from '../../../../services/enc.service';
+import { FunctionsService } from '../../../../services/functions.service';
 import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
+import { lastValueFrom } from 'rxjs';
+import { UserResponse, UsersResponse } from '../../../../interfaces/users.interface';
+import { Organigrama, Usuario } from '../organization.component';
 
+export interface SupervisorOption {
+  value: string;
+  display: string;
+  idUsuario: string;
+}
+
+export interface SupervisorItem {
+  id: string;
+  value: string | null;
+  level: number;
+  required: boolean;
+}
 
 @Component({
   selector: 'app-edit-organization',
@@ -13,49 +30,366 @@ import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
   styleUrl: './edit-organization.component.css',
   standalone: false
 })
-export class EditOrganizationComponent implements OnInit{
+export class EditOrganizationComponent implements OnInit {
   
+  usuario: Usuario;
+  isLoading: boolean = false;
+  hasError: boolean = false;
+  errorMessage: string = '';
+  listaSupervisores: SupervisorOption[] = [];
+  originalUsuario: Usuario;
+  supervisores: SupervisorItem[] = [];
   
-  isLoading: boolean;
-  hasError: boolean;
-  idsupervisor: string;
-  errorStr: string;
-  _supervisorList: UsersProfilesService[];
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: {usuarioDATA: Usuario},
+    private dialogRef: MatDialogRef<EditOrganizationComponent>,
+    private _usersProfilesService: UsersProfilesService,
+    private _encrypt: EncService,
+    private _functionService: FunctionsService
+  ) {
+    this.usuario = {
+      ...data.usuarioDATA,
+      organigrama: data.usuarioDATA.organigrama ? 
+        { ...data.usuarioDATA.organigrama } :
+        {
+          nombre_completo: data.usuarioDATA.nombre,
+          supervisor1: 'No configurado',
+          supervisor2: null,
+          supervisor3: null,
+          supervisor4: null,
+          supervisor5: null,
+          supervisor6: null
+        }
+    };
+    
+    this.originalUsuario = JSON.parse(JSON.stringify(this.usuario));
+    this.initializeSupervisores();
+  }
+  
+  private initializeSupervisores(): void {
+    this.supervisores = [];
+    
+    this.supervisores.push({
+      id: this.generateUniqueId(),
+      value: this.usuario.organigrama?.supervisor1 || 'No configurado',
+      level: 1,
+      required: true
+    });
 
+    const supervisoresConfigurados = this.getAllConfiguredSupervisors();
+    
+    supervisoresConfigurados.forEach((supervisor, index) => {
+      if (supervisor && supervisor !== 'No configurado' && supervisor !== null) {
+        this.supervisores.push({
+          id: this.generateUniqueId(),
+          value: supervisor,
+          level: index + 2, 
+          required: false
+        });
+      }
+    });
 
+    if (this.supervisores.length === 1) {
+      this.supervisores.push({
+        id: this.generateUniqueId(),
+        value: 'No configurado',
+        level: 2,
+        required: false
+      });
+    }
+  }
 
-  ngOnInit(): void {
-    this.getCurrentSupervisor()
-  } 
+  private getAllConfiguredSupervisors(): (string | null)[] {
+    const supervisores: (string | null)[] = [];
+    
+    if (!this.usuario.organigrama) return supervisores;
 
+    const supervisorFields = [
+      this.usuario.organigrama.supervisor2,
+      this.usuario.organigrama.supervisor3,
+      this.usuario.organigrama.supervisor4,
+      this.usuario.organigrama.supervisor5,
+      this.usuario.organigrama.supervisor6
+    ];
 
+    const organigramaKeys = Object.keys(this.usuario.organigrama);
+    const additionalSupervisors = organigramaKeys
+      .filter(key => key.startsWith('supervisor') && !['supervisor1', 'supervisor2', 'supervisor3', 'supervisor4', 'supervisor5', 'supervisor6'].includes(key))
+      .map(key => (this.usuario.organigrama as any)[key]);
 
-  constructor (
-    private _dialogRef: MatDialogRef<EditOrganizationComponent>,
-    private _userProfileService: UsersProfilesService,
-    private __matDialog: MatDialog,
+    return [...supervisorFields, ...additionalSupervisors];
+  }
 
-  ) {
+  private generateUniqueId(): string {
+    return 'supervisor_' + Math.random().toString(36).substr(2, 9) + '_' + Date.now();
+  }
+  
+  async ngOnInit(): Promise<void> {
+    if (!this.usuario.organigrama) {
+      this.hasError = true;
+      this.errorMessage = 'No se pudieron cargar los datos del organigrama';
+      return;
+    }
+    
+    await this.loadSupervisores();
+  }
+  
+  private async loadSupervisores(): Promise<void> {
+    try {
+      this.isLoading = true;
+      
+      let idUser = localStorage.getItem('idusuario')!;
+      let users: UsersResponse = await lastValueFrom(this._usersProfilesService.getUsers(idUser, 1));
+      
+      if (!users.error) {
+        this.listaSupervisores = [];
+        
+        for (const user of users.response) {
+          if (user.PERFIL.includes('Super usuario') && user.ESTATUS !== 'Eliminado') {
+            let idDesencrypt = await this._encrypt.decrypt(user.IDUSUARIO);
+            let username = this._functionService.buildName(user.NOMBRE, user.APEPAT, user.APEMAT);
+            let displayName = `${username} (${idDesencrypt})`;
+            
+            if (displayName !== this.usuario.organigrama?.nombre_completo) {
+              this.listaSupervisores.push({
+                value: displayName,
+                display: displayName,
+                idUsuario: idDesencrypt
+              });
+            }
+          }
+        }
+      } else {
+        this.hasError = true;
+        this.errorMessage = 'Error al cargar la lista de supervisores';
+      }
+      
+    } catch (error) {
+      console.error('Error loading supervisores:', error);
+      this.hasError = true;
+      this.errorMessage = 'Error al cargar la lista de supervisores';
+    } finally {
+      this.isLoading = false;
+    }
+  }
+
+  agregarSupervisor(): void {
+    const nuevoNivel = this.getNextAvailableLevel();
+    
+    const nuevoSupervisor: SupervisorItem = {
+      id: this.generateUniqueId(),
+      value: 'No configurado',
+      level: nuevoNivel,
+      required: false
+    };
+    
+    this.supervisores.push(nuevoSupervisor);
+    this.reorderSupervisores();
+  }
+
+  private getNextAvailableLevel(): number {
+    const nivelesUsados = this.supervisores.map(s => s.level);
+    const maxNivel = Math.max(...nivelesUsados);
+    return maxNivel + 1;
+  }
 
-    this.isLoading = true;
-    this.hasError = false;
-    this.idsupervisor = '';
-    this.errorStr = '';
-    this._supervisorList = []; 
+  eliminarSupervisor(id: string): void {
+    const supervisor = this.supervisores.find(s => s.id === id);
+    
+    if (supervisor && supervisor.level > 1) {
+      this.supervisores = this.supervisores.filter(supervisor => supervisor.id !== id);
+      this.reorderSupervisores();
+    }
   }
 
-  private async getCurrentSupervisor () {
+  private reorderSupervisores(): void {
+    this.supervisores.sort((a, b) => a.level - b.level);
+    
+    this.supervisores.forEach((supervisor, index) => {
+      if (supervisor.required) {
+        supervisor.level = 1; 
+      } else {
+        supervisor.level = index + 1; 
+      }
+    });
+  }
+
+  onSupervisorChange(supervisorId: string, newValue: string): void {
+    const supervisor = this.supervisores.find(s => s.id === supervisorId);
+    if (supervisor) {
+      supervisor.value = newValue;
+    }
+  }
+
+  getAvailableSupervisores(currentSupervisorId: string): SupervisorOption[] {
+    const selectedValues = this.supervisores
+      .filter(s => s.id !== currentSupervisorId && s.value && s.value !== 'No configurado')
+      .map(s => s.value);
+    
+    return this.listaSupervisores.filter(supervisor => 
+      !selectedValues.includes(supervisor.value)
+    );
+  }
+
+  canAddSupervisor(): boolean {
+    return this.listaSupervisores.length > 0 && this.getAvailableSupervisores('').length > 0;
+  }
+
+  canRemoveSupervisor(supervisor: SupervisorItem): boolean {
+    return !supervisor.required && this.supervisores.length > 1;
+  }
+
+  getSupervisorLabel(supervisor: SupervisorItem): string {
+    if (supervisor.level === 1) {
+      return 'Supervisor Principal';
+    } else {
+      return `Supervisor ${supervisor.level}`;
+    }
+  }
+
+  getSupervisorHint(supervisor: SupervisorItem): string {
+    if (supervisor.level === 1) {
+      return 'Supervisor principal (obligatorio)';
+    } else {
+      return 'Supervisor adicional (opcional)';
+    }
+  }
+
+  async guardarCambios(): Promise<void> {
+    const supervisorPrincipal = this.supervisores.find(s => s.required);
+    if (!supervisorPrincipal || !supervisorPrincipal.value || supervisorPrincipal.value === 'No configurado') {
+      this.hasError = true;
+      this.errorMessage = 'El Supervisor Principal es obligatorio';
+      return;
+    }
     
     try {
-      let currentUser = localStorage.getItem('idusuario')!;
-      this.isLoading = false;
+      this.isLoading = true;
       this.hasError = false;
-    } catch(error: any ){
-      console.log(error)
+      this.errorMessage = '';
+      
+      if (!this.usuario.userData) {
+        throw new Error('No se encontraron los datos completos del usuario');
+      }
+      
+      const userData: UserResponse = this.usuario.userData;
+      const encryptedUserIdToModify = userData.IDUSUARIO; 
+      
+      const organigramaArray = [];
+      
+      for (const supervisor of this.supervisores) {
+        if (supervisor.value && supervisor.value !== 'No configurado') {
+          const supervisorMatch = supervisor.value.match(/\((\d+)\)$/);
+          if (supervisorMatch) {
+            const supervisorId = supervisorMatch[1];
+            const encryptedSupervisorId = await this._encrypt.encrypt(supervisorId);
+            organigramaArray.push({
+              level: supervisor.level.toString(),
+              id_chief: encryptedSupervisorId
+            });
+          }
+        }
+      }
+      
+      const formData = new FormData();
+      const currentUserIdFromStorage = localStorage.getItem('idusuario')!;
+      
+      formData.append('configured_user', encryptedUserIdToModify);     
+      formData.append('id_user', currentUserIdFromStorage);
+      const lineaValue = 1;
+      formData.append('linea', lineaValue.toString());
+      
+      if (userData.APEMAT) formData.append('sApe', userData.APEMAT);
+      if (userData.ESTATUS) formData.append('estatus', userData.ESTATUS);
+      
+      formData.append('organization', JSON.stringify(organigramaArray));
+      
+      const result = await lastValueFrom(this._usersProfilesService.ConfigureUserOrganization(formData));
+      
+      if (result.error) {
+        throw new Error(result.msg || 'Error al actualizar el usuario');
+      }
+      
+      this.actualizarUsuarioConSupervisores();
+      this.dialogRef.close(this.usuario);
+      
+    } catch (error) {
+      console.error('Error al guardar cambios:', error);
+      this.hasError = true;
+      this.errorMessage = error instanceof Error ? error.message : 'Error al guardar los cambios. Intente nuevamente.';
+    } finally {
+      this.isLoading = false;
     }
+  }
+
+  private actualizarUsuarioConSupervisores(): void {
+    if (this.usuario.organigrama) {
+      const nuevoOrganigrama: any = {
+        nombre_completo: this.usuario.organigrama.nombre_completo,
+        idUsuario: this.usuario.organigrama.idUsuario
+      };
+
+      nuevoOrganigrama.supervisor1 = 'No configurado';
+      nuevoOrganigrama.supervisor2 = null;
+      nuevoOrganigrama.supervisor3 = null;
+      nuevoOrganigrama.supervisor4 = null;
+      nuevoOrganigrama.supervisor5 = null;
+      nuevoOrganigrama.supervisor6 = null;
 
+      this.supervisores.forEach(supervisor => {
+        if (supervisor.value && supervisor.value !== 'No configurado') {
+          if (supervisor.level <= 6) {
+            nuevoOrganigrama[`supervisor${supervisor.level}`] = supervisor.value;
+          } else {
+            nuevoOrganigrama[`supervisor${supervisor.level}`] = supervisor.value;
+          }
+        }
+      });
+
+      this.usuario.organigrama = nuevoOrganigrama;
+    }
   }
 
+  cancelar(): void {
+    this.dialogRef.close();
+  }
+  
+  hasChanges(): boolean {
+    const currentState = this.supervisores
+      .filter(s => s.value && s.value !== 'No configurado')
+      .map(s => ({
+        level: s.level,
+        value: s.value
+      }))
+      .sort((a, b) => a.level - b.level);
+    
+    const originalSupervisores = [];
+    
+    if (this.originalUsuario.organigrama?.supervisor1 && this.originalUsuario.organigrama.supervisor1 !== 'No configurado') {
+      originalSupervisores.push({
+        level: 1,
+        value: this.originalUsuario.organigrama.supervisor1
+      });
+    }
 
+    const originalAdditional = this.getAllConfiguredSupervisors();
+    originalAdditional.forEach((supervisor, index) => {
+      if (supervisor && supervisor !== 'No configurado' && supervisor !== null) {
+        originalSupervisores.push({
+          level: index + 2,
+          value: supervisor
+        });
+      }
+    });
 
-}
+    const originalState = originalSupervisores.sort((a, b) => a.level - b.level);
+    
+    return JSON.stringify(currentState) !== JSON.stringify(originalState);
+  }
+
+  trackBySupervisor(index: number, supervisor: SupervisorItem): string {
+    return supervisor.id;
+  }
+
+
+}

+ 13 - 4
src/app/components/personal-management/organization/organization.component.html

@@ -19,7 +19,7 @@
           </div>
       </mat-card-header>
 
-      <app-loading-card [isLoading]="isLoading" txtLoading="Cargando la información de los contratos" />
+      <app-loading-card [isLoading]="isLoading" txtLoading="Cargando la información de los organigramas" />
       @if (!isLoading) {
           <div class="content_table">
               <table mat-table matSort [dataSource]="dataSource" class="animated fadeIn" [style.display]="isLoading ? 'none' : 'revert'">
@@ -38,17 +38,26 @@
                   <ng-container matColumnDef="Acciones">
                       <th mat-header-cell *matHeaderCellDef>Acciones</th>
                       <td mat-cell *matCellDef="let element">
-                          <button 
+                            <button 
                               mat-mini-fab 
                               color="primary" 
                               [disabled]="isLoading" 
-                              (click)="openOrganizationEdit(1)"
+                              (click)="openOrganizationEdit(element)"
                               #menuTrigger 
                               matTooltip="Editar"
                               class="override_no_shadow  white_font orange_primary_background gray_dark_font">
                               <mat-icon>edit</mat-icon>
                           </button>
-                          
+                            <button 
+                              mat-mini-fab 
+                              color="primary" 
+                              [disabled]="isLoading" 
+                              (click)="openBlockMenu()"
+                              #menuTrigger 
+                              matTooltip="Bloquear usuario"
+                              class="override_no_shadow  white_font red_primary_background gray_dark_font ml-4">
+                              <mat-icon>block</mat-icon>
+                          </button>
                       </td>
                   </ng-container>
           

+ 208 - 84
src/app/components/personal-management/organization/organization.component.ts

@@ -8,14 +8,35 @@ import { Router } from '@angular/router';
 import { MatDialog } from '@angular/material/dialog';
 import { EditOrganizationComponent } from './edit-organization/edit-organization.component';
 import { FunctionsService } from '../../../services/functions.service';
+import { Profile } from '../../../interfaces/profile.interface';
+import { BlockDialogComponent } from '../../corrective-maintenance/security-management/block-dialog/block-dialog.component';
+import { BlockUserComponent } from './block-user/block-user.component';
 
 export interface Organigrama {
-  nombre_completo: string,
-  supervisor1: string,
-  supervisor2: string | null,
+  nombre_completo: string;
+  supervisor1: string;
+  supervisor2?: string | null;
+  supervisor3?: string | null;
+  supervisor4?: string | null;
+  supervisor5?: string | null;
+  supervisor6?: string | null;
+  idUsuario?: string;
+  
+  [key: string]: string | null | undefined;
 }
 
+export interface Usuario {
+  id: number;
+  nombre: string;
+  organigrama: Organigrama | null;
+  userData?: UserResponse;
+}
 
+export interface BlockUser {
+  id: number;
+  nombre: string;
+  userData?: UserResponse;
+}
 
 @Component({
   selector: 'app-organization',
@@ -23,153 +44,256 @@ export interface Organigrama {
   styleUrl: './organization.component.css',
   standalone: false,
 })
-export class OrganizationComponent implements OnInit{
+export class OrganizationComponent implements OnInit {
 
   ngOnInit(): void {
     this.getUsers()
   }
 
+  public usuarios: Usuario[] = [];
   public isLoading: boolean;
   public dataSource: MatTableDataSource<Organigrama>;
   public displayedColumns: string[];
   public hasError: boolean;
   public Error: string;
-
-  constructor (private _usersProfilesService: UsersProfilesService,
-     private _encrypt: EncService,
-     private _router: Router,
-     private _matDialog: MatDialog,  
-     private _functionService: FunctionsService,  
-     private _dialog: MatDialog) {
-
+  public selectedUsr: Usuario | null = null;
+  
+  private cachedUsers: UserResponse[] = [];
+  private originalEncryptedIds: Map<string, string> = new Map();
+
+  constructor(
+    private _usersProfilesService: UsersProfilesService,
+    private _encrypt: EncService,
+    private _router: Router,
+    private _matDialog: MatDialog,
+    private _functionService: FunctionsService,
+    private _dialog: MatDialog
+  ) {
     this.isLoading = true;
-    this.displayedColumns=['Nombre_completo', 'Supervisor_1', 'Supervisor_2', 'Acciones'];
-    this.hasError= false;
-    this.Error= '';
+    this.displayedColumns = ['Nombre_completo', 'Supervisor_1', 'Supervisor_2', 'Acciones'];
+    this.hasError = false;
+    this.Error = '';
     this.dataSource = new MatTableDataSource();
-
   }
 
-  private async getUsers(){
-
-
-    try{
+  private async getUsers() {
+    try {
+      this.isLoading = true;
+      this.originalEncryptedIds.clear();
+      this.cachedUsers = [];
 
       let idUser = localStorage.getItem('idusuario')!
-      let users: UsersResponse = await lastValueFrom (this._usersProfilesService.getUsers(idUser, 1))
-      
+      let users: UsersResponse = await lastValueFrom(this._usersProfilesService.getUsers(idUser, 1))
+      console.log('estos son los usuarios')
+      console.log(users)
+      let profiles: UsersResponse = await lastValueFrom(this._usersProfilesService.getProfiles(idUser, 1))
+      console.log('estos son los perfiles')
+      console.log(profiles)
+
       this.hasError = users.error;
       this.Error = users.msg;
-      
-      if(!this.hasError){
+
+      if (!this.hasError) {
+
+        this.cachedUsers = users.response.map(user => ({...user}));
         
         let decryptID = await this._encrypt.decrypt(idUser);
         let organigrama: Organigrama[] = [];
         let nombresUsuarios: string[] = [];
 
-        for(const user of users.response){
-             
+        for (const user of users.response) {
           let idDesencrypt = await this._encrypt.decrypt(user.IDUSUARIO)
+          
+          this.originalEncryptedIds.set(idDesencrypt, user.IDUSUARIO);
+          
           let username = this._functionService.buildName(user.NOMBRE, user.APEPAT, user.APEMAT);
           username = (username + ` (${idDesencrypt})`)
           nombresUsuarios.push(username)
-          
         }
 
-
-        for (const user of users.response){
-
+        for (const user of users.response) {
           let idDesencrypt = await this._encrypt.decrypt(user.IDUSUARIO)
-          
-          if(decryptID != idDesencrypt && user.ESTATUS != 'Eliminado') {
+
+          if (decryptID != idDesencrypt && user.ESTATUS != 'Eliminado') {
             let username = this._functionService.buildName(user.NOMBRE, user.APEPAT, user.APEMAT);
             username = (username + ` (${idDesencrypt})`)
 
-            let supervisor1 = 'No configurado';
-            let supervisor2 = null;
-
-            if (user.ORGANIGRAMA != null && user.ORGANIGRAMA != undefined){
-              
-              let organigramaAr = JSON.parse(user.ORGANIGRAMA);
-
-              for(let i = 0; i < 2; i++){
-
-                if(organigramaAr.length > i){
-                  let item = organigramaAr[i];
-                  let idChiefDec = await this._encrypt.decrypt(item.id_chief)
-                  let userFilt = nombresUsuarios.filter(item => item.includes(idChiefDec));
-
-                  if(userFilt.length > 0){
-                    supervisor1 = i == 0 ? userFilt [0] : supervisor1
-                    supervisor2 = i == 1 ? userFilt [0] : supervisor2
-
+            // Crear objeto organigrama dinámico
+            let itemObj: Organigrama = {
+              nombre_completo: username,
+              supervisor1: 'No configurado',
+              supervisor2: null,
+              supervisor3: null,
+              supervisor4: null,
+              supervisor5: null,
+              supervisor6: null,
+              idUsuario: idDesencrypt
+            };
+
+            if (user.ORGANIGRAMA != null && user.ORGANIGRAMA != undefined && user.ORGANIGRAMA !== '[]') {
+              try {
+                let organigramaArray = JSON.parse(user.ORGANIGRAMA);
+                
+                for (const item of organigramaArray) {
+                  if (item.id_chief && item.level) {
+                    let idChiefDec = await this._encrypt.decrypt(item.id_chief);
+                    let userFilt = nombresUsuarios.filter(nombre => nombre.includes(idChiefDec));
+                    
+                    if (userFilt.length > 0) {
+                      const level = parseInt(item.level);
+                      
+                      if (level === 1) {
+                        itemObj.supervisor1 = userFilt[0];
+                      } else if (level <= 6) {
+                        itemObj[`supervisor${level}`] = userFilt[0];
+                      } else {
+                        itemObj[`supervisor${level}`] = userFilt[0];
+                      }
+                    }
                   }
                 }
+              } catch (parseError) {
+                console.error('Error parsing organigrama for user:', username, parseError);
               }
-
-              let itemObj: Organigrama = {
-                nombre_completo: username,
-                supervisor1: supervisor1,
-                supervisor2: supervisor2,
-              } 
-
-              console.log(itemObj)
-              organigrama.push(itemObj)
             }
-          }
-
 
-
-          user.IDUSUARIO = idDesencrypt;
+            console.log('Organigrama procesado:', itemObj);
+            organigrama.push(itemObj);
+          }
         }
 
-         this.dataSource = new MatTableDataSource(organigrama); 
+        this.cachedUsers.forEach(user => {
+          const mappedId = Array.from(this.originalEncryptedIds.entries())
+            .find(([decrypted, encrypted]) => encrypted === user.IDUSUARIO);
+          if (mappedId) {
+          }
+        });
+
+        this.dataSource = new MatTableDataSource(organigrama);
       }
 
+    } catch (error: any) {
+      console.error('Error al cargar usuarios:', error)
+      this.hasError = true;
+      this.Error = 'Error al cargar los datos del organigrama';
+    } finally {
       this.isLoading = false;
+    }
+  }
 
+  async openOrganizationEdit(organigramaElement: Organigrama) {
+    const originalEncryptedId = this.originalEncryptedIds.get(organigramaElement.idUsuario!);
+    
+    if (!originalEncryptedId) {
+      console.error('No se encontró el ID encriptado original para:', organigramaElement.idUsuario);
+      return;
+    }
 
-    } catch (error: any) {
-      console.log(error)
+    let userCompleteData: UserResponse | undefined = this.cachedUsers.find(user => user.IDUSUARIO === originalEncryptedId);
+    
+    if (!userCompleteData) {
+      console.error('No se encontró el usuario en el cache');
+      return;
+    }
+
+    const usuarioParaEditar: Usuario = {
+      id: 0,
+      nombre: organigramaElement.nombre_completo,
+      organigrama: this.cloneOrganigrama(organigramaElement), 
+      userData: userCompleteData 
     }
 
+    this.selectedUsr = usuarioParaEditar;
+
+    console.log('Datos finales para el diálogo:');
+    console.log('- Nombre:', usuarioParaEditar.nombre);
+    console.log('- ID Usuario (userData.IDUSUARIO):', usuarioParaEditar.userData?.IDUSUARIO);
+    console.log('- Organigrama completo:', usuarioParaEditar.organigrama);
+
+    let dialogRef = this._matDialog.open(EditOrganizationComponent, {
+      width: '700px',
+      minWidth: '700px',
+      maxHeight: '90vh',
+      disableClose: true,
+      data: {
+        usuarioDATA: this.selectedUsr
+      }
+    });
 
+    dialogRef.afterClosed().subscribe(res => {
+      if (res != null && res != undefined && res != '') {
+        this.getUsers();
+      }
+    })
   }
 
-  async updateSupervisor(idUSUARIO: string, dataEnc: string){
+  private cloneOrganigrama(organigrama: Organigrama): Organigrama {
+    const cloned: Organigrama = {
+      nombre_completo: organigrama.nombre_completo,
+      supervisor1: organigrama.supervisor1,
+      idUsuario: organigrama.idUsuario
+    };
 
-    try{
-      let idUser = localStorage.getItem('idusuario')!;
-      let dataDec = await this._encrypt.decrypt(dataEnc);
-      let dataObj = JSON.parse(dataDec);
-      let formData = new FormData();
+    Object.keys(organigrama).forEach(key => {
+      if (key.startsWith('supervisor') && key !== 'supervisor1') {
+        cloned[key] = organigrama[key];
+      }
+    });
 
-    } catch (error: any) {
+    return cloned;
+  }
+  
+
+  public getAllSupervisors(organigrama: Organigrama): string[] {
+    const supervisors: string[] = [];
+    
+    Object.keys(organigrama).forEach(key => {
+      if (key.startsWith('supervisor')) {
+        const supervisor = organigrama[key];
+        if (supervisor && supervisor !== 'No configurado' && supervisor !== null) {
+          supervisors.push(supervisor);
+        }
+      }
+    });
+
+    return supervisors;
+  }
 
+  public getSupervisorsText(organigrama: Organigrama): string {
+    const supervisors = this.getAllSupervisors(organigrama);
+    
+    if (supervisors.length === 0) {
+      return 'No configurado';
+    } else if (supervisors.length === 1) {
+      return supervisors[0];
+    } else {
+      return `${supervisors[0]} (+${supervisors.length - 1} más)`;
     }
+  }
 
+  refreshData() {
+    this.getUsers();
   }
 
-  
-  async openOrganizationEdit(idUsr: number, ){
-    let idUsrEnc = await this._encrypt.encrypt(`${idUsr}`);
-    let dialogRef = this._matDialog.open(EditOrganizationComponent, {
+  public openBlockMenu() {
+    
+    let dialogRef = this._matDialog.open(BlockUserComponent, {
       width: '700px',
       minWidth: '700px',
+      maxHeight: '90vh',
+      disableClose: true,
       data: {
-        id: idUsr
       }
     });
 
+      
     dialogRef.afterClosed().subscribe(res => {
-      if(res != null && res != undefined && res != ''){
-        this.updateSupervisor(idUsrEnc, res);
+      if (res != null && res != undefined && res != '') {
       }
     })
 
-  }
 
+  }
 
-  
-    }
- 
+  //Esta función va a bloquear al usuario
+}

+ 2 - 0
src/app/services/functions.service.ts

@@ -119,6 +119,8 @@ export class FunctionsService {
     return name;
   }
 
+
+
   formatBytes(bytes: number, decimals = 2) {
     if (bytes === 0) return '0 Bytes';
 

+ 4 - 0
src/app/services/users-profiles.service.ts

@@ -39,6 +39,10 @@ export class UsersProfilesService {
     return this.postQuery("modify-user", userInfo).pipe(map((data: any) => data))
   }
 
+  ConfigureUserOrganization (form: any){
+    return this.postQuery("configure-user-organization", form).pipe(map((data: any) => data))
+  }
+
   newUser(userInfo: any) {
     return this.postQuery('create-user', userInfo).pipe(
       map((data: any) => data)