From cbed0adecad4dc9b3a345fb6cdcbd1a008af29a3 Mon Sep 17 00:00:00 2001 From: buttsaim2005 <buttsaim2005@gmail.com> Date: Tue, 13 May 2025 20:59:46 +0200 Subject: [PATCH 1/3] add functions and routes --- .../src/controllers/userPokemonController.js | 102 +++++++++++++----- backend/src/routes/main.js | 38 ++++--- 2 files changed, 96 insertions(+), 44 deletions(-) diff --git a/backend/src/controllers/userPokemonController.js b/backend/src/controllers/userPokemonController.js index f327b32..3a0debc 100644 --- a/backend/src/controllers/userPokemonController.js +++ b/backend/src/controllers/userPokemonController.js @@ -1,44 +1,35 @@ import UserPokemon from '../models/userPokemon.js'; +import Entrenador from '../models/entrenador.js'; +import { getEffectiveness } from '../utils/typeEffectiveness.js'; // 1. Listar todos los Pokémon del usuario (con datos de Pokémon) export const listUserPokemons = async (req, res) => { try { - const { userId } = req.params; - const userPokemons = await UserPokemon.findOne({ userId }).populate('pokemons.pokemonId'); - if (!userPokemons) { - return res.status(404).json({ message: 'Pokémons no encontrados' }); - } - res.status(200).json(userPokemons.pokemons); + const pokemons = await UserPokemon + .find({ userId: req.user._id }) + .populate('pokemonId'); + res.status(200).json(pokemons); } catch (err) { console.error(err); - res.status(500).json({ message: 'Error al obtener los Pokémon', error: err.message }); + res.status(500).json({ message: 'Error al obtener tus Pokémon', error: err.message }); } }; // Función auxiliar para actualizar flags const updateFlag = async (req, res, flag, value) => { try { - console.log('userId desde sesión:', req.user.userId); // Verifica si el userId está presente - console.log('pokemonId desde params:', req.params.pokemonId); // Verifica si el pokemonId es correcto - - const userPokemon = await UserPokemon.findOne({ userId: req.user.userId }); - - if (!userPokemon) { - return res.status(404).json({ message: 'Usuario no encontrado' }); - } + const filter = { _id: req.params.id, userId: req.user._id }; + const update = { [flag]: value }; + const options = { new: true }; - const pokemonIndex = userPokemon.pokemons.findIndex(p => p.pokemonId.toString() === req.params.pokemonId); - console.log('Índice del Pokémon encontrado:', pokemonIndex); // Verifica si el índice es correcto + const updated = await UserPokemon + .findOneAndUpdate(filter, update, options) + .populate('pokemonId'); - if (pokemonIndex === -1) { - return res.status(404).json({ message: 'Pokémon no encontrado para este usuario' }); + if (!updated) { + return res.status(404).json({ message: 'Asociación usuario–Pokémon no encontrada' }); } - - userPokemon.pokemons[pokemonIndex][flag] = value; - - await userPokemon.save(); - - res.status(200).json({ message: `Estado de ${flag} actualizado correctamente` }); + res.status(200).json(updated); } catch (err) { console.error(err); @@ -46,7 +37,6 @@ const updateFlag = async (req, res, flag, value) => { } }; - // 2. Añadir a la caja export const addToBox = (req, res) => updateFlag(req, res, 'isInBox', true); // 3. Quitar de la caja @@ -54,4 +44,62 @@ export const removeFromBox = (req, res) => updateFlag(req, res, 'isInBox', false // 4. Añadir al equipo export const addToTeam = (req, res) => updateFlag(req, res, 'isInTeam', true); // 5. Quitar del equipo -export const removeFromTeam = (req, res) => updateFlag(req, res, 'isInTeam', false); \ No newline at end of file +export const removeFromTeam = (req, res) => updateFlag(req, res, 'isInTeam', false); + +// 6. Obtener ubicaciones únicas de entrenadores +export const getTrainerLocations = async (req, res) => { + try { + const locations = await Entrenador.distinct('ubicacion'); + res.status(200).json(locations); + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Error al obtener ubicaciones', error: err.message }); + } +}; + +// 7. Obtener entrenadores por ubicación +export const getTrainersByLocation = async (req, res) => { + try { + const { ubicacion } = req.params; + const entrenadores = await Entrenador.find({ ubicacion }).populate('equipo'); + res.status(200).json(entrenadores); + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Error al obtener entrenadores', error: err.message }); + } +}; + +// 8. Calcular Pokémon efectivos contra entrenadores de una ubicación +export const getEffectiveUserPokemons = async (req, res) => { + try { + const { ubicacion } = req.params; + + // 1. Obtener pokémon en caja del usuario + const userPokemons = await UserPokemon.find({ userId: req.user._id, isInBox: true }).populate('pokemonId'); + + // 2. Obtener entrenadores en esa ubicación con sus equipos + const entrenadores = await Entrenador.find({ ubicacion }).populate('equipo'); + + // 3. Construir lista de tipos de oponentes + const enemyTypes = []; + for (const entrenador of entrenadores) { + for (const poke of entrenador.equipo) { + if (poke.tipo_1) enemyTypes.push(poke.tipo_1); + if (poke.tipo_2) enemyTypes.push(poke.tipo_2); + } + } + + // 4. Evaluar efectividad de cada Pokémon del usuario + const efectivos = userPokemons.filter(p => { + const types = [p.pokemonId.tipo_1, p.pokemonId.tipo_2].filter(Boolean); + const effect = getEffectiveness(types, enemyTypes); + return effect > 1; // Solo devolvemos los que sean efectivos + }); + + res.status(200).json(efectivos); + + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Error al calcular efectividad', error: err.message }); + } +}; \ No newline at end of file diff --git a/backend/src/routes/main.js b/backend/src/routes/main.js index 2a0625f..833363e 100644 --- a/backend/src/routes/main.js +++ b/backend/src/routes/main.js @@ -3,7 +3,7 @@ import * as userController from '../controllers/userController.js'; import * as pokemonController from '../controllers/pokemonController.js'; import * as objectController from '../controllers/objectController.js'; import * as entrenadorController from '../controllers/entrenadorController.js'; -import * as userPokemonController from '../controllers/userPokemonController.js'; // nuevo +import * as userPokemonController from '../controllers/userPokemonController.js'; const router = express.Router(); @@ -21,17 +21,6 @@ const isAuthenticated = (req, res, next) => { return res.status(401).json({ message: 'No autenticado' }); }; -// En el router de Express -router.get('/api/auth/check', isAuthenticated, (req, res) => { - res.json({ username: req.user.username }); -}); - -// Ruta para obtener el userId del usuario autenticado -router.get('/userId', isAuthenticated, (req, res) => { - res.json({ userId: req.session.user.userId }); -}); - - // --- Rutas públicas --- router.get('/', (req, res) => { res.json({ message: 'Conexión exitosa desde el backend :)' }); @@ -47,13 +36,22 @@ router.post('/logout', (req, res) => { }); }); -// --- Rutas de usuario autenticado --- +// --- Rutas autenticadas --- router.use(isAuthenticated); +// Ruta de comprobación de autenticación +router.get('/api/auth/check', (req, res) => { + res.json({ username: req.user.username }); +}); + +// Ruta para obtener el userId del usuario autenticado +router.get('/userId', (req, res) => { + res.json({ userId: req.session.user.userId }); +}); + // Ruta para obtener los Pokémon de un usuario router.get('/user/:userId/pokemons', userPokemonController.listUserPokemons); - // Flags caja/equipo router.put('/user/pokemon/:pokemonId/box', (req, res, next) => { console.log('Ruta accedida:', req.originalUrl); @@ -62,6 +60,12 @@ router.put('/user/pokemon/:pokemonId/box', (req, res, next) => { router.delete('/user/pokemon/:pokemonId/box', userPokemonController.removeFromBox); router.put('/user/pokemon/:pokemonId/team', userPokemonController.addToTeam); router.delete('/user/pokemon/:pokemonId/team', userPokemonController.removeFromTeam); + +// --- Rutas adicionales del usuario --- +router.get('/trainer-locations', userPokemonController.getTrainerLocations); +router.get('/trainers/:ubicacion', userPokemonController.getTrainersByLocation); +router.get('/effective-pokemons/:ubicacion', userPokemonController.getEffectiveUserPokemons); + // --- Rutas de administrador --- router.use('/admin', isAdmin); @@ -72,11 +76,11 @@ router.put('/admin/editPokemon/:id', pokemonController.editPokemon); router.delete('/admin/pokemons/:id', pokemonController.deletePokemon); // Objetos -router.post( '/admin/objects', objectController.createObject); -router.put( '/admin/objects/:id', objectController.editObject); +router.post('/admin/objects', objectController.createObject); +router.put('/admin/objects/:id', objectController.editObject); router.delete('/admin/objects/:id', objectController.deleteObject); // Entrenadores -router.get( '/admin/getEntrenadores', entrenadorController.listEntrenadores); +router.get('/admin/getEntrenadores', entrenadorController.listEntrenadores); export default router; \ No newline at end of file -- GitLab From 951658bffddad66db3f3754ec1d96062d63db4b6 Mon Sep 17 00:00:00 2001 From: SAIM2005 <buttsaim2005@gmail.com> Date: Wed, 14 May 2025 15:36:12 +0200 Subject: [PATCH 2/3] arreglar funcion --- backend/data/entrenadores.json | 34 ++- backend/data/pokemons.json | 251 ++++++++++++++++-- .../src/controllers/userPokemonController.js | 138 +++++++--- backend/src/routes/main.js | 3 +- frontend/src/router/AppRoutes.js | 3 + frontend/src/views/Home.js | 1 + frontend/src/views/PokemonEfectivo.js | 113 ++++++++ frontend/src/views/PokemonUserList.js | 16 +- frontend/src/views/TrainerList.js | 2 +- 9 files changed, 482 insertions(+), 79 deletions(-) create mode 100644 frontend/src/views/PokemonEfectivo.js diff --git a/backend/data/entrenadores.json b/backend/data/entrenadores.json index c74bd52..ea14872 100644 --- a/backend/data/entrenadores.json +++ b/backend/data/entrenadores.json @@ -1,9 +1,8 @@ [ { - "nombre": "Rival (elige Charmander)", + "nombre": "Rival 1", "rol": "Rival", "ubicacion": "Laboratorio del Profesor Oak", - "obligatorio": true, "equipo": [ { "nombre": "Charmander", @@ -12,10 +11,9 @@ ] }, { - "nombre": "Rival (elige Squirtle)", + "nombre": "Rival 2", "rol": "Rival", "ubicacion": "Laboratorio del Profesor Oak", - "obligatorio": true, "equipo": [ { "nombre": "Squirtle", @@ -24,10 +22,9 @@ ] }, { - "nombre": "Rival (elige Bulbasaur)", + "nombre": "Rival 3", "rol": "Rival", "ubicacion": "Laboratorio del Profesor Oak", - "obligatorio": true, "equipo": [ { "nombre": "Bulbasaur", @@ -39,7 +36,6 @@ "nombre": "Brock", "rol": "Líder de gimnasio", "ubicacion": "Gimnasio de Ciudad Plateada", - "obligatorio": true, "equipo": [ { "nombre": "Geodude", @@ -50,5 +46,27 @@ "nivel": 14 } ] + }, + { + "nombre": "Rival 13", + "rol": "Opcional", + "ubicacion": "Cueva Celeste", + "equipo": [ + { + "nombre": "Charizard", + "nivel": 50 + } + ] + }, + { + "nombre": "Rival 99", + "rol": "Opcional", + "ubicacion": "Monte Moon", + "equipo": [ + { + "nombre": "Blastoise", + "nivel": 50 + } + ] } -] +] \ No newline at end of file diff --git a/backend/data/pokemons.json b/backend/data/pokemons.json index 5e240e5..e59cbd2 100644 --- a/backend/data/pokemons.json +++ b/backend/data/pokemons.json @@ -8,81 +8,276 @@ "tipo_2": "Veneno", "ataques": [ { "nombre": "Látigo Cepa", "tipo": "Planta", "poder": 40 }, - { "nombre": "Rastrillo", "tipo": "Normal", "poder": 15 } + { "nombre": "Residuos", "tipo": "Veneno", "poder": 30 } ], "evoluciones": [{ "nivel": 16, "pokemon": "Ivysaur" }] }, { "id": 2, + "nombre": "Ivysaur", + "nivel": 16, + "tipo_1": "Planta", + "tipo_2": "Veneno", + "ataques": [ + { "nombre": "Megaagotar", "tipo": "Planta", "poder": 50 }, + { "nombre": "Residuos", "tipo": "Veneno", "poder": 30 } + ], + "evoluciones": [{ "nivel": 36, "pokemon": "Venusaur" }] + }, + { + "id": 3, + "nombre": "Venusaur", + "nivel": 36, + "tipo_1": "Planta", + "tipo_2": "Veneno", + "ataques": [ + { "nombre": "Gigadrenado", "tipo": "Planta", "poder": 75 }, + { "nombre": "Bomba Lodo", "tipo": "Veneno", "poder": 80 } + ] + }, + { + "id": 4, "nombre": "Charmander", "nivel": 5, "tipo_1": "Fuego", "tipo_2": null, "ataques": [ { "nombre": "Ascuas", "tipo": "Fuego", "poder": 40 }, - { "nombre": "Gruñido", "tipo": "Normal", "poder": 0 } + { "nombre": "Garra Metal", "tipo": "Acero", "poder": 40 } ], "evoluciones": [{ "nivel": 16, "pokemon": "Charmeleon" }] }, { - "id": 3, + "id": 5, + "nombre": "Charmeleon", + "nivel": 16, + "tipo_1": "Fuego", + "tipo_2": null, + "ataques": [ + { "nombre": "Pirotecnia", "tipo": "Fuego", "poder": 60 }, + { "nombre": "Mordisco", "tipo": "Siniestro", "poder": 60 } + ], + "evoluciones": [{ "nivel": 36, "pokemon": "Charizard" }] + }, + { + "id": 6, + "nombre": "Charizard", + "nivel": 36, + "tipo_1": "Fuego", + "tipo_2": "Volador", + "ataques": [ + { "nombre": "Lanzallamas", "tipo": "Fuego", "poder": 90 }, + { "nombre": "Tajo Aéreo", "tipo": "Volador", "poder": 75 } + ] + }, + { + "id": 7, "nombre": "Squirtle", "nivel": 5, "tipo_1": "Agua", "tipo_2": null, "ataques": [ { "nombre": "Pistola Agua", "tipo": "Agua", "poder": 40 }, - { "nombre": "Gruñido", "tipo": "Normal", "poder": 0 } + { "nombre": "Placaje", "tipo": "Normal", "poder": 40 } ], "evoluciones": [{ "nivel": 16, "pokemon": "Wartortle" }] }, { - "id": 4, - "nombre": "Rattata", - "nivel": 3, - "tipo_1": "Normal", + "id": 8, + "nombre": "Wartortle", + "nivel": 16, + "tipo_1": "Agua", "tipo_2": null, "ataques": [ - { "nombre": "Mordisco", "tipo": "Siniestro", "poder": 60 }, - { "nombre": "Gruñido", "tipo": "Normal", "poder": 0 } + { "nombre": "Hidropulso", "tipo": "Agua", "poder": 60 }, + { "nombre": "Mordisco", "tipo": "Siniestro", "poder": 60 } ], - "evoluciones": [{ "nivel": 20, "pokemon": "Raticate" }] + "evoluciones": [{ "nivel": 36, "pokemon": "Blastoise" }] }, { - "id": 5, + "id": 9, + "nombre": "Blastoise", + "nivel": 36, + "tipo_1": "Agua", + "tipo_2": null, + "ataques": [ + { "nombre": "Surf", "tipo": "Agua", "poder": 90 }, + { "nombre": "Rayo Hielo", "tipo": "Hielo", "poder": 90 } + ] + }, + { + "id": 10, + "nombre": "Caterpie", + "nivel": 5, + "tipo_1": "Bicho", + "tipo_2": null, + "ataques": [ + { "nombre": "Placaje", "tipo": "Normal", "poder": 40 }, + { "nombre": "Disparo Demora", "tipo": "Bicho", "poder": 0 } + ], + "evoluciones": [{ "nivel": 7, "pokemon": "Metapod" }] + }, + { + "id": 11, + "nombre": "Metapod", + "nivel": 7, + "tipo_1": "Bicho", + "tipo_2": null, + "ataques": [ + { "nombre": "Placaje", "tipo": "Normal", "poder": 40 }, + { "nombre": "Fortaleza", "tipo": "Normal", "poder": 0 } + ], + "evoluciones": [{ "nivel": 10, "pokemon": "Butterfree" }] + }, + { + "id": 12, + "nombre": "Butterfree", + "nivel": 10, + "tipo_1": "Bicho", + "tipo_2": "Volador", + "ataques": [ + { "nombre": "Picadura", "tipo": "Bicho", "poder": 60 }, + { "nombre": "Tornado", "tipo": "Volador", "poder": 50 } + ] + }, + { + "id": 13, + "nombre": "Weedle", + "nivel": 5, + "tipo_1": "Bicho", + "tipo_2": "Veneno", + "ataques": [ + { "nombre": "Picotazo Venenoso", "tipo": "Veneno", "poder": 20 }, + { "nombre": "Cornada", "tipo": "Normal", "poder": 30 } + ], + "evoluciones": [{ "nivel": 7, "pokemon": "Kakuna" }] + }, + { + "id": 14, + "nombre": "Kakuna", + "nivel": 7, + "tipo_1": "Bicho", + "tipo_2": "Veneno", + "ataques": [ + { "nombre": "Picotazo Venenoso", "tipo": "Veneno", "poder": 20 }, + { "nombre": "Fortaleza", "tipo": "Normal", "poder": 0 } + ], + "evoluciones": [{ "nivel": 10, "pokemon": "Beedrill" }] + }, + { + "id": 15, + "nombre": "Beedrill", + "nivel": 10, + "tipo_1": "Bicho", + "tipo_2": "Veneno", + "ataques": [ + { "nombre": "Picadura", "tipo": "Bicho", "poder": 60 }, + { "nombre": "Puya Nociva", "tipo": "Veneno", "poder": 80 } + ] + }, + { + "id": 16, "nombre": "Pidgey", - "nivel": 3, + "nivel": 5, "tipo_1": "Normal", "tipo_2": "Volador", "ataques": [ - { "nombre": "Ataque Rápido", "tipo": "Normal", "poder": 40 }, - { "nombre": "Giro Rapido", "tipo": "Normal", "poder": 40 } + { "nombre": "Tornado", "tipo": "Volador", "poder": 40 }, + { "nombre": "Placaje", "tipo": "Normal", "poder": 40 } ], - "evoluciones": [{ "nivel": 18, "pokemon": "Pidgeot" }] + "evoluciones": [{ "nivel": 16, "pokemon": "Pidgeotto" }] }, { - "id": 6, + "id": 17, + "nombre": "Pidgeotto", + "nivel": 16, + "tipo_1": "Normal", + "tipo_2": "Volador", + "ataques": [ + { "nombre": "Aire Afilado", "tipo": "Volador", "poder": 55 }, + { "nombre": "Derribo", "tipo": "Normal", "poder": 60 } + ], + "evoluciones": [{ "nivel": 36, "pokemon": "Pidgeot" }] + }, + { + "id": 18, + "nombre": "Pidgeot", + "nivel": 36, + "tipo_1": "Normal", + "tipo_2": "Volador", + "ataques": [ + { "nombre": "Vendaval", "tipo": "Volador", "poder": 100 }, + { "nombre": "Vozarrón", "tipo": "Normal", "poder": 100 } + ] + }, + { + "id": 19, + "nombre": "Rattata", + "nivel": 5, + "tipo_1": "Normal", + "tipo_2": null, + "ataques": [ + { "nombre": "Placaje", "tipo": "Normal", "poder": 40 }, + { "nombre": "Mordisco", "tipo": "Siniestro", "poder": 40 } + ], + "evoluciones": [{ "nivel": 20, "pokemon": "Raticate" }] + }, + { + "id": 20, + "nombre": "Raticate", + "nivel": 20, + "tipo_1": "Normal", + "tipo_2": null, + "ataques": [ + { "nombre": "Derribo", "tipo": "Normal", "poder": 60 }, + { "nombre": "Triturar", "tipo": "Siniestro", "poder": 70 } + ] + }, + { + "id": 74, "nombre": "Geodude", - "nivel": 12, + "nivel": 5, "tipo_1": "Roca", "tipo_2": "Tierra", "ataques": [ - { "nombre": "Lanzarrocas", "tipo": "Roca", "poder": 50 }, - { "nombre": "Magnitud", "tipo": "Tierra", "poder": 60 } + { "nombre": "Lanzarrocas", "tipo": "Roca", "poder": 40 }, + { "nombre": "Disparo Lodo", "tipo": "Tierra", "poder": 40 } ], - "evoluciones": [{ "nivel": 25, "pokemon": "Graveler" }] + "evoluciones": [{ "nivel": 20, "pokemon": "Graveler" }] }, { - "id": 7, - "nombre": "Onix", - "nivel": 14, + "id": 75, + "nombre": "Graveler", + "nivel": 20, "tipo_1": "Roca", "tipo_2": "Tierra", "ataques": [ - { "nombre": "Golpe Roca", "tipo": "Roca", "poder": 50 }, - { "nombre": "Tierra Viva", "tipo": "Tierra", "poder": 100 } + { "nombre": "Magnitud", "tipo": "Tierra", "poder": 60 }, + { "nombre": "Avalancha", "tipo": "Roca", "poder": 60 } ], - "evoluciones": [{ "nivel": 0, "pokemon": "Steelix" }] + "evoluciones": [{ "nivel": 40, "pokemon": "Golem" }] + }, + { + "id": 76, + "nombre": "Golem", + "nivel": 40, + "tipo_1": "Roca", + "tipo_2": "Tierra", + "ataques": [ + { "nombre": "Roca Afilada", "tipo": "Roca", "poder": 100 }, + { "nombre": "Terremoto", "tipo": "Tierra", "poder": 100 } + ] + }, + { + "id": 95, + "nombre": "Onix", + "nivel": 15, + "tipo_1": "Roca", + "tipo_2": "Tierra", + "ataques": [ + { "nombre": "Magnitud", "tipo": "Tierra", "poder": 50 }, + { "nombre": "Antiaéreo", "tipo": "Roca", "poder": 50 } + ] } ] -} +} \ No newline at end of file diff --git a/backend/src/controllers/userPokemonController.js b/backend/src/controllers/userPokemonController.js index 3a0debc..148db55 100644 --- a/backend/src/controllers/userPokemonController.js +++ b/backend/src/controllers/userPokemonController.js @@ -1,35 +1,45 @@ import UserPokemon from '../models/userPokemon.js'; -import Entrenador from '../models/entrenador.js'; -import { getEffectiveness } from '../utils/typeEffectiveness.js'; +import Entrenador from '../models/entrenadores.js'; // 1. Listar todos los Pokémon del usuario (con datos de Pokémon) export const listUserPokemons = async (req, res) => { try { - const pokemons = await UserPokemon - .find({ userId: req.user._id }) - .populate('pokemonId'); - res.status(200).json(pokemons); + const { userId } = req.params; + const userPokemons = await UserPokemon.findOne({ userId }).populate('pokemons.pokemonId'); + if (!userPokemons) { + return res.status(404).json({ message: 'Pokémons no encontrados' }); + } + res.status(200).json(userPokemons.pokemons); } catch (err) { console.error(err); - res.status(500).json({ message: 'Error al obtener tus Pokémon', error: err.message }); + res.status(500).json({ message: 'Error al obtener los Pokémon', error: err.message }); } }; // Función auxiliar para actualizar flags const updateFlag = async (req, res, flag, value) => { try { - const filter = { _id: req.params.id, userId: req.user._id }; - const update = { [flag]: value }; - const options = { new: true }; + console.log('userId desde sesión:', req.user.userId); // Verifica si el userId está presente + console.log('pokemonId desde params:', req.params.pokemonId); // Verifica si el pokemonId es correcto + + const userPokemon = await UserPokemon.findOne({ userId: req.user.userId }); + + if (!userPokemon) { + return res.status(404).json({ message: 'Usuario no encontrado' }); + } - const updated = await UserPokemon - .findOneAndUpdate(filter, update, options) - .populate('pokemonId'); + const pokemonIndex = userPokemon.pokemons.findIndex(p => p._id.toString() === req.params.pokemonId); + console.log('Índice del Pokémon encontrado:', pokemonIndex); // Verifica si el índice es correcto - if (!updated) { - return res.status(404).json({ message: 'Asociación usuario–Pokémon no encontrada' }); + if (pokemonIndex === -1) { + return res.status(404).json({ message: 'Pokémon no encontrado para este usuario' }); } - res.status(200).json(updated); + + userPokemon.pokemons[pokemonIndex][flag] = value; + + await userPokemon.save(); + + res.status(200).json({ message: `Estado de ${flag} actualizado correctamente` }); } catch (err) { console.error(err); @@ -38,11 +48,14 @@ const updateFlag = async (req, res, flag, value) => { }; // 2. Añadir a la caja -export const addToBox = (req, res) => updateFlag(req, res, 'isInBox', true); +export const addToBox = (req, res) => updateFlag(req, res, 'isInBox', true); + // 3. Quitar de la caja export const removeFromBox = (req, res) => updateFlag(req, res, 'isInBox', false); + // 4. Añadir al equipo -export const addToTeam = (req, res) => updateFlag(req, res, 'isInTeam', true); +export const addToTeam = (req, res) => updateFlag(req, res, 'isInTeam', true); + // 5. Quitar del equipo export const removeFromTeam = (req, res) => updateFlag(req, res, 'isInTeam', false); @@ -72,34 +85,93 @@ export const getTrainersByLocation = async (req, res) => { // 8. Calcular Pokémon efectivos contra entrenadores de una ubicación export const getEffectiveUserPokemons = async (req, res) => { try { - const { ubicacion } = req.params; + const { ubicacion, entrenadorId } = req.params; - // 1. Obtener pokémon en caja del usuario - const userPokemons = await UserPokemon.find({ userId: req.user._id, isInBox: true }).populate('pokemonId'); + // 1. Obtener TODOS los Pokémon del usuario + const userData = await UserPokemon.findOne({ userId: req.user.userId }).populate('pokemons.pokemonId'); - // 2. Obtener entrenadores en esa ubicación con sus equipos - const entrenadores = await Entrenador.find({ ubicacion }).populate('equipo'); + if (!userData) { + return res.status(404).json({ message: 'No se encontró el usuario' }); + } + + const pokemonsEnCaja = userData.pokemons.filter(p => p.isInBox && p.pokemonId); + + // 2. Obtener entrenador específico + const entrenador = await Entrenador.findOne({ _id: entrenadorId, ubicacion }).populate('equipo'); - // 3. Construir lista de tipos de oponentes + if (!entrenador) { + return res.status(404).json({ message: 'Entrenador no encontrado en esa ubicación' }); + } + + // 3. Extraer tipos de su equipo const enemyTypes = []; - for (const entrenador of entrenadores) { - for (const poke of entrenador.equipo) { - if (poke.tipo_1) enemyTypes.push(poke.tipo_1); - if (poke.tipo_2) enemyTypes.push(poke.tipo_2); - } + for (const poke of entrenador.equipo) { + if (poke.tipo_1) enemyTypes.push(poke.tipo_1); + if (poke.tipo_2) enemyTypes.push(poke.tipo_2); } - // 4. Evaluar efectividad de cada Pokémon del usuario - const efectivos = userPokemons.filter(p => { + // 4. Calcular efectividad + const efectivos = pokemonsEnCaja.filter(p => { const types = [p.pokemonId.tipo_1, p.pokemonId.tipo_2].filter(Boolean); const effect = getEffectiveness(types, enemyTypes); - return effect > 1; // Solo devolvemos los que sean efectivos + return effect >= 1 && effect <= 2; + }); + + // 5. Filtrar última evolución + const lastEvolutions = []; + const seenNames = new Set(); + const pokemonMap = new Map(); + + efectivos.forEach(pokemon => { + const { nombre, evoluciones } = pokemon.pokemonId; + if (!seenNames.has(nombre)) { + seenNames.add(nombre); + if (evoluciones.length > 0) { + const lastEvo = evoluciones.sort((a, b) => b.nivel - a.nivel)[0]; + pokemonMap.set(nombre, lastEvo); + } else { + pokemonMap.set(nombre, pokemon.pokemonId); + } + } }); - res.status(200).json(efectivos); + pokemonMap.forEach((evolution, nombre) => { + lastEvolutions.push({ + ...evolution, + nombre, + }); + }); + res.status(200).json(lastEvolutions); } catch (err) { console.error(err); res.status(500).json({ message: 'Error al calcular efectividad', error: err.message }); } +}; + +// ------------------------- +// Función local de efectividad +// ------------------------- +const typeChart = { + Agua: { Fuego: 2, Planta: 0.5, Tierra: 2 }, + Fuego: { Planta: 2, Agua: 0.5, Hielo: 2 }, + Planta: { Agua: 2, Fuego: 0.5, Tierra: 2 }, + Eléctrico: { Agua: 2, Tierra: 0, Volador: 2 }, + Tierra: { Fuego: 2, Eléctrico: 2, Planta: 0.5 }, + Hielo: { Planta: 2, Dragón: 2, Fuego: 0.5 }, + Volador: { Planta: 2, Eléctrico: 0.5 }, + Psíquico: { Lucha: 2, Fantasma: 0.5 }, + Lucha: { Normal: 2, Psíquico: 0.5 }, + Fantasma: { Psíquico: 2, Normal: 0 }, +}; + +const getEffectiveness = (userTypes, enemyTypes) => { + let total = 0; + for (const uType of userTypes) { + for (const eType of enemyTypes) { + const mult = typeChart[uType]?.[eType] ?? 1; + total += mult; + } + } + return total / (userTypes.length * enemyTypes.length || 1); // promedio }; \ No newline at end of file diff --git a/backend/src/routes/main.js b/backend/src/routes/main.js index 833363e..e7d3332 100644 --- a/backend/src/routes/main.js +++ b/backend/src/routes/main.js @@ -64,8 +64,7 @@ router.delete('/user/pokemon/:pokemonId/team', userPokemonController.removeFromT // --- Rutas adicionales del usuario --- router.get('/trainer-locations', userPokemonController.getTrainerLocations); router.get('/trainers/:ubicacion', userPokemonController.getTrainersByLocation); -router.get('/effective-pokemons/:ubicacion', userPokemonController.getEffectiveUserPokemons); - +router.get('/effective-pokemons/:ubicacion/:entrenadorId', userPokemonController.getEffectiveUserPokemons); // --- Rutas de administrador --- router.use('/admin', isAdmin); diff --git a/frontend/src/router/AppRoutes.js b/frontend/src/router/AppRoutes.js index da1d814..89df38e 100644 --- a/frontend/src/router/AppRoutes.js +++ b/frontend/src/router/AppRoutes.js @@ -9,6 +9,8 @@ import AdminHome from "../views/AdminHome.js"; import AdminPokemon from "../views/AdminPokemon.js"; import AdminPokemonAdd from "../views/AdminPokemonAdd.js"; import AdminPokemonEdit from "../views/AdminPokemonEdit.js"; +import EffectivePokemonSelector from "../views/PokemonEfectivo.js"; + const AppRoutes = () => ( <Routes> <Route path="/" element={<Navigate to="/login" />} /> @@ -22,6 +24,7 @@ const AppRoutes = () => ( <Route path="/admin/pokemon" element={<AdminPokemon />} /> <Route path="/admin/pokemon/add" element={<AdminPokemonAdd />} /> <Route path="/admin/pokemon/edit/:id" element={<AdminPokemonEdit />} /> + <Route path="/pokemonEfectivo" element={<EffectivePokemonSelector />} /> </Routes> ); diff --git a/frontend/src/views/Home.js b/frontend/src/views/Home.js index 348969b..f5b056f 100644 --- a/frontend/src/views/Home.js +++ b/frontend/src/views/Home.js @@ -11,6 +11,7 @@ const Home = () => ( <Link to="/pokemons" className="btn btn-secondary btn-lg mx-2">Pokemons</Link> <Link to="/trainers" className="btn btn-secondary btn-lg mx-2">Entrenadores</Link> <Link to="/user/pokemons" className="btn btn-secondary btn-lg mx-2">Pokemons del usuario</Link> + <Link to="/pokemonEfectivo" className="btn btn-secondary btn-lg mx-2">Pokemon Efectivo</Link> </div> </div> ); diff --git a/frontend/src/views/PokemonEfectivo.js b/frontend/src/views/PokemonEfectivo.js new file mode 100644 index 0000000..2ec4858 --- /dev/null +++ b/frontend/src/views/PokemonEfectivo.js @@ -0,0 +1,113 @@ +import React, { useEffect, useState } from 'react'; +import axios from 'axios'; + +const EffectivePokemonSelector = () => { + const [locations, setLocations] = useState([]); + const [selectedLocation, setSelectedLocation] = useState(''); + const [trainers, setTrainers] = useState([]); + const [selectedTrainer, setSelectedTrainer] = useState(''); + const [effectivePokemons, setEffectivePokemons] = useState([]); + const [loading, setLoading] = useState(false); + + // Obtener ubicaciones + const fetchLocations = async () => { + try { + const res = await axios.get('http://localhost:5000/trainer-locations', { + withCredentials: true + }); + setLocations(res.data); + } catch (err) { + console.error('Error al obtener ubicaciones:', err); + } + }; + + // Obtener entrenadores en la ubicación seleccionada + const fetchTrainers = async (location) => { + try { + const res = await axios.get(`http://localhost:5000/trainers/${location}`, { + withCredentials: true + }); + setTrainers(res.data); + } catch (err) { + console.error('Error al obtener entrenadores:', err); + } + }; + + // Obtener Pokémon efectivos contra el entrenador seleccionado + const fetchEffectivePokemons = async (location, trainerId) => { + setLoading(true); + try { + const res = await axios.get(`http://localhost:5000/effective-pokemons/${location}/${trainerId}`, { + withCredentials: true + }); + setEffectivePokemons(res.data); + } catch (err) { + console.error('Error al obtener Pokémon efectivos:', err); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchLocations(); + }, []); + + useEffect(() => { + if (selectedLocation) { + fetchTrainers(selectedLocation); + setEffectivePokemons([]); + setSelectedTrainer(''); + } + }, [selectedLocation]); + + useEffect(() => { + if (selectedLocation && selectedTrainer) { + fetchEffectivePokemons(selectedLocation, selectedTrainer); + } + }, [selectedTrainer]); + + return ( + <div> + <h2>Selecciona una ubicación</h2> + <select onChange={(e) => setSelectedLocation(e.target.value)} value={selectedLocation}> + <option value="">-- Ubicación --</option> + {locations.map((loc) => ( + <option key={loc} value={loc}> + {loc} + </option> + ))} + </select> + + {trainers.length > 0 && ( + <> + <h2>Selecciona un entrenador</h2> + <select onChange={(e) => setSelectedTrainer(e.target.value)} value={selectedTrainer}> + <option value="">-- Entrenador --</option> + {trainers.map((trainer) => ( + <option key={trainer._id} value={trainer._id}> + {trainer.nombre} + </option> + ))} + </select> + </> + )} + + {loading ? ( + <p>Cargando Pokémon efectivos...</p> + ) : ( + <> + <h2>Pokémon efectivos</h2> + <ul> + {effectivePokemons.map((pokemon, idx) => ( + <li key={idx}> + {pokemon.nombre} {pokemon.tipo_1 && `(${pokemon.tipo_1}`}{pokemon.tipo_2 && ` / ${pokemon.tipo_2}`}{(pokemon.tipo_1 || pokemon.tipo_2) && ')'} + </li> + ))} + </ul> + </> + )} + </div> + ); +}; + +export default EffectivePokemonSelector; \ No newline at end of file diff --git a/frontend/src/views/PokemonUserList.js b/frontend/src/views/PokemonUserList.js index 3541d26..e71ff37 100644 --- a/frontend/src/views/PokemonUserList.js +++ b/frontend/src/views/PokemonUserList.js @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import axios from 'axios'; - +import { Link } from 'react-router-dom'; const UserPokemonList = () => { const [pokemons, setPokemons] = useState([]); const [loading, setLoading] = useState(true); @@ -81,37 +81,39 @@ const UserPokemonList = () => { return ( <div className="container py-5"> + <Link to="/pokemonEfectivo" className="btn btn-secondary btn-lg mx-2">Pokemon Efectivo</Link> <h2 className="text-center mb-4">Mis Pokémon</h2> <ul className="list-group"> {pokemons.map(pokemon => ( - <li key={pokemon.pokemonId._id} className="list-group-item d-flex justify-content-between align-items-center"> + <li key={pokemon._id} className="list-group-item d-flex justify-content-between align-items-center"> <div> - <strong>{pokemon.pokemonId.nombre}</strong> - Nivel: {pokemon.nivel ? pokemon.nivel : 'Desconocido'} - Tipo: {pokemon.pokemonId.tipo_1} + <strong>{pokemon.pokemonId.nombre}</strong> - Nivel: {pokemon.nivel ?? 'Desconocido'} - Tipo: {pokemon.pokemonId.tipo_1} {pokemon.pokemonId.tipo_2 ? ` / ${pokemon.pokemonId.tipo_2}` : ''} </div> <div> {pokemon.isInBox ? ( - <button className="btn btn-outline-danger btn-sm me-2" onClick={() => removeFromBox(pokemon.pokemonId._id)}> + <button className="btn btn-outline-danger btn-sm me-2" onClick={() => removeFromBox(pokemon._id)}> Quitar de Caja </button> ) : ( - <button className="btn btn-outline-primary btn-sm me-2" onClick={() => addToBox(pokemon.pokemonId._id)}> + <button className="btn btn-outline-primary btn-sm me-2" onClick={() => addToBox(pokemon._id)}> Añadir a Caja </button> )} {pokemon.isInTeam ? ( - <button className="btn btn-outline-danger btn-sm" onClick={() => removeFromTeam(pokemon.pokemonId._id)}> + <button className="btn btn-outline-danger btn-sm" onClick={() => removeFromTeam(pokemon._id)}> Quitar del Equipo </button> ) : ( - <button className="btn btn-outline-success btn-sm" onClick={() => addToTeam(pokemon.pokemonId._id)}> + <button className="btn btn-outline-success btn-sm" onClick={() => addToTeam(pokemon._id)}> Añadir al Equipo </button> )} </div> </li> ))} + </ul> </div> ); diff --git a/frontend/src/views/TrainerList.js b/frontend/src/views/TrainerList.js index 1ed47d8..4114738 100644 --- a/frontend/src/views/TrainerList.js +++ b/frontend/src/views/TrainerList.js @@ -16,7 +16,7 @@ const EntrenadorList = () => { } else { setError('La respuesta de la API no es un array'); } - setLoading(false); + setLoading(false); }) .catch((err) => { if (err.response && err.response.status === 401) { -- GitLab From 28664c111d043f1ead07f0b26054daa90ee727a5 Mon Sep 17 00:00:00 2001 From: SAIM2005 <buttsaim2005@gmail.com> Date: Thu, 15 May 2025 11:26:56 +0200 Subject: [PATCH 3/3] acabado --- backend/data/typeChart.js | 22 ++ .../src/controllers/entrenadorController.js | 18 ++ .../src/controllers/userPokemonController.js | 114 +++----- backend/src/routes/main.js | 16 +- frontend/src/views/PokemonEfectivo.js | 248 ++++++++++++------ 5 files changed, 263 insertions(+), 155 deletions(-) create mode 100644 backend/data/typeChart.js diff --git a/backend/data/typeChart.js b/backend/data/typeChart.js new file mode 100644 index 0000000..e6b9e30 --- /dev/null +++ b/backend/data/typeChart.js @@ -0,0 +1,22 @@ +const typeChart = { + Normal: { Roca: 0.5, Fantasma: 0, Acero: 0.5 }, + Fuego: { Planta: 2, Hielo: 2, Bicho: 2, Acero: 2, Fuego: 0.5, Agua: 0.5, Roca: 0.5, Dragón: 0.5 }, + Agua: { Fuego: 2, Tierra: 2, Roca: 2, Agua: 0.5, Planta: 0.5, Dragón: 0.5 }, + Planta: { Agua: 2, Tierra: 2, Roca: 2, Fuego: 0.5, Planta: 0.5, Veneno: 0.5, Volador: 0.5, Bicho: 0.5, Dragón: 0.5, Acero: 0.5 }, + Eléctrico: { Agua: 2, Volador: 2, Planta: 0.5, Eléctrico: 0.5, Dragón: 0.5, Tierra: 0 }, + Hielo: { Planta: 2, Tierra: 2, Volador: 2, Dragón: 2, Fuego: 0.5, Agua: 0.5, Hielo: 0.5, Acero: 0.5 }, + Lucha: { Normal: 2, Hielo: 2, Roca: 2, Siniestro: 2, Acero: 2, Veneno: 0.5, Volador: 0.5, Psíquico: 0.5, Bicho: 0.5, Fantasma: 0 }, + Veneno: { Planta: 2, Hada: 2, Veneno: 0.5, Tierra: 0.5, Roca: 0.5, Fantasma: 0.5, Acero: 0 }, + Tierra: { Fuego: 2, Eléctrico: 2, Veneno: 2, Roca: 2, Acero: 2, Planta: 0.5, Bicho: 0.5, Volador: 0 }, + Volador: { Planta: 2, Lucha: 2, Bicho: 2, Eléctrico: 0.5, Roca: 0.5, Acero: 0.5 }, + Psíquico: { Lucha: 2, Veneno: 2, Psíquico: 0.5, Acero: 0.5, Siniestro: 0 }, + Bicho: { Planta: 2, Psíquico: 2, Siniestro: 2, Fuego: 0.5, Lucha: 0.5, Veneno: 0.5, Volador: 0.5, Fantasma: 0.5, Acero: 0.5, Hada: 0.5 }, + Roca: { Fuego: 2, Hielo: 2, Volador: 2, Bicho: 2, Lucha: 0.5, Tierra: 0.5, Acero: 0.5 }, + Fantasma: { Fantasma: 2, Psíquico: 2, Siniestro: 0.5, Normal: 0 }, + Dragón: { Dragón: 2, Acero: 0.5, Hada: 0 }, + Siniestro: { Psíquico: 2, Fantasma: 2, Lucha: 0.5, Siniestro: 0.5, Hada: 0.5 }, + Acero: { Hielo: 2, Roca: 2, Hada: 2, Fuego: 0.5, Agua: 0.5, Eléctrico: 0.5, Acero: 0.5 }, + Hada: { Lucha: 2, Dragón: 2, Siniestro: 2, Fuego: 0.5, Veneno: 0.5, Acero: 0.5 } +}; + +export default typeChart; \ No newline at end of file diff --git a/backend/src/controllers/entrenadorController.js b/backend/src/controllers/entrenadorController.js index 4cc282d..71a6092 100644 --- a/backend/src/controllers/entrenadorController.js +++ b/backend/src/controllers/entrenadorController.js @@ -66,3 +66,21 @@ export const listEntrenadores = async (req, res) => { res.status(500).json({ message: 'Error al obtener los entrenadores', error: err }); } }; + +// Obtener Pokémon de un entrenador por su ID +export const getPokemonsByEntrenadorId = async (req, res) => { + try { + const { entrenadorId } = req.params; + + // Populate usando 'equipo', que es el campo correcto en tu esquema + const entrenador = await Entrenador.findById(entrenadorId).populate('equipo'); + + if (!entrenador) return res.status(404).json({ message: 'Entrenador no encontrado' }); + + // Devolver el array de Pokémon + res.json(entrenador.equipo); + } catch (error) { + console.error('Error al obtener Pokémon del entrenador:', error); + res.status(500).json({ message: 'Error interno del servidor' }); + } +}; \ No newline at end of file diff --git a/backend/src/controllers/userPokemonController.js b/backend/src/controllers/userPokemonController.js index 148db55..950dca9 100644 --- a/backend/src/controllers/userPokemonController.js +++ b/backend/src/controllers/userPokemonController.js @@ -1,5 +1,6 @@ import UserPokemon from '../models/userPokemon.js'; import Entrenador from '../models/entrenadores.js'; +import typeChart from '../../data/typeChart.js'; // Asegúrate de que esta ruta sea correcta // 1. Listar todos los Pokémon del usuario (con datos de Pokémon) export const listUserPokemons = async (req, res) => { @@ -19,9 +20,6 @@ export const listUserPokemons = async (req, res) => { // Función auxiliar para actualizar flags const updateFlag = async (req, res, flag, value) => { try { - console.log('userId desde sesión:', req.user.userId); // Verifica si el userId está presente - console.log('pokemonId desde params:', req.params.pokemonId); // Verifica si el pokemonId es correcto - const userPokemon = await UserPokemon.findOne({ userId: req.user.userId }); if (!userPokemon) { @@ -29,7 +27,6 @@ const updateFlag = async (req, res, flag, value) => { } const pokemonIndex = userPokemon.pokemons.findIndex(p => p._id.toString() === req.params.pokemonId); - console.log('Índice del Pokémon encontrado:', pokemonIndex); // Verifica si el índice es correcto if (pokemonIndex === -1) { return res.status(404).json({ message: 'Pokémon no encontrado para este usuario' }); @@ -87,91 +84,62 @@ export const getEffectiveUserPokemons = async (req, res) => { try { const { ubicacion, entrenadorId } = req.params; - // 1. Obtener TODOS los Pokémon del usuario const userData = await UserPokemon.findOne({ userId: req.user.userId }).populate('pokemons.pokemonId'); + if (!userData) return res.status(404).json({ message: 'No se encontró el usuario' }); - if (!userData) { - return res.status(404).json({ message: 'No se encontró el usuario' }); - } - - const pokemonsEnCaja = userData.pokemons.filter(p => p.isInBox && p.pokemonId); - - // 2. Obtener entrenador específico const entrenador = await Entrenador.findOne({ _id: entrenadorId, ubicacion }).populate('equipo'); + if (!entrenador) return res.status(404).json({ message: 'Entrenador no encontrado en esa ubicación' }); - if (!entrenador) { - return res.status(404).json({ message: 'Entrenador no encontrado en esa ubicación' }); - } - - // 3. Extraer tipos de su equipo + // Tipos del equipo enemigo const enemyTypes = []; - for (const poke of entrenador.equipo) { + entrenador.equipo.forEach(poke => { if (poke.tipo_1) enemyTypes.push(poke.tipo_1); if (poke.tipo_2) enemyTypes.push(poke.tipo_2); - } - - // 4. Calcular efectividad - const efectivos = pokemonsEnCaja.filter(p => { - const types = [p.pokemonId.tipo_1, p.pokemonId.tipo_2].filter(Boolean); - const effect = getEffectiveness(types, enemyTypes); - return effect >= 1 && effect <= 2; }); - // 5. Filtrar última evolución - const lastEvolutions = []; - const seenNames = new Set(); - const pokemonMap = new Map(); - - efectivos.forEach(pokemon => { - const { nombre, evoluciones } = pokemon.pokemonId; - if (!seenNames.has(nombre)) { - seenNames.add(nombre); - if (evoluciones.length > 0) { - const lastEvo = evoluciones.sort((a, b) => b.nivel - a.nivel)[0]; - pokemonMap.set(nombre, lastEvo); + const pokemonsEnCaja = userData.pokemons.filter(p => p.isInBox && p.pokemonId); + + // Identificar últimas evoluciones que posee el usuario + const latestEvolutionsMap = new Map(); + for (const p of pokemonsEnCaja) { + const baseName = p.pokemonId.nombre; + const evoList = p.pokemonId.evoluciones; + if (evoList.length > 0) { + const sortedEvos = evoList.sort((a, b) => b.nivel - a.nivel); + const userOwnedEvo = sortedEvos.find(evo => + pokemonsEnCaja.some(up => up.pokemonId.nombre === evo.nombre) + ); + if (userOwnedEvo) { + latestEvolutionsMap.set(baseName, userOwnedEvo); } else { - pokemonMap.set(nombre, pokemon.pokemonId); + latestEvolutionsMap.set(baseName, p.pokemonId); } + } else { + latestEvolutionsMap.set(baseName, p.pokemonId); } - }); + } - pokemonMap.forEach((evolution, nombre) => { - lastEvolutions.push({ - ...evolution, - nombre, - }); - }); + const x2 = []; + const x1 = []; + + for (const [_, pokemon] of latestEvolutionsMap.entries()) { + const types = [pokemon.tipo_1, pokemon.tipo_2].filter(Boolean); + // Revisar multiplicadores para cada tipo + let maxMultiplier = 0; + for (const uType of types) { + for (const eType of enemyTypes) { + const mult = typeChart[uType]?.[eType] ?? 1; + if (mult > maxMultiplier) maxMultiplier = mult; + } + } + + if (maxMultiplier === 2) x2.push(pokemon); + else if (maxMultiplier === 1) x1.push(pokemon); + } - res.status(200).json(lastEvolutions); + res.status(200).json({ x2, x1 }); } catch (err) { console.error(err); res.status(500).json({ message: 'Error al calcular efectividad', error: err.message }); } -}; - -// ------------------------- -// Función local de efectividad -// ------------------------- -const typeChart = { - Agua: { Fuego: 2, Planta: 0.5, Tierra: 2 }, - Fuego: { Planta: 2, Agua: 0.5, Hielo: 2 }, - Planta: { Agua: 2, Fuego: 0.5, Tierra: 2 }, - Eléctrico: { Agua: 2, Tierra: 0, Volador: 2 }, - Tierra: { Fuego: 2, Eléctrico: 2, Planta: 0.5 }, - Hielo: { Planta: 2, Dragón: 2, Fuego: 0.5 }, - Volador: { Planta: 2, Eléctrico: 0.5 }, - Psíquico: { Lucha: 2, Fantasma: 0.5 }, - Lucha: { Normal: 2, Psíquico: 0.5 }, - Fantasma: { Psíquico: 2, Normal: 0 }, -}; - -const getEffectiveness = (userTypes, enemyTypes) => { - let total = 0; - for (const uType of userTypes) { - for (const eType of enemyTypes) { - const mult = typeChart[uType]?.[eType] ?? 1; - total += mult; - } - } - return total / (userTypes.length * enemyTypes.length || 1); // promedio }; \ No newline at end of file diff --git a/backend/src/routes/main.js b/backend/src/routes/main.js index e7d3332..5a336cb 100644 --- a/backend/src/routes/main.js +++ b/backend/src/routes/main.js @@ -39,32 +39,30 @@ router.post('/logout', (req, res) => { // --- Rutas autenticadas --- router.use(isAuthenticated); -// Ruta de comprobación de autenticación +// Comprobación de autenticación router.get('/api/auth/check', (req, res) => { res.json({ username: req.user.username }); }); -// Ruta para obtener el userId del usuario autenticado +// Obtener userId del usuario autenticado router.get('/userId', (req, res) => { res.json({ userId: req.session.user.userId }); }); -// Ruta para obtener los Pokémon de un usuario +// --- User Pokémon --- router.get('/user/:userId/pokemons', userPokemonController.listUserPokemons); // Flags caja/equipo -router.put('/user/pokemon/:pokemonId/box', (req, res, next) => { - console.log('Ruta accedida:', req.originalUrl); - next(); -}, userPokemonController.addToBox); +router.put('/user/pokemon/:pokemonId/box', userPokemonController.addToBox); router.delete('/user/pokemon/:pokemonId/box', userPokemonController.removeFromBox); router.put('/user/pokemon/:pokemonId/team', userPokemonController.addToTeam); router.delete('/user/pokemon/:pokemonId/team', userPokemonController.removeFromTeam); -// --- Rutas adicionales del usuario --- +// --- Funciones de efectividad y entrenadores --- router.get('/trainer-locations', userPokemonController.getTrainerLocations); router.get('/trainers/:ubicacion', userPokemonController.getTrainersByLocation); router.get('/effective-pokemons/:ubicacion/:entrenadorId', userPokemonController.getEffectiveUserPokemons); + // --- Rutas de administrador --- router.use('/admin', isAdmin); @@ -81,5 +79,5 @@ router.delete('/admin/objects/:id', objectController.deleteObject); // Entrenadores router.get('/admin/getEntrenadores', entrenadorController.listEntrenadores); - +router.get('/trainers/:entrenadorId/pokemons', entrenadorController.getPokemonsByEntrenadorId); export default router; \ No newline at end of file diff --git a/frontend/src/views/PokemonEfectivo.js b/frontend/src/views/PokemonEfectivo.js index 2ec4858..efd82b9 100644 --- a/frontend/src/views/PokemonEfectivo.js +++ b/frontend/src/views/PokemonEfectivo.js @@ -1,112 +1,214 @@ import React, { useEffect, useState } from 'react'; import axios from 'axios'; +import { + Container, + Row, + Col, + Form, + Spinner, + ListGroup, + Card, +} from 'react-bootstrap'; const EffectivePokemonSelector = () => { const [locations, setLocations] = useState([]); const [selectedLocation, setSelectedLocation] = useState(''); const [trainers, setTrainers] = useState([]); const [selectedTrainer, setSelectedTrainer] = useState(''); - const [effectivePokemons, setEffectivePokemons] = useState([]); + const [effectivePokemons, setEffectivePokemons] = useState({ x2: [], x1: [] }); const [loading, setLoading] = useState(false); - // Obtener ubicaciones - const fetchLocations = async () => { - try { - const res = await axios.get('http://localhost:5000/trainer-locations', { - withCredentials: true - }); - setLocations(res.data); - } catch (err) { - console.error('Error al obtener ubicaciones:', err); - } - }; + // Estado y carga de Pokémon del entrenador + const [trainerPokemons, setTrainerPokemons] = useState([]); + const [loadingTrainerPokemons, setLoadingTrainerPokemons] = useState(false); - // Obtener entrenadores en la ubicación seleccionada - const fetchTrainers = async (location) => { - try { - const res = await axios.get(`http://localhost:5000/trainers/${location}`, { - withCredentials: true - }); - setTrainers(res.data); - } catch (err) { - console.error('Error al obtener entrenadores:', err); - } - }; + useEffect(() => { + const fetchLocations = async () => { + try { + const res = await axios.get('http://localhost:5000/trainer-locations', { + withCredentials: true, + }); + setLocations(res.data); + } catch (err) { + console.error('Error al obtener ubicaciones:', err); + } + }; + fetchLocations(); + }, []); + + useEffect(() => { + const fetchTrainers = async () => { + if (!selectedLocation) return; + try { + const res = await axios.get(`http://localhost:5000/trainers/${selectedLocation}`, { + withCredentials: true, + }); + setTrainers(res.data); + setSelectedTrainer(''); + setEffectivePokemons({ x2: [], x1: [] }); + setTrainerPokemons([]); + } catch (err) { + console.error('Error al obtener entrenadores:', err); + } + }; + fetchTrainers(); + }, [selectedLocation]); - // Obtener Pokémon efectivos contra el entrenador seleccionado - const fetchEffectivePokemons = async (location, trainerId) => { + // Efecto para cargar Pokémon efectivos +useEffect(() => { + const fetchEffectivePokemons = async () => { + if (!selectedLocation || !selectedTrainer) return; setLoading(true); + console.log('Fetching effective pokemons with params:', { + selectedLocation, + selectedTrainer, + }); // <-- Log params enviados + try { - const res = await axios.get(`http://localhost:5000/effective-pokemons/${location}/${trainerId}`, { - withCredentials: true - }); + const res = await axios.get( + `http://localhost:5000/effective-pokemons/${encodeURIComponent(selectedLocation)}/${selectedTrainer}`, + { + withCredentials: true, + } + ); + console.log('Respuesta recibida de Pokémon efectivos:', res.data); // <-- Log respuesta setEffectivePokemons(res.data); } catch (err) { console.error('Error al obtener Pokémon efectivos:', err); + setEffectivePokemons({ x2: [], x1: [] }); } finally { setLoading(false); } }; + fetchEffectivePokemons(); +}, [selectedTrainer, selectedLocation]); + // Nuevo efecto para cargar Pokémon del entrenador useEffect(() => { - fetchLocations(); - }, []); - - useEffect(() => { - if (selectedLocation) { - fetchTrainers(selectedLocation); - setEffectivePokemons([]); - setSelectedTrainer(''); - } - }, [selectedLocation]); - - useEffect(() => { - if (selectedLocation && selectedTrainer) { - fetchEffectivePokemons(selectedLocation, selectedTrainer); - } + const fetchTrainerPokemons = async () => { + if (!selectedTrainer) { + setTrainerPokemons([]); + return; + } + setLoadingTrainerPokemons(true); + try { + const res = await axios.get(`http://localhost:5000/trainers/${selectedTrainer}/pokemons`, { + withCredentials: true, + }); + setTrainerPokemons(res.data); + } catch (err) { + console.error('Error al obtener Pokémon del entrenador:', err); + setTrainerPokemons([]); + } finally { + setLoadingTrainerPokemons(false); + } + }; + fetchTrainerPokemons(); }, [selectedTrainer]); return ( - <div> - <h2>Selecciona una ubicación</h2> - <select onChange={(e) => setSelectedLocation(e.target.value)} value={selectedLocation}> - <option value="">-- Ubicación --</option> - {locations.map((loc) => ( - <option key={loc} value={loc}> - {loc} - </option> - ))} - </select> + <Container className="py-4 text-center"> + <h2 className="text-primary mb-4">Selecciona una ubicación</h2> + <Row className="justify-content-center"> + <Col xs={12} md={6}> + <Form.Select + value={selectedLocation} + onChange={(e) => setSelectedLocation(e.target.value)} + className="mb-4" + > + <option value="">-- Ubicación --</option> + {locations.map((loc) => ( + <option key={loc} value={loc}> + {loc} + </option> + ))} + </Form.Select> + </Col> + </Row> {trainers.length > 0 && ( <> - <h2>Selecciona un entrenador</h2> - <select onChange={(e) => setSelectedTrainer(e.target.value)} value={selectedTrainer}> - <option value="">-- Entrenador --</option> - {trainers.map((trainer) => ( - <option key={trainer._id} value={trainer._id}> - {trainer.nombre} - </option> - ))} - </select> + <h2 className="text-primary mb-4">Selecciona un entrenador</h2> + <Row className="justify-content-center"> + <Col xs={12} md={6}> + <Form.Select + value={selectedTrainer} + onChange={(e) => setSelectedTrainer(e.target.value)} + className="mb-4" + > + <option value="">-- Entrenador --</option> + {trainers.map((trainer) => ( + <option key={trainer._id} value={trainer._id}> + {trainer.nombre} + </option> + ))} + </Form.Select> + </Col> + </Row> </> )} + {/* Mostrar Pokémon del entrenador */} + {selectedTrainer && ( + <Row className="justify-content-center mt-4"> + <Col xs={12} md={8}> + <Card className="border-info"> + <Card.Header className="bg-info text-white"> + {loadingTrainerPokemons ? 'Cargando Pokémon del entrenador...' : 'Pokémon del entrenador'} + </Card.Header> + <ListGroup variant="flush"> + {!loadingTrainerPokemons && trainerPokemons.length === 0 && ( + <ListGroup.Item>El entrenador no tiene Pokémon.</ListGroup.Item> + )} + {trainerPokemons.map((pokemon) => ( + <ListGroup.Item key={pokemon._id}> + {pokemon.nombre} + {pokemon.tipo_1 && ` (${pokemon.tipo_1}${pokemon.tipo_2 ? ` / ${pokemon.tipo_2}` : ''})`} + </ListGroup.Item> + ))} + </ListGroup> + </Card> + </Col> + </Row> + )} + + {/* Mostrar Pokémon efectivos con la estructura x2 y x1 */} {loading ? ( - <p>Cargando Pokémon efectivos...</p> - ) : ( + <Spinner animation="border" variant="primary" className="mt-4" /> + ) : (effectivePokemons.x2?.length > 0 || effectivePokemons.x1?.length > 0) ? ( <> - <h2>Pokémon efectivos</h2> - <ul> - {effectivePokemons.map((pokemon, idx) => ( - <li key={idx}> - {pokemon.nombre} {pokemon.tipo_1 && `(${pokemon.tipo_1}`}{pokemon.tipo_2 && ` / ${pokemon.tipo_2}`}{(pokemon.tipo_1 || pokemon.tipo_2) && ')'} - </li> - ))} - </ul> + {effectivePokemons.x2.length > 0 && ( + <Card className="border-primary mt-4"> + <Card.Header className="bg-primary text-white">Pokémon x2 (Muy efectivos)</Card.Header> + <ListGroup variant="flush"> + {effectivePokemons.x2.map((pokemon) => ( + <ListGroup.Item key={pokemon._id}> + {pokemon.nombre} + {pokemon.tipo_1 && ` (${pokemon.tipo_1}${pokemon.tipo_2 ? ` / ${pokemon.tipo_2}` : ''})`} + </ListGroup.Item> + ))} + </ListGroup> + </Card> + )} + + {effectivePokemons.x1.length > 0 && ( + <Card className="border-secondary mt-4"> + <Card.Header className="bg-secondary text-white">Pokémon x1 (Efectivos)</Card.Header> + <ListGroup variant="flush"> + {effectivePokemons.x1.map((pokemon) => ( + <ListGroup.Item key={pokemon._id}> + {pokemon.nombre} + {pokemon.tipo_1 && ` (${pokemon.tipo_1}${pokemon.tipo_2 ? ` / ${pokemon.tipo_2}` : ''})`} + </ListGroup.Item> + ))} + </ListGroup> + </Card> + )} </> + ) : ( + selectedTrainer && <p className="mt-4 text-muted">No hay Pokémon efectivos para este entrenador.</p> )} - </div> + </Container> ); }; -- GitLab