Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Edit and Delete Submission with Hotwire #3907

Merged
merged 1 commit into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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| %>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing wrong with your code, but for a second I thought you'd accidentally left in url:. Not sure I like this Ruby feature 😆

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

heh, it's been tripping me up too 😆. Final version of this will get rid of that url and just use the model object. I only need the url atm because of the v2 namespace.

<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 @@ -90,7 +90,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