From 9dc17978def3a08ff42023cc056b8caab8e47aef Mon Sep 17 00:00:00 2001 From: Madeline Collier Date: Fri, 6 Dec 2024 16:56:20 +0100 Subject: [PATCH] WIP store credit refactor --- .../solidus_admin/ui/forms/field/component.rb | 2 +- .../edit_amount/component.html.erb | 33 +++++ .../store_credits/edit_amount/component.rb | 19 +++ .../store_credits/edit_amount/component.yml | 5 + .../users/store_credits/index/component.rb | 2 +- .../store_credits/show/component.html.erb | 48 +++---- .../users/store_credits/show/component.js | 15 +++ .../users/store_credits/show/component.yml | 2 +- .../solidus_admin/store_credits_controller.rb | 120 +++++++++++++++++- admin/config/locales/store_credits.en.yml | 10 ++ admin/config/routes.rb | 9 +- .../admin/store_credits/edit_amount.html.erb | 55 +++++--- 12 files changed, 276 insertions(+), 44 deletions(-) create mode 100644 admin/app/components/solidus_admin/users/store_credits/edit_amount/component.html.erb create mode 100644 admin/app/components/solidus_admin/users/store_credits/edit_amount/component.rb create mode 100644 admin/app/components/solidus_admin/users/store_credits/edit_amount/component.yml create mode 100644 admin/app/components/solidus_admin/users/store_credits/show/component.js create mode 100644 admin/config/locales/store_credits.en.yml diff --git a/admin/app/components/solidus_admin/ui/forms/field/component.rb b/admin/app/components/solidus_admin/ui/forms/field/component.rb index 352d1d9e58a..f15653d957a 100644 --- a/admin/app/components/solidus_admin/ui/forms/field/component.rb +++ b/admin/app/components/solidus_admin/ui/forms/field/component.rb @@ -46,7 +46,7 @@ def self.select(form, method, choices, object: nil, hint: nil, tip: nil, size: : tag: :select, choices:, size:, - value: object.public_send(method), + value: (object.public_send(method) if object.respond_to?(method)), error: (errors.to_sentence.capitalize if errors), **attributes, } diff --git a/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.html.erb b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.html.erb new file mode 100644 index 00000000000..9b4c1454ab1 --- /dev/null +++ b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.html.erb @@ -0,0 +1,33 @@ + <%= render component("ui/modal").new(title: t(".title")) do |modal| %> + <%= form_for @store_credit, url: solidus_admin.update_amount_user_store_credit_path(@user, @store_credit), method: :put, data: { turbo: false }, html: { id: form_id } do |f| %> +
+ <%= render component("ui/forms/field").text_field(f, :amount, class: "required") %> + <%= render component("ui/forms/field").select( + f, + :store_credit_reason_id, + store_credit_reasons_select_options.html_safe, + include_blank: t('spree.choose_reason'), + html: { required: true } + ) %> + + <% if @store_credit.errors.any? %> +
+
    + <% @store_credit.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + <%= render component("ui/forms/field").text_field(f, :memo, class: "required") %> +
