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/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/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 new file mode 100644 index 00000000..052a1539 --- /dev/null +++ b/frontend/src/Internship/NumDislikes.js @@ -0,0 +1,13 @@ +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; + +export default function NumDislikes ({ numDislikes, handleDislike }) { + return ( + + ); +}; \ 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..020c5dae --- /dev/null +++ b/frontend/src/Internship/NumLikes.js @@ -0,0 +1,10 @@ +import Typography from '@mui/material/Typography'; +import Button from '@mui/material/Button'; + +export default function NumLikes({ numLikes, handleLike }) { + return ( + + ); +} diff --git a/frontend/src/Internship/ReviewCard.js b/frontend/src/Internship/ReviewCard.js index 9f3d48d9..f7e3d88b 100644 --- a/frontend/src/Internship/ReviewCard.js +++ b/frontend/src/Internship/ReviewCard.js @@ -1,16 +1,15 @@ import { useEffect, useState } from 'react'; import Typography from '@mui/material/Typography'; -import Paper from '@mui/material/Paper'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; 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'; +import LikesPanel from './LikesPanel'; export default function ReviewCard({ reviewId, @@ -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 ( {userId} - - 👍 {numLikes} - 👎 {numDislikes} - + ) : undefined} {moreComments.length > 0 && moreComments.map((comment, i) => { + console.log(comment); return ( { /** Maps the row of the ResultSet to a Review object. @@ -33,7 +28,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/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; } diff --git a/src/main/java/usecases/votehelpful/HelpfulController.java b/src/main/java/usecases/votehelpful/HelpfulController.java index 6d98be15..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 @@ -23,11 +24,10 @@ public HelpfulController(IHelpfulInputBoundary input) { * @param requestModel the HelpfulRequestModel taken in from the front-end * @return a ResponseEntity holding a HelpfulResponseModel and an HttpStatus */ - @PostMapping("/vote-helpful") + @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 { 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/HelpfulRequestModel.java b/src/main/java/usecases/votehelpful/HelpfulRequestModel.java index f7147fad..2584c274 100644 --- a/src/main/java/usecases/votehelpful/HelpfulRequestModel.java +++ b/src/main/java/usecases/votehelpful/HelpfulRequestModel.java @@ -1,7 +1,7 @@ package usecases.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 { 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 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());