Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added fields to store for organisation structured data for SEO #6113

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<fieldset class="<%= stimulus_id %>"
data-controller="<%= stimulus_id %>"
>
<div class="<%= stimulus_id %>--address-form flex flex-wrap gap-4 pb-4">
<%= render component("ui/forms/field").text_field(@name, :legal_name, object: @store) %>
<%= render component("ui/forms/field").text_field(@name, :address1, object: @store) %>
<%= render component("ui/forms/field").text_field(@name, :address2, object: @store) %>
<div class="flex gap-4 w-full">
<%= render component("ui/forms/field").text_field(@name, :city, object: @store) %>
<%= render component("ui/forms/field").text_field(@name, :zipcode, object: @store) %>
</div>

<%= render component("ui/forms/field").select(
@name,
:country_id,
Spree::Country.pluck(:name, :id),
object: @store,
value: @store.country_id,
"data-#{stimulus_id}-target": "country",
"data-action": "change->#{stimulus_id}#loadStates"
) %>

<%= content_tag :div,
class: "flex flex-col gap-2 w-full #{'hidden' unless @store.country&.states_required}",
data: { "#{stimulus_id}-target": "stateNameWrapper" } do %>
<%= render component("ui/forms/field").text_field(
@name, :state_name,
object: @store,
value: @store.state_name,
data: { "#{stimulus_id}-target": "stateName" }
) %>
<% end %>

<input autocomplete="off" type="hidden" name=<%= "#{@name}[state_id]" %>>

<%= content_tag :div,
class: "flex flex-col gap-2 w-full #{'hidden' if @store.country&.states_required}",
data: { "#{stimulus_id}-target": "stateWrapper" } do %>
<%= render component("ui/forms/field").select(
@name, :state_id,
state_options,
object: @store,
value: @store.state_id,
data: { "#{stimulus_id}-target": "state" }
) %>
<% end %>

<%= render component("ui/forms/field").text_field(@name, :contact_phone, object: @store) %>
</div>
</fieldset>
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["country", "state", "stateName", "stateWrapper", "stateNameWrapper"]

loadStates() {
const countryId = this.countryTarget.value

fetch(`/admin/countries/${countryId}/states`)
.then((response) => response.json())
.then((data) => {
this.updateStateOptions(data)
})
}

updateStateOptions(states) {
if (states.length === 0) {
this.toggleStateFields(false)
} else {
this.toggleStateFields(true)
this.populateStateSelect(states)
}
}

toggleStateFields(showSelect) {
const stateWrapper = this.stateWrapperTarget
const stateNameWrapper = this.stateNameWrapperTarget
const stateSelect = this.stateTarget
const stateName = this.stateNameTarget

if (showSelect) {
// Show state select dropdown.
stateSelect.disabled = false
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)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class SolidusAdmin::Stores::AddressForm::Component < SolidusAdmin::BaseComponent
def initialize(store:)
@name = "store"
@store = store
end

def state_options
country = @store.country
return [] unless country && country.states_required

country.states.pluck(:name, :id)
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<%= page do %>
<%= page_header do %>
<%= page_header_back(solidus_admin.stores_path) %>
<%= page_header_title(t(".title", store: @store&.name)) %>
<% end %>

<%= form_for @store, url: solidus_admin.store_path(@store), html: { id: form_id } do |f| %>
<%= page_with_sidebar do %>
<%= page_with_sidebar_main do %>
<%= render component("ui/panel").new(title: t(".store_details")) do %>
<div class="flex flex-wrap gap-4 pb-4">
<%= render component("ui/forms/field").text_field(f, :name, required: true) %>
<%= render component("ui/forms/field").text_field(f, :code, required: true) %>
<%= render component("ui/forms/field").text_field(f, :seo_title) %>
<%= render component("ui/forms/field").text_field(f, :meta_keywords) %>
<%= render component("ui/forms/field").text_area(f, :meta_description) %>
<%= render component("ui/forms/field").text_field(f, :tax_id) %>
<%= render component("ui/forms/field").text_field(f, :vat_id) %>
<%= render component("ui/forms/field").text_field(f, :url, required: true) %>
<%= render component("ui/forms/field").text_field(f, :mail_from_address, required: true) %>
<%= render component("ui/forms/field").text_field(f, :bcc_email) %>
<%= render component("ui/forms/field").select(
f,
:default_currency,
currency_options,
include_blank: true
) %>
<%= render component("ui/forms/field").select(
f,
:cart_tax_country_iso,
cart_tax_country_options,
include_blank: t(".no_cart_tax_country")
) %>
<%= render component("ui/forms/field").select(
f,
:available_locales,
localization_options,
multiple: true,
class: "select2",
name: "store[available_locales][]"
) %>
</div>
<%= render component("ui/forms/field").text_area(f, :description) %>
<% end %>

<%= render component("ui/panel").new(title: t(".address")) do %>
<div class="js-addresses-form">
<%= render component("stores/address_form").new(
store: @store,
) %>
</div>
<% end %>
<% end %>
<% end %>
<% end %>

<%= page_footer do %>
<%= page_footer_actions do %>
<div class="py-1.5 text-center">
<%= render component("ui/button").new(tag: :button, text: t(".update"), form: form_id) %>
<%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.edit_store_path(@store), scheme: :secondary) %>
</div>
<% end %>
<% end %>
<% end %>
62 changes: 62 additions & 0 deletions admin/app/components/solidus_admin/stores/edit/component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

class SolidusAdmin::Stores::Edit::Component < SolidusAdmin::BaseComponent
include SolidusAdmin::Layout::PageHelpers

