From ffdd5e6128824c239991e25e727a514aac914a12 Mon Sep 17 00:00:00 2001 From: evazion Date: Thu, 28 Jan 2021 17:34:42 -0600 Subject: [PATCH] posts: make post votes work the same way as comment votes. Change post votes to work the same way as comment votes: * Make the upvote arrow blue if you've upvoted the post, or grey if you haven't. Likewise for the downvote arrow. * Make it so you can click the upvote or downvote arrows to undo the vote. * Don't show any notices when you vote on a post. Also fix it so that votes work the same way on the posts page, the comments page, and in the modqueue. Before it wasn't possible to undo votes on the comments page or in the modqueue. --- app/components/application_component.rb | 4 ++ app/components/post_votes_component.rb | 27 +++++++++ .../post_votes_component.html.erb | 19 +++++++ .../post_votes_component.scss | 10 ++++ app/helpers/components_helper.rb | 4 ++ app/models/post_vote.rb | 8 +++ .../comments/partials/index/_header.html.erb | 7 +-- app/views/favorites/_update.js.erb | 10 +--- app/views/modqueue/_post.html.erb | 7 +-- app/views/post_votes/create.js.erb | 6 +- app/views/post_votes/destroy.js.erb | 6 +- .../posts/partials/show/_information.html.erb | 13 +---- test/components/post_votes_component_test.rb | 56 +++++++++++++++++++ 13 files changed, 135 insertions(+), 42 deletions(-) create mode 100644 app/components/post_votes_component.rb create mode 100644 app/components/post_votes_component/post_votes_component.html.erb create mode 100644 app/components/post_votes_component/post_votes_component.scss mode change 100644 => 120000 app/views/post_votes/destroy.js.erb create mode 100644 test/components/post_votes_component_test.rb diff --git a/app/components/application_component.rb b/app/components/application_component.rb index 98d567fbd..d92c68dd0 100644 --- a/app/components/application_component.rb +++ b/app/components/application_component.rb @@ -1,4 +1,8 @@ class ApplicationComponent < ViewComponent::Base + delegate :link_to_user, :time_ago_in_words_tagged, :format_text, :edit_icon, + :delete_icon, :undelete_icon, :flag_icon, :upvote_icon, :downvote_icon, + :link_icon, to: :helpers + def policy(subject) Pundit.policy!(current_user, subject) end diff --git a/app/components/post_votes_component.rb b/app/components/post_votes_component.rb new file mode 100644 index 000000000..0f9ea713c --- /dev/null +++ b/app/components/post_votes_component.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# This component represents the post score and upvote/downvote buttons ("🠉 5 🠋") +class PostVotesComponent < ApplicationComponent + attr_reader :post, :current_user + + def initialize(post:, current_user:) + @post = post + @current_user = current_user + end + + def can_vote? + policy(PostVote).create? + end + + def current_vote + post.votes.find_by(user: current_user) + end + + def upvoted? + can_vote? && current_vote&.is_positive? + end + + def downvoted? + can_vote? && current_vote&.is_negative? + end +end diff --git a/app/components/post_votes_component/post_votes_component.html.erb b/app/components/post_votes_component/post_votes_component.html.erb new file mode 100644 index 000000000..d0fca6863 --- /dev/null +++ b/app/components/post_votes_component/post_votes_component.html.erb @@ -0,0 +1,19 @@ + + <% if can_vote? %> + <% if upvoted? %> + <%= link_to upvote_icon, post_post_votes_path(post_id: post.id), class: "post-upvote-link post-unvote-link active-link", method: :delete, remote: true %> + <% else %> + <%= link_to upvote_icon, post_post_votes_path(post_id: post.id, score: "up"), class: "post-upvote-link inactive-link", method: :post, remote: true %> + <% end %> + <% end %> + + <%= post.score %> + + <% if can_vote? %> + <% if downvoted? %> + <%= link_to downvote_icon, post_post_votes_path(post_id: post.id), class: "post-downvote-link post-unvote-link active-link", method: :delete, remote: true %> + <% else %> + <%= link_to downvote_icon, post_post_votes_path(post_id: post.id, score: "down"), class: "post-downvote-link inactive-link", method: :post, remote: true %> + <% end %> + <% end %> + diff --git a/app/components/post_votes_component/post_votes_component.scss b/app/components/post_votes_component/post_votes_component.scss new file mode 100644 index 000000000..4d2fd99ac --- /dev/null +++ b/app/components/post_votes_component/post_votes_component.scss @@ -0,0 +1,10 @@ +.post-votes { + // Fix it so that the vote buttons don't move when the score changes width. + // XXX duplicated from app/components/comment_component/comment_component.scss + .post-score { + display: inline-block; + text-align: center; + min-width: 1.25em; + white-space: nowrap; + } +} diff --git a/app/helpers/components_helper.rb b/app/helpers/components_helper.rb index 48443a217..c3538dd3e 100644 --- a/app/helpers/components_helper.rb +++ b/app/helpers/components_helper.rb @@ -14,4 +14,8 @@ module ComponentsHelper def render_comment_section(post, **options) render CommentSectionComponent.new(post: post, **options) end + + def render_post_votes(post, **options) + render PostVotesComponent.new(post: post, **options) + end end diff --git a/app/models/post_vote.rb b/app/models/post_vote.rb index ab8ea1090..ff01fec8d 100644 --- a/app/models/post_vote.rb +++ b/app/models/post_vote.rb @@ -33,6 +33,14 @@ class PostVote < ApplicationRecord end end + def is_positive? + score > 0 + end + + def is_negative? + score < 0 + end + def update_post_on_create if score > 0 Post.where(:id => post_id).update_all("score = score + #{score}, up_score = up_score + #{score}") diff --git a/app/views/comments/partials/index/_header.html.erb b/app/views/comments/partials/index/_header.html.erb index ea8d6deac..53a1a1dc0 100644 --- a/app/views/comments/partials/index/_header.html.erb +++ b/app/views/comments/partials/index/_header.html.erb @@ -14,12 +14,7 @@ Score - - <%= post.score %> - <% if policy(PostVote).create? %> - (vote <%= link_to upvote_icon, post_post_votes_path(score: "up", post_id: post.id), remote: true, method: :post %>/<%= link_to downvote_icon, post_post_votes_path(score: "down", post_id: post.id), remote: true, method: :post %>) - <% end %> - + <%= render_post_votes post, current_user: CurrentUser.user %>
diff --git a/app/views/favorites/_update.js.erb b/app/views/favorites/_update.js.erb index 0c2ece4aa..75051f018 100644 --- a/app/views/favorites/_update.js.erb +++ b/app/views/favorites/_update.js.erb @@ -1,17 +1,9 @@ $("#add-to-favorites, #add-fav-button, #remove-from-favorites, #remove-fav-button").toggle(); $("#remove-fav-button").addClass("animate"); -$("#score-for-post-<%= @post.id %>").text(<%= @post.score %>); +$("span.post-votes[data-id=<%= @post.id %>]").replaceWith("<%= j render_post_votes @post, current_user: CurrentUser.user %>"); $("#favcount-for-post-<%= @post.id %>").text(<%= @post.fav_count %>); $(".fav-buttons").toggleClass("fav-buttons-false").toggleClass("fav-buttons-true"); -<% if @post.can_be_voted_by?(CurrentUser.user) %> - $("#vote-links-for-post-<%= @post.id %>").show(); - $("#unvote-link-for-post-<%= @post.id %>").hide(); -<% else %> - $("#vote-links-for-post-<%= @post.id %>").hide(); - $("#unvote-link-for-post-<%= @post.id %>").show(); -<% end %> - <% if policy(@post).can_view_favlist? %> var fav_count = <%= @post.fav_count %>; $("#favlist").html("<%= j render "posts/partials/show/favorite_list", post: @post %>"); diff --git a/app/views/modqueue/_post.html.erb b/app/views/modqueue/_post.html.erb index 862d4d74e..b2c29e1d3 100644 --- a/app/views/modqueue/_post.html.erb +++ b/app/views/modqueue/_post.html.erb @@ -28,12 +28,7 @@ Score - - <%= post.score %> - <% if policy(PostVote).create? %> - (vote <%= link_to upvote_icon, post_post_votes_path(score: "up", post_id: post.id), remote: true, method: :post %>/<%= link_to downvote_icon, post_post_votes_path(score: "down", post_id: post.id), remote: true, method: :post %>) - <% end %> - + <%= render_post_votes post, current_user: CurrentUser.user %>
diff --git a/app/views/post_votes/create.js.erb b/app/views/post_votes/create.js.erb index 92bdeec28..1932aa3a4 100644 --- a/app/views/post_votes/create.js.erb +++ b/app/views/post_votes/create.js.erb @@ -1,5 +1 @@ -Danbooru.Utility.notice("Vote saved"); -$("#score-for-post-<%= @post.id %>").html(<%= @post.score %>); - -$("#vote-links-for-post-<%= @post.id %>").hide(); -$("#unvote-link-for-post-<%= @post.id %>").show(); +$("span.post-votes[data-id=<%= @post.id %>]").replaceWith("<%= j render_post_votes @post, current_user: CurrentUser.user %>"); diff --git a/app/views/post_votes/destroy.js.erb b/app/views/post_votes/destroy.js.erb deleted file mode 100644 index 5466b6cfa..000000000 --- a/app/views/post_votes/destroy.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -Danbooru.Utility.notice("Unvoted successfully"); -$("#score-for-post-<%= @post.id %>").html(<%= @post.score %>); - -$("#vote-links-for-post-<%= @post.id %>").show(); -$("#unvote-link-for-post-<%= @post.id %>").hide(); diff --git a/app/views/post_votes/destroy.js.erb b/app/views/post_votes/destroy.js.erb new file mode 120000 index 000000000..c7f6d951c --- /dev/null +++ b/app/views/post_votes/destroy.js.erb @@ -0,0 +1 @@ +create.js.erb \ No newline at end of file diff --git a/app/views/posts/partials/show/_information.html.erb b/app/views/posts/partials/show/_information.html.erb index a272c1a88..219f9797e 100644 --- a/app/views/posts/partials/show/_information.html.erb +++ b/app/views/posts/partials/show/_information.html.erb @@ -21,17 +21,8 @@
  • Source: <%= post_source_tag(post.source, post.normalized_source) %>
  • Rating: <%= post.pretty_rating %>
  • -
  • Score: <%= post.score %> - <% if policy(PostVote).create? %> - <%= tag.span id: "vote-links-for-post-#{post.id}", style: ("display: none;" if !@post.can_be_voted_by?(CurrentUser.user)) do %> - (vote - <%= link_to upvote_icon, post_post_votes_path(post_id: post.id, score: "up"), remote: true, method: :post %> - <%= link_to downvote_icon, post_post_votes_path(post_id: post.id, score: "down"), remote: true, method: :post %>) - <% end %> - <%= tag.span id: "unvote-link-for-post-#{post.id}", style: ("display: none;" if @post.can_be_voted_by?(CurrentUser.user)) do %> - (<%= link_to "undo vote", post_post_votes_path(post), remote: true, method: :delete, class: "unvote-post-link" %>) - <% end %> - <% end %> +
  • + Score: <%= render_post_votes post, current_user: CurrentUser.user %>
  • Favorites: <%= post.fav_count %> <% if policy(post).can_view_favlist? %> diff --git a/test/components/post_votes_component_test.rb b/test/components/post_votes_component_test.rb new file mode 100644 index 000000000..c40e72052 --- /dev/null +++ b/test/components/post_votes_component_test.rb @@ -0,0 +1,56 @@ +require "test_helper" + +class PostVotesComponentTest < ViewComponent::TestCase + def render_post_votes(post, current_user:) + render_inline(PostVotesComponent.new(post: post, current_user: current_user)) + end + + context "The PostVotesComponent" do + setup do + @post = as(create(:user)) { create(:post) } + end + + context "for a user who can't vote" do + should "not show the vote buttons" do + render_post_votes(@post, current_user: User.anonymous) + + assert_css(".post-score") + assert_no_css(".post-upvote-link") + assert_no_css(".post-downvote-link") + end + end + + context "for a user who can vote" do + setup do + @user = create(:gold_user) + end + + should "show the vote buttons" do + render_post_votes(@post, current_user: @user) + + assert_css(".post-upvote-link.inactive-link") + assert_css(".post-downvote-link.inactive-link") + end + + context "for a downvoted post" do + should "highlight the downvote button as active" do + @post.vote!("down", @user) + render_post_votes(@post, current_user: @user) + + assert_css(".post-upvote-link.inactive-link") + assert_css(".post-downvote-link.active-link") + end + end + + context "for an upvoted post" do + should "highlight the upvote button as active" do + @post.vote!("up", @user) + render_post_votes(@post, current_user: @user) + + assert_css(".post-upvote-link.active-link") + assert_css(".post-downvote-link.inactive-link") + end + end + end + end +end