浏览代码

Merge branch 'develop' of http://209.50.56.224/git/ITTEC/PlataformaEducativaWeb2 into develop

FREDY 3 月之前
父节点
当前提交
f951de520d

+ 11 - 11
Back/backendP-Educativa/.env

@@ -8,21 +8,21 @@ LOG_CHANNEL=stack
 LOG_DEPRECATIONS_CHANNEL=null
 LOG_LEVEL=debug
 
-# DB_CONNECTION=mysql
-# DB_HOST=127.0.0.1
-# DB_PORT=3306
-# # DB_DATABASE=p_educativa
-# DB_DATABASE=platafor_plateduqa
-# DB_USERNAME=root
-# DB_PASSWORD=root
-
 DB_CONNECTION=mysql
 DB_HOST=127.0.0.1
 DB_PORT=3306
 # DB_DATABASE=p_educativa
-DB_DATABASE=qaplataformaeduc_qadb
-DB_USERNAME=qaplataformaeduc_qaus
-DB_PASSWORD=Q%QgpT{w;TK2
+DB_DATABASE=platafor_plateduqa
+DB_USERNAME=root
+DB_PASSWORD=root
+
+# DB_CONNECTION=mysql
+# DB_HOST=127.0.0.1
+# DB_PORT=3306
+# # DB_DATABASE=p_educativa
+# DB_DATABASE=qaplataformaeduc_qadb
+# DB_USERNAME=qaplataformaeduc_qaus
+# DB_PASSWORD=Q%QgpT{w;TK2
 
 BROADCAST_DRIVER=log
 CACHE_DRIVER=file

+ 343 - 300
Front/src/app/modules/Administrador/pages/admin-form/admin-form.component.ts

@@ -204,29 +204,41 @@ constructor(
 ) {}
 
 
-  ngOnInit() {
-    this._enviarInfo.currentTextColor.subscribe(color => this.textColor = color);
-    this._enviarInfo.currentColor.subscribe(color => this.color = color);
-    this.addTab();
-     this.route.queryParams.subscribe(params => {
+ // MÉTODO QUE SE EJECUTA AL INICIAR EL COMPONENTE
+ngOnInit() {
+  // SUSCRIPCIÓN PARA RECIBIR COLOR DEL TEXTO DESDE EL SERVICIO
+  this._enviarInfo.currentTextColor.subscribe(color => this.textColor = color);
+
+  // SUSCRIPCIÓN PARA RECIBIR COLOR DE FONDO DESDE EL SERVICIO
+  this._enviarInfo.currentColor.subscribe(color => this.color = color);
+
+  // AÑADIR UNA NUEVA TAB POR DEFECTO AL INICIAR
+  this.addTab();
+
+  // LEER EL ID DEL FORMULARIO SI VIENE POR QUERY PARAMS PARA CARGARLO
+  this.route.queryParams.subscribe(params => {
     const id = params['id'];
     if (id) {
       this.cargarFormulario(+id);
-      console.log('ID recibido:', id);
+      console.log('ID RECIBIDO:', id);
     }
   });
-    // this.loadSavedForms();
-  }
-  initializeForm(): void {
+
+  // this.loadSavedForms(); // OPCIONAL: CARGAR FORMULARIOS GUARDADOS AL INICIO
+}
+
+// MÉTODO PARA INICIALIZAR EL FORMULARIO DINÁMICO CON TODOS LOS CONTROLES
+initializeForm(): void {
   const formControls: { [key: string]: FormControl } = {};
 
+  // ITERAR POR TODAS LAS TABS Y SUS CUADRÍCULAS
   for (const tab of this.tabs) {
     for (let rowIndex = 0; rowIndex < tab.grid.length; rowIndex++) {
       const row = tab.grid[rowIndex];
       for (let colIndex = 0; colIndex < row.length; colIndex++) {
         const cell = row[colIndex];
         if (cell?.element) {
-          // Usar tab directamente aquí ya que estamos iterando sobre this.tabs
+          // CREAR EL NOMBRE DEL CONTROL Y AGREGARLO AL FORM
           const controlName = this.getControlName(tab, { ...cell, row: rowIndex, col: colIndex });
           formControls[controlName] = new FormControl('');
         }
@@ -234,8 +246,11 @@ constructor(
     }
   }
 
+  // ASIGNAR LOS CONTROLES AL FORM GROUP PRINCIPAL
   this.form = this.fb.group(formControls);
 }
+
+// MÉTODO PARA OBTENER UN NOMBRE DE CONTROL SEGURO (SI NO HAY TAB ACTIVA)
 getSafeControlName(cell: any, rowIndex: number, colIndex: number): string {
   if (!this.currentTab) {
     return `campo_${rowIndex}_${colIndex}`;
@@ -244,173 +259,178 @@ getSafeControlName(cell: any, rowIndex: number, colIndex: number): string {
 }
 
 
-  // MÉTODOS PARA MANEJAR LA API
-
-  loadSavedForms() {
-    this.isLoading = true;
-    this.formApiService.getForms().subscribe({
-      next: (forms) => {
-        this.savedForms = forms;
-        this.isLoading = false;
-      },
-      error: (error) => {
-        console.error('Error al cargar formularios:', error);
-        this.saveStatus = 'Error al cargar formularios';
-        this.isLoading = false;
-      }
-    });
-  }
+// CARGAR FORMULARIOS GUARDADOS
+loadSavedForms() {
+  this.isLoading = true;
+  this.formApiService.getForms().subscribe({
+    next: (forms) => {
+      this.savedForms = forms;
+      this.isLoading = false;
+    },
+    error: (error) => {
+      console.error('ERROR AL CARGAR FORMULARIOS:', error);
+      this.saveStatus = 'ERROR AL CARGAR FORMULARIOS';
+      this.isLoading = false;
+    }
+  });
+}
 
- saveForm() {
+// GUARDAR FORMULARIO NUEVO O EXISTENTE
+saveForm() {
+  // VALIDAR QUE HAYA TÍTULO
   if (!this.formTitle.trim()) {
-    alert('Por favor, ingresa un título para el formulario');
+    alert('POR FAVOR, INGRESA UN TÍTULO PARA EL FORMULARIO');
     return;
   }
 
-
-// ESTO ES UNA VALIDACION EN CASO DE QUE EL USUARIO MALLOGRE PONER UN 0 EN LA CONFIGURACION DE LAS FILAS O COLUMNAS
+  // VALIDAR QUE NINGUNA TAB TENGA FILAS O COLUMNAS EN 0
   const tabConError = this.tabs.find(tab => tab.rows < 1 || tab.columns < 1);
   if (tabConError) {
-    alert(` La sección "${tabConError.name}" tiene un número inválido de filas o columnas.\n\n
-    No se permite 0.\n Usa al menos 1 fila y 1 columna.`);
+    alert(`LA SECCIÓN "${tabConError.name}" TIENE UN NÚMERO INVÁLIDO DE FILAS O COLUMNAS.\n\nNO SE PERMITE 0.\nUSA AL MENOS 1 FILA Y 1 COLUMNA.`);
     return;
   }
 
-  // Guardar la cuadrícula del tab activo actual
+  // GUARDAR LA CUADRÍCULA DEL TAB ACTIVO ACTUAL
   if (this.currentTab) {
     this.currentTab.grid = [...this.grid];
   }
 
-  //Variable para guardar la configuracion del servicio
+  // CONSTRUIR CONFIGURACIÓN PARA EL SERVICIO
   const config = this.buildFormConfiguration();
   this.isLoading = true;
-  this.saveStatus = 'Guardando...';
+  this.saveStatus = 'GUARDANDO...';
 
+  // LLAMAR AL SERVICIO PARA GUARDAR EL FORMULARIO
   this.formApiService.createForm(config).subscribe({
     next: (response) => {
-      console.log('Formulario guardado:', response);
+      console.log('FORMULARIO GUARDADO:', response);
       this.currentFormId = response.id;
-      this.saveStatus = 'Formulario guardado exitosamente';
+      this.saveStatus = 'FORMULARIO GUARDADO EXITOSAMENTE';
       this.isLoading = false;
       this.router.navigate(['/homeAdmin/verFormulario']);
     },
     error: (error) => {
-      console.error('Error al guardar formulario:', error);
-      this.saveStatus = 'Error al guardar el formulario';
+      console.error('ERROR AL GUARDAR FORMULARIO:', error);
+      this.saveStatus = 'ERROR AL GUARDAR EL FORMULARIO';
       this.isLoading = false;
     }
   });
 }
 
+// CARGAR UN FORMULARIO EXISTENTE POR ID
+loadForm(formId: number) {
+  this.isLoading = true;
+  this.formApiService.getForm(formId).subscribe({
+    next: (formData) => {
+      this.loadFormConfiguration(formData);
+      this.currentFormId = formId;
+      this.isLoading = false;
+    },
+    error: (error) => {
+      console.error('ERROR AL CARGAR FORMULARIO:', error);
+      this.saveStatus = 'ERROR AL CARGAR EL FORMULARIO';
+      this.isLoading = false;
+    }
+  });
+}
 
-
-
-  loadForm(formId: number) {
-    this.isLoading = true;
-    this.formApiService.getForm(formId).subscribe({
-      next: (formData) => {
-        this.loadFormConfiguration(formData);
-        this.currentFormId = formId;
-        this.isLoading = false;
-      },
-      error: (error) => {
-        console.error('Error al cargar formulario:', error);
-        this.saveStatus = 'Error al cargar el formulario';
-        this.isLoading = false;
-      }
-    });
+// PUBLICAR FORMULARIO (SOLO UNO PUEDE ESTAR PUBLICADO)
+publishForm(formId: number) {
+  if (!confirm('¿ESTÁS SEGURO DE QUE QUIERES PUBLICAR ESTE FORMULARIO?')) {
+    return;
   }
 
-  publishForm(formId: number) {
-    if (!confirm('¿Estás seguro de que quieres publicar este formulario?')) {
-      return;
+  this.isLoading = true;
+  this.formApiService.publishForm(formId).subscribe({
+    next: (response) => {
+      this.saveStatus = 'FORMULARIO PUBLICADO EXITOSAMENTE';
+      this.loadSavedForms();
+      this.isLoading = false;
+
+      // LIMPIAR MENSAJE DESPUÉS DE 3 SEGUNDOS
+      setTimeout(() => {
+        this.saveStatus = '';
+      }, 3000);
+    },
+    error: (error) => {
+      console.error('ERROR AL PUBLICAR FORMULARIO:', error);
+      this.saveStatus = 'ERROR AL PUBLICAR EL FORMULARIO';
+      this.isLoading = false;
     }
+  });
+}
+
+// CONSTRUIR LA CONFIGURACIÓN DEL FORMULARIO PARA EL SERVICIO
+buildFormConfiguration(): FormConfiguration {
+  return {
+    title: this.formTitle,
+    tabs: this.tabs.map(tab => ({
+      id: tab.id,
+      title: tab.name,
+      rows: tab.rows,
+      columns: tab.columns,
+      elements: this.extractElementsFromGrid(tab.grid)
+    }))
+  };
+}
 
-    this.isLoading = true;
-    this.formApiService.publishForm(formId).subscribe({
-      next: (response) => {
-        this.saveStatus = 'Formulario publicado exitosamente';
-        this.loadSavedForms();
-        this.isLoading = false;
-
-        setTimeout(() => {
-          this.saveStatus = '';
-        }, 3000);
-      },
-      error: (error) => {
-        console.error('Error al publicar formulario:', error);
-        this.saveStatus = 'Error al publicar el formulario';
-        this.isLoading = false;
+// CARGAR CONFIGURACIÓN DEL FORMULARIO DESDE LA API
+loadFormConfiguration(formData: any) {
+  this.formTitle = formData.title || '';
+  this.tabs = [];
+
+  if (formData.tabs && formData.tabs.length > 0) {
+    formData.tabs.forEach((tabData: any) => {
+      const newTab: Tab = {
+        id: tabData.id,
+        name: tabData.title,
+        active: false,
+        rows: tabData.rows,
+        columns: tabData.columns,
+        grid: this.buildNewGrid(tabData.rows, tabData.columns)
+      };
+
+      // CARGAR ELEMENTOS EN LA CUADRÍCULA
+      if (tabData.elements && tabData.elements.length > 0) {
+        tabData.elements.forEach((elementData: any) => {
+          const { row, col } = elementData.position;
+          if (row < newTab.rows && col < newTab.columns) {
+            newTab.grid[row][col].element = { ...elementData.element };
+          }
+        });
       }
+
+      this.tabs.push(newTab);
     });
-  }
 
-  buildFormConfiguration(): FormConfiguration {
-    return {
-      title: this.formTitle,
-      tabs: this.tabs.map(tab => ({
-        id: tab.id,
-        title: tab.name,
-        rows: tab.rows,
-        columns: tab.columns,
-        elements: this.extractElementsFromGrid(tab.grid)
-      }))
-    };
+    this.switchToTab(this.tabs[0]);
+    this.initializeForm();
+  } else {
+    this.addTab();
   }
+}
 
-  loadFormConfiguration(formData: any) {
-    this.formTitle = formData.title || '';
+// CREAR UN NUEVO FORMULARIO (SE PIERDEN CAMBIOS NO GUARDADOS)
+newForm() {
+  if (confirm('¿ESTÁS SEGURO DE QUE QUIERES CREAR UN NUEVO FORMULARIO? SE PERDERÁN LOS CAMBIOS NO GUARDADOS.')) {
+    this.formTitle = '';
+    this.currentFormId = null;
     this.tabs = [];
-
-    if (formData.tabs && formData.tabs.length > 0) {
-      formData.tabs.forEach((tabData: any) => {
-        const newTab: Tab = {
-          id: tabData.id,
-          name: tabData.title,
-          active: false,
-          rows: tabData.rows,
-          columns: tabData.columns,
-          grid: this.buildNewGrid(tabData.rows, tabData.columns)
-        };
-
-        // Cargar elementos en el grid
-        if (tabData.elements && tabData.elements.length > 0) {
-          tabData.elements.forEach((elementData: any) => {
-            const { row, col } = elementData.position;
-            if (row < newTab.rows && col < newTab.columns) {
-              newTab.grid[row][col].element = { ...elementData.element };
-            }
-          });
-        }
-
-        this.tabs.push(newTab);
-      });
-
-      this.switchToTab(this.tabs[0]);
-        this.initializeForm();
-    } else {
-      this.addTab();
-    }
+    this.addTab();
+    this.saveStatus = '';
   }
+}
 
-  newForm() {
-    if (confirm('¿Estás seguro de que quieres crear un nuevo formulario? Se perderán los cambios no guardados.')) {
-      this.formTitle = '';
-      this.currentFormId = null;
-      this.tabs = [];
-      this.addTab();
-      this.saveStatus = '';
-    }
+// ELIMINAR UN FORMULARIO EXISTENTE
+deleteForm(formId: number) {
+  if (!confirm('¿ESTÁS SEGURO DE QUE QUIERES ELIMINAR ESTE FORMULARIO? ESTA ACCIÓN NO SE PUEDE DESHACER.')) {
+    return;
   }
 
-  deleteForm(formId: number) {
-    if (!confirm('¿Estás seguro de que quieres eliminar este formulario? Esta acción no se puede deshacer.')) {
-      return;
-    }
-
+  // AQUÍ IRÍA LLAMADO AL SERVICIO PARA ELIMINAR
+  this.loadSavedForms();
+}
 
-    this.loadSavedForms();
-  }
 
   // MÉTODOS EXISTENTES (sin cambios)
 
@@ -423,186 +443,195 @@ getSafeControlName(cell: any, rowIndex: number, colIndex: number): string {
   }
 
   // TABS
-  addTab(rows = this.defaultRows, columns = this.defaultColumns) {
-    const newTab: Tab = {
-      id: `tab_${this.tabs.length + 1}`,
-      name: `Sección ${this.tabs.length + 1}`,
-      active: false,
-      rows,
-      columns,
-      grid: this.buildNewGrid(rows, columns)
-    };
-    this.tabs.push(newTab);
-    this.switchToTab(newTab);
-  }
+ // ====================== TABS / SECCIONES ======================
+
+// AÑADE UNA NUEVA TAB (SECCIÓN) AL FORMULARIO
+addTab(rows = this.defaultRows, columns = this.defaultColumns) {
+  const newTab: Tab = {
+    id: `tab_${this.tabs.length + 1}`,       // ID ÚNICO
+    name: `Sección ${this.tabs.length + 1}`, // NOMBRE POR DEFECTO
+    active: false,
+    rows,
+    columns,
+    grid: this.buildNewGrid(rows, columns)   // GENERAR GRID VACÍO
+  };
+  this.tabs.push(newTab);                    // AGREGAR A ARRAY DE TABS
+  this.switchToTab(newTab);                  // ACTIVAR LA TAB NUEVA
+}
 
-  removeTab() {
-    if (this.tabs.length <= 1) return;
+// ELIMINA LA TAB ACTIVA
+removeTab() {
+  if (this.tabs.length <= 1) return;         // SI SOLO QUEDA 1 TAB, NO HACE NADA
 
-    const activeIndex = this.tabs.findIndex(tab => tab.active);
-    if (activeIndex === -1) return;
+  const activeIndex = this.tabs.findIndex(tab => tab.active);
+  if (activeIndex === -1) return;
 
-    this.tabs.splice(activeIndex, 1);
-    const newActiveIndex = activeIndex === 0 ? 0 : activeIndex - 1;
-    this.tabs.forEach((tab, index) => {
-      tab.active = index === newActiveIndex;
-    });
-  }
+  this.tabs.splice(activeIndex, 1);          // ELIMINAR TAB ACTIVA
+  const newActiveIndex = activeIndex === 0 ? 0 : activeIndex - 1;
 
+  // ACTIVAR TAB ADYACENTE
+  this.tabs.forEach((tab, index) => {
+    tab.active = index === newActiveIndex;
+  });
+}
+
+// CAMBIA A LA TAB SELECCIONADA
 switchToTab(tab: Tab) {
-  if (this.currentTab) this.currentTab.grid = [...this.grid];
+  if (this.currentTab) this.currentTab.grid = [...this.grid]; // GUARDAR GRID ACTUAL
   this.tabs.forEach(t => t.active = false);
   tab.active = true;
   this.currentTab = tab;
-  this.grid = [...tab.grid];
-  this.clearSelection();
-  this.buildFormGroup();
-    this.cdr.detectChanges();
+  this.grid = [...tab.grid];                  // CARGAR GRID DE LA TAB
+  this.clearSelection();                      // LIMPIAR SELECCIÓN DE CELDAS
+  this.buildFormGroup();                      // RECONSTRUIR FORM GROUP PARA EL TAB
+  this.cdr.detectChanges();                   // DETECTAR CAMBIOS
 }
+
+// ====================== FORM GROUP DINÁMICO ======================
+
+// CONSTRUYE EL FORM GROUP BASADO EN LA CUADRÍCULA ACTUAL
 buildFormGroup() {
   const group: any = {};
   this.grid.forEach((row, i) => {
     row.forEach((cell, j) => {
       if (cell.element && cell.element.name) {
         const controlName = this.getSafeControlName(cell, i, j);
-        group[controlName] = new FormControl('');
+        group[controlName] = new FormControl(''); // CONTROL VACÍO
       }
     });
   });
   this.form = new FormGroup(group);
 }
 
-
+// TRACKBY PARA RENDEREAR FILAS Y CELDAS EFICIENTEMENTE
 trackByRowIndex(index: number, row: GridCell[]): number {
   return index;
 }
-
 trackByCellIndex(index: number, cell: GridCell): string {
   return `${cell.row}_${cell.col}`;
 }
 
+// ACTUALIZA EL NOMBRE DE UNA TAB
+updateTabName(tab: Tab, name: string) {
+  tab.name = name;
+}
 
-  updateTabName(tab: Tab, name: string) {
-    tab.name = name;
-  }
-
-  // GRID
-  buildNewGrid(rows: number, columns: number): GridCell[][] {
-    return Array.from({ length: rows }, (_, r) =>
-      Array.from({ length: columns }, (_, c) => ({
-        row: r, col: c, selected: false
-      }))
-    );
-  }
+// ====================== GRID ======================
 
-  updateTabDimensions(tab: Tab, newRows: number, newColumns: number) {
-    const oldGrid = tab.grid.map(row => row.map(cell => ({ ...cell, element: cell.element ? { ...cell.element } : undefined })));
+// CREA UN GRID VACÍO
+buildNewGrid(rows: number, columns: number): GridCell[][] {
+  return Array.from({ length: rows }, (_, r) =>
+    Array.from({ length: columns }, (_, c) => ({
+      row: r, col: c, selected: false
+    }))
+  );
+}
 
-    tab.rows = newRows;
-    tab.columns = newColumns;
-    tab.grid = this.buildNewGrid(newRows, newColumns);
+// ACTUALIZA DIMENSIONES DE UNA TAB (FILAS Y COLUMNAS)
+updateTabDimensions(tab: Tab, newRows: number, newColumns: number) {
+  const oldGrid = tab.grid.map(row => row.map(cell => ({ ...cell, element: cell.element ? { ...cell.element } : undefined })));
+  tab.rows = newRows;
+  tab.columns = newColumns;
+  tab.grid = this.buildNewGrid(newRows, newColumns);
 
-    this.preserveElementsInNewGrid(oldGrid, tab.grid, newRows, newColumns);
+  // PRESERVAR ELEMENTOS YA EXISTENTES DENTRO DEL NUEVO GRID
+  this.preserveElementsInNewGrid(oldGrid, tab.grid, newRows, newColumns);
 
-    if (this.currentTab?.id === tab.id) {
-      this.grid = tab.grid.map(row => row.map(cell => ({ ...cell, element: cell.element ? { ...cell.element } : undefined })));
-    }
+  if (this.currentTab?.id === tab.id) {
+    this.grid = tab.grid.map(row => row.map(cell => ({ ...cell, element: cell.element ? { ...cell.element } : undefined })));
   }
+}
 
-  preserveElementsInNewGrid(oldGrid: GridCell[][], newGrid: GridCell[][], maxR: number, maxC: number) {
-    for (let r = 0; r < oldGrid.length; r++) {
-      for (let c = 0; c < oldGrid[r]?.length; c++) {
-        const cell = oldGrid[r][c];
-        if (cell?.element && r < maxR && c < maxC) {
-          newGrid[r][c].element = { ...cell.element };
-        }
+// PRESERVA ELEMENTOS EN EL GRID AL CAMBIAR DIMENSIONES
+preserveElementsInNewGrid(oldGrid: GridCell[][], newGrid: GridCell[][], maxR: number, maxC: number) {
+  for (let r = 0; r < oldGrid.length; r++) {
+    for (let c = 0; c < oldGrid[r]?.length; c++) {
+      const cell = oldGrid[r][c];
+      if (cell?.element && r < maxR && c < maxC) {
+        newGrid[r][c].element = { ...cell.element };
       }
     }
   }
+}
 
-  onTabDimensionsChange(event: { tab: Tab, rows: number, columns: number }) {
-    this.updateTabDimensions(event.tab, event.rows, event.columns);
-  }
-
-  buildGrid() {
-    if (this.currentTab) {
-      this.currentTab.grid = this.grid = this.buildNewGrid(this.currentTab.rows, this.currentTab.columns);
-    }
-  }
-
-  verifyGridIntegrity(grid: GridCell[][]): boolean {
-    return grid.every((row, r) => row.every((cell, c) => {
-      cell.row = r;
-      cell.col = c;
-      return true;
-    }));
-  }
+// ESCUCHA CAMBIOS DE DIMENSIONES DESDE EL PANEL DE CONFIGURACIÓN
+onTabDimensionsChange(event: { tab: Tab, rows: number, columns: number }) {
+  this.updateTabDimensions(event.tab, event.rows, event.columns);
+}
 
-  // FORM CONFIG
-  onFormTitleChange(title: string) {
-    this.formTitle = title;
+// RECONSTRUYE EL GRID DE LA TAB ACTUAL
+buildGrid() {
+  if (this.currentTab) {
+    this.currentTab.grid = this.grid = this.buildNewGrid(this.currentTab.rows, this.currentTab.columns);
   }
+}
 
-  onRowsChange(rows: number) {
-    if (this.currentTab) this.updateTabDimensions(this.currentTab, rows, this.currentTab.columns);
-  }
+// VERIFICA INTEGRIDAD DEL GRID (FILAS Y COLUMNAS CORRECTAS)
+verifyGridIntegrity(grid: GridCell[][]): boolean {
+  return grid.every((row, r) => row.every((cell, c) => {
+    cell.row = r;
+    cell.col = c;
+    return true;
+  }));
+}
 
-  onColumnsChange(cols: number) {
-    if (this.currentTab) this.updateTabDimensions(this.currentTab, this.currentTab.rows, cols);
-  }
+// ====================== FORM CONFIG ======================
+onFormTitleChange(title: string) { this.formTitle = title; }
+onRowsChange(rows: number) { if (this.currentTab) this.updateTabDimensions(this.currentTab, rows, this.currentTab.columns); }
+onColumnsChange(cols: number) { if (this.currentTab) this.updateTabDimensions(this.currentTab, this.currentTab.rows, cols); }
+onShowTooltipChange(field: string) { this.showTooltip = field; }
 
-  onShowTooltipChange(field: string) {
-    this.showTooltip = field;
-  }
+// ====================== SERIALIZACIÓN ======================
+logConfiguration() {
+  const config = this.buildFormConfiguration();
+  console.log('CONFIGURACIÓN COMPLETA:', config);
+  return config;
+}
 
-  // SERIALIZACIÓN
-  logConfiguration() {
-    const config = this.buildFormConfiguration();
-    console.log('Configuración completa:', config);
-    return config;
-  }
+extractElementsFromGrid(grid: GridCell[][]) {
+  return grid.flatMap(row => row
+    .filter(cell => cell.element)
+    .map(cell => ({
+      position: { row: cell.row, col: cell.col },
+      element: this.serializeElement(cell.element!)
+    }))
+  );
+}
 
-  extractElementsFromGrid(grid: GridCell[][]) {
-    return grid.flatMap(row => row
-      .filter(cell => cell.element)
-      .map(cell => ({
-        position: { row: cell.row, col: cell.col },
-        element: this.serializeElement(cell.element!)
-      }))
-    );
-  }
+// SERIALIZA UN ELEMENTO INDIVIDUAL PARA GUARDAR EN API
+serializeElement(el: FormElement) {
+  const base: any = { type: el.type, label: el.label, required: el.required };
+  if (el.placeholder) base.placeholder = el.placeholder;
+  if (el.id) base.id = el.id;
+  if (el.name) base.name = el.name;
+  if (el.value) base.value = el.value;
+  if (el.description) base.description = el.description;
+  if (el.options?.length) base.options = el.options;
+  if (el.min !== undefined) base.min = el.min;
+  if (el.max !== undefined) base.max = el.max;
+  if (el.pattern) base.pattern = el.pattern;
+  return base;
+}
 
-  serializeElement(el: FormElement) {
-    const base: any = {
-      type: el.type, label: el.label, required: el.required
-    };
-    if (el.placeholder) base.placeholder = el.placeholder;
-    if (el.id) base.id = el.id;
-    if (el.name) base.name = el.name;
-    if (el.value) base.value = el.value;
-    if (el.description) base.description = el.description;
-    if (el.options?.length) base.options = el.options;
-    if (el.min !== undefined) base.min = el.min;
-    if (el.max !== undefined) base.max = el.max;
-    if (el.pattern) base.pattern = el.pattern;
-    return base;
-  }
+// ====================== INTERACCIÓN CELDAS ======================
 
-  // INTERACCIÓN CON CELDAS Y CAMPOS
-  selectCell(cell: GridCell) {
-    this.clearSelection();
-    cell.selected = true;
-    this.selectedCell = cell;
-    this.showElementSelector = true;
-  }
+// SELECCIONA UNA CELDA
+selectCell(cell: GridCell) {
+  this.clearSelection();
+  cell.selected = true;
+  this.selectedCell = cell;
+  this.showElementSelector = true;
+}
 
-  clearSelection() {
-    this.grid.forEach(row => row.forEach(c => c.selected = false));
-    this.selectedCell = null;
-    this.showElementSelector = false;
-    this.editingElement = null;
-  }
+// LIMPIA SELECCIÓN DE CELDAS Y ELEMENTOS
+clearSelection() {
+  this.grid.forEach(row => row.forEach(c => c.selected = false));
+  this.selectedCell = null;
+  this.showElementSelector = false;
+  this.editingElement = null;
+}
 
+// CONFIRMA IDENTIFICADOR DEL NUEVO ELEMENTO
 confirmarIdentificador() {
   if (this.nombreIdentificadorControl.invalid || !this.pendingTemplate) {
     this.nombreIdentificadorControl.markAsTouched();
@@ -616,14 +645,10 @@ confirmarIdentificador() {
   element.name = nombreClave;
   element.label = this.capitalizeWords(nombreClave.replace(/_/g, ' '));
 
-  // Validaciones según tipo
+  // APLICA VALIDACIONES SEGÚN TIPO
   switch (element.type) {
     case 'email':
-      Object.assign(element, {
-        required: true,
-        pattern: '^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$',
-        placeholder: 'ejemplo@correo.com'
-      });
+      Object.assign(element, { required: true, pattern: '^[\\w.-]+@[\\w.-]+\\.[a-zA-Z]{2,}$', placeholder: 'ejemplo@correo.com' });
       break;
     case 'number':
       Object.assign(element, { required: true, min: 1, max: 100 });
@@ -632,12 +657,11 @@ confirmarIdentificador() {
       element.required = true;
       element.min = element.min ?? 1;
       element.max = element.max ?? 20;
-      if (!element.pattern) {
-        element.pattern = '^\\b(\\w+\\b\\s*){1,20}$';
-      }
+      if (!element.pattern) element.pattern = '^\\b(\\w+\\b\\s*){1,20}$';
       break;
   }
 
+  // ASIGNA ELEMENTO A LA CELDA SELECCIONADA
   this.selectedCell!.element = element;
   this.editingElement = element;
   this.showElementSelector = false;
@@ -646,12 +670,12 @@ confirmarIdentificador() {
   this.pendingTemplate = null;
 }
 
+// AGREGA ELEMENTO A LA CELDA (ABRE MODAL SI YA HAY ELEMENTO)
 addElementToCell(template: FormElement) {
   if (!this.selectedCell || this.selectedCell.element) {
-    this.showModal = true;
+    this.showModal = true;  // MODAL AVISO DE CELDA OCUPADA
     return;
-  };
-
+  }
   this.pendingTemplate = template;
   this.nombreIdentificadorControl.reset();
   this.showModalIdentificador = true;
@@ -659,6 +683,8 @@ addElementToCell(template: FormElement) {
 
 
 
+
+
   // // Solicita un "nombre clave" legible para el input, ejemplo: "nombre_alumno"
   // let nombreClave = prompt('Ingresa el identificador único para este campo (ej. nombre_alumno):');
   // if (!nombreClave) {
@@ -706,6 +732,8 @@ addElementToCell(template: FormElement) {
   this.showModal = false;
 }
 
+
+// DEVUELVE EL NOMBRE DEL CONTROL DE FORMULARIO PARA UNA CELDA
 getControlName(tab: Tab | null, cell: any): string {
   const row = cell.row ?? 0;
   const col = cell.col ?? 0;
@@ -713,57 +741,68 @@ getControlName(tab: Tab | null, cell: any): string {
   const rawName = cell.element?.name;
   const cleaned = rawName?.trim().replace(/\s+/g, '_').toLowerCase();
 
+  // SI NO HAY NOMBRE DEFINIDO, USAR FORMATO POR DEFECTO "campo_row_col"
   return cleaned && cleaned !== '' ? cleaned : `campo_${row}_${col}`;
 }
 
-
+// CAPITALIZA CADA PALABRA DE UN TEXTO
 capitalizeWords(text: string): string {
   return text.replace(/\b\w/g, c => c.toUpperCase());
 }
 
 
-  updateCurrentTabGrid() {
-    if (this.currentTab) this.currentTab.grid = [...this.grid];
-  }
+// ACTUALIZA EL GRID DE LA TAB ACTIVA CON LOS CAMBIOS DEL GRID VISIBLE
+updateCurrentTabGrid() {
+  if (this.currentTab) this.currentTab.grid = [...this.grid];
+}
 
-  removeElementFromCell(cell: GridCell) {
-    cell.element = undefined;
+// ELIMINA EL ELEMENTO DE UNA CELDA
+removeElementFromCell(cell: GridCell) {
+  cell.element = undefined;
+  this.updateCurrentTabGrid();
+}
+
+// SELECCIONA UN ELEMENTO PARA EDITARLO EN EL PANEL DE PROPIEDADES
+selectElementForEditing(cell: GridCell) {
+  this.editingElement = cell.element || null;
+}
+
+// ACTUALIZA EL ELEMENTO EDITADO DESDE EL PANEL DE PROPIEDADES
+onEditingElementChange(updated: FormElement) {
+  if (this.selectedCell) {
+    this.selectedCell.element = updated;
     this.updateCurrentTabGrid();
   }
+}
 
-  selectElementForEditing(cell: GridCell) {
-    this.editingElement = cell.element || null;
+// ACTUALIZA EL ELEMENTO EDITADO DIRECTAMENTE (sin necesidad de selección de celda)
+onElementChange(updated: FormElement) {
+  if (this.editingElement) {
+    Object.assign(this.editingElement, updated);
+    this.updateCurrentTabGrid();
   }
+}
 
-  onEditingElementChange(updated: FormElement) {
-    if (this.selectedCell) {
-      this.selectedCell.element = updated;
-      this.updateCurrentTabGrid();
-    }
-  }
 
-  onElementChange(updated: FormElement) {
-    if (this.editingElement) {
-      Object.assign(this.editingElement, updated);
-      this.updateCurrentTabGrid();
-    }
-  }
+// CARGA UN FORMULARIO EXISTENTE DESDE LA API PARA EDITARLO
 cargarFormulario(id: number): void {
   this.formService.getFormById(id).subscribe(data => {
     this.formData = data;
     console.log('Form a editar:', this.formData);
 
+    // CARGA LA CONFIGURACIÓN DEL FORMULARIO EN EL COMPONENTE
     this.loadFormConfiguration(this.formData.form.configuration);
     this.formTitle = this.formData.form.title;
     this.currentFormId = this.formData.form.id;
 
-    // Inicializa el formulario reactivo basado en los campos
+    // INICIALIZA EL FORMULARIO REACTIVO CON LOS CAMPOS
     this.initializeForm();
   });
 }
 
 
-  updateForm() {
+// ACTUALIZA UN FORMULARIO YA EXISTENTE
+updateForm() {
   if (!this.formTitle.trim()) {
     alert('Por favor, ingresa un título para el formulario');
     return;
@@ -774,12 +813,14 @@ cargarFormulario(id: number): void {
     return;
   }
 
+  // VALIDACIÓN DE DIMENSIONES MÍNIMAS
   const tabConError = this.tabs.find(tab => tab.rows < 1 || tab.columns < 1);
   if (tabConError) {
     alert(`La sección "${tabConError.name}" tiene dimensiones inválidas (mínimo 1 fila y 1 columna).`);
     return;
   }
 
+  // ACTUALIZA EL GRID DEL TAB ACTUAL
   if (this.currentTab) {
     this.currentTab.grid = [...this.grid];
   }
@@ -788,13 +829,13 @@ cargarFormulario(id: number): void {
   this.isLoading = true;
   this.saveStatus = 'Actualizando formulario...';
 
+  // LLAMADA A API PARA ACTUALIZAR
   this.formService.updateForm(this.currentFormId, config).subscribe({
     next: (response) => {
       console.log('Formulario actualizado:', response);
       this.saveStatus = 'Formulario actualizado correctamente';
       this.isLoading = false;
-            this.router.navigate(['/homeAdmin/verFormulario']);
-
+      this.router.navigate(['/homeAdmin/verFormulario']);
     },
     error: (error) => {
       console.error('Error al actualizar formulario:', error);
@@ -803,6 +844,9 @@ cargarFormulario(id: number): void {
     }
   });
 }
+
+
+// DECIDE SI SE DEBE GUARDAR O ACTUALIZAR
 saveOrUpdateForm() {
   if (this.currentFormId) {
     this.updateForm();
@@ -811,8 +855,7 @@ saveOrUpdateForm() {
   }
 }
 
- }
-
+}
 
 // joinCell(cell: GridCell, rowSpan: number = 1, colSpan: number = 1) {
 //   if (!this.currentTab) return;

+ 15 - 7
Front/src/app/modules/Administrador/pages/admin-form/dynamic-form-component/dynamic-form-component.component.html

@@ -1,47 +1,54 @@
-
-
-
-
+<!-- // FORMULARIO PRINCIPAL: SE MUESTRA SOLO SI EL FORM EXISTE, AQUÍ SE MANEJA TODO EL SUBMIT -->
 <form [formGroup]="form" (ngSubmit)="onSubmit()" *ngIf="form" class="containerPagina">
 
+  <!-- // GRUPO DE TABS: CADA TAB ES UNA SECCIÓN DEL FORMULARIO -->
   <mat-tab-group [(selectedIndex)]="selectedTabIndex">
     <mat-tab *ngFor="let tab of configuration.tabs" [label]="tab.title">
 
+      <!-- // GRID DEL TAB: AQUI SE COLOCAN LOS ELEMENTOS SEGUN FILAS Y COLUMNAS -->
       <div class="grid" [style.gridTemplateColumns]="'repeat(' + tab.columns + ', 1fr)'" style="gap: 16px; padding: 16px;">
+
+        <!-- // CADA ELEMENTO DEL FORMULARIO: SE POSICIONA EN SU COLUMNA Y FILA -->
         <div *ngFor="let el of tab.elements" class="form-element"
              [style.gridColumnStart]="el.position.col + 1"
              [style.gridRowStart]="el.position.row + 1">
 
+          <!-- // LABEL DEL ELEMENTO -->
           <label [for]="el.element.name">{{ el.element.label }}</label>
 
+          <!-- // INPUTS SIMPLES: TEXTO, EMAIL, FECHA, NÚMERO -->
           <input *ngIf="['text', 'email', 'date', 'number'].includes(el.element.type)"
                  [attr.type]="el.element.type"
                  [formControlName]="el.element.name"
                  [attr.placeholder]="el.element.placeholder"
                  class="input-field" />
 
+          <!-- // TEXTAREA: SI EL ELEMENTO ES DE TIPO TEXTO GRANDE -->
           <textarea *ngIf="el.element.type === 'textarea'"
                     [formControlName]="el.element.name"
                     [attr.placeholder]="el.element.placeholder"
                     class="textarea-field"></textarea>
 
+          <!-- // SELECT: LISTA DESPLEGABLE -->
           <select *ngIf="el.element.type === 'select'" [formControlName]="el.element.name" class="select-field">
             <option *ngFor="let option of el.element.options" [value]="option">{{ option }}</option>
           </select>
 
+          <!-- // RADIO BUTTONS: OPCIONES MULTIPLES PERO SOLO SE PUEDE SELECCIONAR UNA -->
           <div *ngIf="el.element.type === 'radio'" class="radio-group">
             <label *ngFor="let option of el.element.options" class="radio-label">
               <input type="radio" [formControlName]="el.element.name" [value]="option" /> {{ option }}
             </label>
           </div>
 
+          <!-- // CHECKBOX: CASILLA DE VERIFICACIÓN, SE PUEDE MARCAR O NO -->
           <div *ngIf="el.element.type === 'checkbox'" class="checkbox-group">
             <input type="checkbox" [formControlName]="el.element.name" /> {{ el.element.label }}
           </div>
 
-          <!-- Validaciones simples -->
+          <!-- // VALIDACIONES SIMPLES: SOLO REQUIRED POR AHORA, SE MUESTRA SI EL USUARIO TOCÓ EL CAMPO -->
           <div class="error" *ngIf="form.controls[el.element.name].invalid && form.controls[el.element.name].touched">
-            <small *ngIf="form.controls[el.element.name].errors?.['required']">{{ el.element.label }} es requerido.</small>
+            <small *ngIf="form.controls[el.element.name].errors?.['required']">{{ el.element.label }} ES REQUERIDO.</small>
           </div>
 
         </div>
@@ -50,8 +57,9 @@
     </mat-tab>
   </mat-tab-group>
 
+  <!-- // BOTÓN DE ENVÍO: SOLO SE ACTIVA SI EL FORM ES VÁLIDO -->
   <div class="button-container">
-    <button type="submit" [disabled]="form.invalid" class="submit-button">Enviar</button>
+    <button type="submit" [disabled]="form.invalid" class="submit-button">ENVIAR</button>
   </div>
 
 </form>

+ 31 - 25
Front/src/app/modules/Administrador/pages/admin-form/dynamic-form-component/dynamic-form-component.component.ts

@@ -3,84 +3,90 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 import { ActivatedRoute } from '@angular/router';
 import { FormService } from './../../../services/FormService.service';
 
-
-// ESTE COMPONENTE ES EL PANEL PARA CARGAR LOS CAMPOS QUE SE VAN AGREGAR ES DECIR LOS INPUTS COMO DE TXT, RADIO BUTTON ETC...
+// ESTE COMPONENTE ES EL PANEL QUE GENERA LOS INPUTS DINÁMICOS: TEXTO, RADIO, CHECKBOX, SELECT, ETC.
 @Component({
   selector: 'app-dynamic-form-component',
   templateUrl: './dynamic-form-component.component.html',
   styleUrls: ['./dynamic-form-component.component.css']
 })
 export class DynamicFormComponentComponent implements OnInit, OnChanges {
-  @Input() formId?: string | number;  // Opcional porque puede venir por ruta o input
-  form!: FormGroup;
-  configuration: any;
-  selectedTabIndex = 0;
+
+  @Input() formId?: string | number;  // SI VIENE POR INPUT, USAMOS ESTE ID PARA CARGAR EL FORMULARIO
+  form!: FormGroup;                   // AQUÍ SE GUARDA EL FORMULARIO REACTIVO
+  configuration: any;                 // CONFIGURACIÓN DEL FORM QUE VIENE DEL SERVICIO
+  selectedTabIndex = 0;               // TAB ACTIVO, PARA SABER CUÁL MOSTRAR
+
   constructor(
-    private route: ActivatedRoute,
-    private formService: FormService,
-    private fb: FormBuilder
+    private route: ActivatedRoute,    // PARA LEER EL PARAMETRO DE LA RUTA SI NO VIENE POR INPUT
+    private formService: FormService, // SERVICIO PARA TRAER LA CONFIGURACIÓN DEL FORMULARIO
+    private fb: FormBuilder           // FORM BUILDER PARA CREAR EL FORM REACTIVO
   ) {}
 
   ngOnInit() {
-    // Solo si no hay formId por input, intento leer el parámetro ruta
+    // SI NO HAY FORM ID POR INPUT, INTENTO LEERLO DESDE LA RUTA
     if (!this.formId) {
       this.route.paramMap.subscribe(params => {
         const id = params.get('id');
         if (id) {
-          this.loadForm(+id);
+          this.loadForm(+id); // SI ENCUENTRA ID, CARGA EL FORMULARIO
         }
       });
     }
   }
 
   ngOnChanges(changes: SimpleChanges) {
+    // SI EL INPUT formId CAMBIA, CARGAMOS EL FORMULARIO NUEVAMENTE
     if (changes['formId'] && this.formId) {
       this.loadForm(this.formId);
     }
   }
 
+  // FUNCION PARA TRAER EL FORMULARIO DEL SERVICIO SEGÚN EL ID
   loadForm(id: string | number) {
     this.formService.getFormById(Number(id)).subscribe({
       next: (response) => {
         if (response.success) {
-          this.configuration = response.form.configuration;
-          this.buildForm();
+          this.configuration = response.form.configuration; // GUARDAMOS LA CONFIGURACIÓN
+          this.buildForm();                                  // Y CONSTRUIMOS EL FORM REACTIVO
         } else {
-          console.error('Formulario no encontrado');
+          console.error('FORMULARIO NO ENCONTRADO');
         }
       },
       error: (err) => {
-        console.error('Error al cargar formulario:', err);
+        console.error('ERROR AL CARGAR FORMULARIO:', err);
       }
     });
   }
 
+  // FUNCION PARA CREAR EL FORMULARIO DINÁMICAMENTE SEGÚN LA CONFIGURACIÓN
   buildForm() {
     if (!this.configuration || !this.configuration.tabs) {
-      console.error('Configuración inválida o vacía');
+      console.error('CONFIGURACIÓN INVÁLIDA O VACÍA');
       return;
     }
 
-    const group: any = {};
+    const group: any = {}; // AQUÍ SE GUARDAN LOS CONTROLES DEL FORM
 
+    // RECORREMOS CADA TAB Y CADA ELEMENTO PARA CREAR LOS CONTROLES
     this.configuration.tabs.forEach((tab: any) => {
       tab.elements.forEach((el: any) => {
-        const controlName = el.element.name;
-        const validators = el.element.required ? [Validators.required] : [];
-        group[controlName] = this.fb.control('', validators);
+        const controlName = el.element.name;                   // NOMBRE DEL CONTROL
+        const validators = el.element.required ? [Validators.required] : []; // VALIDACIONES
+        group[controlName] = this.fb.control('', validators);  // CREAMOS EL CONTROL
       });
     });
 
-    this.form = this.fb.group(group);
+    this.form = this.fb.group(group); // FORM REACTIVO LISTO
   }
 
+  // FUNCION QUE SE EJECUTA CUANDO EL USUARIO HACE SUBMIT
   onSubmit() {
     if (this.form.valid) {
-      console.log('Formulario enviado con datos:', this.form.value);
-      // Aquí podrías llamar al servicio para enviar los datos
+      console.log('FORMULARIO ENVIADO CON DATOS:', this.form.value);
+      // AQUÍ PODRÍAS LLAMAR AL SERVICIO PARA ENVIAR LOS DATOS
     } else {
-      console.log('Formulario inválido');
-      this.form.markAllAsTouched();
+      console.log('FORMULARIO INVÁLIDO');
+      this.form.markAllAsTouched(); // MARCA TODOS LOS CAMPOS COMO TOCADO PARA MOSTRAR ERRORES
     }
   }
 }

+ 20 - 3
Front/src/app/modules/Padres/pages/Registro/registro.component.ts

@@ -1212,26 +1212,32 @@ cargarFormulario() {
 }
 
 factura(event: any) {
-  const requiereFactura = event.value;
+  const requiereFactura = event.value; // Valor seleccionado: 'si' o 'no'
 
+  // Detecta si hubo un cambio real respecto al valor anterior
   const cambioReal = this.valorFacturaAnterior !== null && this.valorFacturaAnterior !== requiereFactura;
   this.valorFacturaAnterior = requiereFactura;
 
+  // Opciones para el template (ngIf, ngClass, etc.)
   this.opcionRequiereFaturaSi = requiereFactura === 'si';
   this.opcionRequiereFaturaNO = requiereFactura === 'no';
 
+  // Si hubo un cambio real y se había eliminado el archivo previamente
   if (cambioReal && this.archivoEliminado) {
-    this.obtenerDatosDesdeBD();
+    this.obtenerDatosDesdeBD(); // Recarga los datos originales de la BD
     this.archivoEliminado = false;
   }
 
+  // ========== CASO: NO REQUIERE FACTURA ==========
   if (requiereFactura === 'no') {
+    // Limpiar validadores
     this.form2.get('domicilioFactura')?.clearValidators();
     this.form2.get('correoFactura')?.clearValidators();
     this.form2.get('razonSocial')?.clearValidators();
     this.form2.get('RFCFactura')?.clearValidators();
     this.form2.get('metedoPago')?.clearValidators();
 
+    // Establecer valores por defecto
     this.form2.get('metedoPago')?.setValue('NA');
     this.form2.get('RFCFactura')?.setValue('NA');
     this.form2.get('razonSocial')?.setValue('NA');
@@ -1239,12 +1245,14 @@ factura(event: any) {
     this.form2.get('correoFactura')?.setValue('NA');
     this.form2.get('cuentaPago')?.setValue('NA');
 
+    // Limpiar archivo si no existe o fue eliminado
     if (this.archivoEliminado || !this.rutaArchivo || this.rutaArchivo.trim() === '') {
       this.form2.get('constanciaFiscal')?.setValue('');
       this.rutaArchivo = '';
       this.rutaArchivoOriginal = '';
     }
 
+    // Deshabilitar campos
     this.form2.get('domicilioFactura')?.disable();
     this.form2.get('correoFactura')?.disable();
     this.form2.get('razonSocial')?.disable();
@@ -1252,7 +1260,9 @@ factura(event: any) {
     this.form2.get('metedoPago')?.disable();
     this.form2.get('constanciaFiscal')?.disable();
 
+  // ========== CASO: REQUIERE FACTURA ==========
   } else {
+    // Habilitar campos
     this.form2.get('domicilioFactura')?.enable();
     this.form2.get('correoFactura')?.enable();
     this.form2.get('razonSocial')?.enable();
@@ -1260,6 +1270,7 @@ factura(event: any) {
     this.form2.get('metedoPago')?.enable();
     this.form2.get('constanciaFiscal')?.enable();
 
+    // Restaurar valores originales desde facturaDataOriginal
     this.form2.get('metedoPago')?.setValue(this.facturaDataOriginal?.metodoPago || '', { emitEvent: false });
     this.form2.get('RFCFactura')?.setValue(this.facturaDataOriginal?.RFC || '', { emitEvent: false });
     this.form2.get('razonSocial')?.setValue(this.facturaDataOriginal?.razonSocial || '', { emitEvent: false });
@@ -1268,11 +1279,13 @@ factura(event: any) {
     this.form2.get('cuentaPago')?.setValue(this.facturaDataOriginal?.cuenta || '', { emitEvent: false });
     this.form2.get('becaCurso')?.setValue(this.facturaDataOriginal?.cuenta || '', { emitEvent: false });
 
+    // Restaurar archivo si existe
     if (this.facturaDataOriginal?.archivo) {
       this.form2.get('constanciaFiscal')?.setValue(this.facturaDataOriginal.archivo, { emitEvent: false });
       this.rutaArchivo = this.facturaDataOriginal.archivo;
     }
 
+    // Establecer validadores
     this.form2.get('domicilioFactura')?.setValidators([Validators.required]);
     this.form2.get('correoFactura')?.setValidators([
       Validators.required,
@@ -1281,15 +1294,17 @@ factura(event: any) {
     this.form2.get('razonSocial')?.setValidators([Validators.required]);
     this.form2.get('RFCFactura')?.setValidators([Validators.required]);
     this.form2.get('metedoPago')?.setValidators([Validators.required]);
-     this.form2.get('constanciaFiscal')?.setValidators([Validators.required]);
+    this.form2.get('constanciaFiscal')?.setValidators([Validators.required]);
   }
 
+  // Asegurarse de limpiar el campo constanciaFiscal si es 'NA'
   if (this.form2.get('constanciaFiscal')?.value === 'NA') {
     this.form2.get('constanciaFiscal')?.setValue('');
     this.rutaArchivo = '';
     this.rutaArchivoOriginal = '';
   }
 
+  // Actualizar validez de todos los campos
   this.form2.get('domicilioFactura')?.updateValueAndValidity();
   this.form2.get('correoFactura')?.updateValueAndValidity();
   this.form2.get('razonSocial')?.updateValueAndValidity();
@@ -1297,9 +1312,11 @@ factura(event: any) {
   this.form2.get('metedoPago')?.updateValueAndValidity();
   this.form2.get('constanciaFiscal')?.updateValueAndValidity();
 
+  // Detectar cambios para refrescar la UI
   this.cdr.detectChanges();
 }
 
+
     siguienteTap(index: number) {
         if (this.form.invalid) {
             this.form.markAllAsTouched();