# Define the necessary attributes for the component
attr_reader :store, :available_countries

# Initialize the component with required data
def initialize(store:)
@store = store
@available_countries = fetch_available_countries
end

def form_id
@form_id ||= "#{stimulus_id}--form-#{@store.id}"
end

def currency_options
Spree::Config.available_currencies.map(&:iso_code)
end

# Generates options for cart tax countries
def cart_tax_country_options
fetch_available_countries(restrict_to_zone: Spree::Config[:checkout_zone]).map do |country|
[country.name, country.iso]
end
end

# Generates available locales
def localization_options
Spree.i18n_available_locales.map do |locale|
[
I18n.t('spree.i18n.this_file_language', locale: locale, default: locale.to_s),
locale
]
end
end

# Fetch countries for the address form
def available_country_options
Spree::Country.order(:name).map { |country| [country.name, country.id] }
end

private

# Fetch the available countries for the localization section
def fetch_available_countries(restrict_to_zone: Spree::Config[:checkout_zone])
countries = Spree::Country.available(restrict_to_zone:)

country_names = Carmen::Country.all.map do |country|
[country.code, country.name]
end.to_h

country_names.update I18n.t('spree.country_names', default: {}).stringify_keys

countries.collect do |country|
country.name = country_names.fetch(country.iso, country.name)
country
end.sort_by { |country| country.name.parameterize }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
en:
title: "%{store}"
store_details: Store Details
address: Address
update: Update
cancel: Cancel
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<%= page do %>
<%= page_header do %>
<%= page_header_back(solidus_admin.stores_path) %>
<%= page_header_title(t(".title")) %>
<% end %>

<%= form_for @store, url: solidus_admin.stores_path, html: { id: form_id } do |f| %>
<%= page_with_sidebar do %>
<%= page_with_sidebar_main do %>
<%= render component("ui/panel").new(title: t(".store_details")) do %>
<div class="flex flex-wrap gap-4 pb-4">
<%= render component("ui/forms/field").text_field(f, :name, required: true) %>
<%= render component("ui/forms/field").text_field(f, :code, required: true) %>
<%= render component("ui/forms/field").text_field(f, :seo_title) %>
<%= render component("ui/forms/field").text_field(f, :meta_keywords) %>
<%= render component("ui/forms/field").text_area(f, :meta_description) %>
<%= render component("ui/forms/field").text_field(f, :tax_id) %>
<%= render component("ui/forms/field").text_field(f, :vat_id) %>
<%= render component("ui/forms/field").text_field(f, :url, required: true) %>
<%= render component("ui/forms/field").text_field(f, :mail_from_address, required: true) %>
<%= render component("ui/forms/field").text_field(f, :bcc_email) %>
<%= render component("ui/forms/field").select(
f,
:default_currency,
currency_options,
include_blank: true
) %>
<%= render component("ui/forms/field").select(
f,
:cart_tax_country_iso,
cart_tax_country_options,
include_blank: t(".no_cart_tax_country")
) %>
<%= render component("ui/forms/field").select(
f,
:available_locales,
localization_options,
multiple: true,
class: "select2",
name: "store[available_locales][]"
) %>
</div>
<%= render component("ui/forms/field").text_area(f, :description) %>
<% end %>

<%= render component("ui/panel").new(title: t(".address")) do %>
<div class="js-addresses-form">
<%= render component("stores/address_form").new(
store: @store,
) %>
</div>
<% end %>
<% end %>
<% end %>
<% end %>

<%= page_footer do %>
<%= page_footer_actions do %>
<div class="py-1.5 text-center">
<%= render component("ui/button").new(tag: :button, text: t(".save"), form: form_id) %>
<%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.new_store_path, scheme: :secondary) %>
</div>
<% end %>
<% end %>
<% end %>
62 changes: 62 additions & 0 deletions admin/app/components/solidus_admin/stores/new/component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

class SolidusAdmin::Stores::New::Component < SolidusAdmin::BaseComponent
include SolidusAdmin::Layout::PageHelpers

# Define the necessary attributes for the component
attr_reader :store, :available_countries

# Initialize the component with required data
def initialize(store:)
@store = store
@available_countries = fetch_available_countries
end

def form_id
@form_id ||= "#{stimulus_id}--form-#{@store.id}"
end

def currency_options
Spree::Config.available_currencies.map(&:iso_code)
end

# Generates options for cart tax countries
def cart_tax_country_options
fetch_available_countries(restrict_to_zone: Spree::Config[:checkout_zone]).map do |country|
[country.name, country.iso]
end
end

# Generates available locales
def localization_options
Spree.i18n_available_locales.map do |locale|
[
I18n.t('spree.i18n.this_file_language', locale: locale, default: locale.to_s),
locale
]
end
end

# Fetch countries for the address form
def available_country_options
Spree::Country.order(:name).map { |country| [country.name, country.id] }
end

private

# Fetch the available countries for the localization section
def fetch_available_countries(restrict_to_zone: Spree::Config[:checkout_zone])
countries = Spree::Country.available(restrict_to_zone:)

country_names = Carmen::Country.all.map do |country|
[country.code, country.name]
end.to_h

country_names.update I18n.t('spree.country_names', default: {}).stringify_keys

countries.collect do |country|
country.name = country_names.fetch(country.iso, country.name)
country
end.sort_by { |country| country.name.parameterize }
end
end
6 changes: 6 additions & 0 deletions admin/app/components/solidus_admin/stores/new/component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
en:
title: "New Store"
save: Save
store_details: Store Details
address: Address
cancel: Cancel
Loading
Loading