spree_admin 5.5.3 → 5.6.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/vercel-deploy-button.svg +14 -0
  3. data/app/assets/tailwind/spree/admin/components/_alerts.css +5 -1
  4. data/app/assets/tailwind/spree/admin/components/_badges.css +1 -1
  5. data/app/assets/tailwind/spree/admin/components/_breadcrumbs.css +1 -1
  6. data/app/assets/tailwind/spree/admin/components/_buttons.css +1 -1
  7. data/app/assets/tailwind/spree/admin/components/_cards.css +1 -1
  8. data/app/assets/tailwind/spree/admin/components/_dialogs.css +3 -1
  9. data/app/assets/tailwind/spree/admin/components/_dropdowns.css +2 -2
  10. data/app/assets/tailwind/spree/admin/components/_filters.css +1 -1
  11. data/app/assets/tailwind/spree/admin/components/_forms.css +10 -6
  12. data/app/assets/tailwind/spree/admin/components/_layout.css +30 -23
  13. data/app/assets/tailwind/spree/admin/components/_rtl.css +53 -0
  14. data/app/assets/tailwind/spree/admin/components/_search-picker.css +2 -2
  15. data/app/assets/tailwind/spree/admin/components/_tables.css +1 -1
  16. data/app/assets/tailwind/spree/admin/index.css +1 -0
  17. data/app/assets/tailwind/spree/admin/plugins/_tom-select.css +6 -6
  18. data/app/assets/tailwind/spree/admin/plugins/_trix.css +1 -1
  19. data/app/assets/tailwind/spree/admin/plugins/_uppy.css +1 -1
  20. data/app/assets/tailwind/spree/admin/views/_page-builder.css +8 -5
  21. data/app/controllers/concerns/spree/admin/locale_concern.rb +76 -0
  22. data/app/controllers/spree/admin/base_controller.rb +38 -2
  23. data/app/controllers/spree/admin/countries_controller.rb +18 -4
  24. data/app/controllers/spree/admin/exports_controller.rb +7 -0
  25. data/app/controllers/spree/admin/imports_controller.rb +8 -0
  26. data/app/controllers/spree/admin/products_controller.rb +1 -0
  27. data/app/controllers/spree/admin/storefront_controller.rb +100 -0
  28. data/app/controllers/spree/admin/user_sessions_controller.rb +10 -0
  29. data/app/controllers/spree/admin/variants_controller.rb +3 -1
  30. data/app/helpers/spree/admin/base_helper.rb +10 -0
  31. data/app/helpers/spree/admin/channels_helper.rb +17 -0
  32. data/app/helpers/spree/admin/dropdown_helper.rb +14 -0
  33. data/app/helpers/spree/admin/navigation_helper.rb +1 -1
  34. data/app/helpers/spree/admin/onboarding_helper.rb +1 -1
  35. data/app/helpers/spree/admin/orders_helper.rb +9 -34
  36. data/app/helpers/spree/admin/products_helper.rb +1 -1
  37. data/app/helpers/spree/admin/rtl_helper.rb +15 -0
  38. data/app/helpers/spree/admin/shipment_helper.rb +1 -1
  39. data/app/helpers/spree/admin/storefront_helper.rb +46 -0
  40. data/app/helpers/spree/admin/stores_helper.rb +2 -1
  41. data/app/javascript/spree/admin/application.js +2 -0
  42. data/app/javascript/spree/admin/controllers/autocomplete_select_controller.js +4 -0
  43. data/app/javascript/spree/admin/controllers/calendar_range_controller.js +7 -3
  44. data/app/javascript/spree/admin/controllers/display_name_controller.js +18 -0
  45. data/app/javascript/spree/admin/controllers/query_builder_controller.js +39 -28
  46. data/app/javascript/spree/admin/controllers/variants_form_controller.js +49 -1
  47. data/app/javascript/spree/admin/helpers/display_names.js +54 -0
  48. data/app/models/spree/admin/table/column.rb +15 -1
  49. data/app/models/spree/admin/table/filter.rb +23 -16
  50. data/app/models/spree/admin/table/query_builder.rb +11 -2
  51. data/app/views/active_storage/_upload_form.html.erb +1 -1
  52. data/app/views/layouts/spree/admin.html.erb +1 -1
  53. data/app/views/layouts/spree/admin_settings.html.erb +1 -1
  54. data/app/views/layouts/spree/admin_wizard.html.erb +2 -2
  55. data/app/views/layouts/spree/minimal.html.erb +1 -1
  56. data/app/views/spree/admin/admin_users/_audit_log.html.erb +2 -2
  57. data/app/views/spree/admin/admin_users/new.html.erb +1 -1
  58. data/app/views/spree/admin/assets/edit.html.erb +1 -1
  59. data/app/views/spree/admin/channels/_form.html.erb +10 -0
  60. data/app/views/spree/admin/dashboard/_setup_progress.html.erb +4 -4
  61. data/app/views/spree/admin/dashboard/_setup_tasks.html.erb +5 -4
  62. data/app/views/spree/admin/dashboard/_updater.html.erb +4 -4
  63. data/app/views/spree/admin/dashboard/_visits.html.erb +12 -12
  64. data/app/views/spree/admin/dashboard/analytics.html.erb +5 -5
  65. data/app/views/spree/admin/dashboard/setup_tasks/_add_products.html.erb +4 -4
  66. data/app/views/spree/admin/dashboard/setup_tasks/_set_customer_support_email.html.erb +3 -4
  67. data/app/views/spree/admin/dashboard/setup_tasks/_setup_storefront.html.erb +18 -0
  68. data/app/views/spree/admin/gift_card_batches/_form.html.erb +1 -1
  69. data/app/views/spree/admin/import_rows/show.html.erb +2 -2
  70. data/app/views/spree/admin/imports/_footer.html.erb +1 -1
  71. data/app/views/spree/admin/imports/_mapping_form.html.erb +1 -1
  72. data/app/views/spree/admin/imports/show.html.erb +3 -3
  73. data/app/views/spree/admin/integrations/_integration.html.erb +1 -1
  74. data/app/views/spree/admin/integrations/index.html.erb +2 -4
  75. data/app/views/spree/admin/invitations/_invitation.html.erb +1 -1
  76. data/app/views/spree/admin/invitations/new.html.erb +1 -1
  77. data/app/views/spree/admin/invitations/show.html.erb +1 -1
  78. data/app/views/spree/admin/line_items/new.html.erb +1 -1
  79. data/app/views/spree/admin/markets/_form.html.erb +8 -6
  80. data/app/views/spree/admin/metafields/edit.html.erb +1 -1
  81. data/app/views/spree/admin/option_types/_form.html.erb +9 -6
  82. data/app/views/spree/admin/option_types/index.html.erb +2 -3
  83. data/app/views/spree/admin/orders/_customer.html.erb +1 -1
  84. data/app/views/spree/admin/orders/_customer_summary.html.erb +1 -1
  85. data/app/views/spree/admin/orders/_payments.html.erb +1 -1
  86. data/app/views/spree/admin/orders/_shipment.html.erb +7 -2
  87. data/app/views/spree/admin/orders/_shipments.html.erb +1 -1
  88. data/app/views/spree/admin/orders/_user_overview.html.erb +9 -6
  89. data/app/views/spree/admin/orders/return_authorizations/edit.html.erb +1 -1
  90. data/app/views/spree/admin/payment_methods/_form.html.erb +1 -1
  91. data/app/views/spree/admin/payment_methods/index.html.erb +2 -2
  92. data/app/views/spree/admin/payments/_payment.html.erb +1 -1
  93. data/app/views/spree/admin/price_lists/index.html.erb +2 -2
  94. data/app/views/spree/admin/products/form/_inventory.html.erb +19 -0
  95. data/app/views/spree/admin/products/form/_publishing.html.erb +2 -3
  96. data/app/views/spree/admin/products/index.html.erb +1 -2
  97. data/app/views/spree/admin/profile/edit.html.erb +3 -0
  98. data/app/views/spree/admin/promotion_rules/forms/_channel.html.erb +7 -0
  99. data/app/views/spree/admin/promotion_rules/forms/_country.html.erb +1 -1
  100. data/app/views/spree/admin/promotion_rules/forms/_item_total.html.erb +1 -1
  101. data/app/views/spree/admin/promotion_rules/forms/_market.html.erb +7 -0
  102. data/app/views/spree/admin/promotions/_form.html.erb +2 -2
  103. data/app/views/spree/admin/promotions/_sidebar.html.erb +1 -1
  104. data/app/views/spree/admin/promotions/edit.html.erb +2 -2
  105. data/app/views/spree/admin/promotions/form/_kind.html.erb +11 -11
  106. data/app/views/spree/admin/promotions/form/_settings.html.erb +4 -5
  107. data/app/views/spree/admin/reports/new.html.erb +2 -2
  108. data/app/views/spree/admin/shared/_address.html.erb +1 -1
  109. data/app/views/spree/admin/shared/_analytics_loader_skeleton.html.erb +5 -5
  110. data/app/views/spree/admin/shared/_calendar_range_picker.html.erb +11 -1
  111. data/app/views/spree/admin/shared/_content_header.html.erb +2 -2
  112. data/app/views/spree/admin/shared/_edit_resource_links.html.erb +1 -1
  113. data/app/views/spree/admin/shared/_filters_search_bar.html.erb +1 -1
  114. data/app/views/spree/admin/shared/_growth_rate_badge.html.erb +1 -1
  115. data/app/views/spree/admin/shared/_head.html.erb +4 -1
  116. data/app/views/spree/admin/shared/_index_table_options.html.erb +2 -2
  117. data/app/views/spree/admin/shared/_media_asset.html.erb +1 -1
  118. data/app/views/spree/admin/shared/_media_form.html.erb +1 -1
  119. data/app/views/spree/admin/shared/_seo.html.erb +1 -1
  120. data/app/views/spree/admin/shared/_sidebar.html.erb +1 -1
  121. data/app/views/spree/admin/shared/sidebar/_enterprise_edition_notice.html.erb +2 -2
  122. data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +1 -1
  123. data/app/views/spree/admin/shipping_methods/form/_display.html.erb +2 -2
  124. data/app/views/spree/admin/shipping_methods/form/_estimated_transit_business_days.html.erb +1 -2
  125. data/app/views/spree/admin/shipping_methods/form/_tracking_url.html.erb +1 -1
  126. data/app/views/spree/admin/shipping_methods/form/_zones.html.erb +1 -1
  127. data/app/views/spree/admin/shipping_methods/index.html.erb +1 -1
  128. data/app/views/spree/admin/storefront/show.html.erb +150 -0
  129. data/app/views/spree/admin/stores/form/_basic.html.erb +2 -2
  130. data/app/views/spree/admin/stores/form/_checkout.html.erb +4 -0
  131. data/app/views/spree/admin/stores/form/_emails.html.erb +4 -6
  132. data/app/views/spree/admin/tables/_table.html.erb +3 -2
  133. data/app/views/spree/admin/taxons/_form.html.erb +2 -2
  134. data/app/views/spree/admin/user_sessions/new.html.erb +11 -2
  135. data/app/views/spree/admin/users/_tabs.html.erb +1 -1
  136. data/app/views/spree/admin/variants/_search_result.html.erb +1 -1
  137. data/app/views/spree/admin/variants/_variant.html.erb +1 -1
  138. data/app/views/spree/admin/variants/form/_inventory.html.erb +17 -0
  139. data/app/views/spree/admin/webhook_endpoints/_form.html.erb +2 -2
  140. data/app/views/spree/admin/zones/index.html.erb +1 -1
  141. data/config/i18n-tasks.yml +3 -0
  142. data/config/initializers/spree_admin_navigation.rb +9 -0
  143. data/config/initializers/spree_admin_tables.rb +20 -18
  144. data/config/locales/en.yml +647 -0
  145. data/config/routes.rb +5 -0
  146. metadata +18 -6
