diff --git a/app/components/project_submissions/item_component.html.erb b/app/components/project_submissions/item_component.html.erb index 1ffcd1991c..0b01406c24 100644 --- a/app/components/project_submissions/item_component.html.erb +++ b/app/components/project_submissions/item_component.html.erb @@ -1,9 +1,9 @@
-
- <%= render ProjectSubmissions::LikeComponent.new(project_submission) %> -

<%= project_submission.user.username %>

+
+ <%= render ProjectSubmissions::LikeComponent.new(project_submission:, current_users_submission: current_users_submission?) %> + <%= title %>
@@ -30,7 +30,7 @@ class="hidden absolute right-0 z-10 mt-2 w-32 origin-top-right rounded-md bg-white dark:bg-gray-700 py-2 shadow-lg ring-1 ring-gray-900/5 dark:ring-gray-300/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 dark:text-gray-300 group flex items-center px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-gray-200', role: 'menuitem', tabindex: '-1', data: { turbo_frame: 'modal', test_id: 'edit-submission', action: 'click->visibility#off'} do %> + <%= link_to edit_path, class: 'text-gray-700 dark:text-gray-300 group flex items-center px-4 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600 hover:text-gray-900 dark:hover:text-gray-200', role: 'menuitem', tabindex: '-1', data: { turbo_frame: 'modal', test_id: 'edit-submission', action: 'click->visibility#off'} do %> <%= inline_svg_tag 'icons/pencil-square.svg', class: 'mr-3 h-4 w-4 text-gray-400 group-hover:text-gray-500 dark:group-hover:text-gray-300', aria: true, title: 'edit', desc: 'edit icon' %> Edit <% end %> diff --git a/app/components/project_submissions/item_component.rb b/app/components/project_submissions/item_component.rb index 02989597c2..cf40aa42d4 100644 --- a/app/components/project_submissions/item_component.rb +++ b/app/components/project_submissions/item_component.rb @@ -3,10 +3,12 @@ class ItemComponent < ApplicationComponent CURRENT_USER_SORT_CODE = 10_000_000 # current user's submission should always be first with_collection_parameter :project_submission + renders_one :title, ProjectSubmissions::TitleComponent - def initialize(project_submission:, current_user:) + def initialize(project_submission:, current_user:, edit_path: nil) @project_submission = project_submission @current_user = current_user + @edit_path = edit_path end def render? @@ -17,10 +19,20 @@ def render? attr_reader :project_submission, :current_user + def current_users_submission? + project_submission.user == current_user + end + def sort_code - return CURRENT_USER_SORT_CODE if project_submission.user == current_user + return CURRENT_USER_SORT_CODE if current_users_submission? project_submission.cached_votes_total end + + def edit_path + return @edit_path if @edit_path.present? + + edit_lesson_v2_project_submission_path(project_submission.lesson, project_submission) + end end end diff --git a/app/components/project_submissions/like_component.html.erb b/app/components/project_submissions/like_component.html.erb index ec948e01c7..f3f10805c6 100644 --- a/app/components/project_submissions/like_component.html.erb +++ b/app/components/project_submissions/like_component.html.erb @@ -1,5 +1,5 @@ <%= turbo_frame_tag dom_id(project_submission, :likes) do %> - <%= button_to project_submission_v2_like_path(project_submission), method: http_action, class: 'text-gray-400 mr-4 flex items-center hint--top', data: { test_id: 'like-submission' }, aria: { label: 'Like submission' } do %> + <%= button_to project_submission_v2_like_path(project_submission), method: http_action, disabled: current_users_submission, class: "text-gray-400 mr-4 flex items-center #{'hint--top' unless current_users_submission}", data: { test_id: 'like-submission' }, aria: { label: 'Like submission' } do %> <%= project_submission.cached_votes_total %> <%= inline_svg_tag 'icons/heart.svg', class: "h-5 w-5 #{bg_color_class}", aria: true, title: 'heart', desc: 'heart icon' %> <% end %> diff --git a/app/components/project_submissions/like_component.rb b/app/components/project_submissions/like_component.rb index a772b33c33..6f921231dd 100644 --- a/app/components/project_submissions/like_component.rb +++ b/app/components/project_submissions/like_component.rb @@ -1,19 +1,22 @@ module ProjectSubmissions class LikeComponent < ApplicationComponent - def initialize(project_submission) + def initialize(project_submission:, current_users_submission: false) @project_submission = project_submission + @current_users_submission = current_users_submission end private - attr_reader :project_submission + attr_reader :project_submission, :current_users_submission def http_action project_submission.liked? ? :delete : :post end def bg_color_class - project_submission.liked? ? 'text-teal-700' : 'text-gray-400' + return 'text-teal-700' if current_users_submission || project_submission.liked? + + 'text-gray-400' end end end diff --git a/app/components/project_submissions/title_component.html.erb b/app/components/project_submissions/title_component.html.erb new file mode 100644 index 0000000000..80cd2626d9 --- /dev/null +++ b/app/components/project_submissions/title_component.html.erb @@ -0,0 +1,5 @@ +<% if url.present? %> + <%= link_to title, url, class: 'truncate max-w-xs lgs:max-w-lg font-medium text-lg break-words hover:text-gray-800', data: { turbo_frame: '_top' } %> +<% else %> +

