diff --git a/dependencias.txt b/dependencias.txt index 71e619d..cbb78ba 100644 --- a/dependencias.txt +++ b/dependencias.txt @@ -15,6 +15,7 @@ npm install @mui/joy npm install @mui/x-data-grid npm install @mui/x-charts npm install socket.io-client +npm install @mui/material @emotion/react @emotion/styled diff --git a/eslint.config.js b/eslint.config.js index ec2b712..ad2e3d9 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -2,6 +2,7 @@ import js from '@eslint/js' import globals from 'globals' import reactHooks from 'eslint-plugin-react-hooks' import reactRefresh from 'eslint-plugin-react-refresh' +import react from 'eslint-plugin-react' export default [ { ignores: ['dist'] }, @@ -17,17 +18,26 @@ export default [ }, }, plugins: { + 'react': react, 'react-hooks': reactHooks, 'react-refresh': reactRefresh, }, rules: { ...js.configs.recommended.rules, + ...react.configs.recommended.rules, ...reactHooks.configs.recommended.rules, 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], + 'react/react-in-jsx-scope': 'off', // innecesario en React 17+ + 'react/prop-types': 'off' // si no usás PropTypes porque usás TS }, + settings: { + react: { + version: 'detect' + } + } }, ] diff --git a/index.html b/index.html index 423ade5..e44571b 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + Redema diff --git a/package-lock.json b/package-lock.json index 11e720e..6d33e0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,10 +9,10 @@ "version": "0.0.0", "dependencies": { "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@mui/icons-material": "^7.1.1", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.5", "@mui/joy": "^5.0.0-beta.52", - "@mui/material": "^7.1.1", + "@mui/material": "^7.3.5", "@mui/x-charts": "^8.11.0", "@mui/x-data-grid": "^8.10.2", "@popperjs/core": "^2.11.8", @@ -276,9 +276,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", - "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -441,9 +441,9 @@ "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.14.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz", - "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==", + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -1951,9 +1951,9 @@ } }, "node_modules/@mui/core-downloads-tracker": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.1.1.tgz", - "integrity": "sha512-yBckQs4aQ8mqukLnPC6ivIRv6guhaXi8snVl00VtyojBbm+l6VbVhyTSZ68Abcx7Ah8B+GZhrB7BOli+e+9LkQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-7.3.5.tgz", + "integrity": "sha512-kOLwlcDPnVz2QMhiBv0OQ8le8hTCqKM9cRXlfVPL91l3RGeOsxrIhNRsUt3Xb8wb+pTVUolW+JXKym93vRKxCw==", "license": "MIT", "funding": { "type": "opencollective", @@ -1961,12 +1961,12 @@ } }, "node_modules/@mui/icons-material": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.1.1.tgz", - "integrity": "sha512-X37+Yc8QpEnl0sYmz+WcLFy2dWgNRzbswDzLPXG7QU1XDVlP5TPp1HXjdmCupOWLL/I9m1fyhcyZl8/HPpp/Cg==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-7.3.5.tgz", + "integrity": "sha512-LciL1GLMZ+VlzyHAALSVAR22t8IST4LCXmljcUSx2NOutgO2XnxdIp8ilFbeNf9wpo0iUFbAuoQcB7h+HHIf3A==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1" + "@babel/runtime": "^7.28.4" }, "engines": { "node": ">=14.0.0" @@ -1976,7 +1976,7 @@ "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^7.1.1", + "@mui/material": "^7.3.5", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -2182,22 +2182,22 @@ } }, "node_modules/@mui/material": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.1.1.tgz", - "integrity": "sha512-mTpdmdZCaHCGOH3SrYM41+XKvNL0iQfM9KlYgpSjgadXx/fEKhhvOktxm8++Xw6FFeOHoOiV+lzOI8X1rsv71A==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz", + "integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "@mui/core-downloads-tracker": "^7.1.1", - "@mui/system": "^7.1.1", - "@mui/types": "^7.4.3", - "@mui/utils": "^7.1.1", + "@babel/runtime": "^7.28.4", + "@mui/core-downloads-tracker": "^7.3.5", + "@mui/system": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.12", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1", - "react-is": "^19.1.0", + "react-is": "^19.2.0", "react-transition-group": "^4.4.5" }, "engines": { @@ -2210,7 +2210,7 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@mui/material-pigment-css": "^7.1.1", + "@mui/material-pigment-css": "^7.3.5", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2231,13 +2231,13 @@ } }, "node_modules/@mui/private-theming": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.1.1.tgz", - "integrity": "sha512-M8NbLUx+armk2ZuaxBkkMk11ultnWmrPlN0Xe3jUEaBChg/mcxa5HWIWS1EE4DF36WRACaAHVAvyekWlDQf0PQ==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-7.3.5.tgz", + "integrity": "sha512-cTx584W2qrLonwhZLbEN7P5pAUu0nZblg8cLBlTrZQ4sIiw8Fbvg7GvuphQaSHxPxrCpa7FDwJKtXdbl2TSmrA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "@mui/utils": "^7.1.1", + "@babel/runtime": "^7.28.4", + "@mui/utils": "^7.3.5", "prop-types": "^15.8.1" }, "engines": { @@ -2258,13 +2258,13 @@ } }, "node_modules/@mui/styled-engine": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.1.1.tgz", - "integrity": "sha512-R2wpzmSN127j26HrCPYVQ53vvMcT5DaKLoWkrfwUYq3cYytL6TQrCH8JBH3z79B6g4nMZZVoaXrxO757AlShaw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-7.3.5.tgz", + "integrity": "sha512-zbsZ0uYYPndFCCPp2+V3RLcAN6+fv4C8pdwRx6OS3BwDkRCN8WBehqks7hWyF3vj1kdQLIWrpdv/5Y0jHRxYXQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "@emotion/cache": "^11.13.5", + "@babel/runtime": "^7.28.4", + "@emotion/cache": "^11.14.0", "@emotion/serialize": "^1.3.3", "@emotion/sheet": "^1.4.0", "csstype": "^3.1.3", @@ -2292,16 +2292,16 @@ } }, "node_modules/@mui/system": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.1.1.tgz", - "integrity": "sha512-Kj1uhiqnj4Zo7PDjAOghtXJtNABunWvhcRU0O7RQJ7WOxeynoH6wXPcilphV8QTFtkKaip8EiNJRiCD+B3eROA==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-7.3.5.tgz", + "integrity": "sha512-yPaf5+gY3v80HNkJcPi6WT+r9ebeM4eJzrREXPxMt7pNTV/1eahyODO4fbH3Qvd8irNxDFYn5RQ3idHW55rA6g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.1", - "@mui/private-theming": "^7.1.1", - "@mui/styled-engine": "^7.1.1", - "@mui/types": "^7.4.3", - "@mui/utils": "^7.1.1", + "@babel/runtime": "^7.28.4", + "@mui/private-theming": "^7.3.5", + "@mui/styled-engine": "^7.3.5", + "@mui/types": "^7.4.8", + "@mui/utils": "^7.3.5", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -2332,12 +2332,12 @@ } }, "node_modules/@mui/types": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.5.tgz", - "integrity": "sha512-ZPwlAOE3e8C0piCKbaabwrqZbW4QvWz0uapVPWya7fYj6PeDkl5sSJmomT7wjOcZGPB48G/a6Ubidqreptxz4g==", + "version": "7.4.8", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.4.8.tgz", + "integrity": "sha512-ZNXLBjkPV6ftLCmmRCafak3XmSn8YV0tKE/ZOhzKys7TZXUiE0mZxlH8zKDo6j6TTUaDnuij68gIG+0Ucm7Xhw==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.28.2" + "@babel/runtime": "^7.28.4" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -2349,17 +2349,17 @@ } }, "node_modules/@mui/utils": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.1.tgz", - "integrity": "sha512-/31y4wZqVWa0jzMnzo6JPjxwP6xXy4P3+iLbosFg/mJQowL1KIou0LC+lquWW60FKVbKz5ZUWBg2H3jausa0pw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-7.3.5.tgz", + "integrity": "sha512-jisvFsEC3sgjUjcPnR4mYfhzjCDIudttSGSbe1o/IXFNu0kZuR+7vqQI0jg8qtcVZBHWrwTfvAZj9MNMumcq1g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.28.2", - "@mui/types": "^7.4.5", + "@babel/runtime": "^7.28.4", + "@mui/types": "^7.4.8", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^19.1.1" + "react-is": "^19.2.0" }, "engines": { "node": ">=14.0.0" @@ -5081,9 +5081,9 @@ } }, "node_modules/react-is": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", - "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.0.tgz", + "integrity": "sha512-x3Ax3kNSMIIkyVYhWPyO09bu0uttcAIoecO/um/rKGQ4EltYWVYtyiGkS/3xMynrbVQdS69Jhlv8FXUEZehlzA==", "license": "MIT" }, "node_modules/react-leaflet": { diff --git a/package.json b/package.json index 1aa8817..d1ec27c 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,10 @@ }, "dependencies": { "@emotion/react": "^11.14.0", - "@emotion/styled": "^11.14.0", - "@mui/icons-material": "^7.1.1", + "@emotion/styled": "^11.14.1", + "@mui/icons-material": "^7.3.5", "@mui/joy": "^5.0.0-beta.52", - "@mui/material": "^7.1.1", + "@mui/material": "^7.3.5", "@mui/x-charts": "^8.11.0", "@mui/x-data-grid": "^8.10.2", "@popperjs/core": "^2.11.8", diff --git a/public/404.png b/public/404.png new file mode 100644 index 0000000..6aaccee Binary files /dev/null and b/public/404.png differ diff --git a/src/components/Editar/editar.jsx b/src/components/Editar/editar.jsx index 067e6ca..e54f7af 100644 --- a/src/components/Editar/editar.jsx +++ b/src/components/Editar/editar.jsx @@ -8,7 +8,7 @@ import { useEffect, useState } from 'react'; import { MapContainer, TileLayer, Marker, useMapEvents } from 'react-leaflet'; import CssBaseline from '@mui/material/CssBaseline'; -import Box from '@mui/material/Box'; +import Box from '@mui/material/Box'; import Container from '@mui/material/Container'; import * as React from 'react'; @@ -16,7 +16,7 @@ import Button from '@mui/joy/Button'; import Input from '@mui/joy/Input'; import Textarea from '@mui/joy/Textarea'; import ToggleButtonGroup from '@mui/joy/ToggleButtonGroup'; -import Select, { selectClasses } from '@mui/joy/Select'; +import Select from '@mui/joy/Select'; import Option from '@mui/joy/Option'; import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown'; import Autocomplete from '@mui/joy/Autocomplete'; @@ -28,13 +28,17 @@ import Typography from '@mui/joy/Typography'; import { styled } from '@mui/joy'; import { getAuth } from "firebase/auth"; - import { useNavigate, useParams} from 'react-router-dom'; - import CircularProgress from '@mui/material/CircularProgress'; - import { mostrarAlerta } from '../../utils/confirmservice.js'; +const TITULOS_AMIGABLES = { + "Adopción": "¡Busco un hogar!", + "Pérdida": "¡Me perdí!", + "Encuentro": "¡Me encontraron!", + "Estado crítico": "¡Necesito ayuda urgente!" +}; + const VisuallyHiddenInput = styled('input')` clip: rect(0 0 0 0); clip-path: inset(50%); @@ -76,9 +80,18 @@ function MapaInteractivo({ lat, lng, setLatLng }) { } export default function Editar() { + // --- 1. CORRECCIÓN DE URL (NORMALIZACIÓN) --- + const RAW_URL = import.meta.env.VITE_API_URL; + const API_URL = RAW_URL.endsWith('/') ? RAW_URL : `${RAW_URL}/`; + + const navigate = useNavigate(); + const { id_publicacion } = useParams(); + const [titulo, setTitulo] = useState(''); const [descripcion, setDescripcion] = useState(''); - const [seleccionado, setSeleccionado] = useState(''); + const [categoriasDisponibles, setCategoriasDisponibles] = useState([]); + const [seleccionado, setSeleccionado] = useState(null); + const [provincias, setProvincias] = useState([]); const [departamentos, setDepartamentos] = useState([]); const [localidades, setLocalidades] = useState([]); @@ -88,18 +101,16 @@ export default function Editar() { const [coordenadas, setCoordenadas] = useState({ lat: 0, lng: 0 }); const [etiquetas, setEtiquetas] = useState([]); const [etiquetasSeleccionadas, setEtiquetasSeleccionadas] = useState([]); - const [imagenesSeleccionadas, setImagenesSeleccionadas] = useState([]); + const [imagenesSeleccionadas, setImagenesSeleccionadas] = useState([]); + const [imagenesExistentes, setImagenesExistentes] = useState([]); const [errores, setErrores] = useState([]); - const { id_publicacion } = useParams(); + const [etiquetasDesdePublicacion, setEtiquetasDesdePublicacion] = useState([]); - const [imagenesExistentes, setImagenesExistentes] = useState([]); const [cargando, setCargando] = useState(false); - const navigate = useNavigate(); - const validarCampos = () => { const nuevosErrores = []; - if (!seleccionado) nuevosErrores.push("Categoría"); + if (seleccionado === null || seleccionado === "") nuevosErrores.push("Categoría"); if (!titulo.trim()) nuevosErrores.push("Título"); if (!descripcion.trim()) nuevosErrores.push("Descripción"); if (descripcion.length > 500) nuevosErrores.push("Descripción excede 500 caracteres"); @@ -111,61 +122,75 @@ export default function Editar() { return nuevosErrores; }; - const camposValidos = (campo) => !errores.includes(campo); + // Cargas iniciales - CORREGIDO: Quitar barra inicial + useEffect(() => { + fetch(`${API_URL}api/categorias`) + .then(res => res.json()) + .then(data => setCategoriasDisponibles(data)) + .catch(console.error); + }, [API_URL]); useEffect(() => { - fetch('http://localhost:5000/api/ubicacion/provincias') + fetch(`${API_URL}api/ubicacion/provincias`) .then(res => res.json()) .then(setProvincias) .catch(console.error); - }, []); + }, [API_URL]); useEffect(() => { if (provinciaId) { - fetch(`http://localhost:5000/api/ubicacion/departamentos?provincia_id=${provinciaId}`) + fetch(`${API_URL}api/ubicacion/departamentos?provincia_id=${provinciaId}`) .then(res => res.json()) .then(setDepartamentos); } else { setDepartamentos([]); setDepartamentoId(''); } - }, [provinciaId]); + }, [provinciaId, API_URL]); useEffect(() => { if (departamentoId) { - fetch(`http://localhost:5000/api/ubicacion/localidades?departamento_id=${departamentoId}`) + fetch(`${API_URL}api/ubicacion/localidades?departamento_id=${departamentoId}`) .then(res => res.json()) .then(setLocalidades); } else { setLocalidades([]); setLocalidadId(''); } - }, [departamentoId]); + }, [departamentoId, API_URL]); + // CORREGIDO: Etiquetas sin redirección useEffect(() => { - fetch('http://localhost:5000/api/etiquetas') + fetch(`${API_URL}api/etiquetas`) .then(res => res.json()) .then(data => { const mapped = data.map(e => ({ label: e.nombre, id: e.id })); setEtiquetas(mapped); }); - }, []); + }, [API_URL]); + // Cargar Publicación - CORREGIDO: Quitar barra inicial useEffect(() => { const fetchDatosPublicacion = async () => { try { - const res = await fetch(`http://localhost:5000/publicaciones/${id_publicacion}`); + const res = await fetch(`${API_URL}publicaciones/${id_publicacion}`); if (!res.ok) throw new Error("No se pudo obtener la publicación"); const data = await res.json(); setTitulo(data.titulo || ''); setDescripcion(data.descripcion || ''); - setSeleccionado(data.categoria || ''); + + if (data.categoria && typeof data.categoria === 'object') { + setSeleccionado(data.categoria.id); + } else if (typeof data.categoria === 'number') { + setSeleccionado(data.categoria); + } + if (data.coordenadas && Array.isArray(data.coordenadas)) { setCoordenadas({ lat: parseFloat(data.coordenadas[0]), lng: parseFloat(data.coordenadas[1]) }); } if (data.id_locacion) { - const resLoc = await fetch(`http://localhost:5000/api/ubicacion/localidades/${data.id_locacion}`); + const resLoc = await fetch(`${API_URL}api/ubicacion/localidades/${data.id_locacion}`); if (resLoc.ok) { const localidad = await resLoc.json(); setProvinciaId(localidad.id_provincia.toString()); @@ -174,7 +199,6 @@ export default function Editar() { } } - // Guardamos los nombres de las etiquetas if (Array.isArray(data.etiquetas)) { setEtiquetasDesdePublicacion(data.etiquetas); } @@ -191,7 +215,7 @@ export default function Editar() { if (id_publicacion) { fetchDatosPublicacion(); } - }, [id_publicacion]); + }, [id_publicacion, API_URL]); useEffect(() => { if (etiquetas.length > 0 && etiquetasDesdePublicacion.length > 0) { @@ -212,10 +236,41 @@ export default function Editar() { }; const handleImagenesChange = (event) => { - const files = Array.from(event.target.files); - setImagenesSeleccionadas(files); + const archivos = Array.from(event.target.files); + const totalActuales = imagenesExistentes.length + imagenesSeleccionadas.length; + const disponibles = 5 - totalActuales; + + if (disponibles <= 0) { + mostrarAlerta({ + titulo: "Límite alcanzado", + mensaje: "Ya tienes el máximo de 5 imágenes.", + tipo: "warning" + }); + return; + } + if (archivos.length > disponibles) { + mostrarAlerta({ + titulo: "Demasiadas imágenes", + mensaje: `Solo puedes agregar ${disponibles} imagen(es) más.`, + tipo: "warning" + }); + event.target.value = ""; + return; + } + setImagenesSeleccionadas(prev => [...prev, ...archivos]); + + event.target.value = ""; + }; + + const eliminarImagenExistente = (index) => { + setImagenesExistentes(prev => prev.filter((_, i) => i !== index)); + }; + + const eliminarImagenNueva = (index) => { + setImagenesSeleccionadas(prev => prev.filter((_, i) => i !== index)); }; + const handlePublicar = async () => { const nuevosErrores = validarCampos(); setErrores(nuevosErrores); @@ -223,7 +278,7 @@ export default function Editar() { setCargando(true); try { - let urlsImagenes = [...imagenesExistentes]; // imágenes previas + let urlsImagenes = [...imagenesExistentes]; if (imagenesSeleccionadas.length > 0) { const formData = new FormData(); @@ -231,7 +286,7 @@ export default function Editar() { formData.append("imagenes", img); }); - const resImagenes = await fetch("http://localhost:5000/subir-imagenes", { + const resImagenes = await fetch(`${API_URL}subir-imagenes`, { method: "POST", body: formData, }); @@ -242,28 +297,26 @@ export default function Editar() { urlsImagenes = [...urlsImagenes, ...dataImagenes.urls]; } - const datos = { - categoria: seleccionado, + id_categoria: seleccionado, titulo, descripcion, id_locacion: localidadId, coordenadas: [parseFloat(coordenadas.lat), parseFloat(coordenadas.lng)], etiquetas: etiquetasSeleccionadas.map(e => e.id), - imagenes: urlsImagenes + imagenes: urlsImagenes }; - const auth = getAuth(); const user = auth.currentUser; if (!user) { - alert("Debés iniciar sesión para publicar"); + alert("Debes iniciar sesión para publicar"); setCargando(false); return; } const token = await user.getIdToken(); - const res = await fetch(`http://localhost:5000/publicaciones/${id_publicacion}`, { + const res = await fetch(`${API_URL}publicaciones/${id_publicacion}`, { method: "PATCH", headers: { "Content-Type": "application/json", @@ -274,10 +327,10 @@ export default function Editar() { const data = await res.json(); if (res.ok) { - console.log("Publicación modificada:", data); + console.log("Publicación editada:", data); mostrarAlerta({ titulo: '¡Listo!', - mensaje: 'Publicación modificada con éxito', + mensaje: 'Publicación editada con éxito', tipo: 'success' }); navigate(`/publicacion/${id_publicacion}`); @@ -288,57 +341,106 @@ export default function Editar() { console.error("Error al publicar:", error); mostrarAlerta({ titulo: 'Error', - mensaje: 'Ocurrió un error al publicar', + mensaje: 'Ocurrió un error al editar la publicación.', tipo: 'error' }); }finally { - setCargando(false); // 🔹 siempre reactivar al terminar + setCargando(false); } }; + const totalImagenes = imagenesExistentes.length + imagenesSeleccionadas.length; + const estaLleno = totalImagenes >= 5; + return ( - + Editar Publicación + {/* --- Texto de Categoría --- */} + + Categoría + + setSeleccionado(newValue)} + value={seleccionado !== null ? String(seleccionado) : null} + onChange={(event, newValue) => { + if(newValue !== null) setSeleccionado(Number(newValue)); + }} sx={{ my: 2, gap: 1, flexWrap: 'wrap' }} - exclusive + type="single" > - {["Adopción", "Búsqueda", "Encuentro", "Estado Crítico"].map(opcion => ( - - ))} + {categoriasDisponibles.length === 0 ? ( + Cargando categorías... + ) : ( + categoriasDisponibles.map(cat => { + const isSelected = seleccionado === cat.id; + return ( + + ); + }) + )} + + + Título + setTitulo(e.target.value)} + // 1. Limitar a 50 caracteres + onChange={(e) => setTitulo(e.target.value.slice(0, 80))} color={titulo.trim() ? "success" : errores.includes("Título") ? "danger" : "neutral"} sx={{ my: 2 }} + // 2. Contador visual + endDecorator={ + + {titulo.length}/80 + + } + // 3. Atributo HTML nativo + slotProps={{ input: { maxLength: 80 } }} /> + + + Descripción + +