diff --git a/admin/app/components/solidus_admin/shipping_categories/edit/component.html.erb b/admin/app/components/solidus_admin/shipping_categories/edit/component.html.erb
new file mode 100644
index 00000000000..2afd4813ee1
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/edit/component.html.erb
@@ -0,0 +1,16 @@
+<%= turbo_frame_tag :edit_shipping_category_modal do %>
+ <%= render component("ui/modal").new(title: t(".title")) do |modal| %>
+ <%= form_for @shipping_category, url: solidus_admin.shipping_category_path(@shipping_category), html: { id: form_id } do |f| %>
+
+ <%= render component("ui/forms/field").text_field(f, :name) %>
+
+ <% modal.with_actions do %>
+
+ <%= render component("ui/button").new(form: form_id, type: :submit, text: t('.submit')) %>
+ <% end %>
+ <% end %>
+ <% end %>
+<% end %>
+<%= render component("shipping_categories/index").new(page: @page) %>
\ No newline at end of file
diff --git a/admin/app/components/solidus_admin/shipping_categories/edit/component.rb b/admin/app/components/solidus_admin/shipping_categories/edit/component.rb
new file mode 100644
index 00000000000..62f8b8f1b59
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/edit/component.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class SolidusAdmin::ShippingCategories::Edit::Component < SolidusAdmin::ShippingCategories::Index::Component
+ def initialize(page:, shipping_category:)
+ @page = page
+ @shipping_category = shipping_category
+ end
+
+ def form_id
+ dom_id(@shipping_category, "#{stimulus_id}_edit_shipping_category_form")
+ end
+end
\ No newline at end of file
diff --git a/admin/app/components/solidus_admin/shipping_categories/edit/component.yml b/admin/app/components/solidus_admin/shipping_categories/edit/component.yml
new file mode 100644
index 00000000000..d61ed4ed0c0
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/edit/component.yml
@@ -0,0 +1,6 @@
+# Add your component translations here.
+# Use the translation in the example in your template with `t(".hello")`.
+en:
+ title: "Edit Shipping Category"
+ cancel: "Cancel"
+ submit: "Update Shipping Category"
\ No newline at end of file
diff --git a/admin/app/components/solidus_admin/shipping_categories/index/component.rb b/admin/app/components/solidus_admin/shipping_categories/index/component.rb
index d5bf779136b..37b6b148257 100644
--- a/admin/app/components/solidus_admin/shipping_categories/index/component.rb
+++ b/admin/app/components/solidus_admin/shipping_categories/index/component.rb
@@ -15,12 +15,29 @@ def actions
)
end
+ def page_actions
+ render component("ui/button").new(
+ tag: :a,
+ text: t('.add'),
+ href: solidus_admin.new_shipping_category_path, data: { turbo_frame: :new_shipping_category_modal },
+ icon: "add-line",
+ class: "align-self-end w-full",
+ )
+ end
+
+ def turbo_frames
+ %w[
+ new_shipping_category_modal
+ edit_shipping_category_modal
+ ]
+ end
+
def row_url(shipping_category)
- spree.edit_admin_shipping_category_path(shipping_category)
+ spree.edit_admin_shipping_category_path(shipping_category, _turbo_frame: :edit_shipping_category_modal)
end
def search_key
- :name_or_description_cont
+ :name_cont
end
def search_url
diff --git a/admin/app/components/solidus_admin/shipping_categories/new/component.html.erb b/admin/app/components/solidus_admin/shipping_categories/new/component.html.erb
new file mode 100644
index 00000000000..e3cf3a75937
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/new/component.html.erb
@@ -0,0 +1,17 @@
+<%= turbo_frame_tag :new_shipping_category_modal do %>
+ <%= render component("ui/modal").new(title: t(".title")) do |modal| %>
+ <%= form_for @shipping_category, url: solidus_admin.shipping_categories_path(page: params[:page], q: params[:q]), html: { id: form_id } do |f| %>
+
+ <%= render component("ui/forms/field").text_field(f, :name) %>
+
+ <% modal.with_actions do %>
+
+ <%= render component("ui/button").new(form: form_id, type: :submit, text: t('.submit')) %>
+ <% end %>
+ <% end %>
+ <% end %>
+<% end %>
+
+<%= render component("shipping_categories/index").new(page: @page) %>
diff --git a/admin/app/components/solidus_admin/shipping_categories/new/component.rb b/admin/app/components/solidus_admin/shipping_categories/new/component.rb
new file mode 100644
index 00000000000..ec46b93ae3d
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/new/component.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class SolidusAdmin::ShippingCategories::New::Component < SolidusAdmin::ShippingCategories::Index::Component
+ def initialize(page:, shipping_category:)
+ @page = page
+ @shipping_category = shipping_category
+ end
+
+ def form_id
+ dom_id(@shipping_category, "#{stimulus_id}_new_shipping_category_form")
+ end
+end
diff --git a/admin/app/components/solidus_admin/shipping_categories/new/component.yml b/admin/app/components/solidus_admin/shipping_categories/new/component.yml
new file mode 100644
index 00000000000..f4b77159807
--- /dev/null
+++ b/admin/app/components/solidus_admin/shipping_categories/new/component.yml
@@ -0,0 +1,6 @@
+# Add your component translations here.
+# Use the translation in the example in your template with `t(".hello")`.
+en:
+ title: "New Shipping Category"
+ cancel: "Cancel"
+ submit: "Add Shipping Category"
diff --git a/admin/app/controllers/solidus_admin/shipping_categories_controller.rb b/admin/app/controllers/solidus_admin/shipping_categories_controller.rb
index 7e77234c58b..400482ab822 100644
--- a/admin/app/controllers/solidus_admin/shipping_categories_controller.rb
+++ b/admin/app/controllers/solidus_admin/shipping_categories_controller.rb
@@ -4,13 +4,82 @@ module SolidusAdmin
class ShippingCategoriesController < SolidusAdmin::BaseController
include SolidusAdmin::ControllerHelpers::Search
- def index
- shipping_categories = apply_search_to(
- Spree::ShippingCategory.order(id: :desc),
- param: :q,
- )
+ before_action :find_shipping_category, only: %i[edit update]
- set_page_and_extract_portion_from(shipping_categories)
+ def new
+ @shipping_category = Spree::ShippingCategory.new
+
+ set_index_page
+
+ respond_to do |format|
+ format.html { render component('shipping_categories/new').new(page: @page, shipping_category: @shipping_category) }
+ end
+ end
+
+ def create
+ @shipping_category = Spree::ShippingCategory.new(shipping_category_params)
+
+ if @shipping_category.save
+ respond_to do |format|
+ flash[:notice] = t('.success')
+
+ format.html do
+ redirect_to solidus_admin.shipping_categories_path, status: :see_other
+ end
+
+ format.turbo_stream do
+ # we need to explicitly write the refresh tag for now.
+ # See https://github.com/hotwired/turbo-rails/issues/579
+ render turbo_stream: ''
+ end
+ end
+ else
+ set_index_page
+
+ respond_to do |format|
+ format.html do
+ page_component = component('shipping_categories/new').new(page: @page, shipping_category: @shipping_category)
+ render page_component, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def edit
+ set_index_page
+
+ respond_to do |format|
+ format.html { render component('shipping_categories/edit').new(page: @page, shipping_category: @shipping_category) }
+ end
+ end
+
+ def update
+ if @shipping_category.update(shipping_category_params)
+ respond_to do |format|
+ flash[:notice] = t('.success')
+
+ format.html do
+ redirect_to solidus_admin.shipping_categories_path, status: :see_other
+ end
+
+ format.turbo_stream do
+ render turbo_stream: ''
+ end
+ end
+ else
+ set_index_page
+
+ respond_to do |format|
+ format.html do
+ page_component = component('shipping_categories/edit').new(page: @page, shipping_category: @shipping_category)
+ render page_component, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def index
+ set_index_page
respond_to do |format|
format.html { render component('shipping_categories/index').new(page: @page) }
@@ -33,8 +102,21 @@ def load_shipping_category
authorize! action_name, @shipping_category
end
+ def find_shipping_category
+ @shipping_category = Spree::ShippingCategory.find(params[:id])
+ end
+
def shipping_category_params
- params.require(:shipping_category).permit(:shipping_category_id, permitted_shipping_category_attributes)
+ params.require(:shipping_category).permit(:name)
+ end
+
+ def set_index_page
+ shipping_categories = apply_search_to(
+ Spree::ShippingCategory.order(id: :desc),
+ param: :q,
+ )
+
+ set_page_and_extract_portion_from(shipping_categories)
end
end
end
diff --git a/admin/config/locales/shipping_categories.en.yml b/admin/config/locales/shipping_categories.en.yml
index 69ab216dac5..677230e6607 100644
--- a/admin/config/locales/shipping_categories.en.yml
+++ b/admin/config/locales/shipping_categories.en.yml
@@ -4,3 +4,8 @@ en:
title: "Shipping Categories"
destroy:
success: "Shipping categories were successfully removed."
+ create:
+ success: "Shipping category was successfully created."
+ update:
+ success: "Shipping category was successfully updated."
+
diff --git a/admin/config/routes.rb b/admin/config/routes.rb
index 37003949356..8f0d9bfee77 100644
--- a/admin/config/routes.rb
+++ b/admin/config/routes.rb
@@ -56,7 +56,7 @@
admin_resources :payment_methods, only: [:index, :destroy], sortable: true
admin_resources :stock_items, only: [:index, :edit, :update]
admin_resources :shipping_methods, only: [:index, :destroy]
- admin_resources :shipping_categories, only: [:index, :destroy]
+ admin_resources :shipping_categories, except: [:show]
admin_resources :stock_locations, only: [:index, :destroy]
admin_resources :stores, only: [:index, :destroy]
admin_resources :zones, only: [:index, :destroy]
diff --git a/admin/spec/features/shipping_categories_spec.rb b/admin/spec/features/shipping_categories_spec.rb
index e3d02c4a0d9..d2ab165ad98 100644
--- a/admin/spec/features/shipping_categories_spec.rb
+++ b/admin/spec/features/shipping_categories_spec.rb
@@ -19,4 +19,62 @@
expect(Spree::ShippingCategory.count).to eq(0)
expect(page).to be_axe_clean
end
+
+ context "edition" do
+ before do
+ Spree::ShippingCategory.create(name: "a shipping category")
+ end
+
+ it "allows to edit a shipping category" do
+ visit "/admin/shipping_categories"
+ find_row("a shipping category").click()
+
+ expect(page).to have_content("Edit Shipping Category")
+
+ fill_in "Name", with: "a new name"
+
+ click_on "Update Shipping Category"
+ expect(page).to have_content("Shipping category was successfully updated.")
+ expect(Spree::ShippingCategory.find_by(name: "a new name")).to be_present
+ end
+ end
+
+ context "when creating a new shipping category" do
+ let(:query) { "?page=1&q%5Bname_or_description_cont%5D=What" }
+
+ before do
+ visit "/admin/shipping_categories#{query}"
+ click_on "Add new"
+ expect(page).to have_content("New Shipping Category")
+ expect(page).to be_axe_clean
+ end
+
+ it "opens a modal" do
+ expect(page).to have_selector("dialog")
+ within("dialog") { click_on "Cancel" }
+ expect(page).not_to have_selector("dialog")
+ expect(page.current_url).to include(query)
+ end
+
+ context "with valid data" do
+ it "successfully creates a new shipping category, keeping page and q params" do
+ fill_in "Name", with: "Whatever"
+
+ click_on "Add Shipping Category"
+
+ expect(page).to have_content("Shipping category was successfully created.")
+ expect(Spree::ShippingCategory.find_by(name: "Whatever")).to be_present
+ expect(page.current_url).to include(query)
+ end
+ end
+
+ context "with invalid data" do
+ it "fails to create a new shipping category, keeping page and q params" do
+ click_on "Add Shipping Category"
+
+ expect(page).to have_content "can't be blank"
+ expect(page.current_url).to include(query)
+ end
+ end
+ end
end
diff --git a/core/app/models/spree/shipping_category.rb b/core/app/models/spree/shipping_category.rb
index eca822d9554..8d5da64979f 100644
--- a/core/app/models/spree/shipping_category.rb
+++ b/core/app/models/spree/shipping_category.rb
@@ -2,6 +2,8 @@
module Spree
class ShippingCategory < Spree::Base
+ self.allowed_ransackable_attributes = %w[name]
+
validates :name, presence: true
has_many :products, inverse_of: :shipping_category
has_many :shipping_method_categories, inverse_of: :shipping_category