diff --git a/src/components/ModifyReview.jsx b/src/components/ModifyReview.jsx new file mode 100644 index 0000000..8f70e33 --- /dev/null +++ b/src/components/ModifyReview.jsx @@ -0,0 +1,162 @@ +// ModifyReview.js +import React, { useState } from 'react'; +import { Button, Modal, Form } from 'react-bootstrap'; +import { useAuth } from "./AuthContext"; +import { + StarFill, + Star +} from "react-bootstrap-icons"; + +const ModifyReview = ({ show, reviewId, recipeId, onHide, reloadReviews, funct, reviewInfo }) => { + const [newComment, setNewComment] = useState(reviewInfo.comment); + const [newRating, setNewRating] = useState(reviewInfo.rating); + const [newImage, setNewImage] = useState(reviewInfo.file); + const [characterCount, setCharacterCount] = useState(0); + const { token } = useAuth(); + + const handleUpdateReview = async () => { + const bodyData = { + comment: newComment, + rating: newRating, + }; + if (newImage) { + bodyData.file = newImage; + } + console.log(">>>>NewImage: ", newImage) + + try { + const response = await fetch( + `${process.env.REACT_APP_API_URL}/review/${recipeId}/${reviewId}`, + { + method: 'PUT', + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ comment: newComment, rating: newRating }), + file: newImage + } + ); + + const data = await response.json(); + if (response.ok) { + console.log('Review actualizada:', data); + reloadReviews(); + } else { + console.error('Error al actualizar la revisión:', data); + } + } catch (error) { + console.error('Error en la solicitud de actualización de la revisión:', error); + } + + onHide(); + }; + + const handleDeleteReview = async () => { + try { + const response = await fetch( + `${process.env.REACT_APP_API_URL}/review/${recipeId}/${reviewId}`, + { + method: 'DELETE', + headers: { + Authorization: `Bearer ${token}`, + }, + } + ); + + const data = await response.json(); + if (response.ok) { + console.log('Review eliminada:', data); + reloadReviews(); + } else { + console.error('Error al eliminar la revisión:', data); + } + } catch (error) { + console.error('Error en la solicitud de eliminación de la revisión:', error); + } + + onHide(); + }; + + const renderStars = (amount) => { + let stars = []; + for (let i = 1; i <= 5; i++) { + stars.push( + setNewRating(i)} + > + {i <= amount ? : } + + ); + } + return stars; + }; + + const handleReviewChange = (e) => { + const inputReview = e.target.value; + setNewComment(inputReview) + setCharacterCount(inputReview.length); + }; + + const handleConfirmDelete = () => { + handleDeleteReview(); + }; + + return ( + + + {funct === 'Edit' ? 'Modify' : 'Delete'} review + + + {funct === 'Edit' ? ( + + + New Review + 80 ? 'red' : null }} + /> + {characterCount > 80 && ( + You exceeded 80 characters. + )} + Num characters: {characterCount} + + + New Rating + {renderStars(newRating)} + + + ) : ( + Are you sure delete review? + )} + + + {funct === 'Edit' ? ( + 80}> + Update + + ) : ( + <> + + Accept + + + Cancel + + > + )} + + + ); +}; + +export default ModifyReview; diff --git a/src/components/PostReview.jsx b/src/components/PostReview.jsx index bd7d92a..7dff074 100644 --- a/src/components/PostReview.jsx +++ b/src/components/PostReview.jsx @@ -17,6 +17,8 @@ const PostReview = ({ id, show, onHide, reloadReviews }) => { const { token } = useAuth(); const [error, setError] = useState(null); const [showErrorModal, setShowErrorModal] = useState(false); + const [characterCount, setCharacterCount] = useState(0); + useEffect(() => { @@ -39,6 +41,12 @@ const PostReview = ({ id, show, onHide, reloadReviews }) => { setImage(selectedImage); }; + const handleReviewChange = (e) => { + const inputReview = e.target.value; + setReview(inputReview); + setCharacterCount(inputReview.length); + }; + const handlePostReview = async () => { const reviewData = { username: username, @@ -103,38 +111,47 @@ const PostReview = ({ id, show, onHide, reloadReviews }) => { return (<> - + Post a review - + - + Review setReview(e.target.value)} + onChange={handleReviewChange} + style={{ borderColor: characterCount > 80 ? 'red' : null }} /> + {characterCount > 80 && ( + You exceeded 80 characters. + )} + Num characters: {characterCount} - - + Rating {renderStars(difficulty)} - + Select Image - + Close - + 80} + > Post Review @@ -149,7 +166,7 @@ const PostReview = ({ id, show, onHide, reloadReviews }) => { - setShowErrorModal(false)}> + setShowErrorModal(false)}> Close diff --git a/src/components/RecipeDetail.jsx b/src/components/RecipeDetail.jsx index b19f4a1..55b3151 100644 --- a/src/components/RecipeDetail.jsx +++ b/src/components/RecipeDetail.jsx @@ -2,8 +2,9 @@ import React, { useState, useEffect } from "react"; import { useAuth } from "./AuthContext"; import "../css/common.css"; import "../css/Transitions.css"; +import RecipeCard from "./RecipeCard"; import chefIcon from "../assets/icons/chef.png" -import { useParams, useNavigate } from "react-router-dom"; +import { useParams, useNavigate, Link } from "react-router-dom"; import defaultProfile from "../assets/defaultProfile.png"; import { CSSTransition } from "react-transition-group"; import gyozas from '../assets/gyozas.jpg'; @@ -40,8 +41,7 @@ function RecipeDetail() { const [userId, setUserId] = useState(''); const [userName, setUserName] = useState(''); const [userImage, setUserImage] = useState(''); - const [showModal, setShowModal] = useState(false); - const [user, setUser] = useState({}); + const [similarRecipes, setSimilarRecipes] = useState(''); const { id } = useParams(); const [recipe, setRecipe] = useState({ images: [] }); const [showReviews, setShowReviews] = useState(false); @@ -73,6 +73,7 @@ function RecipeDetail() { useEffect(() => { getRecipe(); + getSimilarRecipes(); if (isLogged()) { getIsLiked(username); } @@ -89,6 +90,17 @@ function RecipeDetail() { .catch((error) => console.error("Error al obtener receta:", error)); }; + const getSimilarRecipes = () => { + fetch(process.env.REACT_APP_API_URL + `/recipe/similar/${id}`) + .then((response) => response.json()) + .then((data) => { + setSimilarRecipes(data) + console.log(">> console.error("Error al obtener recetas similares:", error)); + }; + + const fetchUserData = async (userId) => { try { const response = await fetch(process.env.REACT_APP_API_URL + '/user/' + userId, { @@ -307,8 +319,8 @@ function RecipeDetail() { {recipe.energy ?? "No info of"} kcal - - Toggle Reviews + + Reviews @@ -418,10 +430,31 @@ function RecipeDetail() { + + + + + Similar Recipes + + {similarRecipes.length > 0 ? similarRecipes?.map((recipe) => ( + + + + + + )): null} + + + - {/* Offcanvas para mostrar los comentarios */} + + + setShowReviews(false)} @@ -431,7 +464,7 @@ function RecipeDetail() { Reviews - + { @@ -36,7 +39,7 @@ function Reviews(props) { setShowModalImage(false); }; - const handleOpenModal = (image) => { + const handleOpenModal = () => { setShowModal(true); }; @@ -44,11 +47,25 @@ function Reviews(props) { setShowModal(false); }; + const handleOpenModalReview = (review, funct) => { + setSelectedReview(review); + setShowModalReview(true); + setSelectedFunct(funct); + + }; + + const handleCloseModalReview = () => { + setSelectedReview(null); + setShowModalReview(false); + setSelectedFunct(null); + }; + return ( {isLogged === 'true' ? - + {reviews && reviews.length > 0 && owner !== currentUser ? (<> + Post review + >) : null} : null} - {reviews ? ( + {reviews && reviews.length > 0 ? ( reviews.map((review, index) => ( + {review.image ? - + {review.username}:{" "} - {review.comment} + {review.comment} + /> + {currentUser === review.username && ( + <> + handleOpenModalReview(review, 'Edit')} + /> + handleOpenModalReview(review, 'Trash')} + /> + > + )} + + + + + + : + + + {review.username}:{" "} + + {review.comment} + + + + + + {" "} + {Array(review.rating || 0) + .fill() + .map((_, index) => ( + + + + ))} + + + + + + + {currentUser === review.username && ( + <> + handleOpenModalReview(review, 'Edit')} + /> + handleOpenModalReview(review, 'Trash')} + /> + > + )} - + } )) - ) : ( - Reviews not available + ) : ( owner !== currentUser ? + ( + There are currently no reviews + Be the first one to post a review and share your thoughts! + + Post review + + + ) : + There are currently no reviews + You are the owner of the recipe you can't do reviews + )} @@ -133,8 +239,19 @@ function Reviews(props) { show={showModalImage} onHide={handleCloseModalImage} recipeImage={selectedImage} - recipeName={selectedImage ? "Image" : null} // Puedes cambiar esto según tus necesidades + recipeName={selectedImage ? "Image" : null} /> + {selectedReview && ( + + )} ); }
Are you sure delete review?
Be the first one to post a review and share your thoughts!
You are the owner of the recipe you can't do reviews