Skip to content
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

new campground show comment section #4

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
152 changes: 150 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,151 @@
# YelpCamp
# Collapsible Comment Section Upgrade

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Collapsible Comment Section Upgrade
# Collapsible Comment Section Upgrade


### Refactored by Ian Schoonover
![Comment Section Screenshot](https://i.imgur.com/qZZJxNX.png)

This tutorial uses technologies that we've learned in the course to make an upgraded comment section with collapsible new comment and edit comment forms on the campground's show page.

To make the tutorial as straightforward as possible, all the changes are made only to the show.ejs file. But, do make sure that jQuery and Bootstrap JS script elements are included in your [views/partials/footer.ejs](https://github.com/fewsion/yelp-camp-refactored/blob/comment-section/views/partials/footer.ejs).

### Markup
- Open the `views/campgrounds/show.ejs` page file and edit the comment section code to look like the following:

```
<!--COMMENT SECTION START-->
<div class="well">
<!--Setting up the add new comment button that is used for collapsing-->
<div class="text-right">
<a class="btn btn-success pull-right" role="button" data-toggle="collapse" href="#collapseComment" aria-expanded="false" aria-controls="collapseComment">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add new comment</a>
</div>
```

- For starters, we will place all our content inside of a div element with the Bootstrap class of 'well'.
- After that, we are adding the 'Add new comment button' code, which will have the ability to collapse the new comment form.

```
<!--Comment section title-->
<h4><strong>Comments <span class="glyphicon glyphicon glyphicon-comment" aria-hidden="true"></span></strong></h4>

<!--Collapse Add a comment form START-->
<div class="collapse" id="collapseComment">
<div class="well" style="border-left: 5px solid #00C851;">
<% if(!currentUser) { %>
<!--If the user is not logged in, direct him to the login page-->
<h5>You need to login before you can comment. <a href="/login">Click here</a> to go to the login page.</h5>
<% } %>
<% if(currentUser) { %>
<!--If the user is logged in, show the new comment form-->
<h4>Write your comment <span class="glyphicon glyphicon glyphicon-pencil" aria-hidden="true"></span></h4>
<form id="add-comment-form" action="/campgrounds/<%= campground._id %>/comments" method="POST">
<div class="form-group">
<input class="form-control" type="text" disabled value="<%= currentUser.username %>">
</div>
<div class="form-group">
<textarea class="form-control" name="comment[text]" placeholder="Write your comment..." form="add-comment-form" rows="5" cols="70"></textarea>
</div>
<div class="form-group">
<button class="btn btn-success btn-sm">Comment <span class="glyphicon glyphicon-comment" aria-hidden="true"></span></button>
</div>
</form>
<% } %>
</div>
</div>
<!--Collapse Add a comment form END-->
```

- The comment section title is added via an h4 element.
- After, the new comment form is added which is a familiar piece of code from our `views/campgrounds/new.ejs`.
- We also make a check if the user is logged in before showing the form.

```
<hr>

<!--Check if there are comments, if there are none say no comments.-->
<% if (campground.comments.length === 0) { %>
<em style="color: grey;">No comments yet.</em>
<% } %>

<!--Display comments by looping through them-->
<% campground.comments.forEach(function(comment) { %>
<div class="row">
<div class="col-md-12">
<strong>
<% if (currentUser && currentUser._id.equals(comment.author.id)) { %>
<!--If the current user owns the comment, change the color of the user icon-->
<span style="color: orange;" class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% } else { %>
<!--Else just display it black-->
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% } %>
<!--Print out the author username-->
<%= comment.author.username %>
</strong>

<!--Show when the comment was made-->
<span class="pull-right"><%= moment(comment.createdAt).fromNow() %></span>

<!--Printing the comment-->
<p><%= comment.text %></p>

<!--If the visitor is logged in and the owner of the comment, show the edit and delete buttons-->
<% if (currentUser && currentUser._id.equals(comment.author.id)) { %>
```

- In the above part of the code, we are dealing with showing the existing comments.
- First, we check if the campground has any comments - if it doesn't, we make our page say: `No comments yet`.
- After, we write a forEach loop similar to the one that we've had before, to print all the comments.
- We also add some small details, like changing the user icon color if the current user owns a particular comment.
- If you haven't still implemented Moment.js in your code, please see [Ian's tutorial on how to implement it.](http://slides.com/nax3t/yelpcamp-refactor-moment#/)

```
<!--Edit button used for collapsing the edit comment form-->
<a class="btn btn-xs btn-warning" role="button" data-toggle="collapse" href="#collapseEdit<%= comment._id %>" aria-expanded="false" aria-controls="collapse<%= comment._id %>">
Edit</a>

<!--Delete comment button-->
<form id="delete-form" action="/campgrounds/<%= campground._id %>/comments/<%= comment._id %>?_method=DELETE" method="POST" style="display: inline;">
<button class="btn btn-xs btn-danger">Delete</button>
</form>

<!--Edit comment form-->
<div class="collapse" id="collapseEdit<%= comment._id %>">
<div class="well" style="border-left: 5px solid #ffbb33; margin-top: 15px;">
<h4>Edit your comment <span class="glyphicon glyphicon-edit" aria-hidden="true"></span></h4>
<form id="edit-comment-form<%= comment._id %>" action="/campgrounds/<%= campground._id %>/comments/<%= comment._id %>?_method=PUT" method="POST">
<div class="form-group">
<input class="form-control" type="text" disabled value="<%= currentUser.username %>">
</div>
<div class="form-group">
<textarea class="form-control" name="comment[text]" placeholder="Your comment text..." form="edit-comment-form<%= comment._id %>" rows="5" cols="70"><%= comment.text %></textarea>
</div>
<div class="form-group">
<button class="btn btn-warning btn-sm">Edit comment <span class="glyphicon glyphicon-comment" aria-hidden="true"></span></button>
</div>
</form>
</div>
</div>
<% } %>
<hr>
</div>
</div>
<% }) %>
</div>
<!--COMMENT SECTION END-->
```

- We end the comment section refactor by adding the edit comment and delete comment buttons.
- Also, we add the edit comment form (familiar from `views/campgrounds/edit.ejs` which is collapsible when the comment owner presses the edit comment button.

- The tricky part worth mentioning here was the bug that happened when there were multiple comments that the current user owns:
- The problem was that the connection of the collapsible content and the button is made by an id.
- A collapse bug would happen because there would be multiple elements with the same id that triggers it, and the collapse button wouldn't work.
- It's also against the rules to use id more than once in a page as we know, so I used the power of EJS and this nifty trick to make each `id` attribute unique for the edit comment collapsible forms (more precisely, the parent div element holding the form):

`<div class="collapse" id="collapseEdit<%= comment._id %>">`

- Now we are generating an id attribute based on the comment._id field from MongoDB, which will ensure it's uniqueness.

# And that would be it!
Now we have a new comment section with some smooth collapsible create/edit forms. I tried to keep all the code inside this one file, but feel free to refactor the code further and put the CSS styles in it's own file, for example.

[Click here](https://github.com/fewsion/yelp-camp-refactored/blob/comment-section/views/campgrounds/show.ejs) to see the full, updated `views/campgrounds/show.ejs` file.
149 changes: 113 additions & 36 deletions views/campgrounds/show.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -21,69 +21,146 @@
<p>
<em>Submitted by: <%= campground.author.username %>, <%= moment(campground.createdAt).fromNow() %></em>
</p>
<% if(currentUser && campground.author.id.equals(currentUser._id) || currentUser && currentUser.isAdmin){ %>
<% if(currentUser && campground.author.id.equals(currentUser._id) || currentUser && currentUser.isAdmin){ %>
<a class="btn btn-warning" href="/campgrounds/<%= campground._id %>/edit">Edit</a>
<form action="/campgrounds/<%= campground._id %>?_method=DELETE" method="POST" class="delete-form">
<button class="btn btn-danger">Delete</button>
</form>
<% } %>
<% } %>
</div>
</div>

<!--COMMENT SECTION START-->
<div class="well">
<!--Setting up the add new comment button that is used for collapsing-->
<div class="text-right">
<a class="btn btn-success" href="/campgrounds/<%= campground._id %>/comments/new">Add New Comment</a>
<a class="btn btn-success pull-right" role="button" data-toggle="collapse" href="#collapseComment" aria-expanded="false" aria-controls="collapseComment">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add new comment</a>
</div>

<!--Comment section title-->
<h4><strong>Comments <span class="glyphicon glyphicon glyphicon-comment" aria-hidden="true"></span></strong></h4>

<!--Collapse Add a comment form START-->
<div class="collapse" id="collapseComment">
<div class="well" style="border-left: 5px solid #00C851;">
<% if(!currentUser) { %>
<!--If the user is not logged in, direct him to the login page-->
<h5>You need to login before you can comment. <a href="/login">Click here</a> to go to the login page.</h5>
<% } %>
<% if(currentUser) { %>
<!--If the user is logged in, show the new comment form-->
<h4>Write your comment <span class="glyphicon glyphicon glyphicon-pencil" aria-hidden="true"></span></h4>
<form id="add-comment-form" action="/campgrounds/<%= campground._id %>/comments" method="POST">
<div class="form-group">
<input class="form-control" type="text" disabled value="<%= currentUser.username %>">
</div>
<div class="form-group">
<textarea class="form-control" name="comment[text]" placeholder="Write your comment..." form="add-comment-form" rows="5" cols="70"></textarea>
</div>
<div class="form-group">
<button class="btn btn-success btn-sm">Comment <span class="glyphicon glyphicon-comment" aria-hidden="true"></span></button>
</div>
</form>
<% } %>
</div>
</div>
<!--Collapse Add a comment form END-->

<hr>
<% campground.comments.forEach(function(comment){ %>

<!--Check if there are comments, if there are none say no comments.-->
<% if (campground.comments.length === 0) { %>
<em style="color: grey;">No comments yet.</em>
<% } %>

<!--Display comments by looping through them-->
<% campground.comments.forEach(function(comment) { %>
<div class="row">
<div class="col-md-12">
<strong><%= comment.author.username %></strong>
<strong>
<% if (currentUser && currentUser._id.equals(comment.author.id)) { %>
<!--If the current user owns the comment, change the color of the user icon-->
<span style="color: orange;" class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% } else { %>
<!--Else just display it black-->
<span class="glyphicon glyphicon-user" aria-hidden="true"></span>
<% } %>
<!--Print out the author username-->
<%= comment.author.username %>
</strong>

<!--Show when the comment was made-->
<span class="pull-right"><%= moment(comment.createdAt).fromNow() %></span>
<div>
<%= comment.text %>

<% if(currentUser && comment.author.id.equals(currentUser._id) || currentUser && currentUser.isAdmin){ %>
<div class="pull-right">
<a href="/campgrounds/<%=campground._id%>/comments/<%=comment._id%>/edit" class="btn btn-xs btn-warning">EDIT</a>
<form class="delete-form" action="/campgrounds/<%=campground._id%>/comments/<%=comment._id%>?_method=DELETE" method="POST">
<button class="btn btn-xs btn-danger">DELETE</button>
<!--Printing the comment-->
<p><%= comment.text %></p>

<!--If the visitor is logged in and the owner of the comment, show the edit and delete buttons-->
<% if (currentUser && currentUser._id.equals(comment.author.id)) { %>

<!--Edit button used for collapsing the edit comment form-->
<a class="btn btn-xs btn-warning" role="button" data-toggle="collapse" href="#collapseEdit<%= comment._id %>" aria-expanded="false" aria-controls="collapse<%= comment._id %>">
Edit</a>

<!--Delete comment button-->
<form id="delete-form" action="/campgrounds/<%= campground._id %>/comments/<%= comment._id %>?_method=DELETE" method="POST" style="display: inline;">
<button class="btn btn-xs btn-danger">Delete</button>
</form>

<!--Edit comment form-->
<div class="collapse" id="collapseEdit<%= comment._id %>">
<div class="well" style="border-left: 5px solid #ffbb33; margin-top: 15px;">
<h4>Edit your comment <span class="glyphicon glyphicon-edit" aria-hidden="true"></span></h4>
<form id="edit-comment-form<%= comment._id %>" action="/campgrounds/<%= campground._id %>/comments/<%= comment._id %>?_method=PUT" method="POST">
<div class="form-group">
<input class="form-control" type="text" disabled value="<%= currentUser.username %>">
</div>
<div class="form-group">
<textarea class="form-control" name="comment[text]" placeholder="Your comment text..." form="edit-comment-form<%= comment._id %>" rows="5" cols="70"><%= comment.text %></textarea>
</div>
<div class="form-group">
<button class="btn btn-warning btn-sm">Edit comment <span class="glyphicon glyphicon-comment" aria-hidden="true"></span></button>
</div>
</form>
</div>
<% } %>
</div>
<% } %>
<hr>
</div>
</div>
<% }) %>
</div>
<% }) %>
<!--COMMENT SECTION END-->

</div>
</div>
</div>
<script>
function initMap() {
var lat = <%= campground.lat %>;
var lng = <%= campground.lng %>;
var center = {lat: lat, lng: lng };
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: center,
scrollwheel: false
});
var contentString = `
function initMap() {
var lat = <%= campground.lat %>;
var lng = <%= campground.lng %>;
var center = {lat: lat, lng: lng };
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: center,
scrollwheel: false
});
var contentString = `
<strong><%= campground.name %><br />
<%= campground.location %></strong>
<p><%= campground.description %></p>
`
var infowindow = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: center,
map: map
});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
}
var infowindow = new google.maps.InfoWindow({
content: contentString
});
var marker = new google.maps.Marker({
position: center,
map: map
});
marker.addListener('click', function() {
infowindow.open(map, marker);
});
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBkG51lwJtDvYFKTBdRZlhzYg1D4QFsXPU&callback=initMap"></script>
<% include ../partials/footer %>