<%= title %>

+<% end %> diff --git a/app/components/project_submissions/title_component.rb b/app/components/project_submissions/title_component.rb new file mode 100644 index 0000000000..6b0e534c42 --- /dev/null +++ b/app/components/project_submissions/title_component.rb @@ -0,0 +1,12 @@ +module ProjectSubmissions + class TitleComponent < ApplicationComponent + def initialize(title:, url: nil) + @title = title + @url = url + end + + private + + attr_reader :title, :url + end +end diff --git a/app/controllers/lessons/v2_project_submissions_controller.rb b/app/controllers/lessons/v2_project_submissions_controller.rb index 6366bdd9a2..8503164ace 100644 --- a/app/controllers/lessons/v2_project_submissions_controller.rb +++ b/app/controllers/lessons/v2_project_submissions_controller.rb @@ -21,6 +21,8 @@ def create respond_to do |format| if @project_submission.save + @project_submission.like!(current_user) + format.html { redirect_to lesson_path(@lesson), notice: 'Project submitted' } format.turbo_stream else diff --git a/app/controllers/users/project_submissions_controller.rb b/app/controllers/users/project_submissions_controller.rb new file mode 100644 index 0000000000..c3fa948e96 --- /dev/null +++ b/app/controllers/users/project_submissions_controller.rb @@ -0,0 +1,27 @@ +module Users + class ProjectSubmissionsController < ApplicationController + before_action :authenticate_user! + + def edit + @project_submission = current_user.project_submissions.find(params[:id]) + end + + def update + @project_submission = current_user.project_submissions.find(params[:id]) + + respond_to do |format| + if @project_submission.update(project_submission_params) + format.turbo_stream + else + format.html { render :edit, status: :unprocessable_entity } + end + end + end + + private + + def project_submission_params + params.require(:project_submission).permit(:repo_url, :live_preview_url, :is_public) + end + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b2ce9e4a93..9d7d298f75 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -3,5 +3,6 @@ class UsersController < ApplicationController def show @courses = current_user.path.courses + @project_submissions = current_user.project_submissions.includes(:lesson).order(created_at: :desc) end end diff --git a/app/queries/lesson_project_submissions_query.rb b/app/queries/lesson_project_submissions_query.rb index c4332c5cae..cf485c81d0 100644 --- a/app/queries/lesson_project_submissions_query.rb +++ b/app/queries/lesson_project_submissions_query.rb @@ -14,6 +14,7 @@ def current_user_submission def public_submissions lesson.project_submissions .only_public + .includes(:user) .not_removed_by_admin .where.not(user: current_user) .order(cached_votes_total: :desc, created_at: :desc) diff --git a/app/views/lessons/v2_project_submissions/create.turbo_stream.erb b/app/views/lessons/v2_project_submissions/create.turbo_stream.erb index 2b98e48237..0cf9a9e4ec 100644 --- a/app/views/lessons/v2_project_submissions/create.turbo_stream.erb +++ b/app/views/lessons/v2_project_submissions/create.turbo_stream.erb @@ -1,5 +1,7 @@ <%= turbo_stream.prepend 'submissions-list' do %> - <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) do |component| %> + <%= component.with_title(title: current_user.username, url: dashboard_path) %> + <% end %> <% end %> <%= turbo_stream.remove 'project-solutions-blank-state' %> diff --git a/app/views/lessons/v2_project_submissions/edit.html.erb b/app/views/lessons/v2_project_submissions/edit.html.erb index b89db18b18..bc0e27434f 100644 --- a/app/views/lessons/v2_project_submissions/edit.html.erb +++ b/app/views/lessons/v2_project_submissions/edit.html.erb @@ -1,3 +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) %> + <%= render 'project_submissions/form', project_submission: @project_submission, url: lesson_v2_project_submission_path(@lesson, @project_submission) %> <% end %> diff --git a/app/views/lessons/v2_project_submissions/index.html.erb b/app/views/lessons/v2_project_submissions/index.html.erb index 246b55e940..0da0624a21 100644 --- a/app/views/lessons/v2_project_submissions/index.html.erb +++ b/app/views/lessons/v2_project_submissions/index.html.erb @@ -29,8 +29,15 @@ <%= turbo_frame_tag 'submissions-list', data: { test_id: 'submissions-list', controller: 'sort' } do %> <% if @lesson.project_submissions.any? %> - <%= render ProjectSubmissions::ItemComponent.new(project_submission: @current_user_submission, current_user:) %> - <%= render ProjectSubmissions::ItemComponent.with_collection(@project_submissions, current_user:) %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission: @current_user_submission, current_user:) do |component| %> + <%= component.with_title(title: current_user.username, url: dashboard_path) %> + <% end %> + + <% @project_submissions.each do |project_submission| %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission:, current_user:) do |component| %> + <%= component.with_title(title: project_submission.user.username) %> + <% end %> + <% end %> <% else %> <% render 'lessons/v2_project_submissions/blank_state' %> <% end %> diff --git a/app/views/lessons/v2_project_submissions/new.html.erb b/app/views/lessons/v2_project_submissions/new.html.erb index b78d1eecdb..1c872830c2 100644 --- a/app/views/lessons/v2_project_submissions/new.html.erb +++ b/app/views/lessons/v2_project_submissions/new.html.erb @@ -1,3 +1,3 @@ <%= render ModalComponent.new(title: 'Submit your project') do %> - <%= render 'lessons/v2_project_submissions/form', project_submission: @project_submission, url: lesson_v2_project_submissions_path(@lesson) %> + <%= render 'project_submissions/form', project_submission: @project_submission, url: lesson_v2_project_submissions_path(@lesson) %> <% end %> diff --git a/app/views/lessons/v2_project_submissions/update.turbo_stream.erb b/app/views/lessons/v2_project_submissions/update.turbo_stream.erb index 9ade4fddfe..d8d8aafc88 100644 --- a/app/views/lessons/v2_project_submissions/update.turbo_stream.erb +++ b/app/views/lessons/v2_project_submissions/update.turbo_stream.erb @@ -1,3 +1,5 @@ <%= turbo_stream.replace @project_submission do %> - <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) do |component| %> + <%= component.with_title(title: current_user.username, url: dashboard_path) %> + <% end %> <% end %> diff --git a/app/views/lessons/v2_project_submissions/_form.html.erb b/app/views/project_submissions/_form.html.erb similarity index 100% rename from app/views/lessons/v2_project_submissions/_form.html.erb rename to app/views/project_submissions/_form.html.erb diff --git a/app/views/project_submissions/v2_likes/create.turbo_stream.erb b/app/views/project_submissions/v2_likes/create.turbo_stream.erb index 134c5bc5ad..47744d9209 100644 --- a/app/views/project_submissions/v2_likes/create.turbo_stream.erb +++ b/app/views/project_submissions/v2_likes/create.turbo_stream.erb @@ -1,3 +1,5 @@ <%= turbo_stream.replace @project_submission do %> - <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:) do |component| %> + <%= component.with_title(title: @project_submission.user.username) %> + <% end %> <% end %> diff --git a/app/views/users/_project_submissions.html.erb b/app/views/users/_project_submissions.html.erb index a293844e70..5d95d33f21 100644 --- a/app/views/users/_project_submissions.html.erb +++ b/app/views/users/_project_submissions.html.erb @@ -1,15 +1,25 @@