@@ -5,7 +5,7 @@
5
5
  </h5>
6
6
  </div>
7
7
  <div class="card-body">
8
- <%= f.spree_text_field :name, required: true, autofocus: true, help: 'Customers will see this in their cart and at checkout.' %>
8
+ <%= f.spree_text_field :name, required: true, autofocus: true, help: Spree.t('admin.promotions.name_help') %>
9
9
  </div>
10
10
  </div>
11
11
 
@@ -32,5 +32,5 @@
32
32
  </div>
33
33
 
34
34
  <p class="alert alert-info text-center">
35
- In the next step you will be able to add actions and rules to your promotion
35
+ <%= Spree.t('admin.promotions.next_step_info') %>
36
36
  </p>
@@ -18,7 +18,7 @@
18
18
  <%= Spree.t(:used) %>: <%= used_coupon_codes_count %> / <%= coupon_codes_count %>
19
19
  </span>
20
20
  <span class="badge badge-light">
21
- Remaining: <%= coupon_codes_count - used_coupon_codes_count %>
21
+ <%= Spree.t(:remaining) %>: <%= coupon_codes_count - used_coupon_codes_count %>
22
22
  </span>
23
23
  </div>
24
24
  </div>
@@ -15,14 +15,14 @@
15
15
  <%= f.text_field :name, class: 'form-input', required: true, autofocus: true %>
