|
|
@@ -1,3 +1,4 @@
|
|
|
+import { FormApiService, FormConfiguration, FormListItem } from './../../services/FormApiService.service';
|
|
|
import { Component, OnInit } from '@angular/core';
|
|
|
import { EnviarInfoService } from '../../services/enviar-info.service';
|
|
|
|
|
|
@@ -23,257 +24,428 @@ interface FormElement {
|
|
|
description?: string;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
interface Tab {
|
|
|
id: string;
|
|
|
name: string;
|
|
|
active: boolean;
|
|
|
- rows: number; // Filas específicas de este tab
|
|
|
- columns: number; // Columnas específicas de este tab
|
|
|
+ rows: number;
|
|
|
+ columns: number;
|
|
|
grid: GridCell[][];
|
|
|
}
|
|
|
|
|
|
@Component({
|
|
|
selector: 'app-admin-form',
|
|
|
- templateUrl:'./admin-form.component.html',
|
|
|
+ templateUrl: './admin-form.component.html',
|
|
|
styleUrls: ['./admin-form.component.css']
|
|
|
})
|
|
|
export class AdminFormComponent implements OnInit {
|
|
|
- public color: string = '';
|
|
|
- public textColor: string = '';
|
|
|
+ color: string = '';
|
|
|
+ textColor: string = '';
|
|
|
formTitle: string = '';
|
|
|
|
|
|
- // Dimensiones por defecto para nuevos tabs
|
|
|
- defaultRows: number = 3;
|
|
|
- defaultColumns: number = 3;
|
|
|
+ // Nuevas propiedades para manejar formularios
|
|
|
+ currentFormId: number | null = null;
|
|
|
+ savedForms: FormListItem[] = [];
|
|
|
+ isLoading = false;
|
|
|
+ saveStatus = '';
|
|
|
|
|
|
- showTooltip: string = '';
|
|
|
+ defaultRows = 3;
|
|
|
+ defaultColumns = 3;
|
|
|
+ showTooltip = '';
|
|
|
|
|
|
- // Sistema de tabs
|
|
|
tabs: Tab[] = [];
|
|
|
currentTab: Tab | null = null;
|
|
|
-
|
|
|
- // Grid actual (del tab activo)
|
|
|
grid: GridCell[][] = [];
|
|
|
editingElement: FormElement | null = null;
|
|
|
|
|
|
- constructor(private _enviarInfo: EnviarInfoService) {}
|
|
|
+ showElementSelector = false;
|
|
|
+ selectedCell: GridCell | null = null;
|
|
|
+
|
|
|
+ availableElements: FormElement[] = [
|
|
|
+ { type: 'text', label: 'Texto Corto', required: false },
|
|
|
+ { type: 'number', label: 'Número', required: false },
|
|
|
+ { type: 'email', label: 'Correo Electrónico', required: false },
|
|
|
+ { type: 'date', label: 'Fecha', required: false },
|
|
|
+ { type: 'textarea', label: 'Texto Largo', required: false },
|
|
|
+ { type: 'select', label: 'Lista de Opciones', required: false, options: ['Opción 1'] },
|
|
|
+ { type: 'radio', label: 'Selección Única', required: false, options: ['A', 'B'] },
|
|
|
+ { type: 'checkbox', label: 'Casilla', required: false }
|
|
|
+ ];
|
|
|
+
|
|
|
+ constructor(
|
|
|
+ private _enviarInfo: EnviarInfoService,
|
|
|
+ private formApiService: FormApiService
|
|
|
+ ) {}
|
|
|
|
|
|
ngOnInit() {
|
|
|
- this._enviarInfo.currentTextColor.subscribe(textColor => {
|
|
|
- this.textColor = textColor;
|
|
|
+ this._enviarInfo.currentTextColor.subscribe(color => this.textColor = color);
|
|
|
+ this._enviarInfo.currentColor.subscribe(color => this.color = color);
|
|
|
+ this.addTab();
|
|
|
+ // this.loadSavedForms();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ saveForm() {
|
|
|
+ if (!this.formTitle.trim()) {
|
|
|
+ alert('Por favor, ingresa un título para el formulario');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.currentTab) {
|
|
|
+ this.currentTab.grid = [...this.grid];
|
|
|
+ }
|
|
|
+
|
|
|
+ const config = this.buildFormConfiguration();
|
|
|
+ this.isLoading = true;
|
|
|
+ this.saveStatus = 'Guardando...';
|
|
|
+
|
|
|
+ this.formApiService.createForm(config).subscribe({
|
|
|
+ next: (response) => {
|
|
|
+ console.log('Formulario guardado:', response);
|
|
|
+ this.currentFormId = response.id;
|
|
|
+ this.saveStatus = 'Formulario guardado exitosamente';
|
|
|
+ this.isLoading = false;
|
|
|
+
|
|
|
+ },
|
|
|
+ error: (error) => {
|
|
|
+ console.error('Error al guardar formulario:', error);
|
|
|
+ this.saveStatus = 'Error al guardar 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;
|
|
|
+ }
|
|
|
});
|
|
|
+ }
|
|
|
|
|
|
- this._enviarInfo.currentColor.subscribe(color => {
|
|
|
- this.color = color;
|
|
|
+ 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;
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ this.saveStatus = '';
|
|
|
+ }, 3000);
|
|
|
+ },
|
|
|
+ error: (error) => {
|
|
|
+ console.error('Error al publicar formulario:', error);
|
|
|
+ this.saveStatus = 'Error al publicar el formulario';
|
|
|
+ this.isLoading = false;
|
|
|
+ }
|
|
|
});
|
|
|
+ }
|
|
|
|
|
|
- // Crear el primer tab por defecto
|
|
|
- this.addTab();
|
|
|
+ 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)
|
|
|
+ }))
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 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]);
|
|
|
+ } else {
|
|
|
+ this.addTab();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 = '';
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ deleteForm(formId: number) {
|
|
|
+ if (!confirm('¿Estás seguro de que quieres eliminar este formulario? Esta acción no se puede deshacer.')) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Nota: Necesitarás agregar la ruta DELETE en tu API Laravel
|
|
|
+ // Por ahora, solo actualizar la lista
|
|
|
+ this.loadSavedForms();
|
|
|
+ }
|
|
|
+
|
|
|
+ // MÉTODOS EXISTENTES (sin cambios)
|
|
|
|
|
|
get rows(): number {
|
|
|
- return this.currentTab?.rows || this.defaultRows;
|
|
|
+ return this.currentTab?.rows ?? this.defaultRows;
|
|
|
}
|
|
|
|
|
|
get columns(): number {
|
|
|
- return this.currentTab?.columns || this.defaultColumns;
|
|
|
+ return this.currentTab?.columns ?? this.defaultColumns;
|
|
|
}
|
|
|
|
|
|
- // Métodos para manejo de tabs
|
|
|
- addTab(customRows?: number, customColumns?: number) {
|
|
|
- const newTabId = `tab_${this.tabs.length + 1}`;
|
|
|
- const tabRows = customRows || this.defaultRows;
|
|
|
- const tabColumns = customColumns || this.defaultColumns;
|
|
|
-
|
|
|
+ // TABS
|
|
|
+ addTab(rows = this.defaultRows, columns = this.defaultColumns) {
|
|
|
const newTab: Tab = {
|
|
|
- id: newTabId,
|
|
|
+ id: `tab_${this.tabs.length + 1}`,
|
|
|
name: `Sección ${this.tabs.length + 1}`,
|
|
|
active: false,
|
|
|
- rows: tabRows,
|
|
|
- columns: tabColumns,
|
|
|
- grid: this.buildNewGrid(tabRows, tabColumns)
|
|
|
+ rows,
|
|
|
+ columns,
|
|
|
+ grid: this.buildNewGrid(rows, columns)
|
|
|
};
|
|
|
-
|
|
|
this.tabs.push(newTab);
|
|
|
this.switchToTab(newTab);
|
|
|
}
|
|
|
|
|
|
- removeTab(index: number) {
|
|
|
- if (this.tabs.length === 1) return;
|
|
|
+ removeTab() {
|
|
|
+ if (this.tabs.length <= 1) return;
|
|
|
|
|
|
- const tabToRemove = this.tabs[index];
|
|
|
- this.tabs.splice(index, 1);
|
|
|
+ const activeIndex = this.tabs.findIndex(tab => tab.active);
|
|
|
+ if (activeIndex === -1) return;
|
|
|
|
|
|
- if (this.currentTab === tabToRemove) {
|
|
|
- this.switchToTab(this.tabs[0]);
|
|
|
- }
|
|
|
+ this.tabs.splice(activeIndex, 1);
|
|
|
+ const newActiveIndex = activeIndex === 0 ? 0 : activeIndex - 1;
|
|
|
+ this.tabs.forEach((tab, index) => {
|
|
|
+ tab.active = index === newActiveIndex;
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
switchToTab(tab: Tab) {
|
|
|
- // Guardar el grid actual en el tab anterior
|
|
|
- if (this.currentTab) {
|
|
|
- this.currentTab.grid = [...this.grid];
|
|
|
- }
|
|
|
-
|
|
|
- // Desactivar todos los tabs
|
|
|
+ if (this.currentTab) this.currentTab.grid = [...this.grid];
|
|
|
this.tabs.forEach(t => t.active = false);
|
|
|
-
|
|
|
- // Activar el tab seleccionado
|
|
|
tab.active = true;
|
|
|
this.currentTab = tab;
|
|
|
-
|
|
|
- // Cargar el grid del tab seleccionado
|
|
|
this.grid = [...tab.grid];
|
|
|
-
|
|
|
- // Limpiar selecciones
|
|
|
this.clearSelection();
|
|
|
}
|
|
|
|
|
|
- updateTabName(tab: Tab, newName: string) {
|
|
|
- tab.name = newName;
|
|
|
+ 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
|
|
|
+ }))
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
- // Actualizar dimensiones de un tab específico
|
|
|
updateTabDimensions(tab: Tab, newRows: number, newColumns: number) {
|
|
|
- const oldGrid = [...tab.grid];
|
|
|
+ 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);
|
|
|
|
|
|
- // Preservar elementos existentes si caben en las nuevas dimensiones
|
|
|
this.preserveElementsInNewGrid(oldGrid, tab.grid, newRows, newColumns);
|
|
|
|
|
|
- // Si es el tab activo, actualizar el grid actual
|
|
|
- if (this.currentTab === tab) {
|
|
|
- this.grid = [...tab.grid];
|
|
|
+ if (this.currentTab?.id === tab.id) {
|
|
|
+ this.grid = tab.grid.map(row => row.map(cell => ({ ...cell, element: cell.element ? { ...cell.element } : undefined })));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Preservar elementos al cambiar dimensiones
|
|
|
- private preserveElementsInNewGrid(oldGrid: GridCell[][], newGrid: GridCell[][], newRows: number, newColumns: number) {
|
|
|
- oldGrid.forEach(row => {
|
|
|
- row.forEach(cell => {
|
|
|
- if (cell.element && cell.row < newRows && cell.col < newColumns) {
|
|
|
- newGrid[cell.row][cell.col].element = cell.element;
|
|
|
+ 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 };
|
|
|
}
|
|
|
- });
|
|
|
- });
|
|
|
- }
|
|
|
-
|
|
|
- buildNewGrid(rows: number, columns: number): GridCell[][] {
|
|
|
- const newGrid: GridCell[][] = [];
|
|
|
- for(let r = 0; r < rows; r++) {
|
|
|
- const row: GridCell[] = [];
|
|
|
- for(let c = 0; c < columns; c++) {
|
|
|
- row.push({row: r, col: c, selected: false});
|
|
|
}
|
|
|
- newGrid.push(row);
|
|
|
}
|
|
|
- return newGrid;
|
|
|
+ }
|
|
|
+
|
|
|
+ onTabDimensionsChange(event: { tab: Tab, rows: number, columns: number }) {
|
|
|
+ this.updateTabDimensions(event.tab, event.rows, event.columns);
|
|
|
}
|
|
|
|
|
|
buildGrid() {
|
|
|
if (this.currentTab) {
|
|
|
- this.grid = this.buildNewGrid(this.currentTab.rows, this.currentTab.columns);
|
|
|
- this.currentTab.grid = [...this.grid];
|
|
|
+ this.currentTab.grid = this.grid = this.buildNewGrid(this.currentTab.rows, this.currentTab.columns);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Métodos de configuración JSON optimizados
|
|
|
- logConfiguration() {
|
|
|
- if (this.currentTab) {
|
|
|
- this.currentTab.grid = [...this.grid];
|
|
|
- }
|
|
|
+ verifyGridIntegrity(grid: GridCell[][]): boolean {
|
|
|
+ return grid.every((row, r) => row.every((cell, c) => {
|
|
|
+ cell.row = r;
|
|
|
+ cell.col = c;
|
|
|
+ return true;
|
|
|
+ }));
|
|
|
+ }
|
|
|
|
|
|
- const configuration = {
|
|
|
- title: this.formTitle,
|
|
|
- tabs: this.tabs.map(tab => this.serializeTab(tab))
|
|
|
- };
|
|
|
+ // FORM CONFIG
|
|
|
+ onFormTitleChange(title: string) {
|
|
|
+ this.formTitle = title;
|
|
|
+ }
|
|
|
|
|
|
- console.log('Configuración completa:', configuration);
|
|
|
- return configuration;
|
|
|
+ onRowsChange(rows: number) {
|
|
|
+ if (this.currentTab) this.updateTabDimensions(this.currentTab, rows, this.currentTab.columns);
|
|
|
}
|
|
|
|
|
|
- private serializeTab(tab: Tab) {
|
|
|
- return {
|
|
|
- id: tab.id,
|
|
|
- title: tab.name,
|
|
|
- rows: tab.rows,
|
|
|
- columns: tab.columns,
|
|
|
- elements: this.extractElementsFromGrid(tab.grid)
|
|
|
- };
|
|
|
+ onColumnsChange(cols: number) {
|
|
|
+ if (this.currentTab) this.updateTabDimensions(this.currentTab, this.currentTab.rows, cols);
|
|
|
}
|
|
|
|
|
|
- private extractElementsFromGrid(grid: GridCell[][]): any[] {
|
|
|
- const elements: any[] = [];
|
|
|
+ onShowTooltipChange(field: string) {
|
|
|
+ this.showTooltip = field;
|
|
|
+ }
|
|
|
|
|
|
- grid.forEach(row => {
|
|
|
- row.forEach(cell => {
|
|
|
- if (cell.element) {
|
|
|
- elements.push({
|
|
|
- position: {
|
|
|
- row: cell.row,
|
|
|
- col: cell.col
|
|
|
- },
|
|
|
- element: this.serializeElement(cell.element)
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
+ // SERIALIZACIÓN
|
|
|
+ logConfiguration() {
|
|
|
+ const config = this.buildFormConfiguration();
|
|
|
+ console.log('Configuración completa:', config);
|
|
|
+ return config;
|
|
|
+ }
|
|
|
|
|
|
- return elements;
|
|
|
+ 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!)
|
|
|
+ }))
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
- private serializeElement(element: FormElement): any {
|
|
|
- const serialized: any = {
|
|
|
- type: element.type,
|
|
|
- label: element.label,
|
|
|
- required: element.required
|
|
|
+ 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;
|
|
|
+ }
|
|
|
|
|
|
- if (element.placeholder) serialized.placeholder = element.placeholder;
|
|
|
- if (element.id) serialized.id = element.id;
|
|
|
- if (element.name) serialized.name = element.name;
|
|
|
- if (element.value) serialized.value = element.value;
|
|
|
- if (element.description) serialized.description = element.description;
|
|
|
-
|
|
|
- if (element.options && element.options.length > 0) {
|
|
|
- serialized.options = element.options;
|
|
|
- }
|
|
|
-
|
|
|
- if (element.min !== undefined) serialized.min = element.min;
|
|
|
- if (element.max !== undefined) serialized.max = element.max;
|
|
|
- if (element.pattern) serialized.pattern = element.pattern;
|
|
|
-
|
|
|
- return serialized;
|
|
|
+ // INTERACCIÓN CON CELDAS Y CAMPOS
|
|
|
+ selectCell(cell: GridCell) {
|
|
|
+ this.clearSelection();
|
|
|
+ cell.selected = true;
|
|
|
+ this.selectedCell = cell;
|
|
|
+ this.showElementSelector = true;
|
|
|
}
|
|
|
|
|
|
- // Eventos del panel de configuración
|
|
|
- onFormTitleChange(newTitle: string) {
|
|
|
- this.formTitle = newTitle;
|
|
|
+ clearSelection() {
|
|
|
+ this.grid.forEach(row => row.forEach(c => c.selected = false));
|
|
|
+ this.selectedCell = null;
|
|
|
+ this.showElementSelector = false;
|
|
|
+ this.editingElement = null;
|
|
|
}
|
|
|
|
|
|
- onRowsChange(newRows: number) {
|
|
|
- if (this.currentTab) {
|
|
|
- this.updateTabDimensions(this.currentTab, newRows, this.currentTab.columns);
|
|
|
+ addElementToCell(template: FormElement) {
|
|
|
+ if (!this.selectedCell || this.selectedCell.element) {
|
|
|
+ alert('Esta celda ya tiene un campo. Elimínalo primero.');
|
|
|
+ return;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- onColumnsChange(newCols: number) {
|
|
|
- if (this.currentTab) {
|
|
|
- this.updateTabDimensions(this.currentTab, this.currentTab.rows, newCols);
|
|
|
+ const element = { ...template };
|
|
|
+ element.id = `${this.currentTab?.id}_campo_${this.selectedCell.row}_${this.selectedCell.col}`;
|
|
|
+ element.name = element.id;
|
|
|
+
|
|
|
+ switch (element.type) {
|
|
|
+ case 'email':
|
|
|
+ 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 });
|
|
|
+ break;
|
|
|
+ case 'text':
|
|
|
+ Object.assign(element, {
|
|
|
+ required: true,
|
|
|
+ min: 1,
|
|
|
+ max: 20,
|
|
|
+ pattern: '^\\b(\\w+\\b\\s*){1,20}$'
|
|
|
+ });
|
|
|
+ break;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- onShowTooltipChange(field: string) {
|
|
|
- this.showTooltip = field;
|
|
|
+ this.selectedCell.element = element;
|
|
|
+ this.editingElement = element;
|
|
|
+ this.showElementSelector = false;
|
|
|
+ this.updateCurrentTabGrid();
|
|
|
}
|
|
|
|
|
|
- // Resto de métodos existentes...
|
|
|
- selectElementForEditing(cell: GridCell) {
|
|
|
- this.editingElement = cell.element || null;
|
|
|
+ updateCurrentTabGrid() {
|
|
|
+ if (this.currentTab) this.currentTab.grid = [...this.grid];
|
|
|
}
|
|
|
|
|
|
removeElementFromCell(cell: GridCell) {
|
|
|
@@ -281,62 +453,20 @@ export class AdminFormComponent implements OnInit {
|
|
|
this.updateCurrentTabGrid();
|
|
|
}
|
|
|
|
|
|
- updateCurrentTabGrid() {
|
|
|
- if (this.currentTab) {
|
|
|
- this.currentTab.grid = [...this.grid];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- clearSelection() {
|
|
|
- this.grid.forEach(row => row.forEach(c => c.selected = false));
|
|
|
- this.selectedCell = null;
|
|
|
- this.showElementSelector = false;
|
|
|
- this.editingElement = null;
|
|
|
- }
|
|
|
-
|
|
|
- // Propiedades existentes para el selector de elementos
|
|
|
- showElementSelector: boolean = false;
|
|
|
- selectedCell: GridCell | null = null;
|
|
|
-
|
|
|
- availableElements: FormElement[] = [
|
|
|
- { type: 'text', label: 'Texto Corto', required: false },
|
|
|
- { type: 'number', label: 'Número', required: false },
|
|
|
- { type: 'email', label: 'Correo Electrónico', required: false },
|
|
|
- { type: 'date', label: 'Fecha', required: false },
|
|
|
- { type: 'textarea', label: 'Texto Largo', required: false },
|
|
|
- { type: 'select', label: 'Lista de Opciones', required: false, options: ['Opción 1'] },
|
|
|
- { type: 'radio', label: 'Selección Única', required: false, options: ['A', 'B'] },
|
|
|
- { type: 'checkbox', label: 'Casilla', required: false }
|
|
|
- ];
|
|
|
-
|
|
|
- selectCell(cell: GridCell) {
|
|
|
- this.grid.forEach(row => row.forEach(c => c.selected = false));
|
|
|
- cell.selected = true;
|
|
|
- this.selectedCell = cell;
|
|
|
- this.showElementSelector = true;
|
|
|
+ selectElementForEditing(cell: GridCell) {
|
|
|
+ this.editingElement = cell.element || null;
|
|
|
}
|
|
|
|
|
|
- addElementToCell(element: FormElement) {
|
|
|
+ onEditingElementChange(updated: FormElement) {
|
|
|
if (this.selectedCell) {
|
|
|
- const cloned = { ...element };
|
|
|
- cloned.id = `${this.currentTab?.id}_campo_${this.selectedCell.row}_${this.selectedCell.col}`;
|
|
|
- cloned.name = cloned.id;
|
|
|
- this.selectedCell.element = cloned;
|
|
|
- this.showElementSelector = false;
|
|
|
- this.editingElement = cloned;
|
|
|
+ this.selectedCell.element = updated;
|
|
|
this.updateCurrentTabGrid();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- onEditingElementChange(updatedElement: FormElement) {
|
|
|
- if (!this.selectedCell) return;
|
|
|
- this.selectedCell.element = updatedElement;
|
|
|
- this.updateCurrentTabGrid();
|
|
|
- }
|
|
|
-
|
|
|
- onElementChange(updatedElement: FormElement) {
|
|
|
- if(this.editingElement) {
|
|
|
- Object.assign(this.editingElement, updatedElement);
|
|
|
+ onElementChange(updated: FormElement) {
|
|
|
+ if (this.editingElement) {
|
|
|
+ Object.assign(this.editingElement, updated);
|
|
|
this.updateCurrentTabGrid();
|
|
|
}
|
|
|
}
|