Project Submissions

- <% if project_submissions.any? %> - <%= react_component( - 'project-submissions/user-project-submissions', - { - userId: current_user&.id, - submissions: project_submissions.map { |submission| ProjectSubmissionSerializer.as_json(submission, current_user) }, - } - ) %> +<% if project_submissions.any? %> + <% if Feature.enabled?(:v2_project_submissions, current_user) %> +
+ <% project_submissions.each do |project_submission| %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission:, current_user:, edit_path: edit_users_project_submission_path(project_submission)) do |component| %> + <%= component.with_title(title: project_submission.lesson.display_title, url: lesson_path(project_submission.lesson)) %> + <% end %> + <% end %> +
<% else %> -

No submissions yet

+ <%= react_component( + 'project-submissions/user-project-submissions', + { + userId: current_user&.id, + submissions: project_submissions.map { |submission| ProjectSubmissionSerializer.as_json(submission, current_user) }, + } + ) %> <% end %> +<% else %> +

No submissions yet

+<% end %>
diff --git a/app/views/users/project_submissions/edit.html.erb b/app/views/users/project_submissions/edit.html.erb new file mode 100644 index 0000000000..bfc41f885a --- /dev/null +++ b/app/views/users/project_submissions/edit.html.erb @@ -0,0 +1,3 @@ +<%= render ModalComponent.new(title: 'Update your project') do %> + <%= render 'project_submissions/form', project_submission: @project_submission, url: users_project_submission_path(@project_submission) %> +<% end %> diff --git a/app/views/users/project_submissions/update.turbo_stream.erb b/app/views/users/project_submissions/update.turbo_stream.erb new file mode 100644 index 0000000000..6e8c1877a5 --- /dev/null +++ b/app/views/users/project_submissions/update.turbo_stream.erb @@ -0,0 +1,5 @@ +<%= turbo_stream.replace @project_submission do %> + <%= render ProjectSubmissions::ItemComponent.new(project_submission: @project_submission, current_user:, edit_path: edit_users_project_submission_path(@project_submission)) do |component| %> + <%= component.with_title(title: @project_submission.lesson.display_title, url: lesson_path(@project_submission.lesson)) %> + <% end %> +<% end %> diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index 00ef5ac748..8e3c079f41 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -24,7 +24,7 @@ <%= render partial: 'skill', collection: @courses, as: :course %>
- <%= render 'project_submissions', project_submissions: current_user.project_submissions %> + <%= render 'project_submissions', project_submissions: @project_submissions %>
<%= render 'shared/bottom_cta', diff --git a/config/routes.rb b/config/routes.rb index 28053b5e2e..a4a7cde5de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -78,6 +78,7 @@ resources :paths, only: :create resources :progress, only: :destroy resource :profile, only: %i[edit update] + resources :project_submissions, only: %i[edit update] end namespace :lessons do diff --git a/spec/system/v2_lesson_project_submissions/like_spec.rb b/spec/system/v2_lesson_project_submissions/like_spec.rb index 904573fb2f..1f010f5b7e 100644 --- a/spec/system/v2_lesson_project_submissions/like_spec.rb +++ b/spec/system/v2_lesson_project_submissions/like_spec.rb @@ -4,67 +4,32 @@ let(:user) { create(:user) } let(:lesson) { create(:lesson, :project) } - context "when liking other users' submissions" do - before do - Flipper.enable(:v2_project_submissions) - create(:project_submission, lesson:) + before do + Flipper.enable(:v2_project_submissions) + create(:project_submission, lesson:) - sign_in(user) - visit lesson_path(lesson) - end - - after do - Flipper.disable(:v2_project_submissions) - end - - it 'you can like another users submission' do - within(:test_project_submission, 1) do - expect(find(:test_id, 'like-count')).to have_content('0') - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('1') - end - end - - it 'you can unlike another users submission' do - within(:test_project_submission, 1) do - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('1') - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('0') - end - end + sign_in(user) + visit lesson_path(lesson) end - context 'when liking your own submission' do - before do - Flipper.enable(:v2_project_submissions) - create(:project_submission, lesson:, user:) - - sign_in(user) - visit lesson_path(lesson) - end - - after do - Flipper.disable(:v2_project_submissions) - end + after do + Flipper.disable(:v2_project_submissions) + end - it 'you can like your submission' do - within(:test_project_submission, 1) do |submission| - expect(submission).to have_content(user.username) - expect(find(:test_id, 'like-count')).to have_content('0') - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('1') - end + it 'you can like another users submission' do + within(:test_project_submission, 1) do + expect(find(:test_id, 'like-count')).to have_content('0') + find(:test_id, 'like-submission').click + expect(find(:test_id, 'like-count')).to have_content('1') end + end - it 'you can unlike your submission' do - within(:test_project_submission, 1) do |submission| - expect(submission).to have_content(user.username) - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('1') - find(:test_id, 'like-submission').click - expect(find(:test_id, 'like-count')).to have_content('0') - end + it 'you can unlike another users submission' do + within(:test_project_submission, 1) do + find(:test_id, 'like-submission').click + expect(find(:test_id, 'like-count')).to have_content('1') + find(:test_id, 'like-submission').click + expect(find(:test_id, 'like-count')).to have_content('0') end end end diff --git a/spec/system/v2_user_project_submissions/delete_submission_spec.rb b/spec/system/v2_user_project_submissions/delete_submission_spec.rb new file mode 100644 index 0000000000..161033be2b --- /dev/null +++ b/spec/system/v2_user_project_submissions/delete_submission_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +RSpec.describe 'Deleting a Project Submission on the Dashboard' do + let(:user) { create(:user) } + let(:lesson) { create(:lesson, :project) } + + before do + Flipper.enable(:v2_project_submissions) + + create(:project_submission, user:, lesson:) + sign_in(user) + visit dashboard_path + end + + after do + Flipper.disable(:v2_project_submissions) + end + + it 'successfully deletes a submission' do + sleep 0.1 # it will not open the dropdown without this + within(:test_id, 'user-submissions-list') do + expect(page).to have_content(lesson.title) + end + + find(:test_id, 'submission-action-menu-btn').click + + page.accept_confirm do + find(:test_id, 'delete-submission').click + end + + within(:test_id, 'user-submissions-list') do + expect(page).not_to have_content(lesson.title) + end + end +end diff --git a/spec/system/v2_user_project_submissions/edit_submission_spec.rb b/spec/system/v2_user_project_submissions/edit_submission_spec.rb new file mode 100644 index 0000000000..95d739a68b --- /dev/null +++ b/spec/system/v2_user_project_submissions/edit_submission_spec.rb @@ -0,0 +1,65 @@ +require 'rails_helper' + +RSpec.describe 'Editing a Project Submission on the Dashboard' do + let(:user) { create(:user) } + let(:another_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) + + create(:project_submission, user:, lesson:) + sign_in(user) + visit dashboard_path + end + + after do + Flipper.disable(:v2_project_submissions) + end + + it 'successfully edits a submission' do + sleep 0.1 # it will not open the dropdown without this + find(:test_id, 'submission-action-menu-btn').click + find(:test_id, 'edit-submission').click + + Pages::ProjectSubmissions::Form.new(**edited_field_values).tap do |edit_form| + edit_form.fill_in + edit_form.submit + end + + within(:test_id, 'submission-item') do + expect(page).to have_content(lesson.title) + expect(page.find(:test_id, 'view-code-btn')['href']).to eq('https://github.com/edited-project-repo-url') + expect(page.find(:test_id, 'live-preview-btn')['href']).to eq('http://edited-live-preview-url.com/') + end + + # mark the submission as private + + find(:test_id, 'submission-action-menu-btn').click + find(:test_id, 'edit-submission').click + + Pages::ProjectSubmissions::Form.new.tap do |form| + form.v2_make_private + form.submit + end + + within(:test_id, 'user-submissions-list') do + expect(page).to have_content(lesson.title) + end + + using_session('another_user') do + sign_in(another_user) + visit lesson_path(lesson) + + within(:test_id, 'submissions-list') do + expect(page).not_to have_content(user.username) + end + end + end +end