solidus_admin 0.2.0 → 0.3.1

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 (189) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +60 -6
  3. data/Rakefile +1 -0
  4. data/app/assets/builds/solidus_admin/tailwind.css +198 -163
  5. data/app/assets/stylesheets/solidus_admin/dark.css +1 -0
  6. data/app/assets/stylesheets/solidus_admin/dimmed.css +1 -0
  7. data/app/components/solidus_admin/adjustment_reasons/edit/component.html.erb +27 -0
  8. data/app/components/solidus_admin/adjustment_reasons/edit/component.rb +12 -0
  9. data/app/components/solidus_admin/adjustment_reasons/edit/component.yml +8 -0
  10. data/app/components/solidus_admin/adjustment_reasons/index/component.rb +19 -2
  11. data/app/components/solidus_admin/adjustment_reasons/new/component.html.erb +28 -0
  12. data/app/components/solidus_admin/adjustment_reasons/new/component.rb +12 -0
  13. data/app/components/solidus_admin/adjustment_reasons/new/component.yml +8 -0
  14. data/app/components/solidus_admin/base_component.rb +0 -25
  15. data/app/components/solidus_admin/option_types/index/component.rb +1 -1
  16. data/app/components/solidus_admin/orders/index/component.rb +8 -8
  17. data/app/components/solidus_admin/orders/index/component.yml +1 -0
  18. data/app/components/solidus_admin/orders/show/address/component.html.erb +56 -54
  19. data/app/components/solidus_admin/orders/show/adjustments/index/adjustable/component.rb +27 -0
  20. data/app/components/solidus_admin/orders/show/adjustments/index/adjustable/spree_line_item/component.rb +14 -0
  21. data/app/components/solidus_admin/orders/show/adjustments/index/adjustable/spree_order/component.rb +11 -0
  22. data/app/components/solidus_admin/orders/show/adjustments/index/adjustable/spree_shipment/component.rb +15 -0
  23. data/app/components/solidus_admin/orders/show/adjustments/index/component.rb +147 -0
  24. data/app/components/solidus_admin/orders/show/adjustments/index/component.yml +21 -0
  25. data/app/components/solidus_admin/orders/show/adjustments/index/source/component.rb +26 -0
  26. data/app/components/solidus_admin/orders/show/adjustments/index/source/spree_tax_rate/component.rb +17 -0
  27. data/app/components/solidus_admin/orders/show/adjustments/index/source/spree_unit_cancel/component.rb +7 -0
  28. data/app/components/solidus_admin/orders/show/component.html.erb +7 -3
  29. data/app/components/solidus_admin/orders/show/component.rb +8 -0
  30. data/app/components/solidus_admin/orders/show/email/component.html.erb +18 -13
  31. data/app/components/solidus_admin/orders/show/email/component.rb +0 -4
  32. data/app/components/solidus_admin/orders/show/summary/component.html.erb +1 -1
  33. data/app/components/solidus_admin/payment_methods/index/component.rb +1 -1
  34. data/app/components/solidus_admin/products/index/component.rb +8 -5
  35. data/app/components/solidus_admin/products/show/component.html.erb +14 -3
  36. data/app/components/solidus_admin/products/status/component.rb +4 -1
  37. data/app/components/solidus_admin/products/status/component.yml +1 -0
  38. data/app/components/solidus_admin/properties/index/component.rb +1 -1
  39. data/app/components/solidus_admin/refund_reasons/edit/component.html.erb +27 -0
  40. data/app/components/solidus_admin/refund_reasons/edit/component.rb +12 -0
  41. data/app/components/solidus_admin/refund_reasons/edit/component.yml +8 -0
  42. data/app/components/solidus_admin/refund_reasons/index/component.rb +11 -4
  43. data/app/components/solidus_admin/refund_reasons/new/component.html.erb +27 -0
  44. data/app/components/solidus_admin/refund_reasons/new/component.rb +12 -0
  45. data/app/components/solidus_admin/refund_reasons/new/component.yml +6 -0
  46. data/app/components/solidus_admin/return_reasons/edit/component.html.erb +26 -0
  47. data/app/components/solidus_admin/return_reasons/edit/component.rb +12 -0
  48. data/app/components/solidus_admin/return_reasons/edit/component.yml +8 -0
  49. data/app/components/solidus_admin/return_reasons/index/component.rb +20 -2
  50. data/app/components/solidus_admin/return_reasons/new/component.html.erb +27 -0
  51. data/app/components/solidus_admin/return_reasons/new/component.rb +12 -0
  52. data/app/components/solidus_admin/return_reasons/new/component.yml +8 -0
  53. data/app/components/solidus_admin/roles/edit/component.html.erb +33 -0
  54. data/app/components/solidus_admin/roles/edit/component.rb +20 -0
  55. data/app/components/solidus_admin/roles/edit/component.yml +19 -0
  56. data/app/components/solidus_admin/roles/index/component.rb +70 -0
  57. data/app/components/solidus_admin/roles/index/component.yml +6 -0
  58. data/app/components/solidus_admin/roles/new/component.html.erb +33 -0
  59. data/app/components/solidus_admin/roles/new/component.rb +20 -0
  60. data/app/components/solidus_admin/roles/new/component.yml +19 -0
  61. data/app/components/solidus_admin/shipping_categories/edit/component.html.erb +16 -0
  62. data/app/components/solidus_admin/shipping_categories/edit/component.rb +12 -0
  63. data/app/components/solidus_admin/shipping_categories/edit/component.yml +6 -0
  64. data/app/components/solidus_admin/shipping_categories/index/component.rb +20 -3
  65. data/app/components/solidus_admin/shipping_categories/new/component.html.erb +17 -0
  66. data/app/components/solidus_admin/shipping_categories/new/component.rb +12 -0
  67. data/app/components/solidus_admin/shipping_categories/new/component.yml +6 -0
  68. data/app/components/solidus_admin/shipping_methods/index/component.rb +2 -2
  69. data/app/components/solidus_admin/stock_items/edit/component.html.erb +66 -72
  70. data/app/components/solidus_admin/stock_items/edit/component.rb +0 -5
  71. data/app/components/solidus_admin/stock_items/index/component.rb +5 -6
  72. data/app/components/solidus_admin/stock_locations/index/component.rb +1 -1
  73. data/app/components/solidus_admin/store_credit_reasons/edit/component.html.erb +26 -0
  74. data/app/components/solidus_admin/store_credit_reasons/edit/component.rb +12 -0
  75. data/app/components/solidus_admin/store_credit_reasons/edit/component.yml +8 -0
  76. data/app/components/solidus_admin/store_credit_reasons/index/component.rb +11 -4
  77. data/app/components/solidus_admin/store_credit_reasons/new/component.html.erb +27 -0
  78. data/app/components/solidus_admin/store_credit_reasons/new/component.rb +12 -0
  79. data/app/components/solidus_admin/store_credit_reasons/new/component.yml +8 -0
  80. data/app/components/solidus_admin/stores/index/component.rb +1 -1
  81. data/app/components/solidus_admin/tax_categories/edit/component.html.erb +28 -0
  82. data/app/components/solidus_admin/tax_categories/edit/component.rb +12 -0
  83. data/app/components/solidus_admin/tax_categories/edit/component.yml +8 -0
  84. data/app/components/solidus_admin/tax_categories/index/component.rb +11 -4
  85. data/app/components/solidus_admin/tax_categories/new/component.html.erb +28 -0
  86. data/app/components/solidus_admin/tax_categories/new/component.rb +12 -0
  87. data/app/components/solidus_admin/tax_categories/new/component.yml +8 -0
  88. data/app/components/solidus_admin/tax_rates/index/component.rb +3 -3
  89. data/app/components/solidus_admin/taxonomies/index/component.rb +1 -1
  90. data/app/components/solidus_admin/ui/button/component.rb +1 -1
  91. data/app/components/solidus_admin/ui/checkbox_row/component.html.erb +29 -0
  92. data/app/components/solidus_admin/ui/checkbox_row/component.rb +11 -0
  93. data/app/components/solidus_admin/ui/forms/address/component.html.erb +27 -9
  94. data/app/components/solidus_admin/ui/forms/address/component.js +38 -13
  95. data/app/components/solidus_admin/ui/forms/search/component.html.erb +2 -3
  96. data/app/components/solidus_admin/ui/forms/search/component.js +3 -3
  97. data/app/components/solidus_admin/ui/modal/component.html.erb +7 -7
  98. data/app/components/solidus_admin/ui/modal/component.js +7 -0
  99. data/app/components/solidus_admin/ui/modal/component.rb +1 -1
  100. data/app/components/solidus_admin/ui/pages/index/component.html.erb +17 -3
  101. data/app/components/solidus_admin/ui/pages/index/component.rb +29 -43
  102. data/app/components/solidus_admin/ui/panel/component.html.erb +5 -16
  103. data/app/components/solidus_admin/ui/panel/component.rb +11 -7
  104. data/app/components/solidus_admin/ui/table/component.js +31 -2
  105. data/app/components/solidus_admin/ui/table/component.rb +23 -7
  106. data/app/components/solidus_admin/ui/table/component.yml +1 -0
  107. data/app/components/solidus_admin/ui/thumbnail/component.rb +1 -1
  108. data/app/components/solidus_admin/ui/thumbnail_with_caption/component.html.erb +17 -0
  109. data/app/components/solidus_admin/ui/thumbnail_with_caption/component.rb +15 -0
  110. data/app/components/solidus_admin/users/addresses/component.html.erb +46 -0
  111. data/app/components/solidus_admin/users/addresses/component.rb +61 -0
  112. data/app/components/solidus_admin/users/addresses/component.yml +14 -0
  113. data/app/components/solidus_admin/users/edit/api_access/component.html.erb +49 -0
  114. data/app/components/solidus_admin/users/edit/api_access/component.js +9 -0
  115. data/app/components/solidus_admin/users/edit/api_access/component.rb +7 -0
  116. data/app/components/solidus_admin/users/edit/api_access/component.yml +10 -0
  117. data/app/components/solidus_admin/users/edit/component.html.erb +52 -0
  118. data/app/components/solidus_admin/users/edit/component.rb +51 -0
  119. data/app/components/solidus_admin/users/edit/component.yml +12 -0
  120. data/app/components/solidus_admin/users/index/component.rb +10 -8
  121. data/app/components/solidus_admin/users/items/component.html.erb +41 -0
  122. data/app/components/solidus_admin/users/items/component.rb +170 -0
  123. data/app/components/solidus_admin/users/items/component.yml +16 -0
  124. data/app/components/solidus_admin/users/orders/component.html.erb +42 -0
  125. data/app/components/solidus_admin/users/orders/component.rb +131 -0
  126. data/app/components/solidus_admin/users/orders/component.yml +12 -0
  127. data/app/components/solidus_admin/users/stats/component.html.erb +11 -0
  128. data/app/components/solidus_admin/users/stats/component.rb +9 -0
  129. data/app/components/solidus_admin/users/stats/component.yml +2 -0
  130. data/app/components/solidus_admin/users_and_roles/component.rb +24 -0
  131. data/app/components/solidus_admin/users_and_roles/component.yml +2 -0
  132. data/app/components/solidus_admin/zones/index/component.rb +1 -1
  133. data/app/controllers/solidus_admin/addresses_controller.rb +6 -1
  134. data/app/controllers/solidus_admin/adjustment_reasons_controller.rb +85 -10
  135. data/app/controllers/solidus_admin/adjustments_controller.rb +57 -0
  136. data/app/controllers/solidus_admin/customers_controller.rb +5 -1
  137. data/app/controllers/solidus_admin/orders_controller.rb +5 -1
  138. data/app/controllers/solidus_admin/products_controller.rb +11 -0
  139. data/app/controllers/solidus_admin/refund_reasons_controller.rb +85 -10
  140. data/app/controllers/solidus_admin/reimbursement_types_controller.rb +0 -5
  141. data/app/controllers/solidus_admin/return_reasons_controller.rb +85 -10
  142. data/app/controllers/solidus_admin/roles_controller.rb +118 -0
  143. data/app/controllers/solidus_admin/shipping_categories_controller.rb +87 -10
  144. data/app/controllers/solidus_admin/shipping_methods_controller.rb +0 -5
  145. data/app/controllers/solidus_admin/stock_items_controller.rb +6 -6
  146. data/app/controllers/solidus_admin/stock_locations_controller.rb +0 -5
  147. data/app/controllers/solidus_admin/store_credit_reasons_controller.rb +85 -10
  148. data/app/controllers/solidus_admin/stores_controller.rb +0 -5
  149. data/app/controllers/solidus_admin/tax_categories_controller.rb +89 -10
  150. data/app/controllers/solidus_admin/tax_rates_controller.rb +0 -5
  151. data/app/controllers/solidus_admin/users_controller.rb +85 -6
  152. data/app/controllers/solidus_admin/zones_controller.rb +0 -5
  153. data/app/helpers/solidus_admin/last_login_helper.rb +16 -0
  154. data/app/helpers/solidus_admin/permission_sets_helper.rb +32 -0
  155. data/app/views/layouts/solidus_admin/application.html.erb +2 -1
  156. data/config/locales/adjustment_reasons.en.yml +5 -1
  157. data/config/locales/adjustments.en.yml +10 -0
  158. data/config/locales/refund_reasons.en.yml +10 -0
  159. data/config/locales/return_reasons.en.yml +5 -1
  160. data/config/locales/roles.en.yml +10 -0
  161. data/config/locales/shipping_categories.en.yml +4 -0
  162. data/config/locales/store_credit_reasons.en.yml +5 -1
  163. data/config/locales/tax_categories.en.yml +4 -0
  164. data/config/locales/users.en.yml +10 -0
  165. data/config/routes.rb +24 -7
  166. data/docs/components.md +109 -0
  167. data/docs/{customizing_view_components.md → customizing_components.md} +2 -7
  168. data/docs/index_pages.md +146 -0
  169. data/docs/{customizing_menu_items.md → menu_items.md} +1 -1
  170. data/docs/stimulusjs.md +85 -0
  171. data/docs/{customizing_tailwindcss.md → tailwindcss.md} +27 -8
  172. data/lib/solidus_admin/component_registry.rb +40 -0
  173. data/lib/solidus_admin/configuration.rb +2 -26
  174. data/lib/solidus_admin/install_tailwindcss.rb +4 -2
  175. data/lib/solidus_admin/testing_support/admin_assets.rb +10 -0
  176. data/lib/solidus_admin/testing_support/component_helpers.rb +27 -0
  177. data/lib/solidus_admin/testing_support/dummy_app/rake_tasks.rb +60 -0
  178. data/lib/solidus_admin/testing_support/feature_helpers.rb +34 -0
  179. data/lib/solidus_admin/version.rb +1 -1
  180. data/solidus_admin.gemspec +7 -3
  181. metadata +108 -19
  182. data/app/components/solidus_admin/promotion_categories/index/component.rb +0 -56
  183. data/app/components/solidus_admin/promotions/index/component.rb +0 -104
  184. data/app/components/solidus_admin/promotions/index/component.yml +0 -10
  185. data/app/controllers/solidus_admin/promotion_categories_controller.rb +0 -29
  186. data/app/controllers/solidus_admin/promotions_controller.rb +0 -46
  187. data/config/locales/promotion_categories.en.yml +0 -6
  188. data/config/locales/promotions.en.yml +0 -6
  189. data/config/locales/refund_reasons_.en.yml +0 -6
