diff --git a/app/controllers/staff/ratings_controller.rb b/app/controllers/staff/ratings_controller.rb index 5dd39fe08..840e6d1d6 100644 --- a/app/controllers/staff/ratings_controller.rb +++ b/app/controllers/staff/ratings_controller.rb @@ -11,7 +11,8 @@ def create @rating = Rating.find_or_initialize_by(proposal: @proposal, user: current_user) @rating.update!(rating_params) - render partial: 'shared/proposals/rating_widget', locals: {event: @proposal.event, proposal: @proposal, rating: @rating} + # The first rating reveals the internal comments; replace the whole widget. + render_rating_widget end def update @@ -21,16 +22,31 @@ def update if rating_params[:score].blank? @rating.destroy @rating = current_user.ratings.build(proposal: @proposal) - render partial: 'shared/proposals/rating_widget', locals: {event: @proposal.event, proposal: @proposal, rating: @rating} + # Removing the rating re-hides the internal comments; replace the whole widget. + render_rating_widget return end @rating.update!(rating_params) - render partial: 'shared/proposals/rating_widget', locals: {event: @proposal.event, proposal: @proposal, rating: @rating} + # A score change must not touch the internal comments (a draft may be in + # progress there); replace only the rating form's own frame. + render turbo_stream: turbo_stream.replace( + helpers.dom_id(@proposal, :rating_form), + partial: 'shared/proposals/rating_form_frame', + locals: {event: @proposal.event, proposal: @proposal, rating: @rating} + ) end private + def render_rating_widget + render turbo_stream: turbo_stream.replace( + helpers.dom_id(@proposal, :rating_widget), + partial: 'shared/proposals/rating_widget', + locals: {event: @proposal.event, proposal: @proposal, rating: @rating} + ) + end + def rating_params params.require(:rating).permit(:score).merge(proposal: @proposal, user: current_user) end diff --git a/app/views/shared/proposals/_rating_form_frame.html.haml b/app/views/shared/proposals/_rating_form_frame.html.haml new file mode 100644 index 000000000..d3de8edcf --- /dev/null +++ b/app/views/shared/proposals/_rating_form_frame.html.haml @@ -0,0 +1,3 @@ += turbo_frame_tag dom_id(proposal, :rating_form) do + .widget-content + = render partial: 'shared/proposals/rating_form', locals: {event: event, proposal: proposal, rating: rating} diff --git a/app/views/shared/proposals/_rating_widget.html.haml b/app/views/shared/proposals/_rating_widget.html.haml index 2a1b2c2d6..4bd758b21 100644 --- a/app/views/shared/proposals/_rating_widget.html.haml +++ b/app/views/shared/proposals/_rating_widget.html.haml @@ -1,6 +1,5 @@ = turbo_frame_tag dom_id(proposal, :rating_widget) do - .widget-content - = render partial: 'shared/proposals/rating_form', locals: {event: event, proposal: proposal, rating: rating} + = render partial: 'shared/proposals/rating_form_frame', locals: {event: event, proposal: proposal, rating: rating} .internal-comments{class: !rating.persisted? ? 'hidden' : nil} .widget-header diff --git a/spec/system/staff/rating_preserves_comment_draft_spec.rb b/spec/system/staff/rating_preserves_comment_draft_spec.rb new file mode 100644 index 000000000..17c4b2c80 --- /dev/null +++ b/spec/system/staff/rating_preserves_comment_draft_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +feature 'Rating a proposal with an internal comment draft in progress', type: :system, js: true do + let(:event) { create(:event, state: 'open') } + let(:reviewer_user) { create(:user) } + let(:proposal) { create(:proposal_with_track, event: event) } + let!(:teammate) { create(:teammate, :reviewer, user: reviewer_user, event: event) } + + before do + reviewer_user.ratings.create!(proposal: proposal, score: 3) + login_as(reviewer_user) + visit event_staff_proposal_path(event, proposal) + end + + it 'changing the star rating preserves typed internal comment text' do + fill_in 'internal_comment_body', with: 'Half-typed thought' + + within('#rating-form') do + find("input[value='5']", visible: false).set(true) + end + expect(page).to have_css('.avg-rating', text: '5.0') + + expect(page).to have_field('internal_comment_body', with: 'Half-typed thought') + end + + it 'removing the rating hides the internal comments again' do + within('#rating-form') do + find('input.star-rating-select.delete', visible: false).set(true) + end + + expect(page).to_not have_content('Internal Comment') + end +end