Implement reaction create/destroy with Turbo Streams

This commit is contained in:
Andreas Nedbal 2023-10-31 23:32:36 +01:00 committed by Andreas Nedbal
parent 35be02a1f0
commit 9872d3aace
7 changed files with 102 additions and 13 deletions

View File

@ -50,20 +50,19 @@
text-decoration: none; text-decoration: none;
} }
&[name="ab-smile"], &.smile {
&[name="ab-smile-comment"] {
color: var(--primary); color: var(--primary);
&:hover { &:hover {
color: var(--success); color: var(--success);
} }
}
&[data-action="unsmile"] { &.unsmile {
color: var(--success); color: var(--success);
&:hover { &:hover {
color: var(--danger); color: var(--danger);
}
} }
} }
} }

View File

@ -1,9 +1,65 @@
# frozen_string_literal: true # frozen_string_literal: true
class ReactionsController < ApplicationController class ReactionsController < ApplicationController
include TurboStreamable
before_action :authenticate_user!, only: %w[create destroy]
turbo_stream_actions :create, :destroy
def index def index
answer = Answer.includes([smiles: { user: :profile }]).find(params[:id]) answer = Answer.includes([smiles: { user: :profile }]).find(params[:id])
render "index", locals: { a: answer } render "index", locals: { a: answer }
end end
def create
params.require :id
params.require :type
target = params[:type].constantize.find_by!(id: params[:id])
UseCase::Reaction::Create.call(
source_user: current_user,
target:
)
target.reload
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.replace("reaction-#{params[:type]}-#{params[:id]}", partial: "reactions/destroy", locals: { type: params[:type], target: }),
render_toast(t(".#{params[:type].downcase}.success"))
]
end
format.html { redirect_back(fallback_location: root_path) }
end
end
def destroy
params.require :id
params.require :type
target = params[:type].constantize.find_by!(id: params[:id])
UseCase::Reaction::Destroy.call(
source_user: current_user,
target:
)
target.reload
respond_to do |format|
format.turbo_stream do
render turbo_stream: [
turbo_stream.replace("reaction-#{params[:type]}-#{params[:id]}", partial: "reactions/create", locals: { type: params[:type], target: }),
render_toast(t(".#{params[:type].downcase}.success"))
]
end
format.html { redirect_back(fallback_location: root_path) }
end
end
end end

View File

@ -1,6 +1,7 @@
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile", data: { a_id: a.id, action: a.has_reacted ? :unsmile : :smile, selection_hotkey: "s" }, disabled: !user_signed_in? } - if a.has_reacted
%i.fa.fa-fw.fa-smile-o = render "reactions/destroy", type: "Answer", target: a
%span{ id: "ab-smile-count-#{a.id}" }= a.smile_count - else
= render "reactions/create", type: "Answer", target: a
- unless display_all - unless display_all
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-comments", data: { a_id: a.id, state: :hidden, selection_hotkey: "x" } } %button.btn.btn-link.answerbox__action{ type: :button, name: "ab-comments", data: { a_id: a.id, state: :hidden, selection_hotkey: "x" } }
%i.fa.fa-fw.fa-comments %i.fa.fa-fw.fa-comments

View File

@ -16,9 +16,10 @@
.comment__content .comment__content
= markdown comment.content = markdown comment.content
.flex-shrink-0.ms-auto .flex-shrink-0.ms-auto
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile-comment", data: { c_id: comment.id, action: current_user&.smiled?(comment) ? :unsmile : :smile }, disabled: !user_signed_in? } - if current_user&.smiled?(comment)
%i.fa.fa-fw.fa-smile-o = render "reactions/destroy", type: "Comment", target: comment
%span{ id: "ab-comment-smile-count-#{comment.id}" }= comment.smile_count - else
= render "reactions/create", type: "Comment", target: comment
.btn-group .btn-group
%button.btn.btn-link.btn-sm.dropdown-toggle{ data: { bs_toggle: :dropdown }, aria: { expanded: false } } %button.btn.btn-link.btn-sm.dropdown-toggle{ data: { bs_toggle: :dropdown }, aria: { expanded: false } }
%span.caret %span.caret

View File

@ -0,0 +1,13 @@
- if type == "Answer"
= button_to create_reactions_path(id: target.id, username: target.user.screen_name),
form: { class: "d-inline-block", id: "reaction-#{type}-#{target.id}" },
class: "btn btn-link answerbox__action smile" do
%i.fa.fa-fw.fa-smile-o
%span= target.smile_count
- if type == "Comment"
= button_to create_comment_reactions_path(id: target.id, username: target.user.screen_name),
form: { class: "d-inline-block", id: "reaction-#{type}-#{target.id}" },
class: "btn btn-link answerbox__action smile" do
%i.fa.fa-fw.fa-smile-o
%span= target.smile_count

View File

@ -0,0 +1,15 @@
- if type == "Answer"
= button_to destroy_reactions_path(id: target.id, username: target.user.screen_name),
method: :delete,
form: { class: "d-inline-block", id: "reaction-#{type}-#{target.id}" },
class: "btn btn-link answerbox__action unsmile" do
%i.fa.fa-fw.fa-smile-o
%span= target.smile_count
- if type == "Comment"
= button_to destroy_comment_reactions_path(id: target.id, username: target.user.screen_name),
method: :delete,
form: { class: "d-inline-block", id: "reaction-#{type}-#{target.id}" },
class: "btn btn-link answerbox__action unsmile" do
%i.fa.fa-fw.fa-smile-o
%span= target.smile_count

View File

@ -156,8 +156,12 @@ Rails.application.routes.draw do
delete "/@:username/a/:id/pin", to: "answer#unpin", as: :unpin_answer delete "/@:username/a/:id/pin", to: "answer#unpin", as: :unpin_answer
get "/@:username/a/:id/comments", to: "comments#index", as: :comments get "/@:username/a/:id/comments", to: "comments#index", as: :comments
get "/@:username/a/:id/reactions", to: "reactions#index", as: :reactions get "/@:username/a/:id/reactions", to: "reactions#index", as: :reactions
post "/@:username/a/:id/reactions", to: "reactions#create", as: :create_reactions, defaults: { type: "Answer" }
delete "/@:username/a/:id/reactions", to: "reactions#destroy", as: :destroy_reactions, defaults: { type: "Answer" }
get "/@:username/q/:id", to: "question#show", as: :question get "/@:username/q/:id", to: "question#show", as: :question
get "/@:username/c/:id/reactions", to: "comments/reactions#index", as: :comment_reactions get "/@:username/c/:id/reactions", to: "comments/reactions#index", as: :comment_reactions
post "/@:username/c/:id/reactions", to: "reactions#create", as: :create_comment_reactions, defaults: { type: "Comment" }
delete "/@:username/c/:id/reactions", to: "reactions#destroy", as: :destroy_comment_reactions, defaults: { type: "Comment" }
get "/@:username/followers", to: "user#followers", as: :show_user_followers get "/@:username/followers", to: "user#followers", as: :show_user_followers
get "/@:username/followings", to: "user#followings", as: :show_user_followings get "/@:username/followings", to: "user#followings", as: :show_user_followings
get "/@:username/friends", to: redirect("/@%{username}/followings") get "/@:username/friends", to: redirect("/@%{username}/followings")