16
16
  <%= f.error_message_on :name %>
17
17
  <span class="form-text mt-2">
18
- Customers will see this in their cart and at checkout.
18
+ <%= Spree.t('admin.promotions.name_help') %>
19
19
  </span>
20
20
  </div>
21
21
 
22
22
  <% if @promotion.coupon_code? && !@promotion.multi_codes? %>
23
23
  <div class="form-group">
24
24
  <%= f.label :code %>
25
- <%= f.text_field :code, class: 'form-input uppercase', placeholder: 'Your coupon code' %>
25
+ <%= f.text_field :code, class: 'form-input uppercase', placeholder: Spree.t('admin.promotions.coupon_code_placeholder') %>
26
26
  </div>
27
27
  <% end %>
28
28
  </div>
@@ -8,40 +8,40 @@
8
8
  <div class="custom-control custom-radio">
9
9
  <%= f.radio_button :multi_codes, false, data: { action: 'change->reveal#toggle' }, class: 'custom-control-input' %>
10
10
  <%= f.label :multi_codes_false, class: 'custom-control-label flex-col items-start' do %>
11
- One code for all customers
11
+ <%= Spree.t('admin.promotions.kind.one_code_label') %>
12
12
  <span class="form-text font-normal">
13
- You can limit the number of times this code can be used.
13
+ <%= Spree.t('admin.promotions.kind.one_code_help') %>
14
14
  </span>
15
15
  <% end %>
16
16
  </div>
17
17
  <div data-reveal-target="item" class="mt-2 ml-6 <% if @promotion.multi_codes? %>hidden<% end %>">
18
- <%= f.text_field :code, class: 'form-input uppercase', placeholder: 'Your coupon code' %>
18
+ <%= f.text_field :code, class: 'form-input uppercase', placeholder: Spree.t('admin.promotions.coupon_code_placeholder') %>
19
19
  </div>
20
20
 
21
21
  <div class="mt-6 custom-control custom-radio">
22
22
  <%= f.radio_button :multi_codes, true, data: { action: 'change->reveal#toggle' }, class: 'custom-control-input' %>
23
23
  <%= f.label :multi_codes_true, class: 'custom-control-label flex-col items-start' do %>
24
- Generate unique codes
24
+ <%= Spree.t('admin.promotions.kind.multi_codes_label') %>
25
25
  <span class="form-text font-normal">
26
- These codes are generated automatically and can be downloaded as a CSV file. Codes are unique and can only be used once.
26
+ <%= Spree.t('admin.promotions.kind.multi_codes_help') %>
27
27
  </span>
28
28
  <% end %>
29
29
  </div>
30
30
  <div data-reveal-target="item" class="ml-6 mt-2 grid gap-3 <% unless @promotion.multi_codes? %>hidden<% end %>">
31
31
  <div>
32
- <%= f.text_field :code_prefix, class: 'form-input uppercase', placeholder: 'Coupon Prefix (optional)' %>
32
+ <%= f.text_field :code_prefix, class: 'form-input uppercase', placeholder: Spree.t('admin.promotions.code_prefix_placeholder') %>
33
33
  <span class="form-text mt-1">
34
- eg. <strong>ABC</strong>
34
+ <%= Spree.t('admin.promotions.code_prefix_example_html', example: tag.strong('ABC')) %>
35
35
  </span>
36
36
  </div>
37
37
  <div>
38
38
  <% minimum_number_of_codes = @promotion.persisted? && @promotion.coupon_codes.count.positive? ? @promotion.coupon_codes.count : 1 %>
39
39
  <% maximum_number_of_codes = ENV.fetch('PROMOTION_MAX_NUMBER_OF_CODES', 5000) %>
40
- <%= f.number_field :number_of_codes, class: 'form-input', placeholder: 'Number of codes', min: minimum_number_of_codes, max: maximum_number_of_codes, step: 1 %>
40
+ <%= f.number_field :number_of_codes, class: 'form-input', placeholder: Spree.t('admin.promotions.number_of_codes_placeholder'), min: minimum_number_of_codes, max: maximum_number_of_codes, step: 1 %>
41
41
  <span class="form-text mt-1">
42
- How many codes you want to generate.
42
+ <%= Spree.t('admin.promotions.number_of_codes_help') %>
43
43
  <% if @promotion.persisted? %>
44
- To add more codes just increase this number
44
+ <%= Spree.t('admin.promotions.add_more_codes_help') %>
45
45
  <% end %>
46
46
  </span>
47
47
  </div>
@@ -55,7 +55,7 @@
55
55
  <%= f.label :kind_automatic, Spree.t(:automatic_promotion), class: 'custom-control-label flex-col items-start' do %>
56
56
  <%= Spree.t(:automatic_promotion) %>
57
57
  <span class="form-text font-normal">
58
- This promotion will be automatically applied to all eligible orders.
58
+ <%= Spree.t('admin.promotions.kind.automatic_help') %>
59
59
  </span>
60
60
  <% end %>
61
61
 
@@ -1,18 +1,17 @@
1
1
  <% unless @promotion.multi_codes? %>
