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