+ <% modal.with_actions do %> +
+ <%= render component("ui/button").new(scheme: :secondary, tag: :a, href: solidus_admin.user_store_credit_path(@user, @store_credit), text: t('.cancel')) %> +
+ <%= render component("ui/button").new(form: form_id, type: :submit, text: t('.submit')) %> + <% end %> + <% end %> + <% end %> +<%= render component("users/store_credits/show").new(user: @user, store_credit: @store_credit, events: @store_credit_events) %> + diff --git a/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.rb b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.rb new file mode 100644 index 00000000000..545444fc79c --- /dev/null +++ b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class SolidusAdmin::Users::StoreCredits::EditAmount::Component < SolidusAdmin::BaseComponent + def initialize(user:, store_credit:, events:, reasons:) + @user = user + @store_credit = store_credit + @store_credit_events = events + @store_credit_reasons = reasons + end + + def form_id + dom_id(@store_credit, "#{stimulus_id}_edit_store_credit_form") + end + + def store_credit_reasons_select_options + # Placeholder + Store Credit Reasons + "" + options_from_collection_for_select(@store_credit_reasons, :id, :name) + end +end diff --git a/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.yml b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.yml new file mode 100644 index 00000000000..3bfc972f777 --- /dev/null +++ b/admin/app/components/solidus_admin/users/store_credits/edit_amount/component.yml @@ -0,0 +1,5 @@ +en: + title: Edit Store Credit + cancel: Cancel + submit: Update Store Credit + choose_reason: Choose Reason For Changing Amount diff --git a/admin/app/components/solidus_admin/users/store_credits/index/component.rb b/admin/app/components/solidus_admin/users/store_credits/index/component.rb index f3036e4cd50..615a2163eda 100644 --- a/admin/app/components/solidus_admin/users/store_credits/index/component.rb +++ b/admin/app/components/solidus_admin/users/store_credits/index/component.rb @@ -47,7 +47,7 @@ def rows end def row_url(store_credit) - spree.admin_user_store_credit_path(@user, store_credit) + solidus_admin.user_store_credit_path(@user, store_credit) end def columns diff --git a/admin/app/components/solidus_admin/users/store_credits/show/component.html.erb b/admin/app/components/solidus_admin/users/store_credits/show/component.html.erb index ca89b32b5fd..9e0882593eb 100644 --- a/admin/app/components/solidus_admin/users/store_credits/show/component.html.erb +++ b/admin/app/components/solidus_admin/users/store_credits/show/component.html.erb @@ -2,20 +2,6 @@ <%= page_header do %> <%= page_header_back(solidus_admin.users_path) %> <%= page_header_title(t(".title", email: @user.email, amount: @store_credit.display_amount)) %> - - <%= page_header_actions do %> - <%# TODO: can? actions in admin %> - <%# if @store_credit.editable? && can?(:edit, @store_credit) %> - <% if @store_credit.editable? %> - <%= render component("ui/button").new(tag: :a, text: t(".change_amount"), href: spree.edit_amount_admin_user_store_credit_path(@user, @store_credit)) %> - <% end %> - <%# TODO: can? actions in admin %> - <%# if @store_credit.invalidateable? && can?(:invalidate, @store_credit) %> - <% if @store_credit.invalidateable? %> - <%= render component("ui/button").new(scheme: :danger, tag: :a, text: t(".invalidate"), href: spree.edit_validity_admin_user_store_credit_path(@user, @store_credit)) %> - <% end %> - - <% end %> <% end %> <%= page_header do %> @@ -26,17 +12,31 @@ <%= page_with_sidebar do %> <%= page_with_sidebar_main do %> - <%= render component('ui/panel').new(title: t(".store_credit")) do %> - <%= render component('ui/details_list').new( - items: [ - { label: t('.credited'), value: @store_credit.display_amount }, - { label: t('.created_by'), value: @store_credit.created_by_email }, - { label: t('.type'), value: @store_credit.category_name }, - { label: t('.memo'), value: @store_credit.memo } - ] - ) %> - <% end %> + <%= render component('ui/panel').new(title: t(".store_credit")) do |panel| %> + <% panel.with_section do %> + <%= render component('ui/details_list').new( + items: [ + { label: t('.credited'), value: @store_credit.display_amount }, + { label: t('.created_by'), value: @store_credit.created_by_email }, + { label: t('.type'), value: @store_credit.category_name }, + { label: t('.memo'), value: @store_credit.memo } + ] + ) %> + <% end %> + <% if @store_credit.editable? || @store_credit.invalidateable? %> + <% panel.with_section do %> +
+ <% if @store_credit.invalidateable? %> + <%= render component("ui/button").new(scheme: :danger, tag: :a, "data-action": "click->#{stimulus_id}#confirmDelete", text: t(".invalidate"), href: spree.edit_validity_admin_user_store_credit_path(@user, @store_credit)) %> + <% end %> + <% if @store_credit.editable? %> + <%= render component("ui/button").new(tag: :a, "data-action": "click->#{stimulus_id}#confirmDelete", text: t(".edit"), href: solidus_admin.edit_amount_user_store_credit_path(@user, @store_credit)) %> + <% end %> +
+ <% end %> + <% end %> + <% end %> <% if @events.present? %>

<%= t(".store_credit_history") %>

