Skip to content

Ft0011 vista mascotas #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"""empty message

Revision ID: e6383597b0ac
Revision ID: 3388104734f6
Revises:
Create Date: 2025-03-16 17:29:18.018147
Create Date: 2025-03-17 11:09:47.021713

"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = 'e6383597b0ac'
revision = '3388104734f6'
down_revision = None
branch_labels = None
depends_on = None
Expand Down
50 changes: 31 additions & 19 deletions src/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,23 +90,36 @@ def get_pet(pet_id):
@api.route('/foods/suggestions/<int:pet_id>', methods=['GET'])
@jwt_required()
def get_pet_suggestions(pet_id):
pet = Pet.query.get(pet_id).serialize()
# Problema: Un animal puede tener varias patologias en su campo, habría que coger este campo y tratarlo,
pet = Pet.query.filter_by(id=pet_id).first()
print(pet)
if pet is None:
return jsonify({"msg": "Pet no exist"}), 404
# pet = Pet.query.get(pet_id).serialize()
# Problema: Un animal puede tener varias patologias en su campo, habría que co
# ger este campo y tratarlo,
# separar las patologias en una lista y hacer la query para cada patologia.
# Solucion simple: limitar a 1 patologia cada animal por ahora
#if para pet# anymal_type == perro, animal size #si no no hace falta size
if pet["animal_type"] == "perro":
food_suggestions = db.session.execute(select(Food).where(and_(Food.animal_type==pet["animal_type"]),
Food.size==pet["size"],
Food.age==pet["age"],
Food.pathologies==pet["pathologies"])).all()
# if para pet# anymal_type == perro, animal size #si no no hace falta size
if pet.animal_type == "perro":
food_suggestions = db.session.execute(select(Food).where(and_(Food.animal_type==pet.animal_type),
Food.size==pet.size,
Food.age==pet.age,
Food.pathologies==pet.pathologies)).all()
else:
food_suggestions = db.session.execute(select(Food).where(Food.animal_type==pet["animal_type"]),
Food.age==pet["age"],
Food.pathologies==pet["pathologies"]).all()
food_suggestions = db.session.execute(select(Food).where(Food.animal_type==pet.animal_type),
Food.age==pet.age,
Food.pathologies==pet.pathologies).all()
if not food_suggestions :
return "no suggestions found", 404
return "no suggestions found", 404
return [food[0].serialize() for food in food_suggestions], 200
return jsonify("okey"), 200









# #obtener sugerencias de comida según mascota
Expand Down Expand Up @@ -347,16 +360,16 @@ def create_pet():
current_user_email = get_jwt_identity()
user = User().query.filter_by(email=current_user_email).first()

if not user:
if not user:
return jsonify({"msg": "usuario no encontrado"}), 400

new_pet = Pet(
name=data["name"],
size= None,
breed= None,
size= data["size"],
breed= data["breed"],
age=data["age"],
animal_type=data["animal_type"],
pathologies= None,
pathologies= data["pathologies"],
url=data.get("url"), # Asegúrate de que se está obteniendo correctamente
user_id=user.id
)
Expand Down Expand Up @@ -424,7 +437,7 @@ def update_user():
})


@api.route('/pets/<int:pet_id>', methods=['PUT'])
@api.route('/pet/<int:pet_id>', methods=['PUT'])
@jwt_required()
def new_pet(pet_id):
data = request.get_json()
Expand Down Expand Up @@ -502,7 +515,7 @@ def delete_user():
@jwt_required()
def delete_pet(pet_id):

pet = Pet.query.get(pet_id).first()
pet = Pet.query.get(pet_id)

# Eliminar la mascota de la base de datos
db.session.delete(pet)
Expand All @@ -513,7 +526,6 @@ def delete_pet(pet_id):
'message': f'Pet {pet.name} with id {pet.id} has been deleted successfully.'
}), 200


@api.route('/search', methods=['GET'])
def search_product():
data = request.get_json()
Expand Down
3 changes: 2 additions & 1 deletion src/front/js/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import injectContext from "./store/appContext";

