diff --git a/cosiap_api/solicitudes/admin.py b/cosiap_api/solicitudes/admin.py
index 65dd70440b2232bca4686d9fbc17d7873a79c4f5..8fbecceb8131afec46d2a125ce9ca98ed4e366d8 100644
--- a/cosiap_api/solicitudes/admin.py
+++ b/cosiap_api/solicitudes/admin.py
@@ -1,8 +1,31 @@
from django.contrib import admin
from .models import Solicitud, Minuta, Convenio
-# Register your models here.
+class MinutaAdmin(admin.ModelAdmin):
+ # Definir los campos que serán mostrados en el administrador
+ list_display = ('id', 'archivo', 'get_formato')
+
+ # Campo solo lectura para `_formato`
+ readonly_fields = ('get_formato',)
+
+ def get_formato(self, obj):
+ return Minuta.get_formato()
+ get_formato.short_description = 'Formato Minuta'
+
+class ConvenioAdmin(admin.ModelAdmin):
+ # Definir los campos que serán mostrados en el administrador
+ list_display = ('id', 'archivo', 'get_formato')
+
+ # Campo solo lectura para `_formato`
+ readonly_fields = ('get_formato',)
+
+ def get_formato(self, obj):
+ return Convenio.get_formato()
+ get_formato.short_description = 'Formato Convenio'
+
+# Registrar los modelos en el administrador
+admin.site.register(Minuta, MinutaAdmin)
+admin.site.register(Convenio, ConvenioAdmin)
admin.site.register(Solicitud)
-admin.site.register(Minuta)
-admin.site.register(Convenio)
\ No newline at end of file
+
diff --git a/cosiap_api/solicitudes/models.py b/cosiap_api/solicitudes/models.py
index c7a10d112661aa450686aae69aff510e5d12f26c..d3a085dc6b5b2bfb1fdae4e9c9bd8d6e55c409a7 100644
--- a/cosiap_api/solicitudes/models.py
+++ b/cosiap_api/solicitudes/models.py
@@ -27,7 +27,7 @@ class Minuta(models.Model):
Devuelve el formato común de todas las instancias de Minuta.
'''
if cls._formato is None:
- formato_minuta = DynamicFormat.objects.filter(nombre="formato_minuta_defult").first()
+ formato_minuta = DynamicFormat.objects.filter(nombre="formato_minuta_default").first()
cls._formato = formato_minuta
return cls._formato
@@ -39,6 +39,21 @@ class Minuta(models.Model):
'''
cls._formato = value
+ def save(self, *args, **kwargs):
+ '''
+ Sobrescribe el método save para asegurarse de que el formato
+ se asigne al crear o actualizar la instancia.
+ '''
+ # Intenta encontrar el formato dinámico al guardar la instancia
+ formato_minuta = DynamicFormat.objects.filter(nombre="formato_minuta_default").first()
+ if formato_minuta:
+ self._formato = formato_minuta
+ else:
+ self._formato = None
+
+ # Llama al método save original
+ super(Minuta, self).save(*args, **kwargs)
+
def __str__(self):
return f'Minuta {self.pk}'
@@ -56,8 +71,8 @@ class Convenio(models.Model):
- *archivo*: Archivo del convenio.
Métodos:
- - *get_formato()*: Devuelve el formato común de todas las instancias de Minuta.
- - *set_formato(value)*: Establece el formato común para todas las instancias de Minuta.
+ - *get_formato()*: Devuelve el formato común de todas las instancias de Convenio.
+ - *set_formato(value)*: Establece el formato común para todas las instancias de Convenio.
'''
archivo = models.FileField(upload_to=nombre_archivo_convenio, validators=[validador_archivo_1MB, validador_pdf], verbose_name="Archivo")
# Atributo de clase común a todas las instancias
@@ -69,27 +84,43 @@ class Convenio(models.Model):
Devuelve el formato común de todas las instancias de Convenio.
'''
if cls._formato is None:
- formato_convenio = DynamicFormat.objects.filter(nombre="formato_convenio_defult").first()
+ formato_convenio = DynamicFormat.objects.filter(nombre="formato_convenio_default").first()
cls._formato = formato_convenio
return cls._formato
@classmethod
def set_formato(cls, value):
- '''Establece el formato común para todas las instancias de Minuta.
+ '''Establece el formato común para todas las instancias de Convenio.
Args:
- value: El nuevo valor del formato.
'''
cls._formato = value
+ def save(self, *args, **kwargs):
+ '''
+ Sobrescribe el método save para asegurarse de que el formato
+ se asigne al crear o actualizar la instancia.
+ '''
+ # Intenta encontrar el formato dinámico al guardar la instancia
+ formato_convenio = DynamicFormat.objects.filter(nombre="formato_convenio_default").first()
+ if formato_convenio:
+ self._formato = formato_convenio
+ else:
+ self._formato = None
+
+ # Llama al método save original
+ super(Convenio, self).save(*args, **kwargs)
+
def __str__(self):
- return f'Minuta {self.pk}'
+ return f'Convenio {self.pk}'
class Meta:
- verbose_name = "Minuta"
- verbose_name_plural = "Minutas"
+ verbose_name = "Convenio"
+ verbose_name_plural = "Convenios"
ordering = ['pk']
+
class Solicitud(models.Model):
"""
Modelo que contiene la información de referencia de una solicitud.
diff --git a/cosiap_frontend/src/App.jsx b/cosiap_frontend/src/App.jsx
index a5d5132de5110ed6d534924151482c934f466732..93d6d5528f515894eb4427f859b62f8180881aaa 100644
--- a/cosiap_frontend/src/App.jsx
+++ b/cosiap_frontend/src/App.jsx
@@ -28,6 +28,7 @@ import CreateModalidad from "./components/modalidades/CrearModalidad";
import EditModalidad from "./components/modalidades/EditarModalidad";
import SolicitarModalidad from "./components/modalidades/Modalidad";
import Perfil from '@/components/users/Perfil/Perfil';
+import ListaSolicitudes from "./components/solicitudes/HistorialSolicitudes";
function App() {
const [viewPageLoader, setViewPageLoader] = useState(false);
@@ -98,7 +99,7 @@ function RoutesApp({ setViewPageLoader }) {
element={}
/>
} />
- } />
+ } />
} />
} />
} />
diff --git a/cosiap_frontend/src/components/common/utility/ReusableTable.css b/cosiap_frontend/src/components/common/utility/ReusableTable.css
new file mode 100644
index 0000000000000000000000000000000000000000..a7f45157819fa5aa2ce902cc5901bf1afefc7654
--- /dev/null
+++ b/cosiap_frontend/src/components/common/utility/ReusableTable.css
@@ -0,0 +1,32 @@
+.table-container {
+ border-radius: 15px;
+ overflow: hidden;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ margin: 20px;
+ background-color: #fff;
+ }
+
+ .table {
+ width: 100%;
+ border-collapse: collapse;
+ }
+
+ .table th {
+ background-color: brown;
+ color: #fff;
+ padding: 12px;
+ text-align: left;
+ font-size: 16px;
+ }
+
+ .table td {
+ padding: 12px;
+ text-align: left;
+ font-size: 14px;
+ border-bottom: 1px solid #ddd;
+ }
+
+ .table tr:nth-child(even) {
+ background-color: #f9f9f9; /* Color para filas pares */
+ }
+
\ No newline at end of file
diff --git a/cosiap_frontend/src/components/common/utility/ReusableTable.jsx b/cosiap_frontend/src/components/common/utility/ReusableTable.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7cc44b19186eddec11e928ef36d1209706d0666c
--- /dev/null
+++ b/cosiap_frontend/src/components/common/utility/ReusableTable.jsx
@@ -0,0 +1,30 @@
+import '@/components/common/utility/ReusableTable.css'; // Asegúrate de que la ruta sea correcta
+
+const Tabla = ({ columnas, datos }) => {
+ return (
+
+
+
+
+ {columnas.map((columna, index) => (
+
{columna.label}
+ ))}
+
+
+
+ {datos.map((fila, index) => (
+
+ {columnas.map((columna, colIndex) => (
+
+ {columna.render(fila)}
+
+ ))}
+
+ ))}
+
+
+
+ );
+};
+
+export default Tabla;
\ No newline at end of file
diff --git a/cosiap_frontend/src/components/modalidades/Modalidad.css b/cosiap_frontend/src/components/modalidades/Modalidad.css
index 56eb7cafcb4c7108c69883c782bd2abce60b1ec6..e6111a16d8d88f791826c4ce1d57d7c4e9ec8df6 100644
--- a/cosiap_frontend/src/components/modalidades/Modalidad.css
+++ b/cosiap_frontend/src/components/modalidades/Modalidad.css
@@ -7,21 +7,25 @@
.file-input-class {
width: 100%;
padding: 10px;
+ color: rgb(0, 0, 0);
margin: 10px 0;
font-size: 16px;
- border: 1px solid #ccc;
+ border: 2px solid #555; /* Aumentamos el grosor y un color más oscuro */
border-radius: 4px;
box-sizing: border-box;
+ transition: border-color 0.3s ease;
}
+/* Efecto de enfoque (focus) para resaltarlos cuando el usuario interactúe */
.input-class:focus,
.textarea-class:focus,
.select-class:focus,
.date-input-class:focus,
.time-input-class:focus,
.file-input-class:focus {
- border-color: #4CAF50;
- outline: none;
+ border-color: #4CAF50; /* Cambia el color del borde al interactuar */
+ outline: none; /* Elimina el borde por defecto del navegador */
+ box-shadow: 0 0 5px rgba(76, 175, 80, 0.5); /* Efecto sutil de sombra verde */
}
/* Estilos para el textarea */
@@ -36,20 +40,49 @@
background-color: white;
}
-/* Estilos para grupos de casillas (checkbox) */
+/* Grupo de casillas: Mantener una distribución compacta */
.checkbox-group {
display: flex;
flex-wrap: wrap;
+ gap: 10px; /* Espacio entre las casillas */
}
+/* Etiquetas de las casillas */
.checkbox-label {
+ display: flex;
+ align-items: center;
margin-right: 15px;
+ font-size: 16px; /* Tamaño de texto estándar */
}
-.checkbox-label input {
- margin-right: 5px;
+/* Estilo personalizado para el checkbox */
+.checkbox-label input[type="checkbox"] {
+ width: 20px; /* Tamaño del checkbox */
+ height: 20px; /* Tamaño del checkbox */
+ margin-right: 5px; /* Espacio entre la casilla y el texto */
+ cursor: pointer;
+ border: 2px solid #333; /* Borde visible */
+ border-radius: 4px; /* Esquinas redondeadas */
+ appearance: none; /* Eliminar el estilo por defecto del navegador */
+ position: relative;
}
+/* Estilo cuando está seleccionado */
+.checkbox-label input[type="checkbox"]:checked {
+ background-color: #333; /* Fondo oscuro cuando está seleccionado */
+}
+
+/* Agregar un pseudo-elemento para el 'checkmark' */
+.checkbox-label input[type="checkbox"]:checked::after {
+ color: white;
+ font-size: 14px;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+
/* Estilos para el input de archivo */
.file-input-class {
cursor: pointer;
@@ -142,7 +175,7 @@
font-size: 1.8rem;
font-weight: bold;
margin-bottom: 10px;
- color: var(--secundario);
+ color: brown;
text-align: center;
}
@@ -198,7 +231,7 @@
font-size: 1.8rem;
font-weight: bold;
margin-bottom: 10px;
- color: var(--secundario);
+ color: brown;
text-align: center;
}
@@ -208,33 +241,32 @@
margin-top: 20px;
}
- /* Botones de acción */
- .buttons-container {
- display: flex;
- justify-content: center;
- gap: 20px;
- margin-top: 30px;
- }
-
- .button {
- background-color: var(--secundario);
- color: var(--blanco);
- font-weight: bold;
- padding: 10px 20px;
- border-radius: 10px;
- cursor: pointer;
- transition: background-color 0.3s ease;
- }
+/* Botones de acción */
+.buttons-container {
+ display: flex;
+ justify-content: space-between; /* Un botón a la izquierda, otro a la derecha */
+ width: 100%; /* El contenedor ocupa todo el ancho disponible */
+ margin-top: 20px;
+ padding: 0 40px; /* Espacio a los lados del contenedor, ajusta según lo necesites */
+ box-sizing: border-box; /* Asegura que el padding no afecte el ancho total */
+}
+
+.button, .submit-button {
+ background-color: var(--secundario);
+ color: var(--blanco);
+ font-weight: bold;
+ font-style: normal;
+ padding: 10px 20px;
+ border-radius: 10px;
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+}
+
+.submit-button {
+ background-color: #4CAF50;
+}
+
- .submit-button {
- background-color: #4CAF50;
- color: var(--blanco);
- font-weight: bold;
- padding: 10px 20px;
- border-radius: 10px;
- cursor: pointer;
- transition: background-color 0.3s ease;
- }
.button:hover {
diff --git a/cosiap_frontend/src/components/modalidades/Modalidad.jsx b/cosiap_frontend/src/components/modalidades/Modalidad.jsx
index 2a3bfd82ca46af101ad9930d0bc31560c136d2af..64378f43bffac55cdd6cc240ee99972fcf5cf783 100644
--- a/cosiap_frontend/src/components/modalidades/Modalidad.jsx
+++ b/cosiap_frontend/src/components/modalidades/Modalidad.jsx
@@ -306,8 +306,8 @@ const SolicitarModalidad = () => {
-