2
- <%= f.spree_number_field :usage_limit, min: 0, step: 1, help: 'Leave this field blank for unlimited usage.' %>
2
+ <%= f.spree_number_field :usage_limit, min: 0, step: 1, help: Spree.t('admin.promotions.usage_limit_help') %>
3
3
  <% end %>
4
4
 
5
5
  <%# datetime-local inputs have no timezone; render values in the store's timezone so admins see and submit values in the store's local time. %>
6
6
  <%
7
- store_timezone = ActiveSupport::TimeZone[current_store.preferred_timezone] || Time.zone
8
- to_store_local = ->(value) { value&.in_time_zone(store_timezone)&.strftime('%Y-%m-%dT%H:%M') }
7
+ to_store_local = ->(value) { value&.in_time_zone(current_timezone)&.strftime('%Y-%m-%dT%H:%M') }
9
8
  starts_at_local = to_store_local.call(@promotion.starts_at)
10
9
  expires_at_local = to_store_local.call(@promotion.expires_at)
11
- tz_help = Spree.t('admin.datetime_field_timezone_help', zone: store_timezone.name)
10
+ tz_help = Spree.t('admin.datetime_field_timezone_help', zone: current_timezone.name)
12
11
  %>
13
12
 
14
13
  <%= f.spree_datetime_field :starts_at, value: starts_at_local, help: tz_help %>
15
14
 
16
15
  <%= f.spree_datetime_field :expires_at,
17
16
  value: expires_at_local,
18
- help: "Leave this field blank for no expiration. #{tz_help}" %>
17
+ help: Spree.t('admin.promotions.expires_at_help', zone: current_timezone.name) %>
@@ -28,8 +28,8 @@
28
28
 
29
29
  <div class="flex gap-2">
30
30
  <%= render 'spree/admin/shared/calendar_range_picker',
31
- date_from_value: params[:date_from] || 1.month.ago.in_time_zone(current_store.preferred_timezone).beginning_of_day,
32
- date_to_value: params[:date_to] || Time.current.in_time_zone(current_store.preferred_timezone).end_of_day %>
31
+ date_from_value: params[:date_from] || 1.month.ago.in_time_zone(current_timezone).beginning_of_day,
32
+ date_to_value: params[:date_to] || Time.current.in_time_zone(current_timezone).end_of_day %>
33
33
 
34
34
  <div class="form-group">
35
35
  <%= select_tag :currency,
@@ -23,7 +23,7 @@
23
23
  <span class="locality"><%= address.city %></span>
24
24
  <span class="region"><%= address.state_text %></span>
25
25
  <span class="postal-code"><%= address.zipcode %></span>
26
- <div class="country-name"><%= address.country.try(:name) %></div>
26
+ <div class="country-name"><%= localized_country_name(address.country) if address.country %></div>
27
27
  </div>
28
28
  </div>
29
29
  <% unless address.phone.blank? %>
@@ -4,7 +4,7 @@
4
4
  <div class="col-span-6 lg:col-span-4 gap-2">
5
5
  <div class="analytics-card-tab active" style="min-height: 82px;">
6
6
  <div class="flex justify-center flex-col mb-6 lg:mb-0">
7
- <span class="text-sm text-gray-600">Total Sales</span>
7
+ <span class="text-sm text-gray-600"><%= Spree.t(:total_sales) %></span>
8
8
  <span class="text-lg text-gray-900 font-bold mt-1">
9
9
  <%= @sales_total %>
10
10
  </span>
@@ -18,7 +18,7 @@
18
18
  <div class="col-span-6 lg:col-span-2">
19
19
  <div class="analytics-card-tab" >
20
20
  <div class="flex justify-center flex-col mb-6 lg:mb-0">
21
- <span class="text-sm text-gray-600">Avg. Order Value</span>
21
+ <span class="text-sm text-gray-600"><%= Spree.t('admin.avg_order_value') %></span>
22
22
  <span class="text-lg text-gray-900 font-bold mt-1 mr-3"><%= @orders_average %></span>
23
23
  <div>
24
24
  <%= render 'spree/admin/shared/growth_rate_badge', growth_rate: 0 %>
@@ -30,7 +30,7 @@
30
30
  <div class="col-span-6 lg:col-span-2">
31
31
  <div class="analytics-card-tab" >
32
32
  <div class="flex justify-center flex-col mb-6 lg:mb-0">
33
- <span class="text-sm text-gray-600">Total Orders</span>
33
+ <span class="text-sm text-gray-600"><%= Spree.t('admin.total_orders') %></span>
34
34
  <span class="text-lg text-gray-900 font-bold mt-1 mr-3"><%= @orders_total %></span>
35
35
  <div>
36
36
  <%= render 'spree/admin/shared/growth_rate_badge', growth_rate: 0 %>
@@ -42,7 +42,7 @@
42
42
  <div class="col-span-6 lg:col-span-2">
43
43
  <div class="analytics-card-tab" >
44
44
  <div class="flex justify-center flex-col">
45
- <span class="text-sm text-gray-600">Visits</span>
45
+ <span class="text-sm text-gray-600"><%= Spree.t(:visits) %></span>
46
46
  <span class="text-lg text-gray-900 font-bold mt-1 mr-3"><%= @visits_total %></span>
47
47
  <div>
48
48
  <%= render 'spree/admin/shared/growth_rate_badge', growth_rate: 0 %>
@@ -55,7 +55,7 @@
55
55
  <div class="col-span-6 lg:col-span-2">
56
56
  <div class="analytics-card-tab" >
57
57
  <div class="flex justify-center flex-col">
58
- <span class="text-sm text-gray-600">Sign-ups</span>
58
+ <span class="text-sm text-gray-600"><%= Spree.t('admin.sign_ups') %></span>
59
59
  <span class="text-lg text-gray-900 font-bold mt-1 mr-3"><%= @audience_total %></span>
60
60
  <div>
61
61
  <%= render 'spree/admin/shared/growth_rate_badge', growth_rate: 0 %>
@@ -7,7 +7,17 @@
7
7
 
8
8
  <% dropdown_direction ||= 'left' %>
9
9
 
