+
Gestión de Agrupaciones y Logos
-
+
@@ -127,11 +133,11 @@ export const AgrupacionesManager = () => {
handleInputChange(agrupacion.id, 'nombreCorto', e.target.value)} /> |
handleInputChange(agrupacion.id, 'color', e.target.value)} /> |
- handleLogoInputChange(agrupacion.id, e.target.value)}
+ handleLogoInputChange(agrupacion.id, e.target.value)}
/>
|
@@ -142,6 +148,7 @@ export const AgrupacionesManager = () => {
+
>
)}
diff --git a/Elecciones-Web/frontend-admin/src/components/FormStyles.css b/Elecciones-Web/frontend-admin/src/components/FormStyles.css
new file mode 100644
index 0000000..9b75fd6
--- /dev/null
+++ b/Elecciones-Web/frontend-admin/src/components/FormStyles.css
@@ -0,0 +1,72 @@
+/* src/components/FormStyles.css */
+
+.add-entity-form-container {
+ border-top: 2px solid #007bff;
+ padding-top: 1.5rem;
+ margin-top: 2rem;
+}
+
+.add-entity-form-container h4 {
+ margin-top: 0;
+ margin-bottom: 1rem;
+ color: #333;
+}
+
+.add-entity-form {
+ display: grid;
+ /* Usamos grid para un control preciso de las columnas */
+ grid-template-columns: 3fr 2fr 0.5fr auto;
+ gap: 1rem;
+ align-items: flex-end; /* Alinea los elementos en la parte inferior de la celda */
+}
+
+.form-field {
+ display: flex;
+ flex-direction: column;
+ margin-right: 15px;
+}
+
+.form-field label {
+ font-size: 0.85rem;
+ font-weight: 500;
+ margin-bottom: 0.25rem;
+ color: #555;
+ text-align: left;
+}
+
+.form-field input[type="text"] {
+ padding: 8px;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ font-size: 1rem;
+ width: 100%;
+}
+
+.form-field input[type="color"] {
+ height: 38px; /* Misma altura que los inputs de texto */
+ width: 100%;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+ padding: 4px; /* Padding interno para el color */
+}
+
+.add-entity-form button {
+ padding: 8px 16px;
+ height: 38px; /* Misma altura que los inputs */
+ border: none;
+ background-color: #28a745; /* Un color verde para la acción de "crear" */
+ color: white;
+ font-weight: bold;
+ border-radius: 4px;
+ cursor: pointer;
+ transition: background-color 0.2s;
+}
+
+.add-entity-form button:hover:not(:disabled) {
+ background-color: #218838;
+}
+
+.add-entity-form button:disabled {
+ background-color: #6c757d;
+ cursor: not-allowed;
+}
\ No newline at end of file
diff --git a/Elecciones-Web/frontend-admin/src/services/apiService.ts b/Elecciones-Web/frontend-admin/src/services/apiService.ts
index 9a83b0a..b5869c0 100644
--- a/Elecciones-Web/frontend-admin/src/services/apiService.ts
+++ b/Elecciones-Web/frontend-admin/src/services/apiService.ts
@@ -1,9 +1,11 @@
// src/services/apiService.ts
import axios from 'axios';
import { triggerLogout } from '../context/authUtils';
-import type { CandidatoOverride, AgrupacionPolitica,
+import type {
+ CandidatoOverride, AgrupacionPolitica,
UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria,
- MunicipioSimple, BancaPrevia, ProvinciaSimple } from '../types';
+ MunicipioSimple, BancaPrevia, ProvinciaSimple
+} from '../types';
/**
* URL base para las llamadas a la API.
@@ -29,8 +31,8 @@ const adminApiClient = axios.create({
// Cliente de API para endpoints públicos (no envía token)
const apiClient = axios.create({
- baseURL: API_URL_BASE,
- headers: { 'Content-Type': 'application/json' },
+ baseURL: API_URL_BASE,
+ headers: { 'Content-Type': 'application/json' },
});
@@ -60,26 +62,26 @@ adminApiClient.interceptors.response.use(
// --- INTERFACES PARA COMPOSICIÓN NACIONAL (NECESARIAS PARA EL NUEVO MÉTODO) ---
export interface PartidoComposicionNacional {
- id: string;
- nombre: string;
- nombreCorto: string | null;
- color: string | null;
- bancasFijos: number;
- bancasGanadas: number;
- bancasTotales: number;
- ordenDiputadosNacionales: number | null;
- ordenSenadoresNacionales: number | null;
+ id: string;
+ nombre: string;
+ nombreCorto: string | null;
+ color: string | null;
+ bancasFijos: number;
+ bancasGanadas: number;
+ bancasTotales: number;
+ ordenDiputadosNacionales: number | null;
+ ordenSenadoresNacionales: number | null;
}
export interface CamaraComposicionNacional {
- camaraNombre: string;
- totalBancas: number;
- bancasEnJuego: number;
- partidos: PartidoComposicionNacional[];
- presidenteBancada: { color: string | null; tipoBanca: 'ganada' | 'previa' | null } | null;
+ camaraNombre: string;
+ totalBancas: number;
+ bancasEnJuego: number;
+ partidos: PartidoComposicionNacional[];
+ presidenteBancada: { color: string | null; tipoBanca: 'ganada' | 'previa' | null } | null;
}
export interface ComposicionNacionalData {
- diputados: CamaraComposicionNacional;
- senadores: CamaraComposicionNacional;
+ diputados: CamaraComposicionNacional;
+ senadores: CamaraComposicionNacional;
}
@@ -173,22 +175,34 @@ export const updateLoggingLevel = async (data: UpdateLoggingLevelData): Promise<
// 9. Bancas Previas
export const getBancasPrevias = async (eleccionId: number): Promise
=> {
- const response = await adminApiClient.get(`/bancas-previas/${eleccionId}`);
- return response.data;
+ const response = await adminApiClient.get(`/bancas-previas/${eleccionId}`);
+ return response.data;
};
export const updateBancasPrevias = async (eleccionId: number, data: BancaPrevia[]): Promise => {
- await adminApiClient.put(`/bancas-previas/${eleccionId}`, data);
+ await adminApiClient.put(`/bancas-previas/${eleccionId}`, data);
};
// 10. Obtener Composición Nacional (Endpoint Público)
export const getComposicionNacional = async (eleccionId: number): Promise => {
- // Este es un endpoint público, por lo que usamos el cliente sin token de admin.
- const response = await apiClient.get(`/elecciones/${eleccionId}/composicion-nacional`);
- return response.data;
+ // Este es un endpoint público, por lo que usamos el cliente sin token de admin.
+ const response = await apiClient.get(`/elecciones/${eleccionId}/composicion-nacional`);
+ return response.data;
};
// Obtenemos las provincias para el selector de ámbito
export const getProvinciasForAdmin = async (): Promise => {
-const response = await adminApiClient.get('/catalogos/provincias');
-return response.data;
+ const response = await adminApiClient.get('/catalogos/provincias');
+ return response.data;
+};
+
+export interface CreateAgrupacionData {
+ nombre: string;
+ nombreCorto: string | null;
+ color: string | null;
+}
+
+// Servicio para crear una nueva agrupación
+export const createAgrupacion = async (data: CreateAgrupacionData): Promise => {
+ const response = await adminApiClient.post('/agrupaciones', data);
+ return response.data;
};
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs b/Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs
index 67ce109..3fed898 100644
--- a/Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs
+++ b/Elecciones-Web/src/Elecciones.Api/Controllers/AdminController.cs
@@ -417,4 +417,49 @@ public class AdminController : ControllerBase
_logger.LogInformation("Se actualizaron las bancas previas para la EleccionId: {EleccionId}", eleccionId);
return NoContent();
}
+
+ // Endpoint para crear una nueva agrupación política manualmente
+ [HttpPost("agrupaciones")]
+ public async Task CreateAgrupacion([FromBody] CreateAgrupacionDto agrupacionDto)
+ {
+ // 1. Validar si ya existe una agrupación con el mismo nombre para evitar duplicados
+ if (await _dbContext.AgrupacionesPoliticas.AnyAsync(a => a.Nombre == agrupacionDto.Nombre))
+ {
+ return BadRequest(new { message = $"Ya existe una agrupación con el nombre '{agrupacionDto.Nombre}'." });
+ }
+
+ // 2. Lógica para generar el nuevo ID a partir de 10000
+ var agrupacionesManualesIds = await _dbContext.AgrupacionesPoliticas
+ .Select(a => a.Id)
+ .ToListAsync();
+
+ int maxId = 9999; // Empezamos justo antes de 10000
+ foreach (var idStr in agrupacionesManualesIds)
+ {
+ if (int.TryParse(idStr, out int idNum) && idNum > maxId)
+ {
+ maxId = idNum;
+ }
+ }
+ int nuevoId = maxId + 1;
+
+ // 3. Crear la nueva entidad
+ var nuevaAgrupacion = new AgrupacionPolitica
+ {
+ Id = nuevoId.ToString(),
+ Nombre = agrupacionDto.Nombre,
+ NombreCorto = agrupacionDto.NombreCorto,
+ Color = agrupacionDto.Color,
+ IdTelegrama = $"MANUAL-{nuevoId}" // Asignamos un IdTelegrama distintivo
+ };
+
+ // 4. Guardar en la base de datos
+ await _dbContext.AgrupacionesPoliticas.AddAsync(nuevaAgrupacion);
+ await _dbContext.SaveChangesAsync();
+
+ _logger.LogInformation("Se creó una nueva agrupación manual: {Nombre} (ID: {Id})", nuevaAgrupacion.Nombre, nuevaAgrupacion.Id);
+
+ // 5. Devolver la entidad creada (buena práctica REST)
+ return Ok(nuevaAgrupacion);
+ }
}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
index 418c77a..0043616 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
@@ -14,7 +14,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5c11763386c5031abd33b743abc7508bddb1c9d6")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+99d56033b1a6c61db0f436c43e0d58d9a544cf53")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
index 42a086d..fc443fd 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
@@ -1 +1 @@
-{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","0wGwodjfj889i2s44QRDh9fS1bl2C5rnUPRORJGYKGU=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","fcHt1pC/7h4c2VRBtPGhHnv9Du3oNVywnesibd9Kv5U="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
+{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","QcSegZUKmWiZEM0Lb/6DeWnkj3Sf005BA6CwcKCfcn8=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","fuuUBrp2adKb2JTGKx6DlNAi3cvFULSlaTZ159rWB7w="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
index 9e7b2c3..ef2b40f 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
@@ -1 +1 @@
-{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","0wGwodjfj889i2s44QRDh9fS1bl2C5rnUPRORJGYKGU=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","fcHt1pC/7h4c2VRBtPGhHnv9Du3oNVywnesibd9Kv5U="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
+{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","J\u002Bfv/j3QyIW9bxolc46wDka8641F622/QgIllt0Re80=","Y/o0rakw9VYzEfz9M659qW77P9kvz\u002B2gTe1Lv3zgUDE=","8QWUReqP8upfOnmA5lMNgBxAfYJ1z3zv/WYBUXBEiog=","1L7p1HQI/Uoosqm7RyBuYjKbRFTycFgJEtHPSdlXWhU=","QcSegZUKmWiZEM0Lb/6DeWnkj3Sf005BA6CwcKCfcn8=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","fuuUBrp2adKb2JTGKx6DlNAi3cvFULSlaTZ159rWB7w="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Core/DTOs/ApiRequests/CreateAgrupacionDto.cs b/Elecciones-Web/src/Elecciones.Core/DTOs/ApiRequests/CreateAgrupacionDto.cs
new file mode 100644
index 0000000..685b1e1
--- /dev/null
+++ b/Elecciones-Web/src/Elecciones.Core/DTOs/ApiRequests/CreateAgrupacionDto.cs
@@ -0,0 +1,17 @@
+// src/Elecciones.Core/DTOs/ApiRequests/CreateAgrupacionDto.cs
+using System.ComponentModel.DataAnnotations;
+
+namespace Elecciones.Core.DTOs.ApiRequests;
+
+public class CreateAgrupacionDto
+{
+ [Required(ErrorMessage = "El nombre es obligatorio.")]
+ [MaxLength(255)]
+ public string Nombre { get; set; } = null!;
+
+ [MaxLength(50)]
+ public string? NombreCorto { get; set; }
+
+ [MaxLength(7)] // Formato #RRGGBB
+ public string? Color { get; set; }
+}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
index 0677474..0f3a3e3 100644
--- a/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5c11763386c5031abd33b743abc7508bddb1c9d6")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+99d56033b1a6c61db0f436c43e0d58d9a544cf53")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
index 1dafc9d..d28c50e 100644
--- a/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5c11763386c5031abd33b743abc7508bddb1c9d6")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+99d56033b1a6c61db0f436c43e0d58d9a544cf53")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
index 8dbb4e7..858d828 100644
--- a/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
-[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5c11763386c5031abd33b743abc7508bddb1c9d6")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+99d56033b1a6c61db0f436c43e0d58d9a544cf53")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]