diff --git a/cosiap_frontend/src/api.js b/cosiap_frontend/src/api.js index 603a0e0ceb0b0ce0482088cb59b671452ddf7916..63b9f2eed48b7e8fdaf7c0bf04b83deffafc5f04 100644 --- a/cosiap_frontend/src/api.js +++ b/cosiap_frontend/src/api.js @@ -162,7 +162,8 @@ const api = { }, }, formatos: { - get: () => ax.get('api/plantillas') + get: () => ax.get('api/plantillas'), + getById: (id) => ax.get(`api/plantillas/download/${id}`,{ responseType: 'blob' }) } }; diff --git a/cosiap_frontend/src/components/common/utility/RenderElemento.jsx b/cosiap_frontend/src/components/common/utility/RenderElemento.jsx index 62ef2d121f95059abd9db2b3c1acbd5cd059d175..e6b4abeae40cf6e2c054f50c5211c76b9094851a 100644 --- a/cosiap_frontend/src/components/common/utility/RenderElemento.jsx +++ b/cosiap_frontend/src/components/common/utility/RenderElemento.jsx @@ -1,7 +1,8 @@ import '@/components/modalidades/Modalidad.css' +import api from "@/api"; export const renderElemento = (seccionId, elemento, handleInputChange, handleCheckboxChange) => { - const { tipo, opciones, id, nombre } = elemento; + const { tipo, opciones, id, nombre, formato } = elemento; const handleChange = (e) => { const valor = e.target.value; @@ -9,6 +10,48 @@ export const renderElemento = (seccionId, elemento, handleInputChange, handleChe handleInputChange(seccionId, id, valor); }; + const handleDownload = async (elemento, formato) => { + try { + // Realiza la petición al backend para obtener el archivo + const response = await api.formatos.getById(formato, { + responseType: 'blob', // Esto asegura que obtengas los datos como un archivo binario + }); + + // Verifica si el tipo de contenido es correcto + const contentType = response.headers['content-type']; + console.log('Content Type:', contentType); // Para depuración + + if (contentType !== 'application/vnd.openxmlformats-officedocument.wordprocessingml.document') { + throw new Error('Tipo de archivo inesperado'); + } + + // Crea un Blob a partir de los datos recibidos + const blob = new Blob([response.data], { type: contentType }); + + // Crea un URL para el archivo descargado + const url = window.URL.createObjectURL(blob); + + // Crea un enlace temporal + const link = document.createElement('a'); + link.href = url; + link.setAttribute('download', `${elemento.nombre}_formato.docx`); // Cambia a .docx + + // Añadir el enlace al cuerpo del documento para que sea visible en el navegador + document.body.appendChild(link); + + // En lugar de hacer clic en el enlace, solo configuramos el enlace + link.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window })); + + // Dejar el enlace en el DOM para que sea visible + // document.body.removeChild(link); // No eliminar el enlace si deseas que la descarga sea visible + + // Revoca el URL del blob para liberar memoria + window.URL.revokeObjectURL(url); + } catch (error) { + console.error('Error al descargar el formato:', error); + } + }; + switch (tipo) { case "texto_corto": @@ -74,18 +117,26 @@ export const renderElemento = (seccionId, elemento, handleInputChange, handleChe ))} ); - case "documento": + case "documento": return ( - handleInputChange(seccionId, id, e.target.files[0])} - /> +
+ handleInputChange(seccionId, id, e.target.files[0])} + /> + {formato && ( + + )} +
); case "fecha": return ( diff --git a/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx b/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx index b76498b4f69c6fef8e8b3987c84cdc374ab4da67..fb3ba54e1c7bc111e3529e9d6b5f121222e8b851 100644 --- a/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx +++ b/cosiap_frontend/src/components/modalidades/CrearModalidad.jsx @@ -17,6 +17,9 @@ const CreateModalidad = () => { const [sections, setSections] = useState([]); const [formatos, setFormatos] = useState([]); const navigate = useNavigate(); + // hooks para el manejo de las alertas + const [alertMessage, setAlertMessage] = useState(''); // Estado para el mensaje de alerta + const [isSuccess, setIsSuccess] = useState(false); // Obtener los formatos disponibles al cargar el componente useEffect(() => { @@ -110,6 +113,16 @@ const CreateModalidad = () => { setSections(newSections); }; + // metodo para mostrar una alerta + const showAlert = (message, isSuccess) => { + setAlertMessage(message); + setIsSuccess(isSuccess); + + setTimeout(() => { + setAlertMessage(''); + }, 3000); + }; + // manejar el orden de las peticiones creando un flujo correcto. const handleSubmit = async (e) => { @@ -180,14 +193,19 @@ const CreateModalidad = () => { }); navigate('/modalidades') } catch (error){ - console.error('Error al crear la modalidad.', error); - alert('Ocurrió un error al crear la modalidad.') + const errorMessage = 'Error al crear la modalidad, por favor complete o revise los datos.' + showAlert(`Error: ${errorMessage}`, false); } }; return(
- + {/* Alerta */} + {alertMessage && ( +
+ {alertMessage} +
+ )} {/* Card blanco para el formulario */}
diff --git a/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx b/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx index 6960bfa88574e0c04f0a8317a352dc6dfe5f437d..2b36492bbc5e47d92cd35f2db9260d15d9537f6a 100644 --- a/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx +++ b/cosiap_frontend/src/components/modalidades/EditarModalidad.jsx @@ -29,6 +29,9 @@ const EditModalidad = () => { const [newOptionName, setNewOptionName] = useState(''); const [selectedElementId, setSelectedElementId] = useState(null); const [isAddingOption, setIsAddingOption] = useState(false); + // hooks para el manejo de las alertas + const [alertMessage, setAlertMessage] = useState(''); // Estado para el mensaje de alerta + const [isSuccess, setIsSuccess] = useState(false); @@ -115,7 +118,7 @@ const EditModalidad = () => { const handleAddSection = async () => { try { if (!newSectionName) { - alert('Por favor, ingrese un nombre para la nueva sección.'); + showAlert('Por favor, ingrese un nombre para la nueva sección.', false); return; } @@ -132,9 +135,11 @@ const EditModalidad = () => { // Limpiar el input y ocultar el campo setNewSectionName(''); setIsAddingSection(false); + await handleSubmit(); + window.location.reload(); } catch (error) { console.error('Error al agregar la sección', error); - alert('Ocurrió un error al agregar la sección.'); + showAlert('Ocurrió un error al agregar la sección.', false); } }; @@ -143,7 +148,7 @@ const EditModalidad = () => { const handleAddElement = async (sectionId) => { try { if (!newElementName) { - alert('Por favor, ingrese un nombre para el nuevo elemento.'); + showAlert('Por favor, ingrese un nombre para el nuevo elemento.', false); return; } @@ -156,53 +161,23 @@ const EditModalidad = () => { await api.dynamicForms.secciones.postSectionElement(sectionId, response.data.data.id); - // Actualizar el estado para agregar el nuevo elemento a la sección - setSections(prevSections => { - const updatedSections = { ...prevSections }; - const section = updatedSections[sectionId]; - - if (!section) { - console.error('Sección no encontrada'); - return updatedSections; // No actualizamos si la sección no existe - } - - // Verificar que elementos sea un arreglo, inicializándolo si no lo es - if (!Array.isArray(section.elementos)) { - console.error('Elementos no es un arreglo, inicializando como un arreglo vacío.'); - section.elementos = []; // Asegurarse de que sea un arreglo - } - - // Agregar el nuevo elemento - const newElement = { - ...response.data.data, - opciones: [] // Asegurarnos que el nuevo elemento tenga un array vacío para opciones - }; - - // Asegurarse de que el nuevo elemento se agregue sin perder los existentes - section.elementos = [...section.elementos, newElement]; - - return updatedSections; - }); - // Limpiar el input y ocultar el campo setNewElementName(''); setSelectedSectionId(null); setIsAddingElement(false); await handleSubmit(); - sessionStorage.setItem('scrollPosition', window.scrollY); - window.location.reload(); - console.log(`Elemento "${newElementName}" agregado correctamente a la sección ${sectionId}.`); + window.location.reload(); } catch (error) { console.error('Error al agregar el elemento', error); - alert('Ocurrió un error al agregar el elemento.'); + showAlert('Ocurrió un error al agregar el elemento.', false); } }; // Agregamos una nueva opción a un elemento - const handleAddOption = async (sectionId, elementId) => { + const handleAddOption = async (elementId) => { try { if (!newOptionName) { - alert('Por favor, ingrese un nombre para la nueva opción.'); + showAlert('Por favor, ingrese un nombre para la nueva opción.', false); return; } @@ -213,45 +188,16 @@ const EditModalidad = () => { await api.dynamicForms.elementos.postElementOption(elementId, response.data.data.id); - // Actualizar el estado para agregar la nueva opción al elemento - setSections(prevSections => { - const updatedSections = { ...prevSections }; - const section = updatedSections[sectionId]; - - if (!section) { - console.error('Sección no encontrada'); - return updatedSections; // No actualizamos si la sección no existe - } - - const element = section.elementos[elementId] - if (!element) { - console.error('Elemento no encontrado'); - return updatedSections; // No actualizamos si el elemento no existe - } - - // Asegurarse de que opciones sea un arreglo, inicializándolo si no lo es - if (!Array.isArray(element.opciones)) { - console.error('Opciones no es un arreglo, inicializando como un arreglo vacío.'); - element.opciones = []; // Asegurarse de que sea un arreglo - } - - // Agregar la nueva opción manteniendo las existentes - element.opciones = [...element.opciones, response.data.data]; - - return updatedSections; // Devolver las secciones actualizadas - }); - // Limpiar el input y ocultar el campo setNewOptionName(''); setSelectedElementId(null); setIsAddingOption(false); await handleSubmit(); - sessionStorage.setItem('scrollPosition', window.scrollY); - window.location.reload(); - console.log(`Opción "${newOptionName}" agregada correctamente al elemento ${elementId}.`); + window.location.reload(); + } catch (error) { console.error('Error al agregar la opción', error); - alert('Ocurrió un error al agregar la opción.'); + showAlert('Ocurrió un error al agregar la opción.', false); } }; @@ -395,6 +341,16 @@ const EditModalidad = () => { }); }; + // metodo para mostrar una alerta + const showAlert = (message, isSuccess) => { + setAlertMessage(message); + setIsSuccess(isSuccess); + + setTimeout(() => { + setAlertMessage(''); + }, 3000); + }; + const handleSubmit = async (e) => { if (e) { @@ -505,11 +461,15 @@ const EditModalidad = () => { } await api.modalidades.update(id, formData); if (e) { - navigate('/modalidades'); + showAlert('Modalidad actualizada correctamente', true) + setTimeout(() => { + navigate('/modalidades'); + }, 1000); } + } catch (error) { - console.error('Error al actualizar la modalidad.', error); - alert('Ocurrió un error al actualizar la modalidad.'); + const errorMessage = 'Error al actualizar la modalidad, por favor complete o revise los datos.' + showAlert(`Error: ${errorMessage}`, false); } }; @@ -517,6 +477,12 @@ const EditModalidad = () => { return ( + {/* Alerta */} + {alertMessage && ( +
+ {alertMessage} +
+ )}
@@ -747,7 +713,7 @@ const EditModalidad = () => { /> diff --git a/cosiap_frontend/src/components/modalidades/Modalidad.css b/cosiap_frontend/src/components/modalidades/Modalidad.css index 105c714016f2516358ffde69dee68459773a0e70..56eb7cafcb4c7108c69883c782bd2abce60b1ec6 100644 --- a/cosiap_frontend/src/components/modalidades/Modalidad.css +++ b/cosiap_frontend/src/components/modalidades/Modalidad.css @@ -262,4 +262,31 @@ .error { background-color: #f44336; /* Rojo para error */ +} + + +.download-button { + display: inline-block; + padding: 10px 20px; + margin-top: 10px; + background-color: #955e3d; /* Color de fondo */ + color: white; /* Color del texto */ + text-align: center; + text-decoration: none; + font-size: 12px; + font-weight: bold; + border-radius: 5px; + transition: background-color 0.3s ease; +} + +.download-button:hover { + background-color: #45a049; /* Color de fondo al pasar el mouse */ +} + +.download-button:active { + background-color: #3e8e41; /* Color de fondo al hacer clic */ +} + +.download-button:focus { + outline: none; /* Elimina el borde de enfoque */ } \ No newline at end of file