Skip to content

Commit

Permalink
Feature: Edit and Delete Submission with Hotwire (#3907)
Browse files Browse the repository at this point in the history
Because:
* We are moving our project submissions feature to Hotwire

This commit:
* Add action menu to every project submission. The users submission will
display edit and delete links, everyone else's will have the report link
(yet to be implemented)
* Add edit and update actions/views for v2 project submissions
* Add delete action for v2 project submissions
  • Loading branch information
KevinMulhern committed Jul 4, 2023
1 parent ece135d commit 56dd76c
Show file tree
Hide file tree
Showing 13 changed files with 177 additions and 25 deletions.
3 changes: 3 additions & 0 deletions app/assets/images/icons/pencil-square.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 46 additions & 15 deletions app/components/project_submissions/item_component.html.erb
Original file line number Diff line number Diff line change
@@ -1,21 +1,52 @@
<div data-test-id="submission-item" class="relative py-6 border-solid border-t border-gray-300 flex flex-col md:flex-row justify-between items-center">
<%= turbo_frame_tag project_submission do %>
<div data-test-id="submission-item" class="relative py-6 border-solid border-t border-gray-300 flex flex-col md:flex-row justify-between items-center">

<div class="flex items-center mb-4 md:mb-0">
<div class="flex items-center mb-4 md:mb-0">

<button class="text-gray-300 mr-4 flex items-center hint--top" data-test-id="like-btn" aria-label="Like submission">
<span class="mr-1" data-test-id="number-of-likes"><%= item.votes_for.size %></span>
<%= inline_svg_tag 'icons/heart.svg', class: 'h-5 w-5', aria: true, title: 'heart', desc: 'heart icon' %>
</button>
<button class="text-gray-300 mr-4 flex items-center hint--top" data-test-id="like-btn" aria-label="Like submission">
<span class="mr-1" data-test-id="number-of-likes"><%= project_submission.votes_for.size %></span>
<%= inline_svg_tag 'icons/heart.svg', class: 'h-5 w-5', aria: true, title: 'heart', desc: 'heart icon' %>
</button>

<p class="truncate max-w-xs lg:max-w-lg font-medium text-lg break-words"><%= item.user.username %></p>
</div>
<p class="truncate max-w-xs lg:max-w-lg font-medium text-lg break-words"><%= project_submission.user.username %></p>
</div>

<div class="flex flex-col md:flex-row md:items-center">
<%= link_to 'View code', project_submission.repo_url, target: '_blank', rel: 'noreferrer', class: 'button button--gray font-semibold md:mr-4', data: { test_id: 'view-code-btn' } %>
<%= link_to 'Live preview', project_submission.live_preview_url, target: '_blank', rel: 'noreferrer', class: 'button button--gray font-semibold mt-5 md:mt-0 md:mr-4', data: { test_id: 'live-preview-btn' } %>

<div class="relative flex-none" data-controller="visibility" data-action="visibility:click:outside->visibility#off" data-visibility-visible-value="false">
<button type="button" data-action="click->visibility#toggle" data-test-id="submission-action-menu-btn" class="-m-2.5 block p-2.5 text-gray-500 hover:text-gray-900" id="options-menu-0-button" aria-expanded="false" aria-haspopup="true">
<span class="sr-only">Open options</span>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path d="M10 3a1.5 1.5 0 110 3 1.5 1.5 0 010-3zM10 8.5a1.5 1.5 0 110 3 1.5 1.5 0 010-3zM11.5 15.5a1.5 1.5 0 10-3 0 1.5 1.5 0 003 0z" />
</svg>
</button>

<div
data-visibility-target="content"
data-transition-enter="transition ease-out duration-200"
data-transition-enter-start="transform opacity-0 scale-95"
data-transition-enter-end="transform opacity-100 scale-100"
data-transition-leave="transition ease-in duration-75"
data-transition-leave-start="transform opacity-100 scale-100"
data-transition-leave-end="transform opacity-10 scale-95"
class="absolute right-0 z-10 mt-2 w-32 origin-top-right rounded-md bg-white py-2 shadow-lg ring-1 ring-gray-900/5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="options-menu-0-button" tabindex="-1">

<% if project_submission.user == current_user %>
<%= link_to edit_lesson_v2_project_submission_path(project_submission.lesson, project_submission), class: 'text-gray-700 group flex items-center px-4 py-2 text-sm', role: 'menuitem', tabindex: '-1', data: { turbo_frame: 'modal', test_id: 'edit-submission'} do %>
<%= inline_svg_tag 'icons/pencil-square.svg', class: 'mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-500', aria: true, title: 'edit', desc: 'edit icon' %>
Edit
<% end %>
<div class="flex flex-col md:flex-row md:items-center">
<%= link_to 'View code', item.repo_url, target: '_blank', rel: 'noreferrer', class: 'button button--gray font-semibold md:mr-4', data: { test_id: 'view-code-btn' } %>
<%= link_to 'Live preview', item.live_preview_url, target: '_blank', rel: 'noreferrer', class: 'button button--gray font-semibold mt-5 md:mt-0 md:mr-4', data: { test_id: 'live-preview-btn' } %>
<%= link_to lesson_v2_project_submission_path(project_submission.lesson, project_submission), class: 'text-gray-700 group flex items-center px-4 py-2 text-sm', role: 'menuitem', tabindex: '-1', data: { turbo_method: :delete, turbo_confirm: 'Are you sure? this cannot be undone.', test_id: 'delete-submission' } do %>
<%= inline_svg_tag 'icons/trash.svg', class: 'mr-3 h-5 w-5 text-gray-400 group-hover:text-gray-500', aria: true, title: 'edit', desc: 'edit icon' %>
Delete
<% end %>
<% end %>
</div>
</div>

<button aria-label="Report submission" data-test-id="flag-btn" class="submissions-flag text-gray-300 hover:text-gray-500 dark:text-gray-400 dark:hover:text-gray-300 hint--top-left">
<%= inline_svg_tag 'icons/flag.svg', class: 'h-4 w-4', aria: true, title: 'flag', desc: 'flag icon' %>
</button>
</div>
</div>
</div>
<% end %>
11 changes: 7 additions & 4 deletions app/components/project_submissions/item_component.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
module ProjectSubmissions
class ItemComponent < ApplicationComponent
def initialize(item:)
@item = item
with_collection_parameter :project_submission

def initialize(project_submission:, current_user:)
@project_submission = project_submission
@current_user = current_user
end

def render?
item.present?
project_submission.present?
end

private

attr_reader :item
attr_reader :project_submission, :current_user
end
end
24 changes: 24 additions & 0 deletions app/controllers/lessons/v2_project_submissions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def new
@project_submission = current_user.project_submissions.new(lesson: @lesson)
end

def edit
@project_submission = current_user.project_submissions.find(params[:id])
end

def create
@project_submission = current_user.project_submissions.new(project_submission_params.merge(lesson: @lesson))

Expand All @@ -25,6 +29,26 @@ def create
end
end

def update
@project_submission = current_user.project_submissions.find(params[:id])

respond_to do |format|
if @project_submission.update!(project_submission_params)
format.html { redirect_to lesson_path(@lesson), notice: 'Project updated' }
format.turbo_stream
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end

def destroy
@project_submission = current_user.project_submissions.find(params[:id])
@project_submission.destroy

render turbo_stream: turbo_stream.remove(@project_submission)
end

private

def project_submissions_query
Expand Down
2 changes: 1 addition & 1 deletion app/views/lessons/v2_project_submissions/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= turbo_frame_tag 'project_submission_form', class: 'w-full' do %>
<%= form_with url: lesson_v2_project_submissions_path(lesson.id), model: project_submission, builder: TailwindFormBuilder do |form| %>
<%= form_with url:, model: project_submission, builder: TailwindFormBuilder do |form| %>
<div class='divide-y divide-gray-200 dark:divide-gray-600 space-y-6'>
<div class="space-y-6 pt-4">
<div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= turbo_stream.prepend "submissions-list" do %>
<%= render ProjectSubmissions::ItemComponent.new(item: @project_submission) %>
<%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user: current_user) %>
<% end %>
<%= turbo_stream.remove "add-submission-button" %>
3 changes: 3 additions & 0 deletions app/views/lessons/v2_project_submissions/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= render ModalComponent.new(title: 'Update your project') do %>
<%= render 'lessons/v2_project_submissions/form', project_submission: @project_submission, url: lesson_v2_project_submission_path(@lesson, @project_submission) %>
<% end %>
4 changes: 2 additions & 2 deletions app/views/lessons/v2_project_submissions/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
</header>

