From c42f1efcfa3088405627a6d6ab272f6ed9a9aa92 Mon Sep 17 00:00:00 2001 From: MinGi-K Date: Thu, 8 Dec 2022 05:26:04 -0500 Subject: [PATCH 01/10] added rating system, with some bugs --- frontend/src/Internship/NumDislikes.js | 40 ++++++++++++++++++ frontend/src/Internship/NumLikes.js | 42 +++++++++++++++++++ frontend/src/Internship/ReviewCard.js | 31 +++++++++++++- .../user/votehelpful/HelpfulController.java | 2 +- .../user/votehelpful/HelpfulInteractor.java | 2 +- .../user/votehelpful/HelpfulRequestModel.java | 2 +- 6 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 frontend/src/Internship/NumDislikes.js create mode 100644 frontend/src/Internship/NumLikes.js diff --git a/frontend/src/Internship/NumDislikes.js b/frontend/src/Internship/NumDislikes.js new file mode 100644 index 00000000..6fe610ce --- /dev/null +++ b/frontend/src/Internship/NumDislikes.js @@ -0,0 +1,40 @@ +import { useEffect, useState } from 'react'; +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; +import axios from 'axios'; + +const NumDislikes = ({reviewId, userId, numDislikes}) => { + + const [numberDislikes, setNumberDislikes] = useState(numDislikes); + + useEffect(()=>{ + console.log("work"); + }, [numberDislikes]) + + + const handleDislike = () =>{ + axios.post(`/users/vote-helpful`, { + isHelpful: "Unhelpful", + reviewId: reviewId, + userId: userId + }).then((res) => { + if (res.data.status === 'SUCCESS') { + if (res.data.vote === 'HELPFUL'){ + setNumberDislikes( numberDislikes - 1); + } else if (res.data.vote === 'UNHELPFUL'){ + setNumberDislikes(numberDislikes + 1); + } else { + console.log("do nothing") + } + } + }); + } + + return( + + ) +} + +export default NumDislikes; \ No newline at end of file diff --git a/frontend/src/Internship/NumLikes.js b/frontend/src/Internship/NumLikes.js new file mode 100644 index 00000000..e209aff5 --- /dev/null +++ b/frontend/src/Internship/NumLikes.js @@ -0,0 +1,42 @@ +import { useEffect, useState } from 'react'; +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; +import axios from 'axios'; + + +const NumLikes = ({reviewId, userId, numLikes}) => { + + + const [numberLikes, setNumberLikes] = useState(numLikes); + + useEffect(()=>{ + console.log("work"); + }, []) + + + const handleLike = () =>{ + axios.post(`/users/vote-helpful`, { + isHelpful: "Helpful", + reviewId: reviewId, + userId: userId + }).then((res) => { + if (res.data.status === 'SUCCESS') { + if (res.data.vote === 'HELPFUL'){ + setNumberLikes(numberLikes + 1); + } else if (res.data.vote === 'UNHELPFUL'){ + setNumberLikes(numberLikes - 1); + } else { + console.log("do nothing") + } + } + }); + } + + return( + + ) +} + +export default NumLikes; \ No newline at end of file diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index f631f91f..f107a759 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -11,6 +11,8 @@ import useAuthContext from '../AuthContext'; import Rating from '@mui/material/Rating'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import FavoriteIcon from '@mui/icons-material/Favorite'; +import NumLikes from './NumLikes' +import NumDislikes from "./NumDislikes"; export default function ReviewCard({ reviewId, @@ -24,10 +26,13 @@ export default function ReviewCard({ const { corporateId, internshipId } = useParams(); const [showComment, setShowComment] = useState(false); const [moreComments, setMoreComments] = useState([]); + const [numberLikes, setNumberLikes] = useState(numLikes); + const [numberDislikes, setNumberDislikes] = useState(numDislikes); const authContext = useAuthContext(); const principal = authContext.principal; const handleDelete = () => { console.log('called'); + console.log('numlikes:' + numLikes); axios .delete(`/corporates/${corporateId}/internships/${internshipId}/reviews/${reviewId}`, { data: { @@ -80,6 +85,24 @@ export default function ReviewCard({ }); }; + const handleLike = () =>{ + axios.post(`/users/vote-helpful`, { + isHelpful: "Helpful", + reviewId: reviewId, + userId: userId + }).then((res) => { + if (res.data.status === 'SUCCESS') { + if (res.data.vote === 'HELPFUL'){ + setNumberLikes(numberLikes + 1); + } else if (res.data.vote === 'UNHELPFUL'){ + setNumberDislikes(numberDislikes + 1); + } else { + console.log("do nothing") + } + } + }); + } + return ( - 👍 {numLikes} - 👎 {numDislikes} + {/**/} + + + create(@RequestBody HelpfulRequestModel requestModel) { HelpfulResponseModel responseModel = input.create(requestModel); String status = responseModel.getStatus().toString(); diff --git a/src/main/java/user/votehelpful/HelpfulInteractor.java b/src/main/java/user/votehelpful/HelpfulInteractor.java index 60e3da47..0c7b7109 100644 --- a/src/main/java/user/votehelpful/HelpfulInteractor.java +++ b/src/main/java/user/votehelpful/HelpfulInteractor.java @@ -43,7 +43,7 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { HashMap votedUsers = review.getVotedUsers(); VoteDecision previousVote; - boolean userHasVoted = votedUsers.keySet().contains(userId); + boolean userHasVoted = votedUsers.containsKey(userId); if (userHasVoted) { previousVote = votedUsers.get(userId); diff --git a/src/main/java/user/votehelpful/HelpfulRequestModel.java b/src/main/java/user/votehelpful/HelpfulRequestModel.java index 1fd300b9..08331b13 100644 --- a/src/main/java/user/votehelpful/HelpfulRequestModel.java +++ b/src/main/java/user/votehelpful/HelpfulRequestModel.java @@ -1,7 +1,7 @@ package user.votehelpful; /** A request model for the votehelpful use case that frames the input data into an object. Holds - * a boolean representation of if the review is helpful or not in isHelpful, and an int + * a String isHelpful corresponding to an ENUM class, and an int * representation of the review's id in reviewId. */ public class HelpfulRequestModel { From 49c31af20a4e5c9d5ea617f69a6ac06b4a644d0b Mon Sep 17 00:00:00 2001 From: MinGi-K Date: Thu, 8 Dec 2022 05:34:03 -0500 Subject: [PATCH 02/10] squash --- frontend/src/Internship/ReviewCard.js | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index f107a759..614ac94c 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -26,8 +26,6 @@ export default function ReviewCard({ const { corporateId, internshipId } = useParams(); const [showComment, setShowComment] = useState(false); const [moreComments, setMoreComments] = useState([]); - const [numberLikes, setNumberLikes] = useState(numLikes); - const [numberDislikes, setNumberDislikes] = useState(numDislikes); const authContext = useAuthContext(); const principal = authContext.principal; const handleDelete = () => { @@ -85,23 +83,6 @@ export default function ReviewCard({ }); }; - const handleLike = () =>{ - axios.post(`/users/vote-helpful`, { - isHelpful: "Helpful", - reviewId: reviewId, - userId: userId - }).then((res) => { - if (res.data.status === 'SUCCESS') { - if (res.data.vote === 'HELPFUL'){ - setNumberLikes(numberLikes + 1); - } else if (res.data.vote === 'UNHELPFUL'){ - setNumberDislikes(numberDislikes + 1); - } else { - console.log("do nothing") - } - } - }); - } return ( - {/**/} From 3d520a00aada9dbdc9fa064c306da0a4cb54ac0a Mon Sep 17 00:00:00 2001 From: leowrites <75044178+leowrites@users.noreply.github.com> Date: Thu, 8 Dec 2022 10:51:06 -0500 Subject: [PATCH 03/10] fix bug --- frontend/src/Internship/NumLikes.js | 5 ----- src/main/java/usecases/votehelpful/HelpfulController.java | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/frontend/src/Internship/NumLikes.js b/frontend/src/Internship/NumLikes.js index e209aff5..c0839dab 100644 --- a/frontend/src/Internship/NumLikes.js +++ b/frontend/src/Internship/NumLikes.js @@ -9,11 +9,6 @@ const NumLikes = ({reviewId, userId, numLikes}) => { const [numberLikes, setNumberLikes] = useState(numLikes); - useEffect(()=>{ - console.log("work"); - }, []) - - const handleLike = () =>{ axios.post(`/users/vote-helpful`, { isHelpful: "Helpful", diff --git a/src/main/java/usecases/votehelpful/HelpfulController.java b/src/main/java/usecases/votehelpful/HelpfulController.java index 28a0e4d3..a993b6a2 100644 --- a/src/main/java/usecases/votehelpful/HelpfulController.java +++ b/src/main/java/usecases/votehelpful/HelpfulController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import service.ServerStatus; /** The votehelpful use case controller that connects to Spring. Takes in a HelpfulRequestModel * from the user input in front-end, creates a HelpfulResponseModel by sending the request model to @@ -26,8 +27,7 @@ public HelpfulController(IHelpfulInputBoundary input) { @PostMapping("users/vote-helpful") public ResponseEntity create(@RequestBody HelpfulRequestModel requestModel) { HelpfulResponseModel responseModel = input.create(requestModel); - String status = responseModel.getStatus().toString(); - if (status.equals("Success")) { + if (responseModel.getStatus() == ServerStatus.SUCCESS) { return new ResponseEntity<>(responseModel, HttpStatus.OK); } else { From 4e00bc1a031b278b7475347361d73f33807eb2e4 Mon Sep 17 00:00:00 2001 From: leowrites <75044178+leowrites@users.noreply.github.com> Date: Thu, 8 Dec 2022 14:20:41 -0500 Subject: [PATCH 04/10] bug fix --- src/main/java/usecases/comment/CommentController.java | 4 ++-- src/main/java/usecases/comment/CommentResponseModel.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/usecases/comment/CommentController.java b/src/main/java/usecases/comment/CommentController.java index a4e36f5c..abf606e4 100644 --- a/src/main/java/usecases/comment/CommentController.java +++ b/src/main/java/usecases/comment/CommentController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; +import service.ServerStatus; /** The comment use case controller that connects to Spring. Takes in a CommentRequestModel * from the user input in front-end, creates a CommentResponseModel by sending the request model @@ -26,8 +27,7 @@ public CommentController(ICommentInputBoundary input){ @PostMapping("/corporates/{corporateId}/internships/{internshipId}/reviews/{reviewId}/comments") public ResponseEntity create(@RequestBody CommentRequestModel requestModel) { CommentResponseModel responseModel = input.create(requestModel); - String status = responseModel.getStatus().toString(); - if (status.equals("success")) { + if (responseModel.getStatus() == ServerStatus.SUCCESS) { return new ResponseEntity<>(responseModel, HttpStatus.OK); } else { diff --git a/src/main/java/usecases/comment/CommentResponseModel.java b/src/main/java/usecases/comment/CommentResponseModel.java index dbe4fbdc..56989595 100644 --- a/src/main/java/usecases/comment/CommentResponseModel.java +++ b/src/main/java/usecases/comment/CommentResponseModel.java @@ -29,6 +29,10 @@ public String getMessage() { return this.message; } + public Date getDatePosted() { + return datePosted; + } + public int getId() { return this.id; } From b54563b8a090fb690dd25f3c7c2e109571823cf4 Mon Sep 17 00:00:00 2001 From: MinGi-K Date: Sun, 25 Dec 2022 08:45:07 +0900 Subject: [PATCH 05/10] fixed bug of review DAO mapper always setting a empty hashmap --- .idea/vcs.xml | 1 + frontend/src/Internship/NumDislikes.js | 7 +++++-- frontend/src/Internship/NumLikes.js | 7 +++++-- frontend/src/Internship/ReviewCard.js | 4 ++-- src/main/java/service/dao/ReviewDaoMapper.java | 2 +- src/main/java/usecases/votehelpful/HelpfulInteractor.java | 4 ++++ 6 files changed, 18 insertions(+), 7 deletions(-) diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7f..5938de3c 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/frontend/src/Internship/NumDislikes.js b/frontend/src/Internship/NumDislikes.js index 6fe610ce..6aa33c35 100644 --- a/frontend/src/Internship/NumDislikes.js +++ b/frontend/src/Internship/NumDislikes.js @@ -2,9 +2,12 @@ import { useEffect, useState } from 'react'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; import axios from 'axios'; +import useAuthContext from "../AuthContext"; -const NumDislikes = ({reviewId, userId, numDislikes}) => { +const NumDislikes = ({reviewId, numDislikes}) => { + const authContext = useAuthContext(); + const principal = authContext.principal; const [numberDislikes, setNumberDislikes] = useState(numDislikes); useEffect(()=>{ @@ -16,7 +19,7 @@ const NumDislikes = ({reviewId, userId, numDislikes}) => { axios.post(`/users/vote-helpful`, { isHelpful: "Unhelpful", reviewId: reviewId, - userId: userId + userId: principal.username }).then((res) => { if (res.data.status === 'SUCCESS') { if (res.data.vote === 'HELPFUL'){ diff --git a/frontend/src/Internship/NumLikes.js b/frontend/src/Internship/NumLikes.js index c0839dab..856651c7 100644 --- a/frontend/src/Internship/NumLikes.js +++ b/frontend/src/Internship/NumLikes.js @@ -2,18 +2,21 @@ import { useEffect, useState } from 'react'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; import axios from 'axios'; +import useAuthContext from "../AuthContext"; -const NumLikes = ({reviewId, userId, numLikes}) => { +const NumLikes = ({reviewId, numLikes}) => { const [numberLikes, setNumberLikes] = useState(numLikes); + const authContext = useAuthContext(); + const principal = authContext.principal; const handleLike = () =>{ axios.post(`/users/vote-helpful`, { isHelpful: "Helpful", reviewId: reviewId, - userId: userId + userId: principal.username }).then((res) => { if (res.data.status === 'SUCCESS') { if (res.data.vote === 'HELPFUL'){ diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index 614ac94c..f8dbf224 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -110,8 +110,8 @@ export default function ReviewCard({ borderRadius: 3, }} elevation={5}> - - + + diff --git a/src/main/java/service/dao/ReviewDaoMapper.java b/src/main/java/service/dao/ReviewDaoMapper.java index 6432d25e..c5291618 100644 --- a/src/main/java/service/dao/ReviewDaoMapper.java +++ b/src/main/java/service/dao/ReviewDaoMapper.java @@ -33,7 +33,7 @@ public Review mapRow(ResultSet rs, int rowNum) throws SQLException { try { review.setId(rs.getInt("id")); review.setInternshipId(rs.getInt("internshipid")); - review.setVotedUsers(new HashMap<>()); +// review.setVotedUsers(new HashMap<>()); } catch (PSQLException e) { System.out.print("at ReviewDaoMapper"); System.out.println(e); diff --git a/src/main/java/usecases/votehelpful/HelpfulInteractor.java b/src/main/java/usecases/votehelpful/HelpfulInteractor.java index 7d1d56a3..b7a63b0c 100644 --- a/src/main/java/usecases/votehelpful/HelpfulInteractor.java +++ b/src/main/java/usecases/votehelpful/HelpfulInteractor.java @@ -46,6 +46,7 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { boolean userHasVoted = votedUsers.containsKey(userId); if (userHasVoted) { + System.out.println("userVoted"); previousVote = votedUsers.get(userId); if (newVote.equals(previousVote)) { review = HelpfulHandler.updateCount(newVote, review, "Subtraction"); @@ -53,17 +54,20 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { newVote = VoteDecision.NONE; } else { + review = HelpfulHandler.updateCount(previousVote, review, "Subtraction"); review = HelpfulHandler.updateCount(newVote, review, "Addition"); votedUsers.replace(userId, newVote); } } else { + System.out.println("noVote"); votedUsers.put(userId, newVote); review = HelpfulHandler.updateCount(newVote, review, "Addition"); } review.setVotedUsers(votedUsers); + System.out.println(votedUsers.toString()); reviewDAO.updateReview(review, reviewId); return new HelpfulResponseModel(ServerStatus.SUCCESS, "Vote received.", newVote); From 473a2a86e0124b17dcbe1cd4fcac99e601ef992d Mon Sep 17 00:00:00 2001 From: MinGi-K Date: Sun, 25 Dec 2022 09:14:30 +0900 Subject: [PATCH 06/10] fixed front and backend logic for like and dislike --- frontend/src/Internship/ReviewCard.js | 4 +- frontend/src/Internship/VoteCount.js | 57 +++++++++++++++++++ .../votehelpful/HelpfulInteractor.java | 8 ++- .../votehelpful/HelpfulResponseModel.java | 27 +++++++-- 4 files changed, 87 insertions(+), 9 deletions(-) create mode 100644 frontend/src/Internship/VoteCount.js diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index f8dbf224..0a13064b 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -13,6 +13,7 @@ import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import FavoriteIcon from '@mui/icons-material/Favorite'; import NumLikes from './NumLikes' import NumDislikes from "./NumDislikes"; +import VoteCount from "./VoteCount" export default function ReviewCard({ reviewId, @@ -110,8 +111,7 @@ export default function ReviewCard({ borderRadius: 3, }} elevation={5}> - - + diff --git a/frontend/src/Internship/VoteCount.js b/frontend/src/Internship/VoteCount.js new file mode 100644 index 00000000..2d7892d4 --- /dev/null +++ b/frontend/src/Internship/VoteCount.js @@ -0,0 +1,57 @@ +import { useState } from 'react'; +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; +import axios from 'axios'; +import useAuthContext from "../AuthContext"; + + +const VoteCount = ({reviewId, numLikes, numDislikes}) => { + + const [numberDislikes, setNumberDislikes] = useState(numDislikes); + const [numberLikes, setNumberLikes] = useState(numLikes); + const authContext = useAuthContext(); + const principal = authContext.principal; + + const handleLike = () =>{ + axios.post(`/users/vote-helpful`, { + isHelpful: "Helpful", + reviewId: reviewId, + userId: principal.username + }).then((res) => { + if (res.data.status === 'SUCCESS') { + setNumberLikes(res.data.finalHelpfulVote); + console.log(res.data.finalHelpfulVote); + setNumberDislikes(res.data.finalUnhelpfulVote); + console.log(res.data.finalUnhelpfulVote); + } + }); + } + + const handleDislike = () =>{ + axios.post(`/users/vote-helpful`, { + isHelpful: "Unhelpful", + reviewId: reviewId, + userId: principal.username + }).then((res) => { + if (res.data.status === 'SUCCESS') { + setNumberLikes(res.data.finalHelpfulVote); + console.log(res.data.finalHelpfulVote); + setNumberDislikes(res.data.finalUnhelpfulVote); + console.log(res.data.finalUnhelpfulVote); + } + }); + } + + return( + <> + + + + ) +} + +export default VoteCount; \ No newline at end of file diff --git a/src/main/java/usecases/votehelpful/HelpfulInteractor.java b/src/main/java/usecases/votehelpful/HelpfulInteractor.java index b7a63b0c..0598acf1 100644 --- a/src/main/java/usecases/votehelpful/HelpfulInteractor.java +++ b/src/main/java/usecases/votehelpful/HelpfulInteractor.java @@ -34,7 +34,7 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { } } catch (ReviewNotFoundException e) { - return new HelpfulResponseModel(ServerStatus.ERROR, e.getMessage(), VoteDecision.NONE); + return new HelpfulResponseModel(ServerStatus.ERROR, e.getMessage(), 0, 0, VoteDecision.NONE); } String userId = requestModel.getUserId(); @@ -70,6 +70,10 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { System.out.println(votedUsers.toString()); reviewDAO.updateReview(review, reviewId); - return new HelpfulResponseModel(ServerStatus.SUCCESS, "Vote received.", newVote); + return new HelpfulResponseModel(ServerStatus.SUCCESS, + "Vote received.", + review.getNumLikes(), + review.getNumDislikes(), + newVote); } } diff --git a/src/main/java/usecases/votehelpful/HelpfulResponseModel.java b/src/main/java/usecases/votehelpful/HelpfulResponseModel.java index dc96e22a..eb7c6a80 100644 --- a/src/main/java/usecases/votehelpful/HelpfulResponseModel.java +++ b/src/main/java/usecases/votehelpful/HelpfulResponseModel.java @@ -8,12 +8,21 @@ public class HelpfulResponseModel { private final ServerStatus status; private final String message; - private final VoteDecision vote; + private final int finalHelpfulVote; + private final int finalUnhelpfulVote; - public HelpfulResponseModel(ServerStatus status, String message, VoteDecision vote) { + private final VoteDecision voteDecision; + + public HelpfulResponseModel(ServerStatus status, + String message, + int finalHelpfulVote, + int finalUnhelpfulVote, + VoteDecision voteDecision) { this.status = status; this.message = message; - this.vote = vote; + this.finalHelpfulVote = finalHelpfulVote; + this.finalUnhelpfulVote = finalUnhelpfulVote; + this.voteDecision = voteDecision; } public ServerStatus getStatus() { @@ -24,7 +33,15 @@ public String getMessage() { return this.message; } - public VoteDecision getVote() { - return this.vote; + public int getFinalHelpfulVote() { + return finalHelpfulVote; + } + + public int getFinalUnhelpfulVote() { + return finalUnhelpfulVote; + } + + public VoteDecision getVoteDecision() { + return voteDecision; } } \ No newline at end of file From 9e4cbdd76c35bb711b01f8a0354367bdd91a824f Mon Sep 17 00:00:00 2001 From: leowrites <75044178+leowrites@users.noreply.github.com> Date: Sat, 24 Dec 2022 20:29:50 -0500 Subject: [PATCH 07/10] refactor likes/dislikes --- frontend/src/Internship/LikesPanel.js | 71 ++++++++++++++++++++++++++ frontend/src/Internship/NumDislikes.js | 47 ++++------------- frontend/src/Internship/NumLikes.js | 39 +++----------- frontend/src/Internship/ReviewCard.js | 18 +------ 4 files changed, 89 insertions(+), 86 deletions(-) create mode 100644 frontend/src/Internship/LikesPanel.js diff --git a/frontend/src/Internship/LikesPanel.js b/frontend/src/Internship/LikesPanel.js new file mode 100644 index 00000000..8de119ab --- /dev/null +++ b/frontend/src/Internship/LikesPanel.js @@ -0,0 +1,71 @@ +import Paper from '@mui/material/Paper'; +import NumLikes from './NumLikes'; +import NumDislikes from './NumDislikes'; +import { useState } from 'react'; +import axios from 'axios'; + +export default function LikesPanel({ userId, numLikes, numDislikes, reviewId }) { + const [votes, setVotes] = useState({ + likes: numLikes, + dislikes: numDislikes + }) + + const handleLike = () => { + axios + .post(`/users/vote-helpful`, { + isHelpful: 'Helpful', + reviewId: reviewId, + userId: userId, + }) + .then((res) => { + if (res.data.status === 'SUCCESS') { + setVotes({ + likes: res.data.votes[0], + dislikes: res.data.votes[1] + }) + } + }); + }; + + const handleDislike = () => { + axios + .post(`/users/vote-helpful`, { + isHelpful: 'Unhelpful', + reviewId: reviewId, + userId: userId, + }) + .then((res) => { + if (res.data.status === 'SUCCESS') { + setVotes({ + likes: res.data.votes[0], + dislikes: res.data.votes[1] + }) + } + }); + }; + return ( + + + + + ); +} diff --git a/frontend/src/Internship/NumDislikes.js b/frontend/src/Internship/NumDislikes.js index 6fe610ce..1c4cc513 100644 --- a/frontend/src/Internship/NumDislikes.js +++ b/frontend/src/Internship/NumDislikes.js @@ -1,40 +1,13 @@ -import { useEffect, useState } from 'react'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; -import axios from 'axios'; -const NumDislikes = ({reviewId, userId, numDislikes}) => { - - const [numberDislikes, setNumberDislikes] = useState(numDislikes); - - useEffect(()=>{ - console.log("work"); - }, [numberDislikes]) - - - const handleDislike = () =>{ - axios.post(`/users/vote-helpful`, { - isHelpful: "Unhelpful", - reviewId: reviewId, - userId: userId - }).then((res) => { - if (res.data.status === 'SUCCESS') { - if (res.data.vote === 'HELPFUL'){ - setNumberDislikes( numberDislikes - 1); - } else if (res.data.vote === 'UNHELPFUL'){ - setNumberDislikes(numberDislikes + 1); - } else { - console.log("do nothing") - } - } - }); - } - - return( - - ) -} - -export default NumDislikes; \ No newline at end of file +export default function NumDislikes ({ numDislikes, handleDislike }) { + return ( + + ); +}; diff --git a/frontend/src/Internship/NumLikes.js b/frontend/src/Internship/NumLikes.js index c0839dab..020c5dae 100644 --- a/frontend/src/Internship/NumLikes.js +++ b/frontend/src/Internship/NumLikes.js @@ -1,37 +1,10 @@ -import { useEffect, useState } from 'react'; import Typography from '@mui/material/Typography'; import Button from '@mui/material/Button'; -import axios from 'axios'; - -const NumLikes = ({reviewId, userId, numLikes}) => { - - - const [numberLikes, setNumberLikes] = useState(numLikes); - - const handleLike = () =>{ - axios.post(`/users/vote-helpful`, { - isHelpful: "Helpful", - reviewId: reviewId, - userId: userId - }).then((res) => { - if (res.data.status === 'SUCCESS') { - if (res.data.vote === 'HELPFUL'){ - setNumberLikes(numberLikes + 1); - } else if (res.data.vote === 'UNHELPFUL'){ - setNumberLikes(numberLikes - 1); - } else { - console.log("do nothing") - } - } - }); - } - - return( - - ) +export default function NumLikes({ numLikes, handleLike }) { + return ( + + ); } - -export default NumLikes; \ No newline at end of file diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index 2dfd7776..007ba40d 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -13,6 +13,7 @@ import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import FavoriteIcon from '@mui/icons-material/Favorite'; import NumLikes from './NumLikes' import NumDislikes from "./NumDislikes"; +import LikesPanel from './LikesPanel'; export default function ReviewCard({ reviewId, @@ -100,22 +101,7 @@ export default function ReviewCard({ {userId} - - - - - + Date: Sat, 24 Dec 2022 20:30:07 -0500 Subject: [PATCH 08/10] return votes in response model --- src/main/java/service/dao/ReviewDaoMapper.java | 1 - .../usecases/votehelpful/HelpfulInteractor.java | 14 +++++++------- .../usecases/votehelpful/HelpfulResponseModel.java | 10 +++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/service/dao/ReviewDaoMapper.java b/src/main/java/service/dao/ReviewDaoMapper.java index 3fb99f81..0bd28a8c 100644 --- a/src/main/java/service/dao/ReviewDaoMapper.java +++ b/src/main/java/service/dao/ReviewDaoMapper.java @@ -33,7 +33,6 @@ public Review mapRow(ResultSet rs, int rowNum) throws SQLException { try { review.setId(rs.getInt("id")); review.setInternshipId(rs.getInt("internshipid")); - review.setVotedUsers(new HashMap<>()); } catch (PSQLException e) { System.out.print("at ReviewDaoMapper"); System.out.println(e); diff --git a/src/main/java/usecases/votehelpful/HelpfulInteractor.java b/src/main/java/usecases/votehelpful/HelpfulInteractor.java index 7d1d56a3..c6653bbd 100644 --- a/src/main/java/usecases/votehelpful/HelpfulInteractor.java +++ b/src/main/java/usecases/votehelpful/HelpfulInteractor.java @@ -34,7 +34,7 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { } } catch (ReviewNotFoundException e) { - return new HelpfulResponseModel(ServerStatus.ERROR, e.getMessage(), VoteDecision.NONE); + return new HelpfulResponseModel(ServerStatus.ERROR, e.getMessage(), null); } String userId = requestModel.getUserId(); @@ -48,24 +48,24 @@ public HelpfulResponseModel create(HelpfulRequestModel requestModel) { if (userHasVoted) { previousVote = votedUsers.get(userId); if (newVote.equals(previousVote)) { - review = HelpfulHandler.updateCount(newVote, review, "Subtraction"); + HelpfulHandler.updateCount(newVote, review, "Subtraction"); votedUsers.remove(userId); newVote = VoteDecision.NONE; } else { - review = HelpfulHandler.updateCount(previousVote, review, "Subtraction"); - review = HelpfulHandler.updateCount(newVote, review, "Addition"); + HelpfulHandler.updateCount(previousVote, review, "Subtraction"); + HelpfulHandler.updateCount(newVote, review, "Addition"); votedUsers.replace(userId, newVote); } } else { votedUsers.put(userId, newVote); - review = HelpfulHandler.updateCount(newVote, review, "Addition"); + HelpfulHandler.updateCount(newVote, review, "Addition"); } review.setVotedUsers(votedUsers); reviewDAO.updateReview(review, reviewId); - - return new HelpfulResponseModel(ServerStatus.SUCCESS, "Vote received.", newVote); + int[] votes = { review.getNumLikes(), review.getNumDislikes() }; + return new HelpfulResponseModel(ServerStatus.SUCCESS, "Vote received.", votes); } } diff --git a/src/main/java/usecases/votehelpful/HelpfulResponseModel.java b/src/main/java/usecases/votehelpful/HelpfulResponseModel.java index dc96e22a..2cbed6ea 100644 --- a/src/main/java/usecases/votehelpful/HelpfulResponseModel.java +++ b/src/main/java/usecases/votehelpful/HelpfulResponseModel.java @@ -8,12 +8,12 @@ public class HelpfulResponseModel { private final ServerStatus status; private final String message; - private final VoteDecision vote; + private final int[] votes; - public HelpfulResponseModel(ServerStatus status, String message, VoteDecision vote) { + public HelpfulResponseModel(ServerStatus status, String message, int[] votes) { this.status = status; this.message = message; - this.vote = vote; + this.votes = votes; } public ServerStatus getStatus() { @@ -24,7 +24,7 @@ public String getMessage() { return this.message; } - public VoteDecision getVote() { - return this.vote; + public int[] getVotes() { + return this.votes; } } \ No newline at end of file From 51d044927cd49012682e7a1267692663a2cde801 Mon Sep 17 00:00:00 2001 From: leowrites <75044178+leowrites@users.noreply.github.com> Date: Sat, 24 Dec 2022 21:04:58 -0500 Subject: [PATCH 09/10] Move post comment/review into CommentBox --- frontend/src/Internship/CommentBox.js | 52 +++++++++++++++++++---- frontend/src/Internship/CommentCard.js | 37 +++------------- frontend/src/Internship/InternshipPage.js | 2 +- frontend/src/Internship/ReviewCard.js | 34 +++------------ 4 files changed, 57 insertions(+), 68 deletions(-) diff --git a/frontend/src/Internship/CommentBox.js b/frontend/src/Internship/CommentBox.js index 828d4a92..bf691d02 100644 --- a/frontend/src/Internship/CommentBox.js +++ b/frontend/src/Internship/CommentBox.js @@ -3,23 +3,59 @@ import { useState } from 'react'; import Button from '@mui/material/Button'; import CustomTextField from '../Component/CustomTextfield'; import useTheme from '@mui/material/styles/useTheme'; +import useAuthContext from '../AuthContext'; +import axios from 'axios'; +import { useParams } from 'react-router-dom'; -export default function CommentBox({ handleShowCommentBox, postComment, parentType, parentId, rating }) { +export default function CommentBox({ + handleShowCommentBox, + parentType, + parentId, + reviewId, + postReview, + rating, + handleAddComments, +}) { const [comment, setComment] = useState(''); const [clicked, setClicked] = useState(false); + const authContext = useAuthContext(); + const principal = authContext.principal const theme = useTheme(); + const { corporateId, internshipId } = useParams() const handleClickPost = () => { - setClicked(true) - parentType === 'Internship' - ? postComment(comment, rating) - : postComment(parentType, parentId, comment); + setClicked(true); + parentType === 'Internship' ? postReview(comment, rating) : + postComment(); setTimeout(() => { - setClicked(false) - }, 3000) - } + setClicked(false); + }, 3000); + }; const handleValChange = (e) => { setComment(e.target.value); }; + + const postComment = () => { + axios + .post(`/corporates/${corporateId}/internships/${internshipId}/reviews/${reviewId}/comments`, { + userId: principal.username, + parentType: parentType, + parentId: parentId, + content: comment, + }) + .then((res) => { + if (res.data.status === 'SUCCESS') { + handleShowCommentBox(); + handleAddComments({ + userId: principal.username, + id: res.data.id, + content: comment, + comments: [], + datePosted: res.data.datePosted, + }); + } + }); + }; + return ( { console.log(commentId, parentType, parentId, userId); setClickedDelete(true); @@ -44,6 +42,11 @@ export default function CommentCard({ setClickedDelete(false); }, 3000); }; + + const handleAddComments = (comment) => { + setMoreComments([...moreComments, comment]); + } + const handleShowCommentBox = () => { setShowComment(!showComment); }; @@ -58,32 +61,6 @@ export default function CommentCard({ .then((res) => setMoreComments(res.data)); }; - const postComment = (parentType, parentId, comment) => { - console.log(parentType, parentId, comment, reviewId); - axios - .post(`/corporates/${corporateId}/internships/${internshipId}/reviews/${reviewId}/comments`, { - userId: principal.username, - parentType: parentType, - parentId: parentId, - content: comment, - }) - .then((res) => { - if (res.data.status === 'SUCCESS') { - setShowComment(false); - setMoreComments([ - ...moreComments, - { - userId: principal.username, - id: res.data.id, - content: comment, - comments: [], - datePosted: res.data.datePosted, - }, - ]); - } - }); - }; - return ( ) : undefined} {moreComments.length > 0 && moreComments.map((comment) => { - console.log(comment); return ( diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index 9d076f67..f7e3d88b 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -6,7 +6,6 @@ import axios from 'axios'; import CommentBox from './CommentBox'; import { useParams } from 'react-router-dom'; import CommentCard from './CommentCard'; -import useAuthContext from '../AuthContext'; import Rating from '@mui/material/Rating'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import FavoriteIcon from '@mui/icons-material/Favorite'; @@ -25,8 +24,6 @@ export default function ReviewCard({ const [showComment, setShowComment] = useState(false); const [moreComments, setMoreComments] = useState([]); const [clickedDelete, setClickedDelete] = useState(false); - const authContext = useAuthContext(); - const principal = authContext.principal; const handleDelete = () => { setClickedDelete(true); axios @@ -58,31 +55,9 @@ export default function ReviewCard({ .then((res) => setMoreComments(res.data)); }; - const postComment = (parentType, parentId, comment) => { - console.log(parentType, parentId, comment, reviewId); - axios - .post(`/corporates/${corporateId}/internships/${internshipId}/reviews/${reviewId}/comments`, { - userId: principal.username, - parentType: parentType, - parentId: parentId, - content: comment, - }) - .then((res) => { - if (res.data.status === 'SUCCESS') { - setShowComment(false); - setMoreComments([ - ...moreComments, - { - userId: principal.username, - id: res.data.id, - content: comment, - comments: [], - datePosted: res.data.datePosted, - }, - ]); - } - }); - }; + const handleAddComments = (comment) => { + setMoreComments([...moreComments, comment]); + } return ( ) : undefined} From 9d6b4ad304da0a44e68b35b55a39419277d9cc80 Mon Sep 17 00:00:00 2001 From: leowrites <75044178+leowrites@users.noreply.github.com> Date: Sat, 24 Dec 2022 21:14:17 -0500 Subject: [PATCH 10/10] Fix tests --- .../votehelpful/HelpfulInteractorTest.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/test/java/usecases/votehelpful/HelpfulInteractorTest.java b/src/test/java/usecases/votehelpful/HelpfulInteractorTest.java index 397f8e70..f42ccdea 100644 --- a/src/test/java/usecases/votehelpful/HelpfulInteractorTest.java +++ b/src/test/java/usecases/votehelpful/HelpfulInteractorTest.java @@ -11,10 +11,10 @@ import service.ServerStatus; import service.dao.IReviewDAO; +import java.util.Arrays; import java.util.HashMap; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; @RunWith(SpringRunner.class) @SpringBootTest(classes = Application.class) @@ -47,10 +47,11 @@ public void testUserWithNoPriorVoteVotesReviewAsHelpful() { HelpfulRequestModel requestModel = new HelpfulRequestModel("Helpful", reviewId, "justinli"); HelpfulResponseModel responseModel = interactor.create(requestModel); + int[] expectedVotes = {1, 0}; // test that the interactor returns a successful response model assertEquals(ServerStatus.SUCCESS, responseModel.getStatus()); assertEquals("Vote received.", responseModel.getMessage()); - assertEquals(VoteDecision.HELPFUL, responseModel.getVote()); + assertArrayEquals(expectedVotes, responseModel.getVotes()); // test that the review was properly updated review = reviewDAO.getReview(reviewId); @@ -72,10 +73,11 @@ public void testUserWithNoPriorVotesVotesReviewAsUnhelpful() { HelpfulRequestModel requestModel = new HelpfulRequestModel("Unhelpful", reviewId, "justinli"); HelpfulResponseModel responseModel = interactor.create(requestModel); + int[] expectedVotes = {0, 1}; // test that the interactor returns a success response model assertEquals(ServerStatus.SUCCESS, responseModel.getStatus()); assertEquals("Vote received.", responseModel.getMessage()); - assertEquals(VoteDecision.UNHELPFUL, responseModel.getVote()); + assertArrayEquals(expectedVotes, responseModel.getVotes()); // test that the review was properly updated review = reviewDAO.getReview(reviewId); @@ -96,7 +98,8 @@ public void testUserVotesTwiceForHelpful() { interactor.create(requestModel1); HelpfulResponseModel responseModel = interactor.create(requestModel2); - assertEquals(VoteDecision.NONE, responseModel.getVote()); + int[] expectedVotes = {0, 0}; + assertArrayEquals(expectedVotes, responseModel.getVotes()); review = reviewDAO.getReview(reviewId); assertEquals(0, review.getNumLikes()); assertEquals(0, review.getVotedUsers().keySet().size()); @@ -111,7 +114,8 @@ public void testUserVotesTwiceForUnhelpful() { interactor.create(requestModel1); HelpfulResponseModel responseModel = interactor.create(requestModel2); - assertEquals(VoteDecision.NONE, responseModel.getVote()); + int[] expectedVotes = {0, 0}; + assertArrayEquals(expectedVotes, responseModel.getVotes()); review = reviewDAO.getReview(reviewId); assertEquals(0, review.getNumDislikes()); assertEquals(0, review.getVotedUsers().keySet().size());