10
- <%= dropdown direction: dropdown_direction, data: { controller: 'dropdown calendar-range', action: 'click->calendar-range#open' }, class: 'h-full', portal: false do %>
10
+ <%# Labels MUST match the order of presets in the easepick preset-plugin (today, yesterday, last 7, last 30, this month, last month) %>
11
+ <% preset_labels = [
12
+ Spree.t('date_range_presets.today'),
13
+ Spree.t('date_range_presets.yesterday'),
14
+ Spree.t('date_range_presets.last_7_days'),
15
+ Spree.t('date_range_presets.last_30_days'),
16
+ Spree.t('date_range_presets.this_month'),
17
+ Spree.t('date_range_presets.last_month')
18
+ ] %>
19
+
20
+ <%= dropdown direction: dropdown_direction, data: { controller: 'dropdown calendar-range', action: 'click->calendar-range#open', 'calendar-range-preset-labels-value': preset_labels.to_json }, class: 'h-full', portal: false do %>
11
21
  <%= dropdown_toggle class: css_classes do %>
12
22
  <%= icon('calendar') %>
13
23
  <div data-calendar-range-target="label">
@@ -13,7 +13,7 @@
13
13
  <h3 class="page-header-title mb-0 flex items-center gap-4" id="page_title">
14
14
  <%= yield :page_title %>
15
15
  </h3>
16
- <div id="page_actions" class="ml-auto page-actions flex items-center gap-2">
16
+ <div id="page_actions" class="ms-auto page-actions flex items-center gap-2">
17
17
  <%= yield :page_actions if content_for?(:page_actions) %>
18
18
 
19
19
  <% if action_name == 'edit' && @object %>
@@ -47,7 +47,7 @@
47
47
  <%= hidden_field_tag :record_number, record.number, data: { clipboard_target: 'source' } %>
48
48
  <button data-action="clipboard#copy" class="text-left dropdown-item" data-clipboard-target="button">
49
49
  <%= icon 'copy' %>
50
- <%= 'Copy number' %>
50
+ <%= Spree.t(:copy_number) %>
51
51
  </button>
52
52
  </div>
53
53
  <% end %>
@@ -3,6 +3,6 @@
3
3
  <div class="form-actions">
4
4
  <%= turbo_save_button_tag Spree.t('actions.update'), data: { admin_target: 'save' } %>
5
5
  <% if f.object.can_be_deleted? && can?(:delete, f.object) %>
6
- <%= link_to Spree.t('actions.destroy'), destroy_url, data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure_delete), turbo_frame: defined?(turbo_frame) ? turbo_frame : '_top' }, class: 'btn btn-danger ml-auto' %>
6
+ <%= link_to Spree.t('actions.destroy'), destroy_url, data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure_delete), turbo_frame: defined?(turbo_frame) ? turbo_frame : '_top' }, class: 'btn btn-danger ms-auto' %>
7
7
  <% end %>
8
8
  </div>
@@ -2,7 +2,7 @@
2
2
  <% badge_name ||= label %>
3
3
  <% placeholder ||= [Spree.t(:search), controller_name.humanize.downcase].join(' ') %>
4
4
 
5
- <div class="form-input flex items-center py-0 focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-blue-500 grow max-lg:max-w-[300px] mr-auto max-lg:mb-4 transition-all duration-100 ease-in-out" id="filters-search-bar">
5
+ <div class="form-input flex items-center py-0 focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-blue-500 grow max-lg:max-w-[300px] me-auto max-lg:mb-4 transition-all duration-100 ease-in-out" id="filters-search-bar">
6
6
  <%= icon "search", class: "mr-4 text-gray-600" %>
7
7
  <%= search_field_tag "q[#{param}]", params.dig(:q, param), class: "outline-none border-0 h-full focus:border-0 focus:ring-0 p-0 text-base w-full", placeholder: placeholder, data: { filters_target: :input, badge_name: badge_name } %>
8
8
  </div>
@@ -2,7 +2,7 @@
2
2
 
3
3
  <div class="flex">
4
4
  <% if growth_rate == 0 %>
5
- <svg viewBox="0 0 11 16" height="16" width="11" role="img" class="_SVG_1ou8g_150" tabindex="-1"><title>No change</title><path d="M0.519531 1.79395H12.0039V0.249023H0.519531V1.79395Z" fill="var(--p-icon-subdued, #8c9196)" transform="translate(0, 7)"></path></svg>
5
+ <svg viewBox="0 0 11 16" height="16" width="11" role="img" class="_SVG_1ou8g_150" tabindex="-1"><title><%= Spree.t('admin.no_change') %></title><path d="M0.519531 1.79395H12.0039V0.249023H0.519531V1.79395Z" fill="var(--p-icon-subdued, #8c9196)" transform="translate(0, 7)"></path></svg>
6
6
  <% elsif growth_rate > 0 %>
7
7
  <span class="text-green-700">
8
8
  <%= icon 'arrow-up', class: 'mr-1 text-base' %>
@@ -12,7 +12,7 @@
12
12
  <% if @order.present? && @order.persisted? %><%= @order.number %> - <% end %>
13
13
  <%= Spree.t(controller_name, default: controller_name.titleize) %>
14
14
  <% end %>
15
- <% if defined?(current_store) && current_store.present? %>
15
+ <% if defined?(current_store) && current_store&.name.present? %>
16
16
  - <%= current_store.name.capitalize %>
17
17
  <% end %>
18
18
  </title>
@@ -20,6 +20,9 @@
20
20
  <link rel="preconnect" href="https://fonts.googleapis.com">
21
21
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
22
22
  <link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&family=Geist:wght@100..900&display=swap" rel="stylesheet">
23
+ <% if rtl_locale? %>
24
+ <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet">
25
+ <% end %>
23
26
 
24
27
  <%= stylesheet_link_tag 'spree/admin/application', media: :all, data: { turbo_track: "reload" } %>
25
28
  <%= tinymce_assets %>
@@ -12,7 +12,7 @@
12
12
  <%= link_to icon('chevron-left', class: 'text-gray-900 mr-0'),
13
13
  url_for(request.query_parameters.merge(page: @pagy.previous)),
14
14
  class: "btn btn-light p-2",
15
- 'aria-label': 'Previous page' %>
15
+ 'aria-label': Spree.t('admin.previous_page') %>
16
16
  <% else %>
17
17
  <button class="btn btn-light p-2 cursor-not-allowed opacity-50" disabled>
