spree_admin 5.1.0.beta3 → 5.1.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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/spree/admin/components/_badges.scss +4 -0
- data/app/assets/stylesheets/spree/admin/components/_buttons.scss +13 -2
- data/app/assets/stylesheets/spree/admin/components/_filters.scss +8 -1
- data/app/assets/stylesheets/spree/admin/components/_main.scss +14 -2
- data/app/assets/stylesheets/spree/admin/components/_media_form.scss +1 -1
- data/app/assets/stylesheets/spree/admin/components/_modals.scss +3 -1
- data/app/assets/stylesheets/spree/admin/components/_navbar.scss +1 -1
- data/app/assets/stylesheets/spree/admin/components/_tables.scss +6 -10
- data/app/assets/stylesheets/spree/admin/components/_variants_form.scss +1 -1
- data/app/assets/stylesheets/spree/admin/global/_variables.scss +13 -8
- data/app/assets/stylesheets/spree/admin/shared/_base.scss +5 -0
- data/app/controllers/concerns/spree/admin/order_breadcrumb_concern.rb +12 -0
- data/app/controllers/spree/admin/gift_card_batches_controller.rb +23 -0
- data/app/controllers/spree/admin/gift_cards_controller.rb +94 -0
- data/app/controllers/spree/admin/orders_controller.rb +20 -5
- data/app/controllers/spree/admin/payments_controller.rb +3 -0
- data/app/controllers/spree/admin/products_controller.rb +3 -3
- data/app/controllers/spree/admin/refunds_controller.rb +4 -0
- data/app/controllers/spree/admin/reimbursements_controller.rb +5 -1
- data/app/controllers/spree/admin/resource_controller.rb +12 -1
- data/app/controllers/spree/admin/search_controller.rb +22 -0
- data/app/controllers/spree/admin/store_credits_controller.rb +8 -5
- data/app/helpers/spree/admin/base_helper.rb +55 -0
- data/app/helpers/spree/admin/navigation_helper.rb +2 -2
- data/app/helpers/spree/admin/payments_helper.rb +0 -5
- data/app/helpers/spree/admin/products_helper.rb +1 -1
- data/app/helpers/spree/admin/promotion_rules_helper.rb +13 -1
- data/app/helpers/spree/admin/shipment_helper.rb +2 -0
- data/app/javascript/spree/admin/application.js +2 -0
- data/app/javascript/spree/admin/controllers/active_storage_upload_controller.js +2 -11
- data/app/javascript/spree/admin/controllers/multi_tom_select_controller.js +3 -2
- data/app/javascript/spree/admin/controllers/return_items_controller.js +6 -1
- data/app/javascript/spree/admin/controllers/sticky_controller.js +24 -0
- data/app/javascript/spree/admin/controllers/variants_form_controller.js +23 -17
- data/app/javascript/spree/admin/helpers/uppy_active_storage.js +15 -3
- data/app/views/active_storage/_upload_form.html.erb +3 -3
- data/app/views/spree/admin/coupon_codes/_coupon_code.html.erb +2 -6
- data/app/views/spree/admin/coupon_codes/index.csv.erb +1 -1
- data/app/views/spree/admin/custom_domains/edit.html.erb +2 -3
- data/app/views/spree/admin/custom_domains/new.html.erb +2 -3
- data/app/views/spree/admin/dashboard/_setup_progress.html.erb +2 -3
- data/app/views/spree/admin/dashboard/_store_preview.html.erb +3 -9
- data/app/views/spree/admin/gift_card_batches/_form.html.erb +30 -0
- data/app/views/spree/admin/gift_card_batches/new.html.erb +15 -0
- data/app/views/spree/admin/gift_cards/_filters.html.erb +43 -0
- data/app/views/spree/admin/gift_cards/_form.html.erb +30 -0
- data/app/views/spree/admin/gift_cards/_gift_card.html.erb +28 -0
- data/app/views/spree/admin/gift_cards/_list.html.erb +24 -0
- data/app/views/spree/admin/gift_cards/_table_filter_dropdown.html.erb +25 -0
- data/app/views/spree/admin/gift_cards/edit.html.erb +20 -0
- data/app/views/spree/admin/gift_cards/index.csv.erb +22 -0
- data/app/views/spree/admin/gift_cards/index.html.erb +41 -0
- data/app/views/spree/admin/gift_cards/new.html.erb +30 -0
- data/app/views/spree/admin/gift_cards/show.html.erb +199 -0
- data/app/views/spree/admin/integrations/new.html.erb +7 -4
- data/app/views/spree/admin/oauth_applications/edit.html.erb +2 -3
- data/app/views/spree/admin/oauth_applications/new.html.erb +2 -3
- data/app/views/spree/admin/orders/_customer.html.erb +5 -2
- data/app/views/spree/admin/orders/_payments.html.erb +1 -1
- data/app/views/spree/admin/orders/_return_authorizations.html.erb +3 -1
- data/app/views/spree/admin/orders/_shipment.html.erb +1 -1
- data/app/views/spree/admin/orders/_shipments.html.erb +1 -1
- data/app/views/spree/admin/orders/return_authorizations/_form.html.erb +13 -11
- data/app/views/spree/admin/page_sections/forms/_featured_posts.html.erb +0 -5
- data/app/views/spree/admin/pages/_form.html.erb +20 -26
- data/app/views/spree/admin/pages/new.html.erb +10 -4
- data/app/views/spree/admin/payments/_payment.html.erb +14 -9
- data/app/views/spree/admin/payments/new.html.erb +1 -1
- data/app/views/spree/admin/payments/source_forms/_gateway.html.erb +1 -1
- data/app/views/spree/admin/post_categories/edit.html.erb +2 -3
- data/app/views/spree/admin/post_categories/new.html.erb +2 -3
- data/app/views/spree/admin/preferences/_password_field.html.erb +2 -2
- data/app/views/spree/admin/products/edit.html.erb +2 -2
- data/app/views/spree/admin/promotion_actions/_promotion_action.html.erb +1 -1
- data/app/views/spree/admin/promotion_actions/edit.html.erb +2 -2
- data/app/views/spree/admin/promotion_rules/_promotion_rule.html.erb +26 -9
- data/app/views/spree/admin/promotion_rules/edit.html.erb +2 -2
- data/app/views/spree/admin/promotion_rules/forms/_option_value.html.erb +1 -1
- data/app/views/spree/admin/promotions/_actions.html.erb +2 -2
- data/app/views/spree/admin/promotions/_rules.html.erb +2 -2
- data/app/views/spree/admin/promotions/_sidebar.html.erb +5 -13
- data/app/views/spree/admin/properties/edit.html.erb +9 -5
- data/app/views/spree/admin/properties/new.html.erb +9 -5
- data/app/views/spree/admin/refunds/new.html.erb +5 -2
- data/app/views/spree/admin/reimbursement_types/edit.html.erb +2 -3
- data/app/views/spree/admin/reimbursement_types/new.html.erb +2 -4
- data/app/views/spree/admin/shared/_content_header.html.erb +9 -4
- data/app/views/spree/admin/shared/_edit_resource_links.html.erb +3 -1
- data/app/views/spree/admin/shared/_header.html.erb +2 -2
- data/app/views/spree/admin/shared/_index_table_options.html.erb +1 -1
- data/app/views/spree/admin/shared/_preferences.html.erb +1 -0
- data/app/views/spree/admin/shared/_sidebar.html.erb +1 -1
- data/app/views/spree/admin/shared/_user.html.erb +2 -7
- data/app/views/spree/admin/shared/named_types/_edit.html.erb +2 -3
- data/app/views/spree/admin/shared/named_types/_new.html.erb +2 -3
- data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +1 -1
- data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +1 -1
- data/app/views/spree/admin/shipping_categories/edit.html.erb +7 -4
- data/app/views/spree/admin/shipping_categories/new.html.erb +7 -6
- data/app/views/spree/admin/shipping_methods/form/_display.html.erb +23 -1
- data/app/views/spree/admin/stock_locations/_form.html.erb +35 -51
- data/app/views/spree/admin/stock_locations/edit.html.erb +8 -3
- data/app/views/spree/admin/stock_locations/new.html.erb +8 -5
- data/app/views/spree/admin/store_credit_events/_store_credit_event.html.erb +29 -0
- data/app/views/spree/admin/store_credits/_form.html.erb +13 -21
- data/app/views/spree/admin/store_credits/_list.html.erb +4 -24
- data/app/views/spree/admin/store_credits/_store_credit.html.erb +11 -0
- data/app/views/spree/admin/store_credits/edit.html.erb +16 -31
- data/app/views/spree/admin/store_credits/new.html.erb +14 -12
- data/app/views/spree/admin/store_credits/show.html.erb +145 -0
- data/app/views/spree/admin/stores/form/_basic.html.erb +26 -10
- data/app/views/spree/admin/tax_categories/_form.html.erb +1 -1
- data/app/views/spree/admin/tax_categories/edit.html.erb +7 -4
- data/app/views/spree/admin/tax_categories/new.html.erb +7 -4
- data/app/views/spree/admin/tax_rates/_form.html.erb +34 -32
- data/app/views/spree/admin/tax_rates/edit.html.erb +7 -4
- data/app/views/spree/admin/tax_rates/new.html.erb +7 -7
- data/app/views/spree/admin/taxonomies/edit.html.erb +2 -4
- data/app/views/spree/admin/taxonomies/new.html.erb +2 -2
- data/app/views/spree/admin/translations/edit.html.erb +2 -2
- data/app/views/spree/admin/translations/stores/_form.html.erb +2 -0
- data/app/views/spree/admin/users/_details.html.erb +1 -0
- data/app/views/spree/admin/users/index.html.erb +1 -1
- data/app/views/spree/admin/users/new.html.erb +9 -5
- data/app/views/spree/admin/users/show.html.erb +3 -3
- data/app/views/spree/admin/variants/form/_inventory.html.erb +1 -1
- data/app/views/spree/admin/zones/_form.html.erb +36 -40
- data/app/views/spree/admin/zones/edit.html.erb +7 -5
- data/app/views/spree/admin/zones/new.html.erb +7 -4
- data/config/locales/en.yml +12 -1
- data/config/routes.rb +8 -2
- metadata +28 -8
@@ -243,6 +243,61 @@ module Spree
|
|
243
243
|
content_tag(:span, ' *', class: 'required font-weight-bold text-danger')
|
244
244
|
end
|
245
245
|
|
246
|
+
# renders a clipboard button
|
247
|
+
# @param options [Hash] the options for the button
|
248
|
+
# @option options [String] :class the CSS class(es) of the button
|
249
|
+
# @option options [Hash] :data the data attributes for the button
|
250
|
+
# @option options [String] :title the title of the button
|
251
|
+
# @return [String] the button
|
252
|
+
def clipboard_button(options = {})
|
253
|
+
options[:class] ||= 'btn btn-clipboard with-tip'
|
254
|
+
options[:type] ||= 'button'
|
255
|
+
options[:data] ||= {}
|
256
|
+
options[:data][:action] = 'clipboard#copy'
|
257
|
+
options[:data][:clipboard_target] = 'button'
|
258
|
+
options[:data][:title] = Spree.t('admin.copy_to_clipboard')
|
259
|
+
options[:aria_label] ||= Spree.t('admin.copy_to_clipboard') # screen-reader label
|
260
|
+
|
261
|
+
content_tag(:button, options) do
|
262
|
+
icon('copy', class: 'mr-0 font-size-sm')
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# renders a clipboard component
|
267
|
+
# @param text [String] the text to copy
|
268
|
+
# @param options [Hash] the options for the component
|
269
|
+
# @option options [String] :class the CSS class(es) of the component
|
270
|
+
# @option options [Hash] :data the data attributes for the component
|
271
|
+
# @option options [String] :title the title of the component
|
272
|
+
# @return [String] the component
|
273
|
+
def clipboard_component(text, options = {})
|
274
|
+
options[:data] ||= {}
|
275
|
+
options[:data][:controller] = 'clipboard'
|
276
|
+
options[:data][:clipboard_success_content_value] ||= raw(icon('check', class: 'mr-0 font-size-sm'))
|
277
|
+
|
278
|
+
content_tag(:span, data: options[:data]) do
|
279
|
+
hidden_field_tag(:clipboard_source, text, data: { clipboard_target: 'source' }) +
|
280
|
+
clipboard_button
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# renders a progress bar component
|
285
|
+
# @param options [Hash] the options for the component
|
286
|
+
# @param value [Integer] the value of the progress bar
|
287
|
+
# @option options [Integer] :min the minimum value of the progress bar
|
288
|
+
# @option options [Integer] :max the maximum value of the progress bar
|
289
|
+
# @return [String] the component
|
290
|
+
def progress_bar_component(value, options = {})
|
291
|
+
min = options[:min] || 0
|
292
|
+
max = options[:max] || 100
|
293
|
+
percentage = (value.to_f / max * 100).round
|
294
|
+
|
295
|
+
content_tag(:div, class: 'progress') do
|
296
|
+
content_tag(:div, { class: 'progress-bar', role: 'progressbar', style: "width: #{percentage}%", aria: { valuenow: value, valuemin: min, valuemax: max } }) do
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
246
301
|
# returns the allowed file types for upload, according to the active storage configuration
|
247
302
|
# @return [Array<String>] the allowed file types for upload, eg. ['image/png', 'image/jpeg', 'image/gif', 'image/webp']
|
248
303
|
def allowed_file_types_for_upload
|
@@ -231,7 +231,7 @@ module Spree
|
|
231
231
|
link_to url, opts, &block
|
232
232
|
else
|
233
233
|
link_to url, opts do
|
234
|
-
(label + icon('external-link', class: 'ml-1 mr-0 small')).html_safe
|
234
|
+
(label + icon('external-link', class: 'ml-1 mr-0 small opacity-50')).html_safe
|
235
235
|
end
|
236
236
|
end
|
237
237
|
end
|
@@ -263,7 +263,7 @@ module Spree
|
|
263
263
|
# @param css [String] the css class of the help bubble
|
264
264
|
# @return [String] the help bubble with the icon
|
265
265
|
def help_bubble(text = '', placement = 'bottom', css: nil)
|
266
|
-
css ||= 'text-muted opacity-75 cursor-
|
266
|
+
css ||= 'text-muted opacity-75 cursor-default'
|
267
267
|
content_tag :small, icon('info-square-rounded', class: css), data: { placement: placement }, class: "with-tip #{css}", title: text
|
268
268
|
end
|
269
269
|
|
@@ -11,11 +11,6 @@ module Spree
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
def payment_method_icon_tag(payment_method, opts = {})
|
15
|
-
image_tag "payment_icons/#{payment_method}.svg", opts
|
16
|
-
rescue Sprockets::Rails::Helper::AssetNotFound
|
17
|
-
end
|
18
|
-
|
19
14
|
def available_payment_methods
|
20
15
|
@available_payment_methods ||= Spree::PaymentMethod.providers.map { |provider| provider.name.constantize.new }.delete_if { |payment_method| !payment_method.show_in_admin? || current_store.payment_methods.pluck(:type).include?(payment_method.type) }.sort_by(&:name)
|
21
16
|
end
|
@@ -124,7 +124,7 @@ module Spree
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def sorted_product_properties(product)
|
127
|
-
product.product_properties.sort_by { |product_property| product_property.property.position }
|
127
|
+
product.product_properties.includes(:property).sort_by { |product_property| product_property.property.position }
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
@@ -10,7 +10,19 @@ module Spree
|
|
10
10
|
eligible_values = promotion_rule.preferred_eligible_values || []
|
11
11
|
return [] if eligible_values.empty?
|
12
12
|
|
13
|
-
Spree::
|
13
|
+
Spree::OptionValue.includes(:option_type).where(id: eligible_values).map do |ov|
|
14
|
+
{
|
15
|
+
id: ov.id,
|
16
|
+
name: ov.display_presentation
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the promotion rule option values
|
22
|
+
# @param value_ids [Array<Integer>]
|
23
|
+
# @return [Array<String>]
|
24
|
+
def promotion_rule_option_values(value_ids)
|
25
|
+
Spree::OptionValue.includes(:option_type).where(id: value_ids).map(&:display_presentation)
|
14
26
|
end
|
15
27
|
end
|
16
28
|
end
|
@@ -73,6 +73,7 @@ import SectionFormController from 'spree/admin/controllers/section_form_controll
|
|
73
73
|
import SelectController from 'spree/admin/controllers/select_controller'
|
74
74
|
import SeoFormController from 'spree/admin/controllers/seo_form_controller'
|
75
75
|
import SlugFormController from 'spree/admin/controllers/slug_form_controller'
|
76
|
+
import StickyController from 'spree/admin/controllers/sticky_controller'
|
76
77
|
import SortableTree from 'spree/admin/controllers/sortable_tree_controller'
|
77
78
|
import StockTransferController from 'spree/admin/controllers/stock_transfer_controller'
|
78
79
|
import StoreFormController from 'spree/admin/controllers/store_form_controller'
|
@@ -124,6 +125,7 @@ application.register('section-form', SectionFormController)
|
|
124
125
|
application.register('select', SelectController)
|
125
126
|
application.register('seo-form', SeoFormController)
|
126
127
|
application.register('slug-form', SlugFormController)
|
128
|
+
application.register('sticky', StickyController)
|
127
129
|
application.register('sortable', Sortable)
|
128
130
|
application.register('sortable-tree', SortableTree)
|
129
131
|
application.register('stock-transfer', StockTransferController)
|
@@ -29,7 +29,8 @@ export default class extends Controller {
|
|
29
29
|
})
|
30
30
|
|
31
31
|
this.uppy.use(ActiveStorageUpload, {
|
32
|
-
directUploadUrl: document.querySelector("meta[name='direct-upload-url']").getAttribute('content')
|
32
|
+
directUploadUrl: document.querySelector("meta[name='direct-upload-url']").getAttribute('content'),
|
33
|
+
crop: this.cropValue
|
33
34
|
})
|
34
35
|
|
35
36
|
let dashboardOptions = {}
|
@@ -55,16 +56,6 @@ export default class extends Controller {
|
|
55
56
|
|
56
57
|
this.uppy.on('file-editor:complete', (updatedFile) => {
|
57
58
|
console.log('File editing complete:', updatedFile)
|
58
|
-
// Remove the old file from Uppy's file list
|
59
|
-
this.uppy.removeFile(updatedFile.id)
|
60
|
-
// Add the updated file to Uppy
|
61
|
-
this.uppy.addFile({
|
62
|
-
name: updatedFile.name,
|
63
|
-
type: updatedFile.type,
|
64
|
-
data: updatedFile.data,
|
65
|
-
source: 'local',
|
66
|
-
isRemote: false
|
67
|
-
})
|
68
59
|
|
69
60
|
this.handleUI(updatedFile)
|
70
61
|
|
@@ -26,8 +26,9 @@ export default class extends Controller {
|
|
26
26
|
values() {
|
27
27
|
return this.selectTargets
|
28
28
|
.map((selectTarget) => selectTarget.querySelector('select'))
|
29
|
-
.map((select) => select.options[select.selectedIndex]
|
30
|
-
.filter((
|
29
|
+
.map((select) => select.options[select.selectedIndex])
|
30
|
+
.filter((option) => option.value.length > 0)
|
31
|
+
.map((option) => ({ text: option.text, value: option.value}))
|
31
32
|
}
|
32
33
|
|
33
34
|
setValues() {
|
@@ -21,7 +21,12 @@ export default class extends CheckboxSelectAll {
|
|
21
21
|
var totalPretaxRefund = 0
|
22
22
|
this.checked.forEach((checkbox) => {
|
23
23
|
const returnItemRow = checkbox.closest('tr')
|
24
|
-
const
|
24
|
+
const refundAmountInput = returnItemRow.querySelector('.refund-amount-input')
|
25
|
+
let amount = parseFloat(refundAmountInput.value)
|
26
|
+
if (!Number.isFinite(amount)) {
|
27
|
+
amount = 0
|
28
|
+
refundAmountInput.value = 0
|
29
|
+
}
|
25
30
|
totalPretaxRefund += amount
|
26
31
|
})
|
27
32
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static values = {
|
5
|
+
threshold: { type: Number, default: 60 }
|
6
|
+
}
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
this.handleScroll = this.handleScroll.bind(this)
|
10
|
+
window.addEventListener('scroll', this.handleScroll)
|
11
|
+
}
|
12
|
+
|
13
|
+
disconnect() {
|
14
|
+
window.removeEventListener('scroll', this.handleScroll)
|
15
|
+
}
|
16
|
+
|
17
|
+
handleScroll() {
|
18
|
+
if (window.scrollY > this.thresholdValue) {
|
19
|
+
this.element.classList.add('sticky-top')
|
20
|
+
} else {
|
21
|
+
this.element.classList.remove('sticky-top')
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
@@ -129,7 +129,7 @@ export default class extends CheckboxSelectAll {
|
|
129
129
|
const nestingLevel = internalName.split('/').length
|
130
130
|
if (nestingLevel === 1) {
|
131
131
|
const firstOptionKey = Object.keys(this.optionsValue)[0]
|
132
|
-
const newOptionValues = this.optionsValue[firstOptionKey].values.filter((value) => value !== internalName)
|
132
|
+
const newOptionValues = this.optionsValue[firstOptionKey].values.filter((value) => value.text !== internalName)
|
133
133
|
if (newOptionValues.length === 0) {
|
134
134
|
const newOptionsValue = this.optionsValue
|
135
135
|
delete newOptionsValue[firstOptionKey]
|
@@ -265,12 +265,12 @@ export default class extends CheckboxSelectAll {
|
|
265
265
|
let name = ''
|
266
266
|
let internalName = name
|
267
267
|
if (i === 0) {
|
268
|
-
name = variant[keys[i]]
|
268
|
+
name = variant[keys[i]].text
|
269
269
|
internalName = name
|
270
270
|
} else {
|
271
|
-
const namesPath = keys.slice(1, keys.length).map((key) => variant[key])
|
271
|
+
const namesPath = keys.slice(1, keys.length).map((key) => variant[key].text)
|
272
272
|
name = namesPath.join(' / ')
|
273
|
-
internalName = `${variant[keys[0]]}/${namesPath.join('/')}`
|
273
|
+
internalName = `${variant[keys[0]].text}/${namesPath.join('/')}`
|
274
274
|
}
|
275
275
|
|
276
276
|
return { name, internalName }
|
@@ -495,7 +495,7 @@ export default class extends CheckboxSelectAll {
|
|
495
495
|
const variantEditButton = variantTarget.querySelector('[data-slot="variantEditButton"]')
|
496
496
|
|
497
497
|
if (variantEditButton) {
|
498
|
-
variantEditButton.href =
|
498
|
+
variantEditButton.href = `${Spree.adminPath}/products/${this.productIdValue}/variants/${variantId}/edit`
|
499
499
|
variantEditButton.classList.remove('invisible')
|
500
500
|
}
|
501
501
|
}
|
@@ -572,12 +572,12 @@ export default class extends CheckboxSelectAll {
|
|
572
572
|
refreshParentInputs() {
|
573
573
|
const firstOption = Object.values(this.optionsValue)[0]
|
574
574
|
if (firstOption) {
|
575
|
-
firstOption.values.forEach((
|
575
|
+
firstOption.values.forEach((option) => {
|
576
576
|
this.currenciesValue.forEach((currency) => {
|
577
|
-
this.updateParentPriceRange(
|
577
|
+
this.updateParentPriceRange(option.text, currency)
|
578
578
|
})
|
579
579
|
this.stockLocationsValue.forEach((stockLocationId) => {
|
580
|
-
this.updateParentStockSum(
|
580
|
+
this.updateParentStockSum(option.text, stockLocationId)
|
581
581
|
})
|
582
582
|
this.updateShopLocationCountOnHand()
|
583
583
|
})
|
@@ -615,11 +615,17 @@ export default class extends CheckboxSelectAll {
|
|
615
615
|
.find((option) => option.name === key).position
|
616
616
|
inputs.push(positionInput)
|
617
617
|
|
618
|
-
const
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
inputs.push(
|
618
|
+
const optionNameInput = document.createElement('input')
|
619
|
+
optionNameInput.type = 'hidden'
|
620
|
+
optionNameInput.name = `product[variants_attributes][${i}][options][][option_value_name]`
|
621
|
+
optionNameInput.value = variant[key].value
|
622
|
+
inputs.push(optionNameInput)
|
623
|
+
|
624
|
+
const optionIdInput = document.createElement('input')
|
625
|
+
optionIdInput.type = 'hidden'
|
626
|
+
optionIdInput.name = `product[variants_attributes][${i}][options][][option_value_presentation]`
|
627
|
+
optionIdInput.value = variant[key].text
|
628
|
+
inputs.push(optionIdInput)
|
623
629
|
})
|
624
630
|
|
625
631
|
return inputs
|
@@ -924,8 +930,8 @@ export default class extends CheckboxSelectAll {
|
|
924
930
|
const optionValuesSelectContainer = template.querySelector('[data-slot="optionValuesSelectContainer"]')
|
925
931
|
const tomSelectOptionValues = optionValues.map((optionValue) => {
|
926
932
|
return {
|
927
|
-
id:
|
928
|
-
name: optionValue
|
933
|
+
id: optionValue.value,
|
934
|
+
name: optionValue.text,
|
929
935
|
}
|
930
936
|
})
|
931
937
|
|
@@ -948,8 +954,8 @@ export default class extends CheckboxSelectAll {
|
|
948
954
|
values.forEach((value) => {
|
949
955
|
const template = this.optionValueTemplateTarget.content.cloneNode(true)
|
950
956
|
const optionValueNameEl = template.querySelector('[data-slot="optionValueName"]')
|
951
|
-
optionValueNameEl.textContent = value
|
952
|
-
optionValueNameEl.dataset.name = value
|
957
|
+
optionValueNameEl.textContent = value.text
|
958
|
+
optionValueNameEl.dataset.name = value.text
|
953
959
|
|
954
960
|
templates.push(template)
|
955
961
|
})
|
@@ -20,7 +20,8 @@ export default class ActiveStorageUpload extends BasePlugin {
|
|
20
20
|
limit: 0,
|
21
21
|
timeout: 30 * 1000,
|
22
22
|
directUploadUrl: null,
|
23
|
-
headers: {}
|
23
|
+
headers: {},
|
24
|
+
crop: false
|
24
25
|
}
|
25
26
|
|
26
27
|
this.opts = Object.assign({}, defaultOptions, opts)
|
@@ -37,10 +38,19 @@ export default class ActiveStorageUpload extends BasePlugin {
|
|
37
38
|
|
38
39
|
install() {
|
39
40
|
this.uppy.addUploader(this.handleUpload)
|
41
|
+
this.uppy.on('file-editor:complete', this.onEditorComplete)
|
40
42
|
}
|
41
43
|
|
42
44
|
uninstall() {
|
43
45
|
this.uppy.removeUploader(this.handleUpload)
|
46
|
+
this.uppy.off('file-editor:complete', this.onEditorComplete)
|
47
|
+
}
|
48
|
+
|
49
|
+
onEditorComplete = (updatedFile) => {
|
50
|
+
this.handleUpload([updatedFile.id])
|
51
|
+
|
52
|
+
// call directly upload method after editing image
|
53
|
+
return this.uploadFiles([updatedFile])
|
44
54
|
}
|
45
55
|
|
46
56
|
handleUpload(fileIDs) {
|
@@ -48,6 +58,10 @@ export default class ActiveStorageUpload extends BasePlugin {
|
|
48
58
|
this.uppy.log("[ActiveStorage] No files to upload!")
|
49
59
|
return Promise.resolve()
|
50
60
|
}
|
61
|
+
// do not upload before editing is done
|
62
|
+
if (this.opts.crop) {
|
63
|
+
return Promise.resolve()
|
64
|
+
}
|
51
65
|
|
52
66
|
this.uppy.log("[ActiveStorage] Uploading...")
|
53
67
|
const files = fileIDs.map(fileID => this.uppy.getFile(fileID))
|
@@ -115,8 +129,6 @@ export default class ActiveStorageUpload extends BasePlugin {
|
|
115
129
|
directUploadSignedId: blob.signed_id,
|
116
130
|
}
|
117
131
|
|
118
|
-
this.uppy.setFileState(file.id, { response })
|
119
|
-
|
120
132
|
this.uppy.emit("upload-success", file, blob)
|
121
133
|
|
122
134
|
return resolve(file)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
<% height ||= 300 %>
|
3
3
|
<% crop ||= false unless defined?(crop) %>
|
4
4
|
<% auto_submit ||= false %>
|
5
|
-
<%
|
5
|
+
<% show_delete_button = defined?(can_delete) ? can_delete : true %>
|
6
6
|
<% css ||= '' %>
|
7
7
|
|
8
8
|
<% if field_name && form %>
|
@@ -36,7 +36,7 @@
|
|
36
36
|
|
37
37
|
<% if crop %>
|
38
38
|
<span class="text-muted ml-2 text-center small mt-2">
|
39
|
-
|
39
|
+
<%= Spree.t('admin.recommended_size') %>: <%= width %>x<%= height %>px
|
40
40
|
</span>
|
41
41
|
<% end %>
|
42
42
|
</div>
|
@@ -48,7 +48,7 @@
|
|
48
48
|
<%= Spree.t('actions.select_file') %>
|
49
49
|
</button>
|
50
50
|
|
51
|
-
<% if
|
51
|
+
<% if show_delete_button %>
|
52
52
|
<button type="button" class="btn btn-danger ml-auto" data-action="active-storage-upload#remove" data-turbo-confirm="<%= Spree.t(:are_you_sure) %>">
|
53
53
|
<%= icon('trash') %>
|
54
54
|
|
@@ -1,11 +1,7 @@
|
|
1
1
|
<tr id="spree_coupon_code_<%= coupon_code[0] %>">
|
2
2
|
<td class="w-50">
|
3
|
-
<
|
4
|
-
|
5
|
-
<button type="button" class="btn btn-light p-1 ml-2 with-tip" data-action="clipboard#copy" title="<%= Spree.t('admin.copy_to_clipboard') %>">
|
6
|
-
<%= icon('copy-check', class: 'mr-0 font-size-sm') %>
|
7
|
-
</button>
|
8
|
-
</div>
|
3
|
+
<code><%= coupon_code[1].upcase %></code>
|
4
|
+
<%= clipboard_component(coupon_code[1].upcase) %>
|
9
5
|
</td>
|
10
6
|
<td class="w-25 font-size-sm"><%= active_badge(coupon_code[2] == 'used') %></td>
|
11
7
|
<td class="w-25 font-size-sm"><%= local_time(coupon_code[3]) %></td>
|
@@ -3,11 +3,10 @@
|
|
3
3
|
<%= @custom_domain.url %>
|
4
4
|
<% end %>
|
5
5
|
|
6
|
-
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
7
|
-
|
8
6
|
<%= form_for @object, url: spree.admin_custom_domain_path(@object) do |f| %>
|
9
7
|
<div class="row">
|
10
|
-
<div class="col-lg-6">
|
8
|
+
<div class="col-lg-6 offset-lg-3">
|
9
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
11
10
|
<%= render partial: 'form', locals: { f: f } %>
|
12
11
|
<%= render partial: 'spree/admin/shared/edit_resource_links', locals: { f: f } %>
|
13
12
|
</div>
|
@@ -3,11 +3,10 @@
|
|
3
3
|
<%= Spree.t(:new_custom_domain) %>
|
4
4
|
<% end %>
|
5
5
|
|
6
|
-
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
7
|
-
|
8
6
|
<%= form_for @object, url: spree.admin_custom_domains_path do |f| %>
|
9
7
|
<div class="row">
|
10
|
-
<div class="col-lg-6">
|
8
|
+
<div class="col-lg-6 offset-lg-3">
|
9
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
11
10
|
<%= render partial: 'form', locals: { f: f } %>
|
12
11
|
<%= render partial: 'spree/admin/shared/new_resource_links' %>
|
13
12
|
</div>
|
@@ -12,8 +12,7 @@
|
|
12
12
|
</span>
|
13
13
|
</span>
|
14
14
|
</div>
|
15
|
-
|
16
|
-
|
17
|
-
</div>
|
15
|
+
|
16
|
+
<%= progress_bar_component(current_store.setup_percentage) %>
|
18
17
|
</div>
|
19
18
|
</div>
|
@@ -12,15 +12,9 @@
|
|
12
12
|
<% end %>
|
13
13
|
|
14
14
|
<div class="card-body px-2 pt-0 pb-2">
|
15
|
-
<div class="flex my-2 p-1 w-100 rounded border"
|
16
|
-
|
17
|
-
|
18
|
-
<% else %>
|
19
|
-
<%= text_field_tag :domain, current_store.url, readonly: true, class: 'form-control-plaintext py-0', data: { clipboard_target: 'source' } %>
|
20
|
-
<% end %>
|
21
|
-
<button data-action="clipboard#copy" data-clipboard-target="button" class="btn btn-sm py-1 hover-gray">
|
22
|
-
Copy
|
23
|
-
</button>
|
15
|
+
<div class="flex my-2 p-1 w-100 rounded border">
|
16
|
+
<%= text_field_tag :domain, current_store.url_or_custom_domain, readonly: true, class: 'form-control-plaintext py-0' %>
|
17
|
+
<%= clipboard_component(current_store.url_or_custom_domain) %>
|
24
18
|
</div>
|
25
19
|
|
26
20
|
<div class="d-flex">
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<div class="card mb-4">
|
2
|
+
<div class="card-header">
|
3
|
+
<h5 class="card-title">
|
4
|
+
<%= Spree.t(:gift_card_batch) %>
|
5
|
+
</h5>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="card-body">
|
9
|
+
<div class="form-group">
|
10
|
+
<%= f.label :prefix, raw(Spree.t('admin.gift_card_batches.prefix') + required_span_tag)%>
|
11
|
+
<%= f.text_field :prefix, class: 'form-control', disabled: f.object.persisted? %>
|
12
|
+
<%= f.error_message_on :prefix %>
|
13
|
+
</div>
|
14
|
+
<div class="form-group">
|
15
|
+
<%= f.label :amount, raw(Spree.t(:amount) + required_span_tag) %>
|
16
|
+
<%= f.number_field :amount, class: 'form-control', disabled: f.object.persisted?, required: true %>
|
17
|
+
<%= f.error_message_on :amount %>
|
18
|
+
</div>
|
19
|
+
<div class="form-group">
|
20
|
+
<%= f.label :codes_count, raw(Spree.t('admin.gift_card_batches.codes_count') + required_span_tag) %>
|
21
|
+
<%= f.number_field :codes_count, class: 'form-control', disabled: f.object.persisted?, required: true, min: 1, max: Spree::Config[:gift_card_batch_limit] %>
|
22
|
+
<%= f.error_message_on :codes_count %>
|
23
|
+
</div>
|
24
|
+
<div class="form-group">
|
25
|
+
<%= f.label :expires_at, Spree.t(:expires_at) %>
|
26
|
+
<%= f.date_field :expires_at, class: 'form-control', disabled: f.object.persisted? %>
|
27
|
+
<%= f.error_message_on :expires_at %>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% content_for :page_title do %>
|
2
|
+
<%= page_header_back_button spree.admin_gift_cards_path %>
|
3
|
+
<%= Spree.t('admin.gift_card_batches.new_gift_card_batch') %>
|
4
|
+
<% end %>
|
5
|
+
|
6
|
+
<%= form_for [:admin, @object] do |f| %>
|
7
|
+
<div class="row">
|
8
|
+
<div class="col-lg-6 offset-lg-3">
|
9
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
10
|
+
|
11
|
+
<%= render 'form', f: f %>
|
12
|
+
<%= render 'spree/admin/shared/new_resource_links' %>
|
13
|
+
</div>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<% frame_name ||= nil %>
|
2
|
+
<% filter_form_url = params[:user_id].present? ? spree.admin_user_gift_cards_path(params[:user_id]) : spree.admin_gift_cards_path %>
|
3
|
+
|
4
|
+
<%= search_form_for @search,
|
5
|
+
url: filter_form_url,
|
6
|
+
class: "filter-wrap",
|
7
|
+
data: {
|
8
|
+
controller: "filters reveal",
|
9
|
+
reveal_hidden_class: "d-none",
|
10
|
+
filters_url_value: request.url
|
11
|
+
} do |f| %>
|
12
|
+
<%= hidden_field_tag :frame_name, frame_name if frame_name.present? %>
|
13
|
+
|
14
|
+
<div class="d-flex flex-column flex-lg-row gap-2">
|
15
|
+
<%= render 'spree/admin/shared/filters_search_bar', param: :code_eq, label: Spree.t(:code) %>
|
16
|
+
<%= render "table_filter_dropdown" %>
|
17
|
+
<%= render "spree/admin/shared/filters_button" %>
|
18
|
+
</div>
|
19
|
+
<div data-reveal-target="item" class="d-none" id="table-filter">
|
20
|
+
<% if params[:user_id].blank? %>
|
21
|
+
<div class="form-group">
|
22
|
+
<%= f.label :users_email_eq, Spree.t(:email) %>
|
23
|
+
<%= f.text_field :users_email_eq, class: "form-control", data: {filters_target: :input} %>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<div class="form-group">
|
28
|
+
<%= f.label :batch_prefix_eq, Spree.t('admin.gift_card_batches.prefix') %>
|
29
|
+
<%= f.text_field :batch_prefix_eq, class: "form-control", data: {filters_target: :input} %>
|
30
|
+
</div>
|
31
|
+
|
32
|
+
<div class="form-actions">
|
33
|
+
<%= turbo_save_button_tag Spree.t(:filter_results) do %>
|
34
|
+
<%= icon("search") %>
|
35
|
+
<%= Spree.t(:filter_results) %>
|
36
|
+
<% end %>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<%= render "spree/admin/shared/filter_badge_template" %>
|
41
|
+
|
42
|
+
<div data-filters-target="badgesContainer" class="filter-badges-container"></div>
|
43
|
+
<% end %>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<% unless f.object.persisted? %>
|
2
|
+
<div class="form-group">
|
3
|
+
<%= f.label :code do %>
|
4
|
+
<%= Spree.t(:code) %>
|
5
|
+
<%= help_bubble(Spree.t('admin.gift_cards.code_help_text')) %>
|
6
|
+
<% end %>
|
7
|
+
<%= f.text_field :code, class: 'form-control' %>
|
8
|
+
<%= f.error_message_on :code %>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<div class="form-group">
|
13
|
+
<%= f.label :amount, raw(Spree.t(:amount) + required_span_tag) %>
|
14
|
+
<%= f.text_field :amount, class: 'form-control', required: true %>
|
15
|
+
<%= f.error_message_on :amount %>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
<div class="form-group">
|
19
|
+
<%= f.label :user_id, Spree.t(:customer) %>
|
20
|
+
<%= tom_select_tag 'gift_card[user_id]',
|
21
|
+
active_option: @user&.id || @object.user_id,
|
22
|
+
include_blank: true,
|
23
|
+
options: users_for_select_options %>
|
24
|
+
</div>
|
25
|
+
<div class="form-group">
|
26
|
+
<%= f.label :expires_at, Spree.t(:expires_at) %>
|
27
|
+
<%= f.date_field :expires_at, class: 'form-control' %>
|
28
|
+
<%= f.error_message_on :expires_at %>
|
29
|
+
</div>
|
30
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% link = @user.present? ? spree.admin_user_gift_card_path(gift_card, user_id: @user.id) : spree.admin_gift_card_path(gift_card) %>
|
2
|
+
|
3
|
+
<tr id="<%= spree_dom_id gift_card %>" data-controller="row-link">
|
4
|
+
<td class="w-25 py-0">
|
5
|
+
<%= link_to gift_card.code.upcase, link, class: 'font-weight-bold d-block w-100 h-100 py-2', data: { 'turbo-frame': '_top', row_link_target: :link } %>
|
6
|
+
</td>
|
7
|
+
<td class="w-10 cursor-pointer" data-action="click->row-link#openLink"><%= gift_card.display_amount %></td>
|
8
|
+
<td class="w-10 cursor-pointer" data-action="click->row-link#openLink"><%= gift_card.display_amount_used %></td>
|
9
|
+
<td class="w-10 cursor-pointer" data-action="click->row-link#openLink"><%= gift_card.currency.upcase %></td>
|
10
|
+
<td class="w-10 cursor-pointer" data-action="click->row-link#openLink"><%= active_badge(gift_card.active?, label: gift_card.display_state) %></td>
|
11
|
+
<td class="w-10 cursor-pointer" data-action="click->row-link#openLink">
|
12
|
+
<% if gift_card.expires_at.present? %>
|
13
|
+
<%= local_date(gift_card.expires_at) %>
|
14
|
+
<% else %>
|
15
|
+
<span class="text-muted">
|
16
|
+
<%= Spree.t(:not_available) %>
|
17
|
+
</span>
|
18
|
+
<% end %></td>
|
19
|
+
<td class="w-15 cursor-pointer" data-action="click->row-link#openLink">
|
20
|
+
<% if gift_card.user.present? %>
|
21
|
+
<%= gift_card.user.email %>
|
22
|
+
<% else %>
|
23
|
+
<span class="text-muted">
|
24
|
+
<%= Spree.t(:not_available) %>
|
25
|
+
</span>
|
26
|
+
<% end %>
|
27
|
+
</td>
|
28
|
+
</tr>
|