<%= turbo_frame_tag 'submissions-list', data: { test_id: 'submissions-list' } do %>
<%= render ProjectSubmissions::ItemComponent.new(item: @current_user_submission) %>
<%= render ProjectSubmissions::ItemComponent.with_collection(@project_submissions) %>
<%= render ProjectSubmissions::ItemComponent.new(project_submission: @current_user_submission, current_user:) %>
<%= render ProjectSubmissions::ItemComponent.with_collection(@project_submissions, current_user:) %>
<% end %>
</div>
<% end %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/lessons/v2_project_submissions/new.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<%= render ModalComponent.new(title: 'Submit your project') do %>
<%= render 'lessons/v2_project_submissions/form', lesson: @lesson, project_submission: @project_submission %>
<%= render 'lessons/v2_project_submissions/form', project_submission: @project_submission, url: lesson_v2_project_submissions_path(@lesson) %>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= turbo_stream.replace @project_submission do %>
<%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user: current_user) %>
<% end %>
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@

resources :lessons, only: :show do
resources :project_submissions, only: %i[index], controller: 'lessons/project_submissions'
resources :v2_project_submissions, only: %i[index new create], controller: 'lessons/v2_project_submissions'
resources :v2_project_submissions, controller: 'lessons/v2_project_submissions'
resource :completion, only: %i[create destroy], controller: 'lessons/completions'
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'rails_helper'