diff --git a/admin/app/components/solidus_admin/users/store_credits/show/component.js b/admin/app/components/solidus_admin/users/store_credits/show/component.js new file mode 100644 index 00000000000..b6f7437145d --- /dev/null +++ b/admin/app/components/solidus_admin/users/store_credits/show/component.js @@ -0,0 +1,15 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + actionButtonClicked(event) { + const url = new URL(event.params.url, "http://dummy.com") + const params = new URLSearchParams(url.search) + const frameId = params.get('_turbo_frame') + const frame = frameId ? { frame: frameId } : {} + // remove the custom _turbo_frame param from url search: + params.delete('_turbo_frame') + url.search = params.toString() + + window.Turbo.visit(url.pathname + url.search, frame) + } +} diff --git a/admin/app/components/solidus_admin/users/store_credits/show/component.yml b/admin/app/components/solidus_admin/users/store_credits/show/component.yml index d0a4ec2d378..5da2e914918 100644 --- a/admin/app/components/solidus_admin/users/store_credits/show/component.yml +++ b/admin/app/components/solidus_admin/users/store_credits/show/component.yml @@ -7,7 +7,7 @@ en: store_credit: Store Credit last_active: Last Active add_store_credit: Add Store Credit - change_amount: Change Amount + edit: Edit Store Credit invalidate: Invalidate store_credit_history: Store Credit History credited: Credited diff --git a/admin/app/controllers/solidus_admin/store_credits_controller.rb b/admin/app/controllers/solidus_admin/store_credits_controller.rb index c7032de4907..0a7265c4675 100644 --- a/admin/app/controllers/solidus_admin/store_credits_controller.rb +++ b/admin/app/controllers/solidus_admin/store_credits_controller.rb @@ -3,8 +3,10 @@ module SolidusAdmin class StoreCreditsController < SolidusAdmin::BaseController before_action :set_user - before_action :set_store_credit, only: [:show] + before_action :set_store_credit, only: [:show, :edit_amount, :update_amount] + before_action :set_store_credit_reasons, only: [:edit_amount, :update_amount] + SolidusAdmin::StoreCreditsController def index @store_credits = Spree::StoreCredit.where(user_id: @user.id).order(id: :desc) @@ -18,11 +20,111 @@ def show respond_to do |format| format.html { render component("users/store_credits/show").new(user: @user, store_credit: @store_credit, events: @store_credit_events) } + + format.turbo_stream do + render turbo_stream: turbo_stream.replace( + "store_credit_details", # Target a container ID in your HTML + partial: "users/store_credits/show", # Use the appropriate partial + locals: { user: @user, store_credit: @store_credit, events: @store_credit_events } + ) + end + end + end + + def edit_amount + @store_credit_events = @store_credit.store_credit_events.chronological + + respond_to do |format| + format.html { render component("users/store_credits/edit_amount").new( + user: @user, + store_credit: @store_credit, + events: @store_credit_events, + reasons: @store_credit_reasons + )} + end + end + + # def update_amount + # binding.pry + # + # @store_credit_reason = Spree::StoreCreditReason.find_by(id: params[:store_credit_reason_id]) + # unless @store_credit_reason + # @store_credit.errors.add(:base, t('spree.admin.store_credits.errors.store_credit_reason_required')) + # render_edit_page + # end + # + # amount = params.require(:store_credit).require(:amount) + # if @store_credit.update_amount(amount, @store_credit_reason, spree_current_user) + # flash[:success] = flash_message_for(@store_credit, :successfully_updated) + # redirect_to admin_user_store_credit_path(@user, @store_credit) + # else + # flash[:error] = "#{t("spree.admin.store_credits.unable_to_update")}: #{@store_credit.errors.full_messages.join(', ')}" + # render(:edit_amount) && return + # end + # end + + def wip_old_update_amount + if @store_credit.update(permitted_store_credit_params) + flash[:notice] = t('.success') + redirect_to solidus_admin.user_store_credit_path(@user, @store_credit), status: :see_other + else + respond_to do |format| + format.html { render component("users/store_credits/edit_amount").new( + user: @user, + store_credit: @store_credit, + events: @store_credit_events, + reasons: @store_credit_reasons + ), + status: :unprocessable_entity + } + end + end + end + + def update_amount + @store_credit_reason = Spree::StoreCreditReason.find_by(id: params[:store_credit_reason_id]) + amount = params.require(:store_credit).require(:amount) + + if amount_changed? + if @store_credit_reason.blank? + @store_credit.errors.add(:base, "Store Credit reason must be provided") + render_edit_page_with_errors and return + end + + unless @store_credit.update_amount(amount, @store_credit_reason, spree_current_user) + render_edit_page_with_errors and return + end end + + @store_credit.update(memo: permitted_store_credit_params[:memo]) + + flash[:notice] = t('.success') + redirect_to solidus_admin.user_store_credit_path(@user, @store_credit), status: :see_other end private + def render_edit_page_with_errors + @store_credit_events = @store_credit.store_credit_events.chronological + + respond_to do |format| + format.html do + render component("users/store_credits/edit_amount").new( + user: @user, + store_credit: @store_credit, + events: @store_credit_events, + reasons: @store_credit_reasons + ), + status: :unprocessable_entity + end + end + end + + def permitted_store_credit_params + params.require(:store_credit).permit([:amount, :currency, :category_id, :memo]). + merge(created_by: spree_current_user) + end + def set_store_credit @store_credit = Spree::StoreCredit.find(params[:id]) end @@ -30,5 +132,21 @@ def set_store_credit def set_user @user = Spree.user_class.find(params[:user_id]) end + + def set_store_credit_reasons + @store_credit_reasons = Spree::StoreCreditReason.active.order(:name) + end + + def amount_changed? + # Add error if the amount is blank or nil. Let the model validation handle all other cases. + if permitted_store_credit_params[:amount].blank? + @store_credit.errors.add(:amount, :greater_than, count: 0, value: permitted_store_credit_params[:amount]) + return false + end + + old_amount = @store_credit.amount + new_amount = BigDecimal(permitted_store_credit_params[:amount]) + old_amount != new_amount + end end end diff --git a/admin/config/locales/store_credits.en.yml b/admin/config/locales/store_credits.en.yml new file mode 100644 index 00000000000..e24c5cda30c --- /dev/null +++ b/admin/config/locales/store_credits.en.yml @@ -0,0 +1,10 @@ +en: + solidus_admin: + store_credits: + title: "Store Credits" + destroy: + success: "Store credit was successfully removed." + create: + success: "Store credit was successfully created." + update_amount: + success: "Store credit was successfully updated." diff --git a/admin/config/routes.rb b/admin/config/routes.rb index cf3b11aa03a..4f4cf14b332 100644 --- a/admin/config/routes.rb +++ b/admin/config/routes.rb @@ -53,7 +53,14 @@ get :items end - resources :store_credits, only: [:index, :show], controller: "store_credits" + resources :store_credits, only: [:index, :show], constraints: { id: /\d+/ }, controller: "store_credits" do + member do + get :edit_amount + put :update_amount + # get :edit_validity + # put :invalidate + end + end end admin_resources :promotions, only: [:index, :destroy] diff --git a/backend/app/views/spree/admin/store_credits/edit_amount.html.erb b/backend/app/views/spree/admin/store_credits/edit_amount.html.erb index b3ce218b0fb..ad49a4a7f42 100644 --- a/backend/app/views/spree/admin/store_credits/edit_amount.html.erb +++ b/backend/app/views/spree/admin/store_credits/edit_amount.html.erb @@ -1,14 +1,3 @@ -<% admin_breadcrumb(link_to plural_resource_name(Spree::LegacyUser), spree.admin_users_path) %> -<% admin_breadcrumb(link_to @user.email, edit_admin_user_url(@user)) %> -<% admin_breadcrumb(link_to plural_resource_name(Spree::StoreCredit), spree.admin_user_store_credits_path(@user)) %> -<% admin_breadcrumb(link_to Spree::StoreCredit.model_name.human, admin_user_store_credit_path(@user, @store_credit)) %> -<% admin_breadcrumb(t('spree.edit')) %> - -<%= render 'spree/admin/users/sidebar' %> -<%= render 'spree/admin/users/tabs', current: :store_credits %> -<% content_for :page_actions do %> -<% end %> - <%= form_for [:admin, @user, @store_credit], url: update_amount_admin_user_store_credit_path, method: :put do |f| %>
<%= t('spree.admin.store_credits.edit_amount') %> @@ -16,16 +5,52 @@
<%= f.field_container :amount do %> <%= f.label :amount, class: 'required' %>
- <%= render "spree/admin/shared/number_with_currency", f: f, - amount_attr: :amount, currency: @store_credit.currency, required: true %> + + + <%= render "spree/admin/shared/number_with_currency", f: f, amount_attr: :amount, currency: @store_credit.currency, required: true %> + + + <% amount_attr ||= :amount %> + <% currency_attr ||= :currency %> + <% currency ||= nil %> + <% required ||= nil %> + +
js-number-with-currency"> +
+ +
+ <%= f.text_field amount_attr, value: number_to_currency(f.object.public_send(amount_attr), unit: '', delimiter: ''), class: 'form-control number-with-currency-amount', required: required %> + <% if currency %> +
+ + <%= ::Money::Currency.find(currency).iso_code %> + +
+ <% else %> + <%= f.select currency_attr, Spree::Config.available_currencies.map(&:iso_code), {selected: Spree::Config.currency}, {required: required, class: 'number-with-currency-select'} %> + <% end %> +
+ + <%= f.error_message_on :amount %> <% end %>
+ + <%= render 'store_credit_reason_field', f: f %> + + + <%= f.field_container :reason do %> + <%= f.label :store_credit_reason, t('spree.reason'), class: 'required' %> + <%= select_tag :store_credit_reason_id, options_from_collection_for_select(@store_credit_reasons, :id, :name), + include_blank: t('spree.choose_reason'), class: 'custom-select fullwidth', + placeholder: t('spree.admin.store_credits.select_amount_store_credit_reason') %> + <%= f.error_message_on :store_credit_reason %> + <% end %> + +
- <%= render 'spree/admin/shared/edit_resource_links', - collection_url: admin_user_store_credits_path(@user, @store_credit) %>
<% end %>