From 5de48788b6c4f392d85e31be7ce8c7512ea36d9c Mon Sep 17 00:00:00 2001 From: Madeline Collier Date: Fri, 11 Oct 2024 17:02:58 +0200 Subject: [PATCH] Handle states_required? in admin address component Previously, this component would just disable the state_id field when the selected country did not require states, but this meant that the user would never be able to self-fill the state_name field, which is something that some stores can require with the `Spree::Config[:address_requires_state]` preference. The component now takes this into account and will swap between a state_id dropdown select field, or a blank state_name text input depending on the country the user has selected. This brings this new admin component up to par with the previous backend address forms. --- .../ui/forms/address/component.html.erb | 36 +++++++++---- .../ui/forms/address/component.js | 51 ++++++++++++++----- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/admin/app/components/solidus_admin/ui/forms/address/component.html.erb b/admin/app/components/solidus_admin/ui/forms/address/component.html.erb index 3567418ffb1..0dd61697425 100644 --- a/admin/app/components/solidus_admin/ui/forms/address/component.html.erb +++ b/admin/app/components/solidus_admin/ui/forms/address/component.html.erb @@ -21,15 +21,33 @@ "data-action": "change->#{stimulus_id}#loadStates" ) %> - <%= render component("ui/forms/field").select( - @name, - :state_id, - state_options, - object: @address, - value: @address.try(:state_id), - disabled: @address.country&.states&.empty?, - "data-#{stimulus_id}-target": "state" - ) %> + <%= content_tag(:div, + data: { "#{stimulus_id}-target": "stateNameWrapper" }, + class: (@address.country&.states&.empty? ? "flex flex-col gap-2 w-full" : "hidden flex flex-col gap-2 w-full") + ) do %> + <%= render component("ui/forms/field").text_field( + @name, + :state_name, + object: @address, + value: @address.try(:state_name), + "data-#{stimulus_id}-target": "stateName" + ) %> + <% end %> + > + + <%= content_tag(:div, + data: { "#{stimulus_id}-target": "stateWrapper" }, + class: (@address.country&.states&.empty? ? "hidden flex flex-col gap-2 w-full" : "flex flex-col gap-2 w-full") + ) do %> + <%= render component("ui/forms/field").select( + @name, + :state_id, + state_options, + object: @address, + value: @address.try(:state_id), + "data-#{stimulus_id}-target": "state" + ) %> + <% end %> <%= render component("ui/forms/field").text_field(@name, :phone, object: @address) %> diff --git a/admin/app/components/solidus_admin/ui/forms/address/component.js b/admin/app/components/solidus_admin/ui/forms/address/component.js index 1b255ee39a4..c39c7cd161b 100644 --- a/admin/app/components/solidus_admin/ui/forms/address/component.js +++ b/admin/app/components/solidus_admin/ui/forms/address/component.js @@ -1,7 +1,7 @@ import { Controller } from '@hotwired/stimulus' export default class extends Controller { - static targets = ["country", "state"] + static targets = ["country", "state", "stateName", "stateWrapper", "stateNameWrapper"] loadStates() { const countryId = this.countryTarget.value @@ -13,22 +13,47 @@ export default class extends Controller { }) } - updateStateOptions(data) { + updateStateOptions(states) { + if (states.length === 0) { + // Show state name text input if no states to choose from. + this.toggleStateFields(false) + } else { + // Show state select dropdown. + this.toggleStateFields(true) + this.populateStateSelect(states) + } + } + + toggleStateFields(showSelect) { + const stateWrapper = this.stateWrapperTarget + const stateNameWrapper = this.stateNameWrapperTarget const stateSelect = this.stateTarget + const stateName = this.stateNameTarget - stateSelect.innerHTML = "" - if (data.length === 0) { - stateSelect.disabled = true - } else { + if (showSelect) { + // Show state select dropdown. stateSelect.disabled = false - - data.forEach((state) => { - const option = document.createElement("option") - option.value = state.id - option.innerText = state.name - stateSelect.appendChild(option) - }) + stateName.value = "" + stateWrapper.classList.remove('hidden') + stateNameWrapper.classList.add('hidden') + } else { + // Show state name text input if no states to choose from. + stateSelect.disabled = true + stateWrapper.classList.add("hidden") + stateNameWrapper.classList.remove("hidden") } } + + populateStateSelect(states) { + const stateSelect = this.stateTarget + stateSelect.innerHTML = "" + + states.forEach((state) => { + const option = document.createElement("option") + option.value = state.id + option.innerText = state.name + stateSelect.appendChild(option) + }) + } }