spree_admin 5.1.0.beta4 → 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 +13 -1
- 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 +12 -7
- data/app/assets/stylesheets/spree/admin/shared/_base.scss +5 -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 +19 -2
- 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/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/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 +1 -1
- 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/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 +6 -1
- 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/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 +27 -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
|
|
@@ -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
|
+
}
|
@@ -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
|
}
|
@@ -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>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<% if @collection.any? %>
|
2
|
+
<div class="table-responsive" id="listing_gift_cards">
|
3
|
+
<table class="table">
|
4
|
+
<thead class="text-muted">
|
5
|
+
<tr>
|
6
|
+
<th><%= Spree.t(:code) %></th>
|
7
|
+
<th><%= Spree.t(:amount) %></th>
|
8
|
+
<th><%= Spree.t(:used) %></th>
|
9
|
+
<th><%= Spree.t(:currency) %></th>
|
10
|
+
<th><%= Spree.t(:status) %></th>
|
11
|
+
<th><%= Spree.t(:expires_at) %></th>
|
12
|
+
<th><%= Spree.t(:customer) %></th>
|
13
|
+
</tr>
|
14
|
+
</thead>
|
15
|
+
<tbody>
|
16
|
+
<%= render collection: @collection, partial: 'spree/admin/gift_cards/gift_card' %>
|
17
|
+
</tbody>
|
18
|
+
</table>
|
19
|
+
</div>
|
20
|
+
<%= render partial: 'spree/admin/shared/index_table_options', locals: { collection: @collection } %>
|
21
|
+
<% else %>
|
22
|
+
<% new_object_url = @user.present? ? spree.new_admin_user_gift_card_path(@user) : spree.new_admin_gift_card_path %>
|
23
|
+
<%= render 'spree/admin/shared/no_resource_found', model_class: Spree::GiftCard, new_object_url: new_object_url %>
|
24
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<div class="dropdown">
|
2
|
+
<button class="btn btn-light dropdown-toggle" type="button" data-toggle="dropdown" data-display="static" data-flip="false" aria-expanded="false">
|
3
|
+
<span class="text-muted font-weight-normal">Show:</span>
|
4
|
+
<%= gift_cards_filter_dropdown_value %>
|
5
|
+
</button>
|
6
|
+
<div class="dropdown-menu w-100" style="min-width: 200px">
|
7
|
+
|
8
|
+
<%= active_link_to Spree.t('admin.gift_cards.all_statuses'), params.to_unsafe_h.deep_merge({page: nil, q: {status_eq: nil}}), class: 'dropdown-item', active: (params[:q] || {}).values_at(*%w[status_eq in_stock_items out_of_stock_items] ).all?(&:blank?) %>
|
9
|
+
|
10
|
+
<%= link_to Spree.t('admin.gift_cards.active'),
|
11
|
+
params.to_unsafe_h.deep_merge({page: nil, q: {status_eq: :active}}),
|
12
|
+
class: "dropdown-item #{'active' if params[:q] && params[:q][:status_eq] == 'active'}" %>
|
13
|
+
|
14
|
+
<%= link_to params.to_unsafe_h.deep_merge({page: nil, q: {status_eq: :expired}}),
|
15
|
+
class: "dropdown-item #{'active' if params[:q] && params[:q][:status_eq] == 'expired'}" do %>
|
16
|
+
<%= Spree.t(:expired) %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<%= link_to params.to_unsafe_h.deep_merge({page: nil, q: {status_eq: :redeemed}}),
|
20
|
+
class: "dropdown-item #{'active' if params[:q] && params[:q][:status_eq] == 'redeemed'}" do %>
|
21
|
+
<%= Spree.t('admin.gift_cards.redeemed') %>
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
</div>
|
25
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%= turbo_frame_tag :gift_card_settings do %>
|
2
|
+
<%= form_for [:admin, @user, @object] do |f| %>
|
3
|
+
<div class="card">
|
4
|
+
<div class="card-header d-flex justify-content-between">
|
5
|
+
<h5 class="card-title">
|
6
|
+
<%= Spree.t(:settings) %>
|
7
|
+
</h5>
|
8
|
+
</div>
|
9
|
+
<div class="card-body">
|
10
|
+
<%= render partial: 'spree/admin/shared/error_messages', locals: { target: @object } %>
|
11
|
+
<%= render 'form', f: f %>
|
12
|
+
</div>
|
13
|
+
<div class="card-footer d-flex justify-content-between">
|
14
|
+
<%= turbo_save_button_tag Spree.t('actions.update') %>
|
15
|
+
|
16
|
+
<%= link_to Spree.t('actions.discard'), spree.admin_gift_card_path(@object), class: 'btn btn-light' %>
|
17
|
+
</div>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<%- headers = [
|
2
|
+
Spree.t(:code),
|
3
|
+
Spree.t(:amount),
|
4
|
+
Spree.t(:used),
|
5
|
+
Spree.t(:currency),
|
6
|
+
Spree.t(:status),
|
7
|
+
Spree.t(:expires_at),
|
8
|
+
Spree.t(:customer)
|
9
|
+
]
|
10
|
+
-%>
|
11
|
+
<%= CSV.generate_line(headers).strip %>
|
12
|
+
<%- @collection.find_each do |gift_card| -%>
|
13
|
+
<%= CSV.generate_line([
|
14
|
+
gift_card.display_code,
|
15
|
+
gift_card.display_amount,
|
16
|
+
gift_card.display_amount_used,
|
17
|
+
gift_card.currency,
|
18
|
+
gift_card.display_state,
|
19
|
+
gift_card.expires_at,
|
20
|
+
gift_card.user&.email,
|
21
|
+
]).strip %>
|
22
|
+
<%- end -%>
|