18
18
  <%= icon('chevron-left', class: 'text-gray-900 mr-0') %>
@@ -23,7 +23,7 @@
23
23
  <%= link_to icon('chevron-right', class: 'text-gray-900 mr-0'),
24
24
  url_for(request.query_parameters.merge(page: @pagy.next)),
25
25
  class: "btn btn-light p-2",
26
- 'aria-label': 'Next page' %>
26
+ 'aria-label': Spree.t('admin.next_page') %>
27
27
  <% else %>
28
28
  <button class="btn btn-light p-2 cursor-not-allowed opacity-50" disabled>
29
29
  <%= icon('chevron-right', class: 'text-gray-900 mr-0') %>
@@ -3,7 +3,7 @@
3
3
  <%= check_box_tag "ids[]", asset.id, false, class: "custom-control-input", id: "#{asset.id}-checkbox", data: { media_form_target: "checkbox", action: 'media-form#showDeleteButton' } %>
4
4
  <label class="custom-control-label" for="<%= asset.id %>-checkbox"><span></span></label>
5
5
  </div>
6
- <div class="move-handle text-center hidden ml-auto">
6
+ <div class="move-handle text-center hidden ms-auto">
7
7
  <button class="btn btn-light btn-sm px-1"><%= icon('grip-vertical', class: 'mr-0') %></button>
8
8
  </div>
9
9
 
@@ -1,7 +1,7 @@
1
1
  <%= turbo_frame_tag 'media-form', class: 'card mb-6', data: { controller: 'media-form', media_form_delete_url_value: spree.bulk_destroy_admin_assets_path(viewable_id: viewable&.id) } do %>
2
2
  <div class="card-header">
3
3
  <h5 class="card-title mr-2"><%= Spree.t(:media) %></h5>
4
- <button type="button" data-media-form-target="deleteButton" class="btn btn-sm btn-danger btn-outline hidden ml-auto" data-action="media-form#deleteSelected">
4
+ <button type="button" data-media-form-target="deleteButton" class="btn btn-sm btn-danger btn-outline hidden ms-auto" data-action="media-form#deleteSelected">
5
5
  <%= icon('trash') %>
6
6
  <%= Spree.t(:delete_selected) %>
7
7
  </button>
@@ -1,7 +1,7 @@
1
1
  <div class="card mb-6 seo-form">
2
2
  <div class="card-header flex justify-between">
3
3
  <h5 class="card-title"><%= Spree.t(:search_engine_listing) %></h5>
4
- <button class="btn btn-light btn-sm ml-auto" data-action="click->seo-form#toggleInputs" type="button">Edit</button>
4
+ <button class="btn btn-light btn-sm ms-auto" data-action="click->seo-form#toggleInputs" type="button"><%= Spree.t('actions.edit') %></button>
5
5
  </div>
6
6
  <div class="card-body flex flex-col">
7
7
  <div class="seo__preview <% if title.blank? && description.blank? %>hidden<% else %>flex flex-col<% end %>" data-seo-form-target="preview">
@@ -33,7 +33,7 @@
33
33
  <%= render 'spree/admin/shared/sidebar/store_dropdown' %>
34
34
  <% end %>
35
35
  <% end %>
36
- <button type="button" class="btn btn-sm ml-auto" data-action="click->sidebar#closeMobile" aria-label="<%= Spree.t('admin.close_sidebar') %>">
36
+ <button type="button" class="btn btn-sm ms-auto" data-action="click->sidebar#closeMobile" aria-label="<%= Spree.t('admin.close_sidebar') %>">
37
37
  <%= icon('x') %>
38
38
  </button>
39
39
  </div>
@@ -3,9 +3,9 @@
3
3
  <section class="hidden lg:block">
4
4
  <div id="enterprise-edition-notice">
5
5
  <%= link_to '', spree.admin_dismiss_enterprise_edition_notice_path, data: { turbo_method: :patch }, class: 'btn-close' %>
6
- <p>Thank you for using Spree Community Edition! Please consider upgrading to Enterprise Edition for access to all features and support.</p>
6
+ <p><%= Spree.t('admin.enterprise_edition_notice.body') %></p>
7
7
 
8
- <%= external_link_to 'Upgrade', 'https://spreecommerce.org/pricing', target: '_blank', class: 'btn btn-secondary btn-sm shadow-xs' %>
8
+ <%= external_link_to Spree.t('admin.enterprise_edition_notice.upgrade'), 'https://spreecommerce.org/pricing', target: '_blank', class: 'btn btn-secondary btn-sm shadow-xs' %>
9
9
  </div>
10
10
  </section>
11
11
  <% end %>
@@ -20,7 +20,7 @@
20
20
  </div>
21
21
  </div>
22
22
 
23
- <div class="overflow-hidden text-gray-600 text-sm ml-auto">
23
+ <div class="overflow-hidden text-gray-600 text-sm ms-auto">
24
24
  <% if taxon.classification_count.positive? %>
25
25
  <%= pluralize(taxon.classification_count, Spree.t(:product)) %>
26
26
  <% end %>
@@ -1,9 +1,9 @@
1
1
  <div class="card mb-6">
2
2
  <div class="card-body pb-0">
3
3
  <div class="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-3">
4
- <%= f.spree_text_field :name, required: true, autofocus: f.object.new_record?, help: 'This will be displayed to customers' %>
4
+ <%= f.spree_text_field :name, required: true, autofocus: f.object.new_record?, help: Spree.t('admin.shipping_methods.name_help') %>
5
5
  <%= f.spree_select :display_on, display_on_options, { label: Spree.t(:display_on) }, { required: true } %>
6
- <%= f.spree_text_field :admin_name, label: Spree.t(:internal_name), help: 'This will be displayed to admins' %>
6
+ <%= f.spree_text_field :admin_name, label: Spree.t(:internal_name), help: Spree.t('admin.shipping_methods.admin_name_help') %>
7
7
  <%= f.spree_text_field :code, label: Spree.t(:code)%>
8
8
  </div>
9
9
  </div>
@@ -6,8 +6,7 @@
6
6
  </div>
7
7
  <div class="card-body">
8
8
  <div class="alert alert-info">