@@ -5,6 +5,7 @@ en:
5
5
  select_row: 'Select row'
6
6
  filter: 'Filter'
7
7
  search_placeholder: 'Search all %{resources}'
8
+ action_confirmation: 'Are you sure you want to %{action} ${count} ${resource}?'
8
9
  refine_search: 'Refine Search'
9
10
  batch_actions: Batch actions
10
11
  cancel: Cancel
@@ -31,7 +31,7 @@ class SolidusAdmin::UI::Thumbnail::Component < SolidusAdmin::BaseComponent
31
31
 
32
32
  def self.for(record, **attrs)
33
33
  case record
34
- when Spree::PromotionAction then new(icon: "megaphone-line", **attrs)
34
+ when *Spree::Config.adjustment_promotion_source_types then new(icon: "megaphone-line", **attrs)
35
35
  when Spree::UnitCancel then new(icon: "close-circle-line", **attrs)
36
36
  when Spree::TaxRate then new(icon: "percent-line", **attrs)
37
37
  when Spree::LineItem then self.for(record.variant, **attrs)
@@ -0,0 +1,17 @@
1
+ <figure class="flex items-center gap-2">
2
+ <% if content? %>
3
+ <%= content %>
4
+ <% else %>
5
+ <%= icon_thumbnail %>
6
+ <% end %>
7
+ <figcaption class="flex flex-col gap-0 max-w-[15rem]">
8
+ <div class="text-black body-small whitespace-nowrap text-ellipsis overflow-hidden">
9
+ <%= caption %>
10
+ </div>
11
+ <% if detail %>
12
+ <div class="text-gray-500 body-small whitespace-nowrap text-ellipsis overflow-hidden">
13
+ <%= detail %>
14
+ </div>
15
+ <% end %>
16
+ </figcaption>
17
+ </figure>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::UI::ThumbnailWithCaption::Component < SolidusAdmin::BaseComponent
4
+ attr_reader :icon, :caption, :detail
5
+
6
+ def initialize(icon: "question-line", caption: "", detail: nil)
7
+ @icon = icon
8
+ @caption = caption
9
+ @detail = detail
10
+ end
11
+
12
+ def icon_thumbnail
13
+ render component("ui/thumbnail").new(icon: icon)
14
+ end
15
+ end
@@ -0,0 +1,46 @@
1
+ <%= page do %>
2
+ <%= page_header do %>
3
+ <%= page_header_back(solidus_admin.users_path) %>
4
+ <%= page_header_title(t(".title", email: @user.email)) %>
5
+
6
+ <%= page_header_actions do %>
7
+ <%= render component("ui/button").new(tag: :a, text: t(".create_order_for_user"), href: spree.new_admin_order_path(user_id: @user.id)) %>
8
+ <% end %>
9
+ <% end %>
10
+
11
+ <%= page_header do %>
12
+ <% tabs.each do |tab| %>
13
+ <%= render(component("ui/button").new(tag: :a, scheme: :ghost, text: tab[:text], 'aria-current': tab[:current], href: tab[:href])) %>
14
+ <% end %>
15
+ <% end %>
16
+
17
+ <%= page_with_sidebar do %>
18
+ <%= page_with_sidebar_main do %>
19
+ <%= render component('ui/panel').new(title: t(".billing_address")) do %>
20
+ <%= form_for @user, url: solidus_admin.update_addresses_user_path(@user), method: :put, html: { id: "#{form_id}_billing", autocomplete: "off", class: "bill_address" } do |f| %>
21
+
22
+ <%= render component('ui/forms/address').new(address: @bill_address, name: "user[bill_address_attributes]") %>
23
+ <div class="py-1.5 text-center">
24
+ <%= render component("ui/button").new(tag: :button, text: t(".update"), form: "#{form_id}_billing") %>
25
+ <%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.addresses_user_path(@user), scheme: :secondary) %>
26
+ </div>
27
+ <% end %>
28
+ <% end %>
29
+
30
+ <%= render component('ui/panel').new(title: t(".shipping_address")) do %>
31
+ <%= form_for @user, url: solidus_admin.update_addresses_user_path(@user), method: :put, html: { id: "#{form_id}_shipping", autocomplete: "off", class: "ship_address" } do |f| %>
32
+
33
+ <%= render component('ui/forms/address').new(address: @ship_address, name: "user[ship_address_attributes]") %>
34
+ <div class="py-1.5 text-center">
35
+ <%= render component("ui/button").new(tag: :button, text: t(".update"), form: "#{form_id}_shipping") %>
36
+ <%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.addresses_user_path(@user), scheme: :secondary) %>
37
+ </div>
38
+ <% end %>
39
+ <% end %>
40
+ <% end %>
41
+
42
+ <%= page_with_sidebar_aside do %>
43
+ <%= render component("users/stats").new(user: @user) %>
44
+ <% end %>
45
+ <% end %>
46
+ <% end %>
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::Users::Addresses::Component < SolidusAdmin::BaseComponent
4
+ include SolidusAdmin::Layout::PageHelpers
5
+
6
+ def initialize(user:, address: nil, type: nil)
7
+ @user = user
8
+ @bill_address = bill_address(address, type)
9
+ @ship_address = ship_address(address, type)
10
+ end
11
+
12
+ def form_id
13
+ @form_id ||= "#{stimulus_id}--form-#{@user.id}"
14
+ end
15
+
16
+ def tabs
17
+ [
18
+ {
19
+ text: t('.account'),
20
+ href: solidus_admin.user_path(@user),
21
+ current: false,
22
+ },
23
+ {
24
+ text: t('.addresses'),
25
+ href: solidus_admin.addresses_user_path(@user),
26
+ current: true,
27
+ },
28
+ {
29
+ text: t('.order_history'),
30
+ href: solidus_admin.orders_user_path(@user),
31
+ current: false,
32
+ },
33
+ {
34
+ text: t('.items'),
35
+ href: spree.items_admin_user_path(@user),
36
+ current: false,
37
+ },
38
+ {
39
+ text: t('.store_credit'),
40
+ href: spree.admin_user_store_credits_path(@user),
41
+ current: false,
42
+ },
43
+ ]
44
+ end
45
+
46
+ def bill_address(address, type)
47
+ if address.present? && type == "bill"
48
+ address
49
+ else
50
+ @user.bill_address || Spree::Address.build_default
51
+ end
52
+ end
53
+
54
+ def ship_address(address, type)
55
+ if address.present? && type == "ship"
56
+ address
57
+ else
58
+ @user.ship_address || Spree::Address.build_default
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,14 @@
1
+ en:
2
+ title: "Users / %{email} / Addresses"
3
+ account: Account
4
+ addresses: Addresses
5
+ order_history: Order History
6
+ items: Items
7
+ store_credit: Store Credit
8
+ last_active: Last Active
9
+ create_order_for_user: Create order for this user
10
+ update: Update
11
+ cancel: Cancel
12
+ back: Back
13
+ billing_address: Billing Address
14
+ shipping_address: Shipping Address
@@ -0,0 +1,49 @@
1
+ <%= render component('ui/panel').new(title: t('.api_access')) do %>
2
+ <section>
3
+ <% if @user.spree_api_key.present? %>
4
+ <div id="current-api-key">
5
+ <h2 class="py-1.5 font-semibold"><%= t('.key') %></h2>
6
+ <% if @user == helpers.current_solidus_admin_user %>
7
+ <%= @user.spree_api_key %>
8
+ <% else %>
9
+ <i>(<%= t('spree.hidden') %>)</i>
10
+ <% end %>
11
+ </div>
12
+
13
+ <div class="py-1.5 text-center">
14
+ <%= form_with url: spree.admin_user_api_key_path(@user), method: :delete, local: true, html: { class: 'clear_api_key inline-flex' } do %>
15
+ <%= render component("ui/button").new(
16
+ text: t('.clear_key'),
17
+ scheme: :secondary,
18
+ type: :submit,
19
+ "data-action": "click->#{stimulus_id}#confirm",
20
+ "data-#{stimulus_id}-message-param": t(".confirm_clear_key"),
21
+ ) %>
22
+ <% end %>
23
+
24
+ <%= form_with url: spree.admin_user_api_key_path(@user), method: :post, local: true, html: { class: 'regen_api_key inline-flex' } do %>
25
+ <%= render component("ui/button").new(
26
+ text: t('.regenerate_key'),
27
+ scheme: :secondary,
28
+ type: :submit,
29
+ "data-action": "click->#{stimulus_id}#confirm",
30
+ "data-#{stimulus_id}-message-param": t(".confirm_regenerate_key"),
31
+ ) %>
32
+ <% end %>
33
+ </div>
34
+
35
+ <% else %>
36
+ <div class="no-objects-found"><%= t('.no_key') %></div>
37
+ <div class="filter-actions actions">
38
+ <div class="py-1.5 text-center">
39
+ <%= form_with url: spree.admin_user_api_key_path(@user), method: :post, local: true, html: { class: 'generate_api_key inline-flex' } do %>
40
+ <%= render component("ui/button").new(
41
+ text: t('.generate_key'),
42
+ type: :submit,
43
+ ) %>
44
+ <% end %>
45
+ </div>
46
+ </div>
47
+ <% end %>
48
+ </section>
49
+ <% end %>
@@ -0,0 +1,9 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ confirm(event) {
5
+ if (!confirm(event.params.message)) {
6
+ event.preventDefault()
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::Users::Edit::ApiAccess::Component < SolidusAdmin::BaseComponent
4
+ def initialize(user:)
5
+ @user = user
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ en:
2
+ api_access: API Access
3
+ no_key: No key
4
+ key: "Key"
5
+ generate_key: Generate API key
6
+ clear_key: Clear key
7
+ regenerate_key: Regenerate key
8
+ hidden: Hidden
9
+ confirm_clear_key: Are you sure you want to clear this user's API key? It will invalidate the existing key.
10
+ confirm_regenerate_key: Are you sure you want to regenerate this user's API key? It will invalidate the existing key.
@@ -0,0 +1,52 @@
1
+ <%= page do %>
2
+ <%= page_header do %>
3
+ <%= page_header_back(solidus_admin.users_path) %>
4
+ <%= page_header_title(t(".title", email: @user.email)) %>
5
+
6
+ <% # @todo: I am not sure how we want to handle Cancan stuff in the new admin. %>
7
+ <% # if can?(:admin, Spree::Order) && can?(:create, Spree::Order) %>
8
+ <%= page_header_actions do %>
9
+ <%= render component("ui/button").new(tag: :a, text: t(".create_order_for_user"), href: spree.new_admin_order_path(user_id: @user.id)) %>
10
+ <% end %>
11
+ <% # end %>
12
+ <% end %>
13
+
14
+ <%= page_header do %>
15
+ <% tabs.each do |tab| %>
16
+ <%= render(component("ui/button").new(tag: :a, scheme: :ghost, text: tab[:text], 'aria-current': tab[:current], href: tab[:href])) %>
17
+ <% end %>
18
+ <% end %>
19
+
20
+ <%= page_with_sidebar do %>
21
+ <%= page_with_sidebar_main do %>
22
+
23
+ <%= render component('ui/panel').new(title: Spree.user_class.model_name.human) do %>
24
+ <%= form_for @user, url: solidus_admin.user_path(@user), html: { id: form_id, autocomplete: "off" } do |f| %>
25
+ <div class="py-1.5">
26
+ <%= render component("ui/forms/field").text_field(f, :email) %>
27
+ </div>
28
+ <div class="py-1.5">
29
+ <%= render component("ui/forms/field").text_field(f, :password) %>
30
+ </div>
31
+ <div class="py-1.5">
32
+ <%= render component("ui/forms/field").text_field(f, :password_confirmation) %>
33
+ </div>
34
+ <div class="py-1.5">
35
+ <%= render component("ui/checkbox_row").new(options: role_options, row_title: "Roles", form: f, method: "spree_role_ids", layout: :subsection) %>
36
+ </div>
37
+ <div class="py-1.5 text-center">
38
+ <%= render component("ui/button").new(tag: :button, text: t(".update"), form: form_id) %>
39
+ <%= render component("ui/button").new(tag: :a, text: t(".cancel"), href: solidus_admin.user_path(@user), scheme: :secondary) %>
40
+ </div>
41
+ <% end %>
42
+ <% end %>
43
+
44
+ <%= render component("users/edit/api_access").new(user: @user) %>
45
+
46
+ <% end %>
47
+
48
+ <%= page_with_sidebar_aside do %>
49
+ <%= render component("users/stats").new(user: @user) %>
50
+ <% end %>
51
+ <% end %>
52
+ <% end %>
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::Users::Edit::Component < SolidusAdmin::BaseComponent
4
+ include SolidusAdmin::Layout::PageHelpers
5
+
6
+ def initialize(user:)
7
+ @user = user
8
+ end
9
+
10
+ def form_id
11
+ @form_id ||= "#{stimulus_id}--form-#{@user.id}"
12
+ end
13
+
14
+ def tabs
15
+ [
16
+ {
17
+ text: t('.account'),
18
+ href: solidus_admin.user_path(@user),
19
+ current: action_name == "edit",
20
+ },
21
+ {
22
+ text: t('.addresses'),
23
+ href: solidus_admin.addresses_user_path(@user),
24
+ current: action_name == "addresses",
25
+ },
26
+ {
27
+ text: t('.order_history'),
28
+ href: solidus_admin.orders_user_path(@user),
29
+ current: action_name == "orders",
30
+ },
31
+ {
32
+ text: t('.items'),
33
+ href: spree.items_admin_user_path(@user),
34
+ # @todo: update this "current" logic once folded into new admin
35
+ current: action_name != "edit",
36
+ },
37
+ {
38
+ text: t('.store_credit'),
39
+ href: spree.admin_user_store_credits_path(@user),
40
+ # @todo: update this "current" logic once folded into new admin
41
+ current: action_name != "edit",
42
+ },
43
+ ]
44
+ end
45
+
46
+ def role_options
47
+ Spree::Role.all.map do |role|
48
+ { label: role.name, id: role.id }
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,12 @@
1
+ en:
2
+ title: "Users / %{email}"
3
+ account: Account
4
+ addresses: Addresses
5
+ order_history: Order History
6
+ items: Items
7
+ store_credit: Store Credit
8
+ last_active: Last Active
9
+ create_order_for_user: Create order for this user
10
+ update: Update
11
+ cancel: Cancel
12
+ back: Back
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class SolidusAdmin::Users::Index::Component < SolidusAdmin::UI::Pages::Index::Component
3
+ class SolidusAdmin::Users::Index::Component < SolidusAdmin::UsersAndRoles::Component
4
+ include SolidusAdmin::LastLoginHelper
5
+
4
6
  def model_class
5
7
  Spree.user_class
6
8
  end
@@ -14,7 +16,7 @@ class SolidusAdmin::Users::Index::Component < SolidusAdmin::UI::Pages::Index::Co
14
16
  end
15
17
 
16
18
  def row_url(user)
17
- spree.admin_user_path(user)
19
+ solidus_admin.edit_user_path(user)
18
20
  end
19
21
 
20
22
  def page_actions
@@ -29,7 +31,7 @@ class SolidusAdmin::Users::Index::Component < SolidusAdmin::UI::Pages::Index::Co
29
31
  def batch_actions
30
32
  [
31
33
  {
32
- display_name: t('.batch_actions.delete'),
34
+ label: t('.batch_actions.delete'),
33
35
  action: solidus_admin.users_path,
34
36
  method: :delete,
35
37
  icon: 'delete-bin-7-line',
@@ -39,18 +41,18 @@ class SolidusAdmin::Users::Index::Component < SolidusAdmin::UI::Pages::Index::Co
39
41
 
40
42
  def scopes
41
43
  [
42
- { name: :customers, label: t('.scopes.customers'), default: true },
44
+ { name: :all, label: t('.scopes.all'), default: true },
45
+ { name: :customers, label: t('.scopes.customers') },
43
46
  { name: :admin, label: t('.scopes.admin') },
44
47
  { name: :with_orders, label: t('.scopes.with_orders') },
45
48
  { name: :without_orders, label: t('.scopes.without_orders') },
46
- { name: :all, label: t('.scopes.all') },
47
49
  ]
48
50
  end
49
51
 
50
52
  def filters
51
53
  [
52
54
  {
53
- presentation: Spree::Role.model_name.human.pluralize,
55
+ label: Spree::Role.model_name.human.pluralize,
54
56
  attribute: "spree_roles_id",
55
57
  predicate: "in",
56
58
  options: Spree::Role.pluck(:name, :id)
@@ -88,8 +90,8 @@ class SolidusAdmin::Users::Index::Component < SolidusAdmin::UI::Pages::Index::Co
88
90
  data: -> { _1.display_lifetime_value.to_html },
89
91
  },
90
92
  {
91
- header: :created_at,
92
- data: ->(user) { l(user.created_at.to_date, format: :long) },
93
+ header: :last_active,
94
+ data: ->(user) { last_login(user) },
93
95
  },
94
96
  ]
95
97
  end
@@ -0,0 +1,41 @@
1
+ <%= page do %>
2
+ <%= page_header do %>
3
+ <%= page_header_back(solidus_admin.users_path) %>
4
+ <%= page_header_title(t(".title", email: @user.email)) %>
5
+
6
+ <%= page_header_actions do %>
7
+ <%= render component("ui/button").new(tag: :a, text: t(".create_order_for_user"), href: spree.new_admin_order_path(user_id: @user.id)) %>
8
+ <% end %>
9
+ <% end %>
10
+
11
+ <%= page_header do %>
12
+ <% tabs.each do |tab| %>
13
+ <%= render(component("ui/button").new(tag: :a, scheme: :ghost, text: tab[:text], 'aria-current': tab[:current], href: tab[:href])) %>
14
+ <% end %>
15
+ <% end %>
16
+
17
+ <%= page_with_sidebar do %>
18
+ <%= page_with_sidebar_main do %>
19
+ <%= render component('ui/panel').new(title: t(".items_purchased")) do %>
20
+ <% if @items.present? %>
21
+ <%= render component('ui/table').new(
22
+ id: stimulus_id,
23
+ data: {
24
+ class: model_class,
25
+ rows: rows,
26
+ columns: columns,
27
+ url: -> { row_url(_1.order) },
28
+ },
29
+ )%>
30
+ <% else %>
31
+ <%= t(".no_orders_found") %>
32
+ <%= render component("ui/button").new(tag: :a, text: t(".create_one"), href: spree.new_admin_order_path(user_id: @user.id)) %>
33
+ <% end %>
34
+ <% end %>
35
+ <% end %>
36
+
37
+ <%= page_with_sidebar_aside do %>
38
+ <%= render component("users/stats").new(user: @user) %>
39
+ <% end %>
40
+ <% end %>
41
+ <% end %>
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::Users::Items::Component < SolidusAdmin::BaseComponent
4
+ include SolidusAdmin::Layout::PageHelpers
5
+
6
+ def initialize(user:, items:)
7
+ @user = user
8
+ @items = items
9
+ end
10
+
11
+ def tabs
12
+ [
13
+ {
14
+ text: t('.account'),
15
+ href: solidus_admin.user_path(@user),
16
+ current: false,
17
+ },
18
+ {
19
+ text: t('.addresses'),
20
+ href: solidus_admin.addresses_user_path(@user),
21
+ current: false,
22
+ },
23
+ {
24
+ text: t('.order_history'),
25
+ href: solidus_admin.orders_user_path(@user),
26
+ current: false,
27
+ },
28
+ {
29
+ text: t('.items'),
30
+ href: solidus_admin.items_user_path(@user),
31
+ current: true,
32
+ },
33
+ {
34
+ text: t('.store_credit'),
35
+ href: spree.admin_user_store_credits_path(@user),
36
+ current: false,
37
+ },
38
+ ]
39
+ end
40
+
41
+ def model_class
42
+ Spree::LineItem
43
+ end
44
+
45
+ def row_url(order)
46
+ spree.edit_admin_order_path(order)
47
+ end
48
+
49
+ def rows
50
+ @items
51
+ end
52
+
53
+ def columns
54
+ [
55
+ date_column,
56
+ image_column,
57
+ description_column,
58
+ price_column,
59
+ quantity_column,
60
+ total_column,
61
+ state_column,
62
+ number_column,
63
+ ]
64
+ end
65
+
66
+ def date_column
67
+ {
68
+ col: { class: "w-[8%]" },
69
+ header: :date,
70
+ data: ->(item) do
71
+ content_tag :div, l(item.order.created_at, format: :short), class: "text-sm"
72
+ end
73
+ }
74
+ end
75
+
76
+ def image_column
77
+ {
78
+ col: { class: "w-[8%]" },
79
+ header: tag.span('aria-label': Spree::Image.model_name.human, role: 'text'),
80
+ data: ->(item) do
81
+ image = item.variant.gallery.images.first || item.variant.product.gallery.images.first or return
82
+
83
+ render(
84
+ component('ui/thumbnail').new(
85
+ src: image.url(:small),
86
+ alt: item.product.name
87
+ )
88
+ )
89
+ end
90
+ }
91
+ end
92
+
93
+ def description_column
94
+ {
95
+ col: { class: "w-[24%]" },
96
+ header: t(".description_column_header"),
97
+ data: ->(item) { item_name_with_variant_and_sku(item) }
98
+ }
99
+ end
100
+
101
+ def price_column
102
+ {
103
+ col: { class: "w-[10%]" },
104
+ header: :price,
105
+ data: ->(item) do
106
+ content_tag :div, item.single_money.to_html
107
+ end
108
+ }
109
+ end
110
+
111
+ def quantity_column
112
+ {
113
+ col: { class: "w-[7%]" },
114
+ header: :qty,
115
+ data: ->(item) do
116
+ content_tag :div, item.quantity
117
+ end
118
+ }
119
+ end
120
+
121
+ def total_column
122
+ {
123
+ col: { class: "w-[10%]" },
124
+ header: t(".total_column_header"),
125
+ data: ->(item) do
126
+ content_tag :div, item.money.to_html
127
+ end
128
+ }
129
+ end
130
+
131
+ def state_column
132
+ {
133
+ col: { class: "w-[15%]" },
134
+ header: :state,
135
+ data: ->(item) do
136
+ color = {
137
+ 'complete' => :green,
138
+ 'returned' => :red,
139
+ 'canceled' => :blue,
140
+ 'cart' => :graphite_light,
141
+ }[item.order.state] || :yellow
142
+ component('ui/badge').new(name: item.order.state.humanize, color: color)
143
+ end
144
+ }
145
+ end
146
+
147
+ def number_column
148
+ {
149
+ col: { class: "w-[18%]" },
150
+ header: t(".number_column_header"),
151
+ data: ->(item) do
152
+ content_tag :div, item.order.number, class: "font-semibold text-sm"
153
+ end
154
+ }
155
+ end
156
+
157
+ private
158
+
159
+ def item_name_with_variant_and_sku(item)
160
+ content = []
161
+ content << item.product.name
162
+ content << "(#{item.variant.options_text})" if item.variant.option_values.any?
163
+ content << "<strong>#{t('spree.sku')}:</strong> #{item.variant.sku}" if item.variant.sku.present?
164
+
165
+ # The `.html_safe` is required for the description to display as desired.
166
+ # rubocop:disable Rails/OutputSafety
167
+ safe_join([content_tag(:div, content.join("<br>").html_safe, class: "text-sm")])
168
+ # rubocop:enable Rails/OutputSafety
169
+ end
170
+ end
@@ -0,0 +1,16 @@
1
+ en:
2
+ title: "Users / %{email} / Items Purchased"
3
+ account: Account
4
+ addresses: Addresses
5
+ order_history: Order History
6
+ items: Items
7
+ store_credit: Store Credit
8
+ last_active: Last Active
9
+ create_order_for_user: Create order for this user
10
+ items_purchased: Items Purchased
11
+ no_orders_found: No Orders found.
12
+ create_one: Create One
13
+ back: Back
14
+ number_column_header: "Order #"
15
+ description_column_header: "Description"
16
+ total_column_header: "Total"