From fb07794cf3e71916e88fb5b763caeb0009ee7c7b Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 28 May 2024 01:10:30 +0500 Subject: [PATCH] 12398: add slide-out animation --- app/components/confirm_modal_component.rb | 4 +- .../confirm_modal_component.html.haml | 7 +-- .../admin/products_v3_controller.rb | 8 ++- .../admin/products_v3/_delete_modal.html.haml | 5 +- .../admin/products_v3/_product_row.html.haml | 2 +- .../admin/products_v3/_variant_row.html.haml | 2 +- .../destroy_product_variant.turbo_stream.haml | 7 ++- .../controllers/modal_link_controller.js | 15 ------ .../controllers/products_controller.js | 49 +++++++++++++++++++ app/webpacker/css/admin/products_v3.scss | 15 ++++++ 10 files changed, 81 insertions(+), 33 deletions(-) diff --git a/app/components/confirm_modal_component.rb b/app/components/confirm_modal_component.rb index 7034db03c6..8149a729e3 100644 --- a/app/components/confirm_modal_component.rb +++ b/app/components/confirm_modal_component.rb @@ -12,8 +12,7 @@ class ConfirmModalComponent < ModalComponent confirm_button_class: :primary, confirm_button_text: I18n.t('js.admin.modals.confirm'), cancel_button_text: I18n.t('js.admin.modals.cancel'), - actions_alignment_class: 'justify-space-around', - confirm_submit_method: nil + actions_alignment_class: 'justify-space-around' ) super(id:, close_button: true) @confirm_actions = confirm_actions @@ -25,7 +24,6 @@ class ConfirmModalComponent < ModalComponent @confirm_button_text = confirm_button_text @cancel_button_text = cancel_button_text @actions_alignment_class = actions_alignment_class - @confirm_submit_method = confirm_submit_method end private diff --git a/app/components/confirm_modal_component/confirm_modal_component.html.haml b/app/components/confirm_modal_component/confirm_modal_component.html.haml index 210bc724a8..1184602a67 100644 --- a/app/components/confirm_modal_component/confirm_modal_component.html.haml +++ b/app/components/confirm_modal_component/confirm_modal_component.html.haml @@ -7,9 +7,4 @@ %div{ class: "modal-actions #{@actions_alignment_class}" } %input{ class: "button icon-plus #{close_button_class}", type: 'button', value: @cancel_button_text, "data-action": "click->modal#close" } - - # TODO: This if block needs to be removed when we completely get rid of Reflex - - # The button's form action will be dynamically set when the modal is opened via modal-link-controller - - if @confirm_submit_method - = button_to @confirm_button_text, '', id: 'modal-confirm-button', method: @confirm_submit_method, data: { action: @confirm_actions } - - else - %input{ id: 'modal-confirm-button', class: "button icon-plus #{@confirm_button_class}", type: 'button', value: @confirm_button_text, "data-action": @confirm_actions, "data-reflex": @confirm_reflexes } + %input{ id: 'modal-confirm-button', class: "button icon-plus #{@confirm_button_class}", type: 'button', value: @confirm_button_text, "data-action": @confirm_actions, "data-reflex": @confirm_reflexes } diff --git a/app/controllers/admin/products_v3_controller.rb b/app/controllers/admin/products_v3_controller.rb index 15d12d3849..80eefbaca7 100644 --- a/app/controllers/admin/products_v3_controller.rb +++ b/app/controllers/admin/products_v3_controller.rb @@ -37,14 +37,16 @@ module Admin { id: params[:id] } ).find_product + status = :ok if @record.destroy flash[:success] = I18n.t('admin.products_v3.delete_product.success') else flash[:error] = I18n.t('admin.products_v3.delete_product.error') + status = :internal_server_error end respond_with do |format| - format.turbo_stream { render :destroy_product_variant } + format.turbo_stream { render :destroy_product_variant, status: } end # using flash with turbo stream doesn't clear it because the page is not refreshed. @@ -56,14 +58,16 @@ module Admin @record = Spree::Variant.active.find(params[:id]) authorize! :delete, @record + status = :ok if VariantDeleter.new.delete(@record) flash[:success] = I18n.t('admin.products_v3.delete_variant.success') else flash[:error] = I18n.t('admin.products_v3.delete_variant.error') + status = :internal_server_error end respond_with do |format| - format.turbo_stream { render :destroy_product_variant } + format.turbo_stream { render :destroy_product_variant, status: } end flash.discard diff --git a/app/views/admin/products_v3/_delete_modal.html.haml b/app/views/admin/products_v3/_delete_modal.html.haml index ca0987ab4e..87208c5dbe 100644 --- a/app/views/admin/products_v3/_delete_modal.html.haml +++ b/app/views/admin/products_v3/_delete_modal.html.haml @@ -5,9 +5,8 @@ cancel_button_text: t("#{base_translation_key}.cancellation_text"), confirm_button_class: :red, actions_alignment_class: 'justify-end', - confirm_reflexes: "click->products#delete_#{object_type}", - confirm_actions: "click->modal#close", - confirm_submit_method: :delete, + controller: "products", + confirm_actions: "click->products#delete_#{object_type} click->modal#close", ) = render delete_modal do %h2.margin-bottom-20.black-text diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 0e16514257..d009b544ed 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -43,5 +43,5 @@ = link_to t('admin.products_page.actions.clone'), clone_admin_product_path(product), 'data-turbo': false %a{ "data-controller": "modal-link", "data-action": "click->modal-link#setModalDataSetOnConfirm click->modal-link#open", "data-modal-link-target-value": "product-delete-modal", "class": "delete", - "data-modal-link-modal-dataset-value": {'data-path': admin_product_destroy_path(product)}.to_json } + "data-modal-link-modal-dataset-value": {'data-delete-path': admin_product_destroy_path(product)}.to_json } = t('admin.products_page.actions.delete') diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 02f23b8eeb..3b3b38ac54 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -66,7 +66,7 @@ - if variant.product.variants.size > 1 %a{ "data-controller": "modal-link", "data-action": "click->modal-link#setModalDataSetOnConfirm click->modal-link#open", "data-modal-link-target-value": "variant-delete-modal", "class": "delete", - "data-modal-link-modal-dataset-value": {'data-path': admin_destroy_variant_path(variant)}.to_json } + "data-modal-link-modal-dataset-value": {'data-delete-path': admin_destroy_variant_path(variant)}.to_json } = t('admin.products_page.actions.delete') - else %a{ 'data-action': "nested-form#remove", class: 'delete' } diff --git a/app/views/admin/products_v3/destroy_product_variant.turbo_stream.haml b/app/views/admin/products_v3/destroy_product_variant.turbo_stream.haml index 74c600fe84..6ea1bc1a8f 100644 --- a/app/views/admin/products_v3/destroy_product_variant.turbo_stream.haml +++ b/app/views/admin/products_v3/destroy_product_variant.turbo_stream.haml @@ -1,3 +1,6 @@ - # @record can either be Product or Variant -= turbo_stream.remove dom_id(@record) -= render partial: "admin/shared/flashes", locals: { flashes: flash } if defined? flash +- unless flash[:error] + = turbo_stream.remove(dom_id(@record)) +-# Without +formats+ option here, by default render is trying to render the equivalant turbo stream +-# It's strange that it works just fine if I remove the +unless+ above += render(partial: 'admin/shared/flashes', locals: { flashes: flash }, formats: [:html]) diff --git a/app/webpacker/controllers/modal_link_controller.js b/app/webpacker/controllers/modal_link_controller.js index c77e2864fe..9eb765c35f 100644 --- a/app/webpacker/controllers/modal_link_controller.js +++ b/app/webpacker/controllers/modal_link_controller.js @@ -17,9 +17,6 @@ export default class extends Controller { const modalId = this.targetValue; const moodalConfirmButtonQuery = `#${modalId} #modal-confirm-button`; const confirmButton = document.querySelector(moodalConfirmButtonQuery); - - this.#setPathToFormAction(confirmButton); - Object.keys(this.modalDatasetValue).forEach((datasetKey) => { confirmButton.setAttribute(datasetKey, this.modalDatasetValue[datasetKey]); }); @@ -33,16 +30,4 @@ export default class extends Controller { getIdentifier() { return "modal"; } - - #setPathToFormAction(confirmButton) { - const isSubmitButton = confirmButton.type === 'submit'; - const path = this.modalDatasetValue['data-path']; - - if(isSubmitButton && path){ - const form = confirmButton.parentElement; - form.setAttribute('action', path); - - delete this.modalDatasetValue['data-path']; - } - } } diff --git a/app/webpacker/controllers/products_controller.js b/app/webpacker/controllers/products_controller.js index 9ec3ac1a86..8396d9edf7 100644 --- a/app/webpacker/controllers/products_controller.js +++ b/app/webpacker/controllers/products_controller.js @@ -17,6 +17,14 @@ export default class extends ApplicationController { this.hideLoading(); } + delete_product() { + this.#deleteByRecordType('product'); + } + + delete_variant() { + this.#deleteByRecordType('variant'); + } + showLoading = () => { if (this.getLoadingController()) { this.getLoadingController().showLoading(); @@ -39,4 +47,45 @@ export default class extends ApplicationController { "loading" )); }; + + // +recordType+ can either be 'product' or 'variant' + #deleteByRecordType(recordType) { + const deletePath = document.querySelector(`#${recordType}-delete-modal #modal-confirm-button`).getAttribute('data-delete-path'); + const elementToBeRemoved = this.#getElementToBeRemoved(deletePath, recordType); + + const handleSlideOutAnimationEnd = async () => { + const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); + + try { + const response = await fetch(deletePath, { + method: 'DELETE', + headers: { + Accept: 'text/vnd.turbo-stream.html', + 'X-CSRF-Token': csrfToken, + } + }); + // need to render the turboStream message, that's why not throwing error here + if(response.status === 500) elementToBeRemoved.classList.remove('slide-out'); + + const responseTurboStream = await response.text(); + Turbo.renderStreamMessage(responseTurboStream); + } catch(error) { + console.error(error.message); + elementToBeRemoved.classList.remove('slide-out'); + } + finally { + elementToBeRemoved.removeEventListener('animationend', handleSlideOutAnimationEnd); + } + }; + + elementToBeRemoved.classList.add('slide-out'); + elementToBeRemoved.addEventListener('animationend', handleSlideOutAnimationEnd); + }; + + #getElementToBeRemoved(path, recordType) { + const recordId = path.substring(path.lastIndexOf('/') + 1); + const elementDomId = `${recordType}_${recordId}`; + + return document.getElementById(elementDomId); + }; } diff --git a/app/webpacker/css/admin/products_v3.scss b/app/webpacker/css/admin/products_v3.scss index a06019bebb..2b277f0e33 100644 --- a/app/webpacker/css/admin/products_v3.scss +++ b/app/webpacker/css/admin/products_v3.scss @@ -413,4 +413,19 @@ } } } + + @keyframes slideOutLeft { + from { + transform: translateX(0); + opacity: 1; + } + to { + transform: translateX(-100%); + opacity: 0; + } + } + + .slide-out { + animation: slideOutLeft 0.5s forwards; + } }