import { Navbar } from "./component/navbar";
import { Footer } from "./component/footer";

import { VistaMascota } from "./pages/vistaMascota";
import { VistaProducto } from "./pages/VistaProducto";

import { LoginSignup } from "./pages/loginSignup";
Expand Down Expand Up @@ -52,6 +52,7 @@ const PageWithNavbar = () => {
<Route element={<Home />} path="/" />
<Route element={<VistaProducto />} path="/vista-producto/:id" />
<Route element={<LoginSignup />} path="/loginSignup" />
<Route element={<VistaMascota />} path="/pets/:id" />
<Route element={<PerfilUsuario />} path="/perfilUsuario" />
<Route element={<Demo />} path="/demo" />
<Route element={<Single />} path="/single/:theid" />
Expand Down
2 changes: 1 addition & 1 deletion src/front/js/pages/perfilUsuario.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const PerfilUsuario = () => {
<div
key={index}
className="text-center cursor-pointer"
onClick={() => navigate(`/mascota/${pet.id}`)}
onClick={() => navigate(`/pets/${pet.id}`)}
style={{ cursor: "pointer" }}
>
<img
Expand Down
239 changes: 239 additions & 0 deletions src/front/js/pages/vistaMascota.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
import React, { useEffect, useState, useContext } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Context } from "../store/appContext";
import { Modal, Button, Form } from 'react-bootstrap';
import "../../styles/home.css";

export const VistaMascota = () => {
const { id } = useParams();
const navigate = useNavigate();
const { actions } = useContext(Context);

const [petDetails, setPetDetails] = useState(null);
const [loading, setLoading] = useState(true);
const [showModal, setShowModal] = useState(false);
const [editedPet, setEditedPet] = useState({
name: "",
animal_type: "",
breed: "",
size: "",
age: "",
pathologies: ""
});
const [foodSuggestions, setFoodSuggestions] = useState([]);

const getPetDetails = async (id) => {
try {
const resp = await fetch(`${process.env.BACKEND_URL}/api/pets/${id}`);
if (resp.status === 404) {
setPetDetails(null);
} else {
const petData = await resp.json();
setPetDetails(petData);
setEditedPet({
name: petData.name || "",
animal_type: petData.animal_type || "",
breed: petData.breed || "",
size: petData.size || "",
age: petData.age || "",
pathologies: petData.pathologies || ""
});
}
} catch (error) {
console.error("Error al obtener los detalles de la mascota", error);
setPetDetails(null);
} finally {
setLoading(false);
}
};

useEffect(() => {
getPetDetails(id);
}, [id]);

useEffect(() => {
if (petDetails) {
actions.getFoodSuggestions(id).then(data => {
setFoodSuggestions(data);
});
}
}, [petDetails, id, actions]);

useEffect(() => {
if (!loading && petDetails === null) {
navigate("/not-found");
}
}, [loading, petDetails, navigate]);

const handleDelete = async () => {
try {
await actions.deletePet(id);
} catch (error) {
console.error("Error al eliminar la mascota (se ignora):", error);
}
navigate("/perfilUsuario");
};

const handleEdit = async () => {
try {
await actions.editPet(id, editedPet);
} catch (error) {
console.error("Error al editar la mascota (se ignora):", error);
}
setShowModal(false);
navigate("/perfilUsuario");
};

if (loading) return <div className="text-center mt-5">Cargando...</div>;
if (!petDetails) return null;

return (
<div className="container mt-5">
<h2>Detalles de la Mascota</h2>
<div className="row">
<div className="col-md-6">
<div className="card">
<img
src={petDetails.url || '/default-image.jpg'}
alt={petDetails.name}
className="card-img-top"
style={{ width: '100%', height: 'auto' }}
/>
<div className="card-body">
<h5 className="card-title">{petDetails.name}</h5>
<p className="card-text"><strong>Especie:</strong> {petDetails.animal_type}</p>
<p className="card-text"><strong>Raza:</strong> {petDetails.breed}</p>
<p className="card-text"><strong>Tamaño:</strong> {petDetails.size}</p>
<p className="card-text"><strong>Edad:</strong> {petDetails.age}</p>
<p className="card-text"><strong>Patologías:</strong> {petDetails.pathologies}</p>
<Button variant="warning" onClick={() => setShowModal(true)} className="me-2">
✏️ Editar
</Button>
<Button variant="danger" onClick={handleDelete}>
🗑️ Eliminar
</Button>
</div>
</div>
</div>
</div>

<div className="row mt-4">
<div className="col-md-12">
<h2>Comida Recomendada</h2>
<div className="d-flex flex-wrap">
{foodSuggestions.length > 0 ? (
foodSuggestions.map((food, index) => (
<div className="card m-2" style={{ width: "18rem" }} key={index}>
<img
src={food.url || "/default-food.jpg"}
className="card-img-top"
alt={food.name}
/>
<div className="card-body">
<h5 className="card-title">{food.name}</h5>
{food.description && <p className="card-text">{food.description}</p>}
</div>
</div>
))
) : (
<p>No se encontraron sugerencias de comida.</p>
)}
</div>
</div>
</div>

{/* Modal para editar mascota */}
<Modal show={showModal} onHide={() => setShowModal(false)}>
<Modal.Header closeButton>
<Modal.Title>Editar Mascota</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3">
<Form.Label>Nombre</Form.Label>
<Form.Control
type="text"
value={editedPet.name || ""}
onChange={(e) => setEditedPet({ ...editedPet, name: e.target.value })}
/>
</Form.Group>

<Form.Group className="mb-3">
<Form.Label>Especie</Form.Label>
<Form.Select
value={editedPet.animal_type || ""}
onChange={(e) => setEditedPet({ ...editedPet, animal_type: e.target.value })}
>
<option value="">Selecciona una especie</option>
<option value="perro">Canina</option>
<option value="gato">Felina</option>
<option value="exótico">Exótico</option>
</Form.Select>
</Form.Group>

<Form.Group className="mb-3">
<Form.Label>Raza</Form.Label>
<Form.Control
type="text"
value={editedPet.breed || ""}
onChange={(e) => setEditedPet({ ...editedPet, breed: e.target.value })}
/>
</Form.Group>

<Form.Group className="mb-3">
<Form.Label>Tamaño</Form.Label>
<Form.Select
value={editedPet.size || ""}
onChange={(e) => setEditedPet({ ...editedPet, size: e.target.value })}
>
<option value="">Selecciona una opción</option>
<option value="razaPequeña">Pequeño (0-10kg)</option>
<option value="razaMediana">Mediano (10-25kg)</option>
<option value="razaGrande">Grande (+25Kg)</option>
</Form.Select>
</Form.Group>

<Form.Group className="mb-3">
<Form.Label>Etapa Vital</Form.Label>
<Form.Select
value={editedPet.age || ""}
onChange={(e) => setEditedPet({ ...editedPet, age: e.target.value })}
>
<option value="">Selecciona una opción</option>
<option value="cachorro">Cachorro (0-1 año)</option>
<option value="adulto">Adulto (1-7 años)</option>
<option value="senior">Senior (+7 años)</option>
</Form.Select>
</Form.Group>

<Form.Group className="mb-3">
<Form.Label>Patologías</Form.Label>
<Form.Select
value={editedPet.pathologies || ""}
onChange={(e) => setEditedPet({ ...editedPet, pathologies: e.target.value })}
>
<option value="">Selecciona una opción</option>
<option value="ninguna">Sin patologias</option>
<option value="diabetico">Diabetes</option>
<option value="renal">Insuficiencia renal</option>
<option value="urinarioStruvita">Urinario Struvita</option>
<option value="urinarioOxalatos">Urinario Oxalatos</option>
<option value="escorbuto">Escorbuto</option>
<option value="obesidad">Obesidad</option>
<option value="hipoalergénico">Hipoalergénico</option>
</Form.Select>
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="primary" onClick={handleEdit}>
Guardar Cambios
</Button>
<Button variant="secondary" onClick={() => setShowModal(false)}>
Cancelar
</Button>
</Modal.Footer>
</Modal>
</div>
);
};
Loading