From f5c9713d1d2156701c2a86eeb3d9d4caaebd070c Mon Sep 17 00:00:00 2001 From: aortigos Date: Fri, 8 May 2026 17:24:36 +0200 Subject: [PATCH] Oferta page --- backend/index.js | 7 ++-- backend/routes/offer.js | 11 ++++++ frontend/src/App.jsx | 2 + frontend/src/pages/Home.jsx | 4 +- frontend/src/pages/Oferta.jsx | 74 +++++++++++++++++++++++++++++++++++ 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 frontend/src/pages/Oferta.jsx diff --git a/backend/index.js b/backend/index.js index 3117f52..73397e2 100644 --- a/backend/index.js +++ b/backend/index.js @@ -17,7 +17,7 @@ import { validateToken } from './middleware/auth.js' import { register, login } from './routes/auth.js' import { deleteUser } from './routes/user.js' -import { createOffer, deleteOffer, getOffers } from './routes/offer.js' +import { createOffer, deleteOffer, getOffers, getOffer } from './routes/offer.js' /* Test route so nxckwc can test axios*/ app.get('/users', async (req, res) => { @@ -33,8 +33,9 @@ app.post('/register', register) app.delete('/user/:userId', deleteUser) app.post('/crear-oferta', validateToken, createOffer) -app.get('/offers', getOffers) -app.delete('/oferta/:projectId', validateToken, deleteOffer) +app.get('/ofertas', getOffers) +app.get('/oferta/:offerId', validateToken, getOffer) +app.delete('/oferta/:offerId', validateToken, deleteOffer) app.listen(port, () => { diff --git a/backend/routes/offer.js b/backend/routes/offer.js index ffbbd26..cc97574 100644 --- a/backend/routes/offer.js +++ b/backend/routes/offer.js @@ -6,16 +6,27 @@ export const getOffers = async(req, res) => { res.json(offers) } +export const getOffer = async(req, res) => { + const { offerId } = req.params + const id = parseInt(offerId) + const offer = await prisma.oferta.findFirst({ where: { id } }) + + res.json(offer); +} + export const createOffer = async (req, res) => { const { titulo, empresa, ubicacion, salario, contrato, descripcion } = req.body; const authorId = req.user.id + const salarioRegex = /\d/ + if (!titulo || !empresa || !ubicacion || !salario || !contrato || !descripcion) return res.status(400).json({ error: ""}) if (titulo.length < 3 || titulo.length > 64) { return res.status(400).json({ error: 'El titulo debe tener entre 3 y 64 caracteres' })} if (empresa.length < 2 || empresa.length > 32) { return res.status(400).json({ error: 'El nombre de la empresa debe tener entre 2 y 32 caracteres' })} if (ubicacion.length < 3 || ubicacion.length > 16) { return res.status(400).json({ error: 'La ubicacion debe tener entre 3 y 16 caracteres' })} if (salario.length < 3 || salario.length > 10) { return res.status(400).json({ error: 'El salario debe seguir este formato: 500€ o 20€/hora' })} + if (!salarioRegex.test(salario)) return res.status(400).json({ error: "El salario debe contener un numero"}) if (descripcion.length < 10 || descripcion.length > 256) { return res.status(400).json({ error: 'La descripcion debe tener entre 10 y 256 caracteres' })} const contratosValidos = ["freelance", "completo", "medio"] diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 2f7f08f..c496cf5 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -9,6 +9,7 @@ import Login from './pages/Login' import PublicRoute from './components/PublicRoute' import PrivateRoute from './components/PrivateRoute' import Register from './pages/Register' +import Oferta from './pages/Oferta' function App() { @@ -21,6 +22,7 @@ function App() { } /> } /> } /> + } /> diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx index 8ee85a4..8af4903 100644 --- a/frontend/src/pages/Home.jsx +++ b/frontend/src/pages/Home.jsx @@ -7,7 +7,7 @@ function Home() { const [offers, setOffers] = useState([]) useEffect(() => { - fetch(`${API_URL}/offers`) + fetch(`${API_URL}/ofertas`) .then(res => res.json()) .then(data => setOffers(data)) }, []) @@ -50,7 +50,7 @@ function Home() {
Info + href={`/oferta/${offer.id}`}>Info
))} diff --git a/frontend/src/pages/Oferta.jsx b/frontend/src/pages/Oferta.jsx new file mode 100644 index 0000000..476f522 --- /dev/null +++ b/frontend/src/pages/Oferta.jsx @@ -0,0 +1,74 @@ +import { useEffect, useState } from 'react' +import { useParams } from 'react-router-dom' +import { API_URL } from '../config' + +const Oferta = () => { + const { offerId } = useParams() + + const [offer, setOffer] = useState() + + useEffect(() => { + fetch(`${API_URL}/oferta/${offerId}`, { + headers: { + 'Authorization': `Bearer ${localStorage.getItem('token')}` + } + }) + .then(res => res.json()) + .then(data => setOffer(data)) + }, []) + + const contratos = { + freelance: "Freelance", + completo: "Jornada completa", + medio: "Media jornada" + } + + if (!offer) return

Cargando...

+ + return ( + <> +
+

Oferta {offer?.titulo}

+ +
+ Enviar CV +
+
+
+
+
+

Empresa

+

{offer.empresa}

+
+ +
+

Ubicacion

+

{offer.ubicacion}

+
+ +
+

Contrato

+

{contratos[offer.contrato]}

+
+ +
+

Salario

+

{offer.salario} €

+
+
+
+ + +
+
+
+

Descripcion del puesto

+

{offer.descripcion}

+
+
+
+ + ) +} + +export default Oferta \ No newline at end of file