RSpec.describe 'Deleting a Project Submission' do
let(:user) { create(:user) }
let(:lesson) { create(:lesson, :project) }

before do
Flipper.enable(:v2_project_submissions)

sign_in(user)
visit lesson_path(lesson)
Pages::ProjectSubmissions::Form.new.open.fill_in.submit
end

after do
Flipper.disable(:v2_project_submissions)
end

it 'removes a submission' do
users_submission = first(:test_id, 'submission-item')

within(:test_id, 'submissions-list') do
expect(page).to have_content(user.username)
end

within(users_submission) do
find(:test_id, 'submission-action-menu-btn').click

page.accept_confirm do
find(:test_id, 'delete-submission').click
end
end

within(:test_id, 'submissions-list') do
expect(page).not_to have_content(user.username)
end
end
end
47 changes: 47 additions & 0 deletions spec/system/v2_lesson_project_submissions/edit_submission_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'rails_helper'

RSpec.describe 'Editing a Project Submission' do
let(:user) { create(:user) }
let(:lesson) { create(:lesson, :project) }
let(:edited_field_values) do
{
repo_url: 'https://github.com/edited-project-repo-url',
live_preview_url: 'http://edited-live-preview-url.com'
}
end

before do
Flipper.enable(:v2_project_submissions)

sign_in(user)
visit lesson_path(lesson)
Pages::ProjectSubmissions::Form.new.open.fill_in.submit
end

after do
Flipper.disable(:v2_project_submissions)
end

it 'successfully edits a submission' do
users_submission = first(:test_id, 'submission-item')

within(users_submission) do
find(:test_id, 'submission-action-menu-btn').click
find(:test_id, 'edit-submission').click
end

Pages::ProjectSubmissions::Form.new(**edited_field_values).tap do |form|
form.fill_in
form.submit
end

# We need to find the user submission again because it is replaced by a turbo stream
users_submission = first(:test_id, 'submission-item')

within(users_submission) do
expect(users_submission).to have_content(user.username)
expect(users_submission.find(:test_id, 'view-code-btn')['href']).to eq('https://github.com/edited-project-repo-url')
expect(users_submission.find(:test_id, 'live-preview-btn')['href']).to eq('http://edited-live-preview-url.com/')
end
end
end

0 comments on commit 56dd76c

Please sign in to comment.