9
- This is the estimated number of business days it will take for the package to arrive at the customer's address.
10
- It will be displayed on the checkout page.
9
+ <%= Spree.t('admin.shipping_methods.estimated_transit_business_days_help') %>
11
10
  </div>
12
11
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
13
12
  <%= f.spree_number_field :estimated_transit_business_days_min, size: 2, placeholder: Spree.t(:min), min: 1, label: Spree.t(:min) %>
@@ -12,7 +12,7 @@
12
12
 
13
13
  <p class="form-text small mt-2">
14
14
  <code>:tracking</code>
15
- <span>will be replaced with the tracking number.</span>
15
+ <span><%= Spree.t('admin.shipping_methods.tracking_url_token_help') %></span>
16
16
  </p>
17
17
  </div>
18
18
  </div>
@@ -4,7 +4,7 @@
4
4
  <%= Spree.t(:zones) %>
5
5
  </h5>
6
6
 
7
- <%= link_to_with_icon('adjustments', Spree.t('admin.manage_zones'), spree.admin_zones_path, class: 'btn btn-sm btn-light ml-auto') if can?(:manage, Spree::Zone) %>
7
+ <%= link_to_with_icon('adjustments', Spree.t('admin.manage_zones'), spree.admin_zones_path, class: 'btn btn-sm btn-light ms-auto') if can?(:manage, Spree::Zone) %>
8
8
  </div>
9
9
 
10
10
  <div class="card-body">
@@ -11,7 +11,7 @@
11
11
 
12
12
  <% content_for :page_alerts do %>
13
13
  <div class="alert alert-info">
14
- Shipping methods are options that the customer sees when they reach the checkout, they are the carriers and services used to send your products.
14
+ <%= Spree.t('admin.shipping_methods.checkout_info') %>
15
15
  </div>
16
16
  <% end %>
17
17
 
@@ -0,0 +1,150 @@
1
+ <div class="grid grid-cols-12 gap-6 pt-6">
2
+ <div class="col-span-12 lg:col-span-8 lg:col-start-3 mb-6">
3
+ <h2 class="page-header-title">
4
+ <%= onboarding_check_circle(current_store.storefront_setup?) %>
5
+ <%= Spree.t('admin.storefront_setup.title') %>
6
+ </h2>
7
+ <p class="mb-4">
8
+ <%= Spree.t('admin.storefront_setup.description') %>
9
+ </p>
10
+
11
+ <% if @deployment_origin.present? %>
12
+ <div class="card mb-6">
13
+ <div class="card-body flex flex-col gap-3">
14
+ <% if @deployment_origin_allowed %>
15
+ <div class="flex items-center gap-2">
16
+ <%= onboarding_check_circle(true) %>
17
+ <span>
18
+ <%= Spree.t('admin.storefront_setup.deployment_already_allowed') %>
19
+ <%= link_to @deployment_origin, @deployment_origin, target: :_blank, rel: 'noopener', class: 'font-medium' %>
20
+ </span>
21
+ </div>
22
+ <% else %>
23
+ <h5 class="font-medium">
24
+ 🎉 <%= Spree.t('admin.storefront_setup.deployed_title') %>
25
+ </h5>
26
+ <p>
27
+ <%= Spree.t('admin.storefront_setup.deployed_copy') %>
28
+ <%= link_to @deployment_origin, @deployment_origin, target: :_blank, rel: 'noopener', class: 'font-medium' %>
29
+ </p>
30
+ <div class="flex items-center gap-2">
31
+ <%= form_with url: spree.admin_storefront_allow_origin_path, method: :post, data: { turbo: false } do %>
32
+ <%= hidden_field_tag :origin, @deployment_origin %>
33
+ <button type="submit" class="btn btn-primary">
34
+ <%= Spree.t('admin.storefront_setup.allow_origin_button') %>
35
+ </button>
36
+ <% end %>
37
+ <% if @vercel_dashboard_url.present? %>
38
+ <%= link_to @vercel_dashboard_url, target: :_blank, rel: 'noopener', class: 'btn btn-light' do %>
39
+ <%= icon('external-link') %>
40
+ <%= Spree.t('admin.storefront_setup.view_on_vercel') %>
41
+ <% end %>
42
+ <% end %>
43
+ </div>
44
+ <% end %>
45
+ </div>
46
+ </div>
47
+ <% end %>
48
+
49
+ <% if current_store.storefront_setup? %>
50
+ <div class="alert alert-success mb-6">
51
+ <%= Spree.t('admin.storefront_setup.done') %>
52
+ <%= link_to current_store.storefront_url, current_store.storefront_url, target: :_blank, rel: 'noopener', class: 'font-medium' %>
53
+ </div>
54
+ <% end %>
55
+
56
+ <div class="card mb-6">
57
+ <div class="card-header flex justify-between">
58
+ <h5 class="card-title"><%= Spree.t('admin.storefront_setup.deploy_title') %></h5>
59
+
60
+ <%= external_link_to Spree.t('admin.storefront_setup.see_online_demo'), 'https://demo.spreecommerce.org' %>
61
+ </div>
62
+ <div class="card-body">
63
+ <p class="mb-3"><%= Spree.t('admin.storefront_setup.deploy_copy') %></p>
64
+ <div class="mb-2">
65
+ <% if store_url_loopback?(current_store) %>
66
+ <div class="cursor-not-allowed flex gap-2 items-center">
67
+ <%= image_tag 'vercel-deploy-button.svg', alt: Spree.t('admin.storefront_setup.deploy_button'), height: 32, class: 'disabled opacity-25' %>
68
+ <span data-controller="tooltip">
69
+ <%= icon('alert-circle', class: 'text-yellow-500') %>
70
+ <%= tooltip(Spree.t('admin.storefront_setup.loopback_warning')) %>
71
+ </span>
72
+ </div>
73
+ <% else %>
74
+ <%= link_to vercel_deploy_url(current_store, @publishable_key) do %>
75
+ <%= image_tag 'vercel-deploy-button.svg', alt: Spree.t('admin.storefront_setup.deploy_button'), height: 32 %>
76
+ <% end %>
77
+ <% end %>
78
+ </div>
79
+ <p class="text-gray-500 text-sm mb-3"><%= Spree.t('admin.storefront_setup.deploy_finish_hint') %></p>
80
+ <%= external_link_to Spree.t('admin.storefront_setup.local_installation_instructions'), 'https://spreecommerce.org/docs/developer/storefront/nextjs/quickstart' %>
81
+ </div>
82
+ </div>
83
+
84
+ <div class="card mb-6">
85
+ <div class="card-header">
86
+ <h5 class="card-title"><%= Spree.t('admin.storefront_setup.connect_title') %></h5>
87
+ </div>
88
+ <div class="card-body flex flex-col gap-3">
89
+ <p><%= Spree.t('admin.storefront_setup.connect_copy') %></p>
90
+
91
+ <div class="form-group mb-0">
92
+ <label><%= Spree.t('admin.storefront_setup.api_url_label') %></label>
93
+ <div class="input-group gap-0 pr-1">
94
+ <input type="text" class="grow text-truncate" spellcheck="false" value="<%= current_store.formatted_url %>" readonly>
95
+ <%= clipboard_component(current_store.formatted_url,
96
+ button_class: 'btn hover:bg-gray-100 p-1 rounded',
97
+ icon_class: 'mr-0') %>
98
+ </div>
99
+ </div>
100
+
101
+ <div class="form-group mb-0">
102
+ <label><%= Spree.t('admin.storefront_setup.publishable_key_label') %></label>
103
+ <div data-controller="password-visibility" class="input-group gap-0 pr-1">
104
+ <input type="password" class="grow text-truncate" data-password-visibility-target="input" spellcheck="false" value="<%= @publishable_key.token %>" readonly>
105
+
106
+ <button type="button" class="btn hover:bg-gray-100 p-1 mr-1 rounded" data-action="password-visibility#toggle">
107
+ <span data-password-visibility-target="icon"><%= icon 'eye', class: 'mr-0' %></span>
108
+ <span data-password-visibility-target="icon" class="hidden"><%= icon 'eye-off', class: 'mr-0' %></span>
109
+ </button>
110
+
111
+ <%= clipboard_component(@publishable_key.token,
112
+ button_class: 'btn hover:bg-gray-100 p-1 rounded',
113
+ icon_class: 'mr-0') %>
114
+ </div>
115
+ </div>
116
+
117
+ <%= form_with url: spree.admin_storefront_path, method: :patch, data: { turbo: false }, class: 'flex flex-col gap-3 mt-2' do %>
118
+ <div class="form-group mb-0">
119
+ <label for="storefront_url"><%= Spree.t('admin.storefront_setup.storefront_url_label') %></label>
120
+ <input type="text" name="storefront_url" id="storefront_url" class="form-input" spellcheck="false"
121
+ placeholder="https://myshop.com" value="<%= current_store.preferred_storefront_url %>">
122
+ <p class="text-gray-500 text-sm mt-1 mb-0"><%= Spree.t('admin.storefront_setup.storefront_url_help') %></p>
123
+ </div>
124
+ <div>
125
+ <button type="submit" class="btn btn-primary"><%= Spree.t('actions.save') %></button>
126
+ </div>
127
+ <% end %>
128
+ </div>
129
+ </div>
130
+
131
+ <% if @storefront_origins.any? %>
132
+ <div class="card mb-6">
133
+ <div class="card-header">
134
+ <h5 class="card-title"><%= Spree.t('admin.storefront_setup.connected_title') %></h5>
135
+ </div>
136
+ <div class="card-body flex flex-col gap-2">
137
+ <% @storefront_origins.each do |allowed_origin| %>
138
+ <div class="flex items-center gap-2">
139
+ <%= icon('world', class: 'text-gray-500') %>
140
+ <%= link_to allowed_origin.origin, allowed_origin.origin, target: :_blank, rel: 'noopener' %>
141
+ </div>
142
+ <% end %>
143
+ <p class="text-gray-500 text-sm mb-0 mt-2">
144
+ <%= link_to Spree.t('admin.storefront_setup.manage_allowed_origins'), spree.admin_allowed_origins_path %>
145
+ </p>
146
+ </div>
147
+ </div>
148
+ <% end %>
149
+ </div>
150
+ </div>
@@ -13,7 +13,7 @@
13
13
  </p>
