diff --git a/cosiap_api/dynamic_tables/DynamicTable.py b/cosiap_api/dynamic_tables/DynamicTable.py index a8f7cbb0063d3ad568e5c5b23b30fa8122e0f53c..ca3343271e977f4f29595ad12bcb189fa374fe5e 100644 --- a/cosiap_api/dynamic_tables/DynamicTable.py +++ b/cosiap_api/dynamic_tables/DynamicTable.py @@ -198,6 +198,7 @@ class DynamicTable(serializers.ModelSerializer): field_path = column.split('__') field = model label = "" + for part in field_path: if field._meta.get_field(part).is_relation: field = field._meta.get_field(part).related_model @@ -208,30 +209,34 @@ class DynamicTable(serializers.ModelSerializer): else: label = part.capitalize() + # Inicializar lookups como un diccionario con valores nulos + lookups_dict = {lookup: None for lookup in []} + filter_info = { 'campo': column, 'label': label, 'html_type': '', - 'lookups': [], + 'lookups': lookups_dict, } + # Verificamos el tipo de campo actual para poder enviar los filtros disponibles # correctos según el tipo de campo, y el html_value correspondiente if isinstance(field, models.CharField) or isinstance(field, models.TextField): filter_info['html_type'] = 'textInput' - filter_info['lookups'] = ['icontains'] + filter_info['lookups'] = {'icontains': None} # verificamos si existen choices para crear un nuevo diccionario "exact" con las keys y values if field.choices: - filter_info['lookups'] = ['iexact'] + filter_info['lookups'] = {'iexact': None} filter_info['choices'] = [{'label': choice[1], 'value': choice[0]} for choice in field.choices] elif isinstance(field, models.IntegerField) or isinstance(field, models.FloatField) or isinstance(field, models.DecimalField): filter_info['html_type'] = 'numberInput' - filter_info['lookups'] = ['gt', 'lt'] + filter_info['lookups'] = {'gt': None, 'lt': None} elif isinstance(field, models.DateField) or isinstance(field, models.DateTimeField): filter_info['html_type'] = 'dateInput' - filter_info['lookups'] = ['gt', 'lt', 'gte', 'lte'] + filter_info['lookups'] = {'gt': None, 'lt': None, 'gte': None, 'lte': None} elif isinstance(field, models.BooleanField): filter_info['html_type'] = 'checkbox' - filter_info['lookups'] = ['iexact'] + filter_info['lookups'] = {'iexact': None} filter_info['choices'] = ['True', 'False'] available_filters.append(filter_info) @@ -239,6 +244,7 @@ class DynamicTable(serializers.ModelSerializer): return available_filters + @staticmethod def validate_and_clean_filters(request_data, available_filters): ''' diff --git a/cosiap_frontend/src/App.css b/cosiap_frontend/src/App.css index 61cc03bcd74ba8b63684cb059d233fe065e863d6..c6e36f4dcd91d178bc6098eb323da433fffcca6f 100644 --- a/cosiap_frontend/src/App.css +++ b/cosiap_frontend/src/App.css @@ -126,12 +126,18 @@ textarea { background-color: #696d69; color: white; border: none; - padding: 8px 12px; + padding: 12px 18px; /* Más espacio para alargar el botón */ font-size: 14px; border-radius: 16px; cursor: pointer; margin-top: 10px; margin-right: 10px; + + display: flex; /* Alinear el contenido del botón */ + align-items: center; + justify-content: center; + gap: 8px; /* Espacio entre el ícono y el texto */ + transition: background-color 0.3s ease; } .add-button:hover { @@ -225,13 +231,50 @@ input[type="checkbox"] { } .card { - border: 1px solid #ddd; - border-radius: 5px; - margin: 15px 0; - padding: 10px; - background-color: #f5f5f5; + border: 2px solid #b4756e; + border-radius: 12px; + margin: 20px 0; + padding: 15px; + background-color: #f1f1f1; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; +} + + +.card-header-section { + font-weight: bold; + font-size: 18px; + color: brown; /* Color verde oscuro para el título */ + margin-bottom: 10px; + border-bottom: 1px solid #6b1a08; /* Línea inferior */ + padding-bottom: 5px; +} + +.card-header-element { + font-weight: bold; + font-size: 16px; + color: brown; /* Color verde oscuro para el título */ + margin-bottom: 10px; + border-bottom: 1px solid #6b1a08; /* Línea inferior */ + padding-bottom: 5px; } +.card-header-option { + font-weight: bold; + font-size: 14px; + color: brown; /* Color verde oscuro para el título */ + margin-bottom: 10px; + border-bottom: 1px solid #6b1a08; /* Línea inferior */ + padding-bottom: 5px; +} + +.card-body { + padding: 10px 0; + font-size: 16px; + line-height: 1.6; /* Mejor legibilidad */ +} + + .element-card { border: 1px solid #ddd; border-radius: 5px; @@ -893,3 +936,4 @@ th, td { .confirm-delete-menu button:hover { opacity: 0.9; /* Efecto hover */ } + diff --git a/cosiap_frontend/src/components/admin/HistorialAdmin.jsx b/cosiap_frontend/src/components/admin/HistorialAdmin.jsx index 7f0b1105c7bdeff49f641f61714872e854c3063a..aa9232c3c91618746a5e596e08cc1881a912eaaf 100644 --- a/cosiap_frontend/src/components/admin/HistorialAdmin.jsx +++ b/cosiap_frontend/src/components/admin/HistorialAdmin.jsx @@ -101,7 +101,7 @@ const ListaSolicitudesSolicitante = () => {
) diff --git a/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx b/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx index b2b18e131a62105f9cd72fb2335cf8d67001d282..bbe75e5a543527bca93e3803df7fa13c15c108b1 100644 --- a/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx +++ b/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-key */ import { useState, useEffect } from "react"; import api from '../../api'; import '@/App.css'; @@ -191,7 +192,12 @@ const CreateModalidad = () => { 'Content-Type': 'multipart/form-data', }, }); - navigate('/modalidades') + if (e) { + showAlert('Modalidad creada correctamente.', true) + setTimeout(() => { + navigate('/modalidades'); + }, 1000); + } } catch (error){ const errorMessage = 'Error al crear la modalidad, por favor complete o revise los datos.' showAlert(`Error: ${errorMessage}`, false); @@ -281,16 +287,28 @@ const CreateModalidad = () => { onClick={addSection} className="add-button" > - (+) Sección + + + + + Sección {/* Creación de secciones */} + {sections.map((section, sectionIndex) => ( +
-

Sección {sectionIndex + 1}

+

Sección {sectionIndex + 1}

@@ -306,23 +324,35 @@ const CreateModalidad = () => { type="button" onClick={() => addElementToSection(sectionIndex)} className="add-button" + style={{ display: 'flex', alignItems: 'center', gap: '8px' }} > - (+) Elemento + + + + + Elemento
- {section.elements.map((element, elementIndex) => ( +
-

Elemento {elementIndex + 1}

+

Elemento {elementIndex + 1}

@@ -343,7 +373,17 @@ const CreateModalidad = () => { onClick={() => addOptionToElement(sectionIndex, elementIndex)} className="add-button" > - (+) Opción + + + + + Opción )} @@ -353,7 +393,8 @@ const CreateModalidad = () => { onClick={() => removeElementFromSection(sectionIndex, elementIndex)} className="delete-button" > - (-) Elemento + + Elemento
@@ -404,9 +445,10 @@ const CreateModalidad = () => { />
{['opcion_multiple', 'desplegable', 'casillas'].includes(element.type) && ( - <> -
Opciones:
+ <> {element.options.map((option, optionIndex) => ( +
+
Nueva opción:
@@ -425,18 +467,29 @@ const CreateModalidad = () => { onClick={() => removeOptionFromElement(sectionIndex, elementIndex, optionIndex)} className="delete-button" > - (-) Opción + + Opción
+
))} + )}
+ +
+ ))}
+ + + ))} + +
diff --git a/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx b/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx index f63a223d4e9750d42a96ffcf2cb2a9cd4fdd94d7..b67cec5f12b29fbae8ab59bc59db6307c0c7868d 100644 --- a/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx +++ b/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx @@ -561,7 +561,17 @@ const EditModalidad = () => { className="add-button" onClick={() => setIsAddingSection(true)} > - (+) Sección + + + + + Sección
@@ -593,7 +603,7 @@ const EditModalidad = () => { {Object.values(sections).map((section,sectionIndex) => (
-

Sección {sectionIndex + 1}

+

Sección {sectionIndex + 1}

{ setIsAddingElement(true); }} > - (+) Elemento + + + + + Elemento
{isAddingElement && selectedSectionId === section.id && ( @@ -682,10 +703,9 @@ const EditModalidad = () => {
)}
-
- {Object.values(section.elementos).map((element, elementIndex) => ( + {Object.values(section.elementos).map((element, elementIndex) => (
-

Elemento {elementIndex + 1}

+

Elemento {elementIndex + 1}

@@ -710,7 +730,17 @@ const EditModalidad = () => { setIsAddingOption(true); }} > - (+) Opción + + + + + Opción @@ -720,7 +750,8 @@ const EditModalidad = () => { className="delete-button" onClick={() => removeElementFromSectionAPI(section.id, element.id)} > - (-) Elemento + + Elemento
@@ -793,7 +824,7 @@ const EditModalidad = () => { {/* Opciones del elemento (si existen) */} {element.opciones && Object.values(element.opciones).map((option, optionIndex) => (
-

Opción {optionIndex +1}

+

Opción {optionIndex +1}

@@ -820,7 +852,6 @@ const EditModalidad = () => {
))}
-
))}
diff --git a/cosiap_frontend/src/components/solicitudes/HistorialSolicitudes.jsx b/cosiap_frontend/src/components/solicitudes/HistorialSolicitudes.jsx index c44f2af6734a4d2e89e6cef46e0660b697031449..5c9628135b9ba1e43ee058ff465a70f0cdb0b9df 100644 --- a/cosiap_frontend/src/components/solicitudes/HistorialSolicitudes.jsx +++ b/cosiap_frontend/src/components/solicitudes/HistorialSolicitudes.jsx @@ -100,12 +100,12 @@ const ListaSolicitudes = () => {
{fila.status === 'Pendiente' && ( )}