14
14
  <%= f.spree_text_field :name, required: true, autofocus: f.object.new_record? %>
15
15
 
16
- <%= f.spree_file_field :logo, width: 240, height: 240, crop: true, help_bubble: "Used in the admin dashboard" %>
16
+ <%= f.spree_file_field :logo, width: 240, height: 240, crop: true, help_bubble: Spree.t('admin.store_form.logo_help') %>
17
17
  </div>
18
18
  </div>
19
19
 
@@ -24,7 +24,7 @@
24
24
  <div class="card-body">
25
25
  <div class="alert alert-info w-full mb-0">
26
26
  <span>
27
- Currencies and locales are now managed by <%= link_to 'Markets', spree.admin_markets_path %>.
27
+ <%= Spree.t('admin.store_form.currencies_managed_by_markets_html', markets_link: link_to(Spree.t('admin.markets.list'), spree.admin_markets_path)) %>
28
28
  </span>
29
29
  </div>
30
30
  </div>
@@ -15,6 +15,10 @@
15
15
 
16
16
  <hr class="my-6">
17
17
 
18
+ <%= f.spree_select :preferred_storefront_access,
19
+ options_for_select(channel_storefront_access_options, f.object.preferred_storefront_access),
20
+ { label: Spree.t('admin.checkout_settings.storefront_access.label'),
21
+ help_bubble: Spree.t('admin.checkout_settings.storefront_access.description') } %>
18
22
  <%= f.spree_check_box :preferred_guest_checkout, label: Spree.t('admin.checkout_settings.guest_checkout.label'), help: Spree.t('admin.checkout_settings.guest_checkout.description') %>
19
23
  <%= f.spree_check_box :preferred_company_field_enabled, label: Spree.t('admin.store_form.company_field.label'), help: Spree.t('admin.store_form.company_field.description') %>
20
24
  <%= f.spree_check_box :preferred_special_instructions_enabled, label: Spree.t('admin.checkout_settings.special_instructions.label'), help: Spree.t('admin.checkout_settings.special_instructions.description') %>