spree_admin 5.0.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 +7 -0
- data/LICENSE.md +13 -0
- data/README.md +4 -0
- data/Rakefile +15 -0
- data/app/assets/config/spree_admin_manifest.js +10 -0
- data/app/assets/images/favicon_256x256.png +0 -0
- data/app/assets/stylesheets/spree/admin/actiontext.css +36 -0
- data/app/assets/stylesheets/spree/admin/application.scss +43 -0
- data/app/assets/stylesheets/spree/admin/components/_alerts.scss +48 -0
- data/app/assets/stylesheets/spree/admin/components/_badges.scss +117 -0
- data/app/assets/stylesheets/spree/admin/components/_bulk_panel.scss +31 -0
- data/app/assets/stylesheets/spree/admin/components/_buttons.scss +198 -0
- data/app/assets/stylesheets/spree/admin/components/_cards.scss +126 -0
- data/app/assets/stylesheets/spree/admin/components/_dropdowns.scss +148 -0
- data/app/assets/stylesheets/spree/admin/components/_filters.scss +41 -0
- data/app/assets/stylesheets/spree/admin/components/_line_items_form.scss +32 -0
- data/app/assets/stylesheets/spree/admin/components/_main.scss +148 -0
- data/app/assets/stylesheets/spree/admin/components/_media_form.scss +91 -0
- data/app/assets/stylesheets/spree/admin/components/_modals.scss +42 -0
- data/app/assets/stylesheets/spree/admin/components/_navbar.scss +10 -0
- data/app/assets/stylesheets/spree/admin/components/_navigation.scss +53 -0
- data/app/assets/stylesheets/spree/admin/components/_offcanvas.scss +26 -0
- data/app/assets/stylesheets/spree/admin/components/_search_picker.scss +55 -0
- data/app/assets/stylesheets/spree/admin/components/_seo_form.scss +16 -0
- data/app/assets/stylesheets/spree/admin/components/_sortable_tree.scss +58 -0
- data/app/assets/stylesheets/spree/admin/components/_tables.scss +187 -0
- data/app/assets/stylesheets/spree/admin/components/_variants_form.scss +203 -0
- data/app/assets/stylesheets/spree/admin/global/_variables.scss +190 -0
- data/app/assets/stylesheets/spree/admin/plugins/_dropdown.scss +102 -0
- data/app/assets/stylesheets/spree/admin/plugins/_items.scss +115 -0
- data/app/assets/stylesheets/spree/admin/plugins/_tinymce_custom.scss +74 -0
- data/app/assets/stylesheets/spree/admin/plugins/_trix_custom.scss +110 -0
- data/app/assets/stylesheets/spree/admin/plugins/flatfile.scss +4 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/checkbox_options.scss +5 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/clear_button.scss +30 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/drag_drop.scss +16 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/dropdown_header.scss +23 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/dropdown_input.scss +47 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/input_autogrow.scss +18 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/optgroup_columns.scss +23 -0
- data/app/assets/stylesheets/spree/admin/plugins/plugins/remove_button.scss +44 -0
- data/app/assets/stylesheets/spree/admin/plugins/tom-select.bootstrap4.scss +219 -0
- data/app/assets/stylesheets/spree/admin/plugins/tom-select.bootstrap5.scss +274 -0
- data/app/assets/stylesheets/spree/admin/plugins/tom-select.default.scss +87 -0
- data/app/assets/stylesheets/spree/admin/plugins/tom-select.scss +175 -0
- data/app/assets/stylesheets/spree/admin/plugins/uppy_fixes.scss +25 -0
- data/app/assets/stylesheets/spree/admin/shared/_base.scss +674 -0
- data/app/assets/stylesheets/spree/admin/shared/_forms.scss +184 -0
- data/app/assets/stylesheets/spree/admin/views/_dashboard.scss +34 -0
- data/app/assets/stylesheets/spree/admin/views/_page_builder.scss +237 -0
- data/app/controllers/concerns/spree/admin/analytics_concern.rb +51 -0
- data/app/controllers/concerns/spree/admin/bulk_operations_concern.rb +38 -0
- data/app/controllers/concerns/spree/admin/order_concern.rb +24 -0
- data/app/controllers/concerns/spree/admin/page_builder_concern.rb +44 -0
- data/app/controllers/spree/admin/action_text/video_embeds_controller.rb +44 -0
- data/app/controllers/spree/admin/addresses_controller.rb +86 -0
- data/app/controllers/spree/admin/assets_controller.rb +70 -0
- data/app/controllers/spree/admin/base_controller.rb +131 -0
- data/app/controllers/spree/admin/checkouts_controller.rb +23 -0
- data/app/controllers/spree/admin/classifications_controller.rb +74 -0
- data/app/controllers/spree/admin/coupon_codes_controller.rb +21 -0
- data/app/controllers/spree/admin/custom_domains_controller.rb +19 -0
- data/app/controllers/spree/admin/customer_returns_controller.rb +20 -0
- data/app/controllers/spree/admin/dashboard_controller.rb +145 -0
- data/app/controllers/spree/admin/digital_assets_controller.rb +45 -0
- data/app/controllers/spree/admin/errors_controller.rb +11 -0
- data/app/controllers/spree/admin/exports_controller.rb +48 -0
- data/app/controllers/spree/admin/line_items_controller.rb +121 -0
- data/app/controllers/spree/admin/oauth_applications_controller.rb +27 -0
- data/app/controllers/spree/admin/option_types_controller.rb +23 -0
- data/app/controllers/spree/admin/option_values_controller.rb +21 -0
- data/app/controllers/spree/admin/orders/billing_address_controller.rb +103 -0
- data/app/controllers/spree/admin/orders/contact_information_controller.rb +45 -0
- data/app/controllers/spree/admin/orders/customer_returns_controller.rb +81 -0
- data/app/controllers/spree/admin/orders/payment_links_controller.rb +33 -0
- data/app/controllers/spree/admin/orders/return_authorizations_controller.rb +90 -0
- data/app/controllers/spree/admin/orders/shipping_address_controller.rb +85 -0
- data/app/controllers/spree/admin/orders/user_controller.rb +94 -0
- data/app/controllers/spree/admin/orders_controller.rb +87 -0
- data/app/controllers/spree/admin/page_blocks_controller.rb +40 -0
- data/app/controllers/spree/admin/page_links_controller.rb +43 -0
- data/app/controllers/spree/admin/page_sections_controller.rb +57 -0
- data/app/controllers/spree/admin/pages_controller.rb +40 -0
- data/app/controllers/spree/admin/payment_methods_controller.rb +45 -0
- data/app/controllers/spree/admin/payments_controller.rb +122 -0
- data/app/controllers/spree/admin/post_categories_controller.rb +6 -0
- data/app/controllers/spree/admin/posts_controller.rb +23 -0
- data/app/controllers/spree/admin/products_controller.rb +366 -0
- data/app/controllers/spree/admin/profile_controller.rb +31 -0
- data/app/controllers/spree/admin/promotion_actions_controller.rb +47 -0
- data/app/controllers/spree/admin/promotion_rules_controller.rb +39 -0
- data/app/controllers/spree/admin/promotions_controller.rb +61 -0
- data/app/controllers/spree/admin/properties_controller.rb +23 -0
- data/app/controllers/spree/admin/refund_reasons_controller.rb +6 -0
- data/app/controllers/spree/admin/refunds_controller.rb +43 -0
- data/app/controllers/spree/admin/reimbursement_types_controller.rb +6 -0
- data/app/controllers/spree/admin/reimbursements_controller.rb +47 -0
- data/app/controllers/spree/admin/reports_controller.rb +52 -0
- data/app/controllers/spree/admin/resource_controller.rb +325 -0
- data/app/controllers/spree/admin/return_authorization_reasons_controller.rb +6 -0
- data/app/controllers/spree/admin/return_authorizations_controller.rb +29 -0
- data/app/controllers/spree/admin/return_items_controller.rb +9 -0
- data/app/controllers/spree/admin/roles_controller.rb +6 -0
- data/app/controllers/spree/admin/shipments_controller.rb +102 -0
- data/app/controllers/spree/admin/shipping_categories_controller.rb +6 -0
- data/app/controllers/spree/admin/shipping_methods_controller.rb +29 -0
- data/app/controllers/spree/admin/stock_items_controller.rb +25 -0
- data/app/controllers/spree/admin/stock_locations_controller.rb +24 -0
- data/app/controllers/spree/admin/stock_transfers_controller.rb +48 -0
- data/app/controllers/spree/admin/store_credit_categories_controller.rb +6 -0
- data/app/controllers/spree/admin/store_credits_controller.rb +93 -0
- data/app/controllers/spree/admin/storefront_controller.rb +38 -0
- data/app/controllers/spree/admin/stores_controller.rb +87 -0
- data/app/controllers/spree/admin/tax_categories_controller.rb +6 -0
- data/app/controllers/spree/admin/tax_rates_controller.rb +20 -0
- data/app/controllers/spree/admin/taxonomies_controller.rb +21 -0
- data/app/controllers/spree/admin/taxons_controller.rb +98 -0
- data/app/controllers/spree/admin/themes_controller.rb +75 -0
- data/app/controllers/spree/admin/translations_controller.rb +74 -0
- data/app/controllers/spree/admin/users_controller.rb +91 -0
- data/app/controllers/spree/admin/variants_controller.rb +90 -0
- data/app/controllers/spree/admin/webhooks_subscribers_controller.rb +48 -0
- data/app/controllers/spree/admin/zones_controller.rb +37 -0
- data/app/helpers/spree/admin/base_helper.rb +246 -0
- data/app/helpers/spree/admin/custom_domains_helper.rb +9 -0
- data/app/helpers/spree/admin/customer_returns_helper.rb +18 -0
- data/app/helpers/spree/admin/flash_helper.rb +15 -0
- data/app/helpers/spree/admin/navigation_helper.rb +195 -0
- data/app/helpers/spree/admin/onboarding_helper.rb +18 -0
- data/app/helpers/spree/admin/orders_filters_helper.rb +68 -0
- data/app/helpers/spree/admin/orders_helper.rb +179 -0
- data/app/helpers/spree/admin/page_builder_helper.rb +130 -0
- data/app/helpers/spree/admin/payments_helper.rb +24 -0
- data/app/helpers/spree/admin/posts_helper.rb +9 -0
- data/app/helpers/spree/admin/products_helper.rb +127 -0
- data/app/helpers/spree/admin/promotion_actions_helper.rb +10 -0
- data/app/helpers/spree/admin/promotion_rules_helper.rb +17 -0
- data/app/helpers/spree/admin/promotions_helper.rb +25 -0
- data/app/helpers/spree/admin/reimbursement_type_helper.rb +9 -0
- data/app/helpers/spree/admin/session_assets_helper.rb +24 -0
- data/app/helpers/spree/admin/shipment_helper.rb +27 -0
- data/app/helpers/spree/admin/sortable_tree_helper.rb +31 -0
- data/app/helpers/spree/admin/stock_locations_helper.rb +22 -0
- data/app/helpers/spree/admin/store_helper.rb +46 -0
- data/app/helpers/spree/admin/stores_helper.rb +86 -0
- data/app/helpers/spree/admin/tags_helper.rb +35 -0
- data/app/helpers/spree/admin/taxons_helper.rb +27 -0
- data/app/helpers/spree/admin/themes_helper.rb +9 -0
- data/app/helpers/spree/admin/translations_helper.rb +14 -0
- data/app/helpers/spree/admin/turbo_helper.rb +41 -0
- data/app/helpers/spree/admin/users_helper.rb +37 -0
- data/app/helpers/spree/admin/webhooks_subscribers_helper.rb +31 -0
- data/app/helpers/tom_select_helper.rb +42 -0
- data/app/javascript/spree/admin/application.js +157 -0
- data/app/javascript/spree/admin/controllers/active_storage_upload_controller.js +168 -0
- data/app/javascript/spree/admin/controllers/address_form_controller.js +98 -0
- data/app/javascript/spree/admin/controllers/asset_uploader_controller.js +58 -0
- data/app/javascript/spree/admin/controllers/autocomplete_select_controller.js +36 -0
- data/app/javascript/spree/admin/controllers/better_slider_controller.js +23 -0
- data/app/javascript/spree/admin/controllers/block_form_controller.js +11 -0
- data/app/javascript/spree/admin/controllers/bootstrap_tabs_controller.js +9 -0
- data/app/javascript/spree/admin/controllers/bulk_operation_controller.js +78 -0
- data/app/javascript/spree/admin/controllers/calculator_fields_controller.js +24 -0
- data/app/javascript/spree/admin/controllers/calendar_range_controller.js +52 -0
- data/app/javascript/spree/admin/controllers/clipboard_controller.js +17 -0
- data/app/javascript/spree/admin/controllers/color_palette_controller.js +22 -0
- data/app/javascript/spree/admin/controllers/color_picker_controller.js +52 -0
- data/app/javascript/spree/admin/controllers/enable_button_controller.js +29 -0
- data/app/javascript/spree/admin/controllers/filters_controller.js +66 -0
- data/app/javascript/spree/admin/controllers/font_picker_controller.js +55 -0
- data/app/javascript/spree/admin/controllers/media_form_controller.js +38 -0
- data/app/javascript/spree/admin/controllers/multi_input_controller.js +75 -0
- data/app/javascript/spree/admin/controllers/multi_tom_select_controller.js +80 -0
- data/app/javascript/spree/admin/controllers/order_billing_address_controller.js +39 -0
- data/app/javascript/spree/admin/controllers/page_builder_controller.js +316 -0
- data/app/javascript/spree/admin/controllers/password_toggle_controller.js +14 -0
- data/app/javascript/spree/admin/controllers/product_form_controller.js +70 -0
- data/app/javascript/spree/admin/controllers/range_input_controller.js +9 -0
- data/app/javascript/spree/admin/controllers/replace_controller.js +15 -0
- data/app/javascript/spree/admin/controllers/return_items_controller.js +47 -0
- data/app/javascript/spree/admin/controllers/row_link_controller.js +18 -0
- data/app/javascript/spree/admin/controllers/rule_form_controller.js +17 -0
- data/app/javascript/spree/admin/controllers/search_picker_controller.js +38 -0
- data/app/javascript/spree/admin/controllers/section_form_controller.js +14 -0
- data/app/javascript/spree/admin/controllers/select_controller.js +117 -0
- data/app/javascript/spree/admin/controllers/seo_form_controller.js +116 -0
- data/app/javascript/spree/admin/controllers/slug_form_controller.js +17 -0
- data/app/javascript/spree/admin/controllers/sortable_tree_controller.js +55 -0
- data/app/javascript/spree/admin/controllers/stock_transfer_controller.js +87 -0
- data/app/javascript/spree/admin/controllers/store_form_controller.js +17 -0
- data/app/javascript/spree/admin/controllers/unit_system_controller.js +27 -0
- data/app/javascript/spree/admin/controllers/variants_form_controller.js +1048 -0
- data/app/javascript/spree/admin/controllers/webhook_subscriber_events_controller.js +19 -0
- data/app/javascript/spree/admin/helpers/bootstrap.js +49 -0
- data/app/javascript/spree/admin/helpers/canvas.js +29 -0
- data/app/javascript/spree/admin/helpers/index.js +0 -0
- data/app/javascript/spree/admin/helpers/tinymce.js +65 -0
- data/app/javascript/spree/admin/helpers/trix/video_embed.js +182 -0
- data/app/javascript/spree/admin/helpers/uppy_active_storage.js +210 -0
- data/app/models/spree/admin/resource.rb +36 -0
- data/app/models/spree/admin/updater.rb +42 -0
- data/app/views/active_storage/_upload_form.html.erb +65 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_first_page.html.erb +13 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_gap.html.erb +12 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_last_page.html.erb +13 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_next_page.html.erb +13 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_page.html.erb +18 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_paginator.html.erb +17 -0
- data/app/views/kaminari/admin-twitter-bootstrap-4/_prev_page.html.erb +13 -0
- data/app/views/layouts/spree/admin.html.erb +21 -0
- data/app/views/layouts/spree/page_builder.html.erb +45 -0
- data/app/views/spree/admin/addresses/edit.html.erb +12 -0
- data/app/views/spree/admin/addresses/new.html.erb +16 -0
- data/app/views/spree/admin/assets/bulk_destroy.turbo_stream.erb +3 -0
- data/app/views/spree/admin/assets/create.turbo_stream.erb +5 -0
- data/app/views/spree/admin/assets/destroy.turbo_stream.erb +4 -0
- data/app/views/spree/admin/assets/edit.html.erb +27 -0
- data/app/views/spree/admin/assets/update.turbo_stream.erb +7 -0
- data/app/views/spree/admin/classifications/_classification.html.erb +38 -0
- data/app/views/spree/admin/classifications/create.turbo_stream.erb +7 -0
- data/app/views/spree/admin/classifications/destroy.turbo_stream.erb +2 -0
- data/app/views/spree/admin/classifications/index.html.erb +20 -0
- data/app/views/spree/admin/classifications/new.html.erb +1 -0
- data/app/views/spree/admin/coupon_codes/_coupon_code.html.erb +12 -0
- data/app/views/spree/admin/coupon_codes/index.csv.erb +14 -0
- data/app/views/spree/admin/coupon_codes/index.html.erb +70 -0
- data/app/views/spree/admin/custom_domains/_custom_domain.html.erb +13 -0
- data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +24 -0
- data/app/views/spree/admin/custom_domains/_form.html.erb +19 -0
- data/app/views/spree/admin/custom_domains/create.turbo_stream.erb +3 -0
- data/app/views/spree/admin/custom_domains/edit.html.erb +15 -0
- data/app/views/spree/admin/custom_domains/index.html.erb +50 -0
- data/app/views/spree/admin/custom_domains/new.html.erb +15 -0
- data/app/views/spree/admin/customer_returns/_customer_return.html.erb +31 -0
- data/app/views/spree/admin/customer_returns/index.html.erb +57 -0
- data/app/views/spree/admin/dashboard/_analytics.html.erb +3 -0
- data/app/views/spree/admin/dashboard/_setup_progress.html.erb +17 -0
- data/app/views/spree/admin/dashboard/_setup_tasks.html.erb +24 -0
- data/app/views/spree/admin/dashboard/_store_preview.html.erb +45 -0
- data/app/views/spree/admin/dashboard/_top_products.html.erb +71 -0
- data/app/views/spree/admin/dashboard/_updater.html.erb +9 -0
- data/app/views/spree/admin/dashboard/_visits.html.erb +112 -0
- data/app/views/spree/admin/dashboard/analytics.html.erb +118 -0
- data/app/views/spree/admin/dashboard/getting_started.html.erb +22 -0
- data/app/views/spree/admin/dashboard/setup_tasks/_add_products.html.erb +22 -0
- data/app/views/spree/admin/dashboard/setup_tasks/_set_customer_support_email.html.erb +23 -0
- data/app/views/spree/admin/dashboard/setup_tasks/_setup_payment_method.html.erb +6 -0
- data/app/views/spree/admin/dashboard/setup_tasks/_setup_taxes_collection.html.erb +6 -0
- data/app/views/spree/admin/dashboard/show.html.erb +33 -0
- data/app/views/spree/admin/digital_assets/_digital_asset.html.erb +30 -0
- data/app/views/spree/admin/digital_assets/_form.html.erb +18 -0
- data/app/views/spree/admin/digital_assets/_table.html.erb +40 -0
- data/app/views/spree/admin/digital_assets/create.turbo_stream.erb +2 -0
- data/app/views/spree/admin/digital_assets/edit.html.erb +22 -0
- data/app/views/spree/admin/digital_assets/index.html.erb +27 -0
- data/app/views/spree/admin/digital_assets/new.html.erb +22 -0
- data/app/views/spree/admin/digital_assets/update.turbo_stream.erb +2 -0
- data/app/views/spree/admin/exports/_export.html.erb +42 -0
- data/app/views/spree/admin/exports/create.turbo_stream.erb +2 -0
- data/app/views/spree/admin/exports/index.html.erb +30 -0
- data/app/views/spree/admin/exports/new.html.erb +42 -0
- data/app/views/spree/admin/line_items/edit.html.erb +20 -0
- data/app/views/spree/admin/line_items/new.html.erb +32 -0
- data/app/views/spree/admin/oauth_applications/_form.html.erb +11 -0
- data/app/views/spree/admin/oauth_applications/create.turbo_stream.erb +41 -0
- data/app/views/spree/admin/oauth_applications/edit.html.erb +19 -0
- data/app/views/spree/admin/oauth_applications/index.html.erb +75 -0
- data/app/views/spree/admin/oauth_applications/new.html.erb +25 -0
- data/app/views/spree/admin/option_types/_filter.html.erb +7 -0
- data/app/views/spree/admin/option_types/_form.html.erb +87 -0
- data/app/views/spree/admin/option_types/_option_type.html.erb +19 -0
- data/app/views/spree/admin/option_types/_option_value_fields.html.erb +29 -0
- data/app/views/spree/admin/option_types/edit.html.erb +11 -0
- data/app/views/spree/admin/option_types/index.html.erb +63 -0
- data/app/views/spree/admin/option_types/new.html.erb +11 -0
- data/app/views/spree/admin/option_types/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/option_values/destroy.turbo_stream.erb +1 -0
- data/app/views/spree/admin/orders/_body_custom.html.erb +0 -0
- data/app/views/spree/admin/orders/_customer.html.erb +79 -0
- data/app/views/spree/admin/orders/_customer_returns.html.erb +26 -0
- data/app/views/spree/admin/orders/_customer_summary.html.erb +22 -0
- data/app/views/spree/admin/orders/_extra_filters.html.erb +0 -0
- data/app/views/spree/admin/orders/_filters.html.erb +106 -0
- data/app/views/spree/admin/orders/_header.html.erb +76 -0
- data/app/views/spree/admin/orders/_header_custom.html.erb +0 -0
- data/app/views/spree/admin/orders/_line_item.html.erb +61 -0
- data/app/views/spree/admin/orders/_line_items.html.erb +68 -0
- data/app/views/spree/admin/orders/_list.html.erb +30 -0
- data/app/views/spree/admin/orders/_order.html.erb +28 -0
- data/app/views/spree/admin/orders/_payments.html.erb +35 -0
- data/app/views/spree/admin/orders/_refunds.html.erb +49 -0
- data/app/views/spree/admin/orders/_return_authorizations.html.erb +26 -0
- data/app/views/spree/admin/orders/_risk_analysis.html.erb +26 -0
- data/app/views/spree/admin/orders/_shipment.html.erb +104 -0
- data/app/views/spree/admin/orders/_shipment_manifest_item.html.erb +17 -0
- data/app/views/spree/admin/orders/_shipments.html.erb +22 -0
- data/app/views/spree/admin/orders/_summary.html.erb +100 -0
- data/app/views/spree/admin/orders/_summary_custom.html.erb +0 -0
- data/app/views/spree/admin/orders/_table_filter_dropdown.html.erb +34 -0
- data/app/views/spree/admin/orders/_tax_lines.html.erb +11 -0
- data/app/views/spree/admin/orders/_user_overview.html.erb +13 -0
- data/app/views/spree/admin/orders/billing_address/_form.html.erb +14 -0
- data/app/views/spree/admin/orders/billing_address/create.turbo_stream.erb +35 -0
- data/app/views/spree/admin/orders/billing_address/edit.html.erb +42 -0
- data/app/views/spree/admin/orders/billing_address/new.html.erb +35 -0
- data/app/views/spree/admin/orders/billing_address/update.turbo_stream.erb +35 -0
- data/app/views/spree/admin/orders/contact_information/edit.html.erb +20 -0
- data/app/views/spree/admin/orders/customer_returns/_customer_return.html.erb +70 -0
- data/app/views/spree/admin/orders/customer_returns/_reimbursements_table.html.erb +40 -0
- data/app/views/spree/admin/orders/customer_returns/_return_item_decision.html.erb +54 -0
- data/app/views/spree/admin/orders/customer_returns/_return_item_selection.html.erb +72 -0
- data/app/views/spree/admin/orders/customer_returns/edit.html.erb +144 -0
- data/app/views/spree/admin/orders/customer_returns/new.html.erb +67 -0
- data/app/views/spree/admin/orders/edit.html.erb +23 -0
- data/app/views/spree/admin/orders/index.html.erb +23 -0
- data/app/views/spree/admin/orders/return_authorizations/_form.html.erb +176 -0
- data/app/views/spree/admin/orders/return_authorizations/_return_authorization.html.erb +36 -0
- data/app/views/spree/admin/orders/return_authorizations/edit.html.erb +44 -0
- data/app/views/spree/admin/orders/return_authorizations/new.html.erb +13 -0
- data/app/views/spree/admin/orders/return_authorizations/show.html.erb +128 -0
- data/app/views/spree/admin/orders/shipping_address/_form.html.erb +13 -0
- data/app/views/spree/admin/orders/shipping_address/create.turbo_stream.erb +17 -0
- data/app/views/spree/admin/orders/shipping_address/edit.html.erb +17 -0
- data/app/views/spree/admin/orders/shipping_address/new.html.erb +17 -0
- data/app/views/spree/admin/orders/shipping_address/update.turbo_stream.erb +17 -0
- data/app/views/spree/admin/orders/user/create.turbo_stream.erb +12 -0
- data/app/views/spree/admin/orders/user/edit.html.erb +3 -0
- data/app/views/spree/admin/orders/user/new.html.erb +30 -0
- data/app/views/spree/admin/orders/user/update.turbo_stream.erb +5 -0
- data/app/views/spree/admin/page_blocks/_form_tab_buttons.html.erb +7 -0
- data/app/views/spree/admin/page_blocks/create.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_blocks/destroy.turbo_stream.erb +9 -0
- data/app/views/spree/admin/page_blocks/edit.html.erb +48 -0
- data/app/views/spree/admin/page_blocks/forms/_brand.html.erb +15 -0
- data/app/views/spree/admin/page_blocks/forms/_brand_logo.html.erb +4 -0
- data/app/views/spree/admin/page_blocks/forms/_buttons.html.erb +13 -0
- data/app/views/spree/admin/page_blocks/forms/_buy_buttons.html.erb +10 -0
- data/app/views/spree/admin/page_blocks/forms/_heading.html.erb +28 -0
- data/app/views/spree/admin/page_blocks/forms/_image.html.erb +1 -0
- data/app/views/spree/admin/page_blocks/forms/_link.html.erb +19 -0
- data/app/views/spree/admin/page_blocks/forms/_mega_nav.html.erb +14 -0
- data/app/views/spree/admin/page_blocks/forms/_mega_nav_with_subcategories.html.erb +9 -0
- data/app/views/spree/admin/page_blocks/forms/_nav.html.erb +6 -0
- data/app/views/spree/admin/page_blocks/forms/_newsletter_form.html.erb +20 -0
- data/app/views/spree/admin/page_blocks/forms/_price.html.erb +15 -0
- data/app/views/spree/admin/page_blocks/forms/_quantity_selector.html.erb +10 -0
- data/app/views/spree/admin/page_blocks/forms/_share.html.erb +5 -0
- data/app/views/spree/admin/page_blocks/forms/_subheading.html.erb +26 -0
- data/app/views/spree/admin/page_blocks/forms/_text.html.erb +21 -0
- data/app/views/spree/admin/page_blocks/forms/_title.html.erb +20 -0
- data/app/views/spree/admin/page_blocks/forms/_variant_picker.html.erb +10 -0
- data/app/views/spree/admin/page_blocks/move_higher.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_blocks/move_lower.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_blocks/show.html.erb +1 -0
- data/app/views/spree/admin/page_blocks/update.turbo_stream.erb +6 -0
- data/app/views/spree/admin/page_builder/_add_block.html.erb +20 -0
- data/app/views/spree/admin/page_builder/_color_palette.html.erb +17 -0
- data/app/views/spree/admin/page_builder/_color_picker.html.erb +26 -0
- data/app/views/spree/admin/page_builder/_header.html.erb +99 -0
- data/app/views/spree/admin/page_builder/_labeled_range_input.html.erb +10 -0
- data/app/views/spree/admin/page_builder/_pages_dropdown.html.erb +23 -0
- data/app/views/spree/admin/page_builder/_range_input.html.erb +12 -0
- data/app/views/spree/admin/page_builder/_sidebar.html.erb +14 -0
- data/app/views/spree/admin/page_builder/_sidebar_block.html.erb +29 -0
- data/app/views/spree/admin/page_builder/_sidebar_colors.html.erb +84 -0
- data/app/views/spree/admin/page_builder/_sidebar_fonts.html.erb +85 -0
- data/app/views/spree/admin/page_builder/_sidebar_section.html.erb +46 -0
- data/app/views/spree/admin/page_builder/_sidebar_sections.html.erb +33 -0
- data/app/views/spree/admin/page_builder/_sidebar_sections_toolbar.html.erb +65 -0
- data/app/views/spree/admin/page_links/_form.html.erb +19 -0
- data/app/views/spree/admin/page_links/_linkable_type_dropdown.html.erb +15 -0
- data/app/views/spree/admin/page_links/_list.html.erb +36 -0
- data/app/views/spree/admin/page_links/_refresh_theme_preview.turbo_stream.erb +5 -0
- data/app/views/spree/admin/page_links/create.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_links/destroy.turbo_stream.erb +11 -0
- data/app/views/spree/admin/page_links/edit.html.erb +18 -0
- data/app/views/spree/admin/page_links/update.turbo_stream.erb +6 -0
- data/app/views/spree/admin/page_sections/_form_tab_buttons.html.erb +12 -0
- data/app/views/spree/admin/page_sections/create.turbo_stream.erb +11 -0
- data/app/views/spree/admin/page_sections/destroy.turbo_stream.erb +16 -0
- data/app/views/spree/admin/page_sections/edit.html.erb +42 -0
- data/app/views/spree/admin/page_sections/fields/_background_color.html.erb +6 -0
- data/app/views/spree/admin/page_sections/fields/_border_bottom_width.html.erb +5 -0
- data/app/views/spree/admin/page_sections/fields/_border_color.html.erb +7 -0
- data/app/views/spree/admin/page_sections/fields/_border_top_width.html.erb +6 -0
- data/app/views/spree/admin/page_sections/fields/_bottom_padding.html.erb +5 -0
- data/app/views/spree/admin/page_sections/fields/_button.html.erb +15 -0
- data/app/views/spree/admin/page_sections/fields/_header_layout.html.erb +26 -0
- data/app/views/spree/admin/page_sections/fields/_height.html.erb +6 -0
- data/app/views/spree/admin/page_sections/fields/_text_color.html.erb +7 -0
- data/app/views/spree/admin/page_sections/fields/_top_padding.html.erb +6 -0
- data/app/views/spree/admin/page_sections/forms/_announcement_bar.html.erb +5 -0
- data/app/views/spree/admin/page_sections/forms/_brand_story.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_collection_banner.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_custom_code.html.erb +4 -0
- data/app/views/spree/admin/page_sections/forms/_featured_posts.html.erb +38 -0
- data/app/views/spree/admin/page_sections/forms/_featured_product.html.erb +4 -0
- data/app/views/spree/admin/page_sections/forms/_featured_taxon.html.erb +59 -0
- data/app/views/spree/admin/page_sections/forms/_featured_taxons.html.erb +13 -0
- data/app/views/spree/admin/page_sections/forms/_footer.html.erb +20 -0
- data/app/views/spree/admin/page_sections/forms/_header.html.erb +14 -0
- data/app/views/spree/admin/page_sections/forms/_image_banner.html.erb +13 -0
- data/app/views/spree/admin/page_sections/forms/_image_with_text.html.erb +31 -0
- data/app/views/spree/admin/page_sections/forms/_main_password_footer.html.erb +9 -0
- data/app/views/spree/admin/page_sections/forms/_main_password_header.erb +13 -0
- data/app/views/spree/admin/page_sections/forms/_newsletter.html.erb +15 -0
- data/app/views/spree/admin/page_sections/forms/_page_title.html.erb +4 -0
- data/app/views/spree/admin/page_sections/forms/_post_details.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_post_grid.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_product_details.html.erb +1 -0
- data/app/views/spree/admin/page_sections/forms/_product_grid.html.erb +1 -0
- data/app/views/spree/admin/page_sections/forms/_related_products.html.erb +32 -0
- data/app/views/spree/admin/page_sections/forms/_rich_text.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_taxon_banner.html.erb +0 -0
- data/app/views/spree/admin/page_sections/forms/_taxon_grid.html.erb +5 -0
- data/app/views/spree/admin/page_sections/forms/_video.html.erb +15 -0
- data/app/views/spree/admin/page_sections/move_higher.turbo_stream.erb +7 -0
- data/app/views/spree/admin/page_sections/move_lower.turbo_stream.erb +7 -0
- data/app/views/spree/admin/page_sections/new.html.erb +28 -0
- data/app/views/spree/admin/page_sections/remove_attachment.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_sections/restore_design_settings_to_defaults.turbo_stream.erb +4 -0
- data/app/views/spree/admin/page_sections/show.html.erb +1 -0
- data/app/views/spree/admin/page_sections/update.turbo_stream.erb +10 -0
- data/app/views/spree/admin/pages/_filters.html.erb +7 -0
- data/app/views/spree/admin/pages/_form.html.erb +29 -0
- data/app/views/spree/admin/pages/_page.erb +8 -0
- data/app/views/spree/admin/pages/edit.html.erb +18 -0
- data/app/views/spree/admin/pages/index.html.erb +28 -0
- data/app/views/spree/admin/pages/new.html.erb +11 -0
- data/app/views/spree/admin/payment_methods/_available_payment_method.html.erb +21 -0
- data/app/views/spree/admin/payment_methods/_check.html.erb +0 -0
- data/app/views/spree/admin/payment_methods/_form.html.erb +71 -0
- data/app/views/spree/admin/payment_methods/_payment_method.html.erb +38 -0
- data/app/views/spree/admin/payment_methods/descriptions/_check.html.erb +0 -0
- data/app/views/spree/admin/payment_methods/descriptions/_gateway.html.erb +1 -0
- data/app/views/spree/admin/payment_methods/descriptions/_store_credit.html.erb +1 -0
- data/app/views/spree/admin/payment_methods/edit.html.erb +10 -0
- data/app/views/spree/admin/payment_methods/index.html.erb +38 -0
- data/app/views/spree/admin/payment_methods/new.html.erb +12 -0
- data/app/views/spree/admin/payment_methods/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/payments/_payment.html.erb +89 -0
- data/app/views/spree/admin/payments/new.html.erb +64 -0
- data/app/views/spree/admin/payments/source_forms/_gateway.html.erb +54 -0
- data/app/views/spree/admin/payments/source_forms/_previous_cards.html.erb +21 -0
- data/app/views/spree/admin/payments/source_forms/_spree_stripe.html.erb +7 -0
- data/app/views/spree/admin/payments/source_forms/_store_credit.html.erb +22 -0
- data/app/views/spree/admin/payments/source_views/_check.html.erb +0 -0
- data/app/views/spree/admin/payments/source_views/_gateway.html.erb +22 -0
- data/app/views/spree/admin/payments/source_views/_storecredit.html.erb +31 -0
- data/app/views/spree/admin/post_categories/_form.html.erb +15 -0
- data/app/views/spree/admin/post_categories/_post_category.html.erb +6 -0
- data/app/views/spree/admin/post_categories/edit.html.erb +15 -0
- data/app/views/spree/admin/post_categories/index.html.erb +27 -0
- data/app/views/spree/admin/post_categories/new.html.erb +15 -0
- data/app/views/spree/admin/posts/_extra_actions.html.erb +0 -0
- data/app/views/spree/admin/posts/_filters.html.erb +40 -0
- data/app/views/spree/admin/posts/_form.html.erb +81 -0
- data/app/views/spree/admin/posts/_post.html.erb +32 -0
- data/app/views/spree/admin/posts/edit.html.erb +15 -0
- data/app/views/spree/admin/posts/index.html.erb +36 -0
- data/app/views/spree/admin/posts/new.html.erb +11 -0
- data/app/views/spree/admin/preferences/_password_field.html.erb +26 -0
- data/app/views/spree/admin/products/_bulk_operations.html.erb +122 -0
- data/app/views/spree/admin/products/_edit_page_title.html.erb +3 -0
- data/app/views/spree/admin/products/_empty_list.html.erb +1 -0
- data/app/views/spree/admin/products/_filters.html.erb +60 -0
- data/app/views/spree/admin/products/_form.html.erb +29 -0
- data/app/views/spree/admin/products/_import_button.html.erb +0 -0
- data/app/views/spree/admin/products/_index_header.html.erb +7 -0
- data/app/views/spree/admin/products/_list.html.erb +50 -0
- data/app/views/spree/admin/products/_product.html.erb +30 -0
- data/app/views/spree/admin/products/_product_status.html.erb +3 -0
- data/app/views/spree/admin/products/_search_result.html.erb +9 -0
- data/app/views/spree/admin/products/_search_results.html.erb +9 -0
- data/app/views/spree/admin/products/_table_filter_dropdown.html.erb +42 -0
- data/app/views/spree/admin/products/bulk_modal.html.erb +23 -0
- data/app/views/spree/admin/products/bulk_status_update.turbo_stream.erb +7 -0
- data/app/views/spree/admin/products/edit.html.erb +38 -0
- data/app/views/spree/admin/products/form/_base.html.erb +16 -0
- data/app/views/spree/admin/products/form/_categorization.html.erb +35 -0
- data/app/views/spree/admin/products/form/_extra_filters.html.erb +0 -0
- data/app/views/spree/admin/products/form/_extra_form.html.erb +0 -0
- data/app/views/spree/admin/products/form/_extra_form_sidebar.erb +0 -0
- data/app/views/spree/admin/products/form/_inventory.html.erb +63 -0
- data/app/views/spree/admin/products/form/_properties.html.erb +46 -0
- data/app/views/spree/admin/products/form/_shipping.html.erb +16 -0
- data/app/views/spree/admin/products/form/_status.html.erb +52 -0
- data/app/views/spree/admin/products/form/_stores.html.erb +27 -0
- data/app/views/spree/admin/products/form/_variants.html.erb +171 -0
- data/app/views/spree/admin/products/form/variants/_option_template.html.erb +59 -0
- data/app/views/spree/admin/products/form/variants/_variant_template.html.erb +44 -0
- data/app/views/spree/admin/products/index.html.erb +18 -0
- data/app/views/spree/admin/products/new.html.erb +9 -0
- data/app/views/spree/admin/profile/edit.html.erb +79 -0
- data/app/views/spree/admin/promotion_actions/_promotion_action.html.erb +45 -0
- data/app/views/spree/admin/promotion_actions/edit.html.erb +17 -0
- data/app/views/spree/admin/promotion_actions/forms/_create_adjustment.html.erb +1 -0
- data/app/views/spree/admin/promotion_actions/forms/_create_item_adjustments.html.erb +1 -0
- data/app/views/spree/admin/promotion_actions/forms/_create_line_items.html.erb +35 -0
- data/app/views/spree/admin/promotion_actions/forms/_create_line_items_row.html.erb +28 -0
- data/app/views/spree/admin/promotion_actions/forms/_free_shipping.html.erb +0 -0
- data/app/views/spree/admin/promotion_actions/new.html.erb +48 -0
- data/app/views/spree/admin/promotion_rules/_promotion_rule.html.erb +53 -0
- data/app/views/spree/admin/promotion_rules/edit.html.erb +17 -0
- data/app/views/spree/admin/promotion_rules/forms/_country.html.erb +7 -0
- data/app/views/spree/admin/promotion_rules/forms/_currency.html.erb +10 -0
- data/app/views/spree/admin/promotion_rules/forms/_first_order.html.erb +0 -0
- data/app/views/spree/admin/promotion_rules/forms/_item_total.html.erb +26 -0
- data/app/views/spree/admin/promotion_rules/forms/_one_use_per_user.html.erb +0 -0
- data/app/views/spree/admin/promotion_rules/forms/_option_value.html.erb +9 -0
- data/app/views/spree/admin/promotion_rules/forms/_product.html.erb +9 -0
- data/app/views/spree/admin/promotion_rules/forms/_taxon.html.erb +9 -0
- data/app/views/spree/admin/promotion_rules/forms/_user.html.erb +7 -0
- data/app/views/spree/admin/promotion_rules/forms/_user_logged_in.html.erb +0 -0
- data/app/views/spree/admin/promotion_rules/new.html.erb +48 -0
- data/app/views/spree/admin/promotions/_actions.html.erb +30 -0
- data/app/views/spree/admin/promotions/_form.html.erb +47 -0
- data/app/views/spree/admin/promotions/_header.html.erb +16 -0
- data/app/views/spree/admin/promotions/_promotion.html.erb +34 -0
- data/app/views/spree/admin/promotions/_rules.html.erb +44 -0
- data/app/views/spree/admin/promotions/_sidebar.html.erb +117 -0
- data/app/views/spree/admin/promotions/_status.html.erb +16 -0
- data/app/views/spree/admin/promotions/_table_filter_dropdown.html.erb +17 -0
- data/app/views/spree/admin/promotions/_usage_limit.html.erb +13 -0
- data/app/views/spree/admin/promotions/edit.html.erb +59 -0
- data/app/views/spree/admin/promotions/form/_kind.html.erb +57 -0
- data/app/views/spree/admin/promotions/form/_settings.html.erb +24 -0
- data/app/views/spree/admin/promotions/index.html.erb +62 -0
- data/app/views/spree/admin/promotions/new.html.erb +11 -0
- data/app/views/spree/admin/promotions/show.html.erb +12 -0
- data/app/views/spree/admin/properties/_form.html.erb +22 -0
- data/app/views/spree/admin/properties/_property.html.erb +25 -0
- data/app/views/spree/admin/properties/edit.html.erb +15 -0
- data/app/views/spree/admin/properties/index.html.erb +53 -0
- data/app/views/spree/admin/properties/new.html.erb +14 -0
- data/app/views/spree/admin/properties/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/refund_reasons/edit.html.erb +3 -0
- data/app/views/spree/admin/refund_reasons/index.html.erb +40 -0
- data/app/views/spree/admin/refund_reasons/new.html.erb +4 -0
- data/app/views/spree/admin/refunds/_form.html.erb +17 -0
- data/app/views/spree/admin/refunds/edit.html.erb +20 -0
- data/app/views/spree/admin/refunds/new.html.erb +29 -0
- data/app/views/spree/admin/reimbursement_types/_form.html.erb +30 -0
- data/app/views/spree/admin/reimbursement_types/edit.html.erb +15 -0
- data/app/views/spree/admin/reimbursement_types/index.html.erb +44 -0
- data/app/views/spree/admin/reimbursement_types/new.html.erb +16 -0
- data/app/views/spree/admin/reimbursements/edit.html.erb +130 -0
- data/app/views/spree/admin/reimbursements/show.html.erb +113 -0
- data/app/views/spree/admin/reports/_report.html.erb +22 -0
- data/app/views/spree/admin/reports/create.turbo_stream.erb +1 -0
- data/app/views/spree/admin/reports/index.html.erb +28 -0
- data/app/views/spree/admin/reports/new.html.erb +39 -0
- data/app/views/spree/admin/return_authorization_reasons/edit.html.erb +3 -0
- data/app/views/spree/admin/return_authorization_reasons/index.html.erb +45 -0
- data/app/views/spree/admin/return_authorization_reasons/new.html.erb +4 -0
- data/app/views/spree/admin/return_authorizations/_filters.html.erb +39 -0
- data/app/views/spree/admin/return_authorizations/_list.html.erb +30 -0
- data/app/views/spree/admin/return_authorizations/_return_authorization.html.erb +40 -0
- data/app/views/spree/admin/return_authorizations/index.html.erb +14 -0
- data/app/views/spree/admin/roles/_form.html.erb +6 -0
- data/app/views/spree/admin/roles/edit.html.erb +13 -0
- data/app/views/spree/admin/roles/index.html.erb +32 -0
- data/app/views/spree/admin/roles/new.html.erb +15 -0
- data/app/views/spree/admin/shared/_address.html.erb +42 -0
- data/app/views/spree/admin/shared/_alerts.html.erb +22 -0
- data/app/views/spree/admin/shared/_analytics_loader_skeleton.html.erb +76 -0
- data/app/views/spree/admin/shared/_audit_nav.html.erb +3 -0
- data/app/views/spree/admin/shared/_bulk_modal.html.erb +21 -0
- data/app/views/spree/admin/shared/_calculator_fields.html.erb +34 -0
- data/app/views/spree/admin/shared/_calendar_range_picker.html.erb +28 -0
- data/app/views/spree/admin/shared/_close_bulk_modal.turbo_stream.erb +2 -0
- data/app/views/spree/admin/shared/_content_header.html.erb +81 -0
- data/app/views/spree/admin/shared/_custom_head.html.erb +0 -0
- data/app/views/spree/admin/shared/_developers_nav.html.erb +7 -0
- data/app/views/spree/admin/shared/_edit_resource_links.html.erb +6 -0
- data/app/views/spree/admin/shared/_error_messages.html.erb +22 -0
- data/app/views/spree/admin/shared/_filter_badge_template.erb +3 -0
- data/app/views/spree/admin/shared/_filters_button.html.erb +8 -0
- data/app/views/spree/admin/shared/_filters_search_bar.html.erb +15 -0
- data/app/views/spree/admin/shared/_footer.html.erb +2 -0
- data/app/views/spree/admin/shared/_growth_rate_badge.html.erb +17 -0
- data/app/views/spree/admin/shared/_head.html.erb +52 -0
- data/app/views/spree/admin/shared/_header.html.erb +28 -0
- data/app/views/spree/admin/shared/_index_table_options.html.erb +22 -0
- data/app/views/spree/admin/shared/_map.html.erb +9 -0
- data/app/views/spree/admin/shared/_modal.html.erb +37 -0
- data/app/views/spree/admin/shared/_multi_product_picker.html.erb +26 -0
- data/app/views/spree/admin/shared/_new_resource_links.html.erb +3 -0
- data/app/views/spree/admin/shared/_no_image.html.erb +6 -0
- data/app/views/spree/admin/shared/_no_resource_found.html.erb +6 -0
- data/app/views/spree/admin/shared/_offcanvas_nav.html.erb +25 -0
- data/app/views/spree/admin/shared/_page_section_image.html.erb +1 -0
- data/app/views/spree/admin/shared/_page_section_logo.html.erb +1 -0
- data/app/views/spree/admin/shared/_posts_tabs.html.erb +8 -0
- data/app/views/spree/admin/shared/_preferences.html.erb +9 -0
- data/app/views/spree/admin/shared/_product_image.html.erb +21 -0
- data/app/views/spree/admin/shared/_refunds.html.erb +30 -0
- data/app/views/spree/admin/shared/_returns_and_refunds_nav.html.erb +9 -0
- data/app/views/spree/admin/shared/_seo.html.erb +39 -0
- data/app/views/spree/admin/shared/_shipping_nav.html.erb +4 -0
- data/app/views/spree/admin/shared/_sidebar.html.erb +15 -0
- data/app/views/spree/admin/shared/_spinner.html.erb +7 -0
- data/app/views/spree/admin/shared/_stock_nav.html.erb +4 -0
- data/app/views/spree/admin/shared/_tax_nav.html.erb +4 -0
- data/app/views/spree/admin/shared/_user.html.erb +24 -0
- data/app/views/spree/admin/shared/_user_dropdown.html.erb +41 -0
- data/app/views/spree/admin/shared/named_types/_edit.html.erb +15 -0
- data/app/views/spree/admin/shared/named_types/_form.html.erb +15 -0
- data/app/views/spree/admin/shared/named_types/_new.html.erb +15 -0
- data/app/views/spree/admin/shared/sidebar/_custom_nav.html.erb +0 -0
- data/app/views/spree/admin/shared/sidebar/_enterprise_edition_notice.html.erb +10 -0
- data/app/views/spree/admin/shared/sidebar/_integrations_nav.html.erb +7 -0
- data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +35 -0
- data/app/views/spree/admin/shared/sidebar/_products_nav.html.erb +41 -0
- data/app/views/spree/admin/shared/sidebar/_returns_nav.html.erb +20 -0
- data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +67 -0
- data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +176 -0
- data/app/views/spree/admin/shared/sidebar/_storefront_nav.html.erb +29 -0
- data/app/views/spree/admin/shared/sidebar/_vendors_nav.html.erb +8 -0
- data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +66 -0
- data/app/views/spree/admin/shipments/edit.html.erb +28 -0
- data/app/views/spree/admin/shipments/split.html.erb +16 -0
- data/app/views/spree/admin/shipping_categories/_form.html.erb +9 -0
- data/app/views/spree/admin/shipping_categories/edit.html.erb +11 -0
- data/app/views/spree/admin/shipping_categories/index.html.erb +36 -0
- data/app/views/spree/admin/shipping_categories/new.html.erb +13 -0
- data/app/views/spree/admin/shipping_methods/_actions.html.erb +5 -0
- data/app/views/spree/admin/shipping_methods/_form.html.erb +141 -0
- data/app/views/spree/admin/shipping_methods/_shipping_method.html.erb +33 -0
- data/app/views/spree/admin/shipping_methods/edit.html.erb +12 -0
- data/app/views/spree/admin/shipping_methods/index.html.erb +34 -0
- data/app/views/spree/admin/shipping_methods/new.html.erb +13 -0
- data/app/views/spree/admin/shipping_methods/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/stock_items/_filters.html.erb +39 -0
- data/app/views/spree/admin/stock_items/_stock_item.html.erb +43 -0
- data/app/views/spree/admin/stock_items/index.html.erb +38 -0
- data/app/views/spree/admin/stock_items/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/stock_locations/_form.html.erb +56 -0
- data/app/views/spree/admin/stock_locations/_stock_location.html.erb +30 -0
- data/app/views/spree/admin/stock_locations/edit.html.erb +9 -0
- data/app/views/spree/admin/stock_locations/index.html.erb +26 -0
- data/app/views/spree/admin/stock_locations/new.html.erb +11 -0
- data/app/views/spree/admin/stock_transfers/_destination_movement_form.html.erb +36 -0
- data/app/views/spree/admin/stock_transfers/_filters.html.erb +46 -0
- data/app/views/spree/admin/stock_transfers/_new_variant_modal.html.erb +30 -0
- data/app/views/spree/admin/stock_transfers/_new_variant_template.html.erb +8 -0
- data/app/views/spree/admin/stock_transfers/_source_movement_form.html.erb +8 -0
- data/app/views/spree/admin/stock_transfers/_stock_movement.html.erb +5 -0
- data/app/views/spree/admin/stock_transfers/_stock_transfer.html.erb +11 -0
- data/app/views/spree/admin/stock_transfers/index.html.erb +38 -0
- data/app/views/spree/admin/stock_transfers/new.html.erb +85 -0
- data/app/views/spree/admin/stock_transfers/show.html.erb +58 -0
- data/app/views/spree/admin/store_credit_categories/_form.html.erb +5 -0
- data/app/views/spree/admin/store_credit_categories/edit.html.erb +13 -0
- data/app/views/spree/admin/store_credit_categories/index.html.erb +32 -0
- data/app/views/spree/admin/store_credit_categories/new.html.erb +15 -0
- data/app/views/spree/admin/store_credits/_form.html.erb +24 -0
- data/app/views/spree/admin/store_credits/_list.html.erb +41 -0
- data/app/views/spree/admin/store_credits/edit.html.erb +36 -0
- data/app/views/spree/admin/store_credits/index.html.erb +20 -0
- data/app/views/spree/admin/store_credits/new.html.erb +26 -0
- data/app/views/spree/admin/storefront/edit.html.erb +146 -0
- data/app/views/spree/admin/stores/create.turbo_stream.erb +5 -0
- data/app/views/spree/admin/stores/edit.html.erb +13 -0
- data/app/views/spree/admin/stores/edit_emails.html.erb +11 -0
- data/app/views/spree/admin/stores/form/_basic.html.erb +160 -0
- data/app/views/spree/admin/stores/form/_buttons.html.erb +3 -0
- data/app/views/spree/admin/stores/form/_checkout.html.erb +50 -0
- data/app/views/spree/admin/stores/form/_custom.html.erb +0 -0
- data/app/views/spree/admin/stores/form/_emails.html.erb +59 -0
- data/app/views/spree/admin/stores/form/_policies.html.erb +85 -0
- data/app/views/spree/admin/stores/new.html.erb +135 -0
- data/app/views/spree/admin/stores/new.turbo_stream.erb +1 -0
- data/app/views/spree/admin/stores/update.turbo_stream.erb +11 -0
- data/app/views/spree/admin/tax_categories/_form.html.erb +25 -0
- data/app/views/spree/admin/tax_categories/_tax_category.html.erb +13 -0
- data/app/views/spree/admin/tax_categories/edit.html.erb +11 -0
- data/app/views/spree/admin/tax_categories/index.html.erb +30 -0
- data/app/views/spree/admin/tax_categories/new.html.erb +11 -0
- data/app/views/spree/admin/tax_rates/_form.html.erb +48 -0
- data/app/views/spree/admin/tax_rates/_tax_rate.html.erb +15 -0
- data/app/views/spree/admin/tax_rates/edit.html.erb +11 -0
- data/app/views/spree/admin/tax_rates/index.html.erb +32 -0
- data/app/views/spree/admin/tax_rates/new.html.erb +14 -0
- data/app/views/spree/admin/taxonomies/_taxonomy.html.erb +16 -0
- data/app/views/spree/admin/taxonomies/edit.html.erb +28 -0
- data/app/views/spree/admin/taxonomies/index.html.erb +40 -0
- data/app/views/spree/admin/taxonomies/new.html.erb +23 -0
- data/app/views/spree/admin/taxonomies/show.html.erb +28 -0
- data/app/views/spree/admin/taxons/_form.html.erb +148 -0
- data/app/views/spree/admin/taxons/_rule_form.html.erb +24 -0
- data/app/views/spree/admin/taxons/_rules_form.html.erb +34 -0
- data/app/views/spree/admin/taxons/destroy.turbo_stream.erb +1 -0
- data/app/views/spree/admin/taxons/edit.html.erb +19 -0
- data/app/views/spree/admin/taxons/new.html.erb +12 -0
- data/app/views/spree/admin/taxons/rule_forms/_available_on.html.erb +4 -0
- data/app/views/spree/admin/taxons/rule_forms/_sale.html.erb +4 -0
- data/app/views/spree/admin/taxons/rule_forms/_tag.html.erb +1 -0
- data/app/views/spree/admin/themes/_theme.html.erb +53 -0
- data/app/views/spree/admin/themes/_theme_preview_image.html.erb +24 -0
- data/app/views/spree/admin/themes/edit.html.erb +14 -0
- data/app/views/spree/admin/themes/index.html.erb +79 -0
- data/app/views/spree/admin/themes/update.turbo_stream.erb +1 -0
- data/app/views/spree/admin/translations/_translations_unavailable.html.erb +10 -0
- data/app/views/spree/admin/translations/edit.html.erb +47 -0
- data/app/views/spree/admin/translations/products/_form.html.erb +23 -0
- data/app/views/spree/admin/translations/stores/_form.html.erb +23 -0
- data/app/views/spree/admin/translations/taxonomies/_form.html.erb +20 -0
- data/app/views/spree/admin/translations/taxons/_form.html.erb +37 -0
- data/app/views/spree/admin/users/_billing.html.erb +78 -0
- data/app/views/spree/admin/users/_details.html.erb +52 -0
- data/app/views/spree/admin/users/_extra_actions.html.erb +0 -0
- data/app/views/spree/admin/users/_filters.html.erb +85 -0
- data/app/views/spree/admin/users/_form.html.erb +36 -0
- data/app/views/spree/admin/users/_last_order.html.erb +33 -0
- data/app/views/spree/admin/users/_last_order_line_item.html.erb +19 -0
- data/app/views/spree/admin/users/_lifetime_stats.html.erb +65 -0
- data/app/views/spree/admin/users/_shipping.html.erb +33 -0
- data/app/views/spree/admin/users/_tabs.html.erb +74 -0
- data/app/views/spree/admin/users/_user.html.erb +20 -0
- data/app/views/spree/admin/users/bulk_modal.html.erb +21 -0
- data/app/views/spree/admin/users/edit.html.erb +17 -0
- data/app/views/spree/admin/users/index.csv.erb +43 -0
- data/app/views/spree/admin/users/index.html.erb +102 -0
- data/app/views/spree/admin/users/new.html.erb +14 -0
- data/app/views/spree/admin/users/show.html.erb +38 -0
- data/app/views/spree/admin/variants/_search_result.html.erb +28 -0
- data/app/views/spree/admin/variants/_search_results.html.erb +9 -0
- data/app/views/spree/admin/variants/_variant.html.erb +13 -0
- data/app/views/spree/admin/variants/edit.html.erb +20 -0
- data/app/views/spree/admin/variants/form/_basic.html.erb +31 -0
- data/app/views/spree/admin/variants/form/_dimensions.html.erb +33 -0
- data/app/views/spree/admin/variants/form/_inventory.html.erb +45 -0
- data/app/views/spree/admin/variants/form/_media.html.erb +32 -0
- data/app/views/spree/admin/variants/form/_media_asset.html.erb +21 -0
- data/app/views/spree/admin/variants/form/_pricing.html.erb +48 -0
- data/app/views/spree/admin/webhook_events/_webhook_event.html.erb +17 -0
- data/app/views/spree/admin/webhooks_subscribers/_form.html.erb +66 -0
- data/app/views/spree/admin/webhooks_subscribers/_webhooks_subscriber.html.erb +16 -0
- data/app/views/spree/admin/webhooks_subscribers/edit.html.erb +9 -0
- data/app/views/spree/admin/webhooks_subscribers/index.html.erb +26 -0
- data/app/views/spree/admin/webhooks_subscribers/new.html.erb +11 -0
- data/app/views/spree/admin/webhooks_subscribers/show.html.erb +54 -0
- data/app/views/spree/admin/zones/_country_members.html.erb +16 -0
- data/app/views/spree/admin/zones/_form.html.erb +52 -0
- data/app/views/spree/admin/zones/_state_members.html.erb +21 -0
- data/app/views/spree/admin/zones/edit.html.erb +12 -0
- data/app/views/spree/admin/zones/index.html.erb +45 -0
- data/app/views/spree/admin/zones/new.html.erb +11 -0
- data/config/i18n-tasks.yml +190 -0
- data/config/importmap.rb +149 -0
- data/config/initializers/action_text.rb +8 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/chartkick.rb +5 -0
- data/config/initializers/dartsass.rb +3 -0
- data/config/initializers/form_builder.rb +10 -0
- data/config/initializers/ransack.rb +19 -0
- data/config/locales/en.yml +304 -0
- data/config/routes.rb +240 -0
- data/lib/generators/spree/admin/install/install_generator.rb +42 -0
- data/lib/generators/spree/admin/install/templates/dev +16 -0
- data/lib/spree/admin/action_callbacks.rb +27 -0
- data/lib/spree/admin/callbacks.rb +51 -0
- data/lib/spree/admin/engine.rb +51 -0
- data/lib/spree/admin/runtime_configuration.rb +12 -0
- data/lib/spree/admin/testing_support/capybara_utils.rb +45 -0
- data/lib/spree/admin.rb +23 -0
- data/lib/spree_admin.rb +18 -0
- data/vendor/javascript/@easepick--base-plugin.js +4 -0
- data/vendor/javascript/@easepick--core.js +4 -0
- data/vendor/javascript/@easepick--datetime.js +4 -0
- data/vendor/javascript/@easepick--preset-plugin.js +4 -0
- data/vendor/javascript/@easepick--range-plugin.js +4 -0
- data/vendor/javascript/@orchidjs--sifter.js +17 -0
- data/vendor/javascript/@orchidjs--unicode-variants.js +11 -0
- data/vendor/javascript/@rails--actiontext@7.2.201.js +4 -0
- data/vendor/javascript/@simonwep--pickr.js +4 -0
- data/vendor/javascript/@stimulus-components--rails-nested-form.js +4 -0
- data/vendor/javascript/bootstrap--dist--js--bootstrap.bundle.min.js.js +8 -0
- data/vendor/javascript/dompurify.js +139 -0
- data/vendor/javascript/hotkeys-js.js +4 -0
- data/vendor/javascript/jquery.min.js +2 -0
- data/vendor/javascript/local-time.js +4 -0
- data/vendor/javascript/sortablejs.js +136 -0
- data/vendor/javascript/stimulus-checkbox-select-all.js +4 -0
- data/vendor/javascript/stimulus-clipboard.js +4 -0
- data/vendor/javascript/stimulus-notification.js +4 -0
- data/vendor/javascript/stimulus-password-visibility.js +4 -0
- data/vendor/javascript/stimulus-reveal-controller.js +4 -0
- data/vendor/javascript/stimulus-sortable.js +4 -0
- data/vendor/javascript/stimulus-textarea-autogrow.js +4 -0
- data/vendor/javascript/stimulus-use.js +4 -0
- data/vendor/javascript/tom-select--dist--esm--tom-select.complete.js.js +32 -0
- data/vendor/javascript/trix@2.1.12.js +5 -0
- metadata +1084 -0
@@ -0,0 +1,1048 @@
|
|
1
|
+
import CheckboxSelectAll from 'stimulus-checkbox-select-all'
|
2
|
+
import { Sortable } from 'sortablejs'
|
3
|
+
import { get } from '@rails/request.js'
|
4
|
+
|
5
|
+
export default class extends CheckboxSelectAll {
|
6
|
+
static targets = [
|
7
|
+
'optionTemplate',
|
8
|
+
'optionValueTemplate',
|
9
|
+
'optionsContainer',
|
10
|
+
'optionFormTemplate',
|
11
|
+
'newOptionForm',
|
12
|
+
'newOptionValuesSelectContainer',
|
13
|
+
'newOptionValuesSelect',
|
14
|
+
'newOptionNameInput',
|
15
|
+
'newOptionButton',
|
16
|
+
'newOptionButtonLabel',
|
17
|
+
'option',
|
18
|
+
'variantsContainer',
|
19
|
+
'variantTemplate',
|
20
|
+
'variantsTable',
|
21
|
+
'deleteButton',
|
22
|
+
'checkboxAll',
|
23
|
+
'checkbox',
|
24
|
+
'stockItemsCount'
|
25
|
+
]
|
26
|
+
|
27
|
+
static values = {
|
28
|
+
productId: String,
|
29
|
+
options: Object,
|
30
|
+
availableOptions: Object,
|
31
|
+
variants: Array,
|
32
|
+
stock: Object,
|
33
|
+
prices: Object,
|
34
|
+
currentCurrency: String,
|
35
|
+
currencies: Array,
|
36
|
+
variantIds: Object,
|
37
|
+
currentStockLocationId: String,
|
38
|
+
stockLocations: Array,
|
39
|
+
optionValuesSelectOptions: Array
|
40
|
+
}
|
41
|
+
|
42
|
+
connect() {
|
43
|
+
super.connect()
|
44
|
+
this.optionNameOptions = this.newOptionNameInputTarget.options
|
45
|
+
this.sortable = new Sortable(this.optionsContainerTarget, {
|
46
|
+
group: 'options',
|
47
|
+
animation: 150,
|
48
|
+
onEnd: this.reorderOptions.bind(this),
|
49
|
+
handle: '.draggable',
|
50
|
+
filter: '.color-option',
|
51
|
+
draggable: '.options-creator__option'
|
52
|
+
})
|
53
|
+
this.ignoredVariants = new Set()
|
54
|
+
this.productFormController = this.application.getControllerForElementAndIdentifier(
|
55
|
+
this.element.closest('[data-controller*="product-form"]'),
|
56
|
+
'product-form'
|
57
|
+
)
|
58
|
+
this.currentOptionValues = {}
|
59
|
+
|
60
|
+
// Set ignoredVariants to all the variants that are not on the server
|
61
|
+
const existingVariantsOnServer = Object.keys(this.variantIdsValue)
|
62
|
+
if (existingVariantsOnServer.length > 0) {
|
63
|
+
this.ignoredVariants = new Set(
|
64
|
+
this.variantsValue
|
65
|
+
.map((variant) => variant.internalName)
|
66
|
+
.filter((internalName) => !existingVariantsOnServer.includes(internalName))
|
67
|
+
)
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
toggleQuantityTracked() {
|
72
|
+
this.element.querySelectorAll('.column-quantity').forEach((el) => el.classList.toggle('d-none'))
|
73
|
+
|
74
|
+
this.variantTemplateTarget.content
|
75
|
+
.querySelectorAll('.column-quantity')
|
76
|
+
.forEach((el) => el.classList.toggle('d-none'))
|
77
|
+
}
|
78
|
+
|
79
|
+
toggle(e) {
|
80
|
+
super.toggle(e)
|
81
|
+
this.toggleDeleteButton()
|
82
|
+
}
|
83
|
+
|
84
|
+
refresh() {
|
85
|
+
super.refresh()
|
86
|
+
|
87
|
+
// Set indeterminate state for parent checkboxes
|
88
|
+
this.element.querySelectorAll('input[id^="parent_checkbox_"]').forEach((checkbox) => {
|
89
|
+
checkbox.indeterminate = false
|
90
|
+
})
|
91
|
+
|
92
|
+
// Set checked state for parent checkboxes based on the amount of checked children
|
93
|
+
const firstOptionKeys = new Set(this.checked.map((c) => c.value.split('/')[0]))
|
94
|
+
firstOptionKeys.forEach((key) => {
|
95
|
+
const parentCheckbox = this.element.querySelector(`input[id="parent_checkbox_${key}"]`)
|
96
|
+
if (!parentCheckbox) return
|
97
|
+
|
98
|
+
const childCheckboxes = Array.from(this.element.querySelectorAll(`input[value^="${key}/"]`))
|
99
|
+
const allChildrenChecked = childCheckboxes.length > 0 && childCheckboxes.every((c) => c.checked)
|
100
|
+
|
101
|
+
parentCheckbox.checked = allChildrenChecked
|
102
|
+
parentCheckbox.indeterminate = !allChildrenChecked && childCheckboxes.some((c) => c.checked)
|
103
|
+
})
|
104
|
+
|
105
|
+
this.toggleDeleteButton()
|
106
|
+
}
|
107
|
+
|
108
|
+
toggleDeleteButton() {
|
109
|
+
if (this.checked.length > 0) {
|
110
|
+
this.deleteButtonTarget.classList.remove('d-none')
|
111
|
+
} else {
|
112
|
+
this.deleteButtonTarget.classList.add('d-none')
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
deleteSelected() {
|
117
|
+
const newStockValue = this.stockValue
|
118
|
+
const newPricesValue = this.pricesValue
|
119
|
+
this.checked.forEach((checkbox) => {
|
120
|
+
const internalName = checkbox.value
|
121
|
+
|
122
|
+
this.ignoredVariants.add(internalName)
|
123
|
+
const variant = this.variantsContainerTarget.querySelector(`[data-variant-name="${internalName}"]`)
|
124
|
+
|
125
|
+
const nestingLevel = internalName.split('/').length
|
126
|
+
if (nestingLevel === 1) {
|
127
|
+
const firstOptionKey = Object.keys(this.optionsValue)[0]
|
128
|
+
const newOptionValues = this.optionsValue[firstOptionKey].values.filter((value) => value !== internalName)
|
129
|
+
if (newOptionValues.length === 0) {
|
130
|
+
const newOptionsValue = this.optionsValue
|
131
|
+
delete newOptionsValue[firstOptionKey]
|
132
|
+
this.optionsValue = newOptionsValue
|
133
|
+
this.optionsContainerTarget.querySelector(`#option-${firstOptionKey}`).remove()
|
134
|
+
} else {
|
135
|
+
this.optionsValue = {
|
136
|
+
...this.optionsValue,
|
137
|
+
[firstOptionKey]: {
|
138
|
+
...this.optionsValue[firstOptionKey],
|
139
|
+
values: newOptionValues
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
this.optionsContainerTarget.querySelector(`#option-${firstOptionKey} [data-name="${internalName}"]`).remove()
|
144
|
+
}
|
145
|
+
checkbox.checked = false
|
146
|
+
}
|
147
|
+
|
148
|
+
delete newStockValue[internalName]
|
149
|
+
delete newPricesValue[internalName]
|
150
|
+
variant.remove()
|
151
|
+
})
|
152
|
+
|
153
|
+
this.stockValue = newStockValue
|
154
|
+
this.pricesValue = newPricesValue
|
155
|
+
|
156
|
+
this.checkboxAllTarget.checked = false
|
157
|
+
this.refresh()
|
158
|
+
this.refreshParentInputs()
|
159
|
+
}
|
160
|
+
|
161
|
+
reorderOptions(event) {
|
162
|
+
const optionId = event.item.id.replace('option-', '')
|
163
|
+
const newPosition = event.newDraggableIndex + 1
|
164
|
+
const oldPosition = event.oldDraggableIndex + 1
|
165
|
+
const options = Object.keys(this.optionsValue).reduce((acc, key) => {
|
166
|
+
if (key === optionId) {
|
167
|
+
acc[key] = { ...this.optionsValue[key], position: newPosition }
|
168
|
+
} else if (newPosition < oldPosition) {
|
169
|
+
if (this.optionsValue[key].position >= newPosition && this.optionsValue[key].position < oldPosition) {
|
170
|
+
acc[key] = { ...this.optionsValue[key], position: this.optionsValue[key].position + 1 }
|
171
|
+
} else {
|
172
|
+
acc[key] = this.optionsValue[key]
|
173
|
+
}
|
174
|
+
} else {
|
175
|
+
if (this.optionsValue[key].position > oldPosition && this.optionsValue[key].position <= newPosition) {
|
176
|
+
acc[key] = { ...this.optionsValue[key], position: this.optionsValue[key].position - 1 }
|
177
|
+
} else {
|
178
|
+
acc[key] = this.optionsValue[key]
|
179
|
+
}
|
180
|
+
}
|
181
|
+
return acc
|
182
|
+
}, {})
|
183
|
+
this.optionsValue = options
|
184
|
+
}
|
185
|
+
|
186
|
+
updateShopLocationCountOnHand() {
|
187
|
+
const inputs = this.variantsContainerTarget.querySelectorAll(
|
188
|
+
`input[data-slot='[stock_items_attributes][${this.currentStockLocationIdValue}][count_on_hand]_input'][name$='[count_on_hand]']`
|
189
|
+
)
|
190
|
+
|
191
|
+
const sum = Array.from(inputs).reduce((acc, input) => {
|
192
|
+
if (input.value === '') return acc
|
193
|
+
return acc + parseInt(input.value)
|
194
|
+
}, 0)
|
195
|
+
this.stockItemsCountTarget.textContent = sum
|
196
|
+
}
|
197
|
+
|
198
|
+
updateStockLocationId({ target: { value: newStockLocationId } }) {
|
199
|
+
newStockLocationId = String(newStockLocationId)
|
200
|
+
|
201
|
+
this.currentStockLocationIdValue = newStockLocationId
|
202
|
+
this.stockLocationsValue.forEach((stockLocationId) => {
|
203
|
+
this.variantsContainerTarget
|
204
|
+
.querySelectorAll(`input[data-slot='[stock_items_attributes][${stockLocationId}][count_on_hand]_input']`)
|
205
|
+
.forEach((el) => {
|
206
|
+
if (stockLocationId === newStockLocationId) {
|
207
|
+
el.classList.remove('d-none')
|
208
|
+
el.classList.add('d-block')
|
209
|
+
} else {
|
210
|
+
el.classList.remove('d-block')
|
211
|
+
el.classList.add('d-none')
|
212
|
+
}
|
213
|
+
})
|
214
|
+
})
|
215
|
+
this.updateShopLocationCountOnHand()
|
216
|
+
}
|
217
|
+
|
218
|
+
updateCurrency({ target: { value: newCurrency } }) {
|
219
|
+
this.currentCurrencyValue = newCurrency
|
220
|
+
this.currenciesValue.forEach((currency) => {
|
221
|
+
this.variantsContainerTarget
|
222
|
+
.querySelectorAll(
|
223
|
+
`.price-input-container:has(input[data-slot="[prices_attributes][${currency}][amount]_input"])`
|
224
|
+
)
|
225
|
+
.forEach((el) => {
|
226
|
+
if (currency === newCurrency) {
|
227
|
+
el.classList.remove('d-none')
|
228
|
+
el.classList.add('d-flex')
|
229
|
+
} else {
|
230
|
+
el.classList.remove('d-flex')
|
231
|
+
el.classList.add('d-none')
|
232
|
+
}
|
233
|
+
})
|
234
|
+
})
|
235
|
+
}
|
236
|
+
|
237
|
+
optionsValueChanged(value, previousValue) {
|
238
|
+
if (this.hasNewOptionButtonTarget) {
|
239
|
+
const label = this.newOptionButtonLabelTarget
|
240
|
+
|
241
|
+
if (Object.values(value).filter(Boolean).length) {
|
242
|
+
label.textContent = label.dataset.hasOptionsText
|
243
|
+
} else {
|
244
|
+
label.textContent = label.dataset.noOptionsText
|
245
|
+
}
|
246
|
+
}
|
247
|
+
this.refreshOptionNameSelect()
|
248
|
+
this.variantsValue = this.generateVariants(value)
|
249
|
+
|
250
|
+
// We want to clear the ignoredVariants when the options change
|
251
|
+
if (previousValue && Object.keys(previousValue).length === 0) return
|
252
|
+
this.ignoredVariants = new Set()
|
253
|
+
}
|
254
|
+
|
255
|
+
calculateVariantName(variant, keys, i) {
|
256
|
+
let name = ''
|
257
|
+
let internalName = name
|
258
|
+
if (i === 0) {
|
259
|
+
name = variant[keys[i]]
|
260
|
+
internalName = name
|
261
|
+
} else {
|
262
|
+
const namesPath = keys.slice(1, keys.length).map((key) => variant[key])
|
263
|
+
name = namesPath.join(' / ')
|
264
|
+
internalName = `${variant[keys[0]]}/${namesPath.join('/')}`
|
265
|
+
}
|
266
|
+
|
267
|
+
return { name, internalName }
|
268
|
+
}
|
269
|
+
|
270
|
+
updateParentCountOnHand(event) {
|
271
|
+
const { variantName } = event.target.closest('[data-variants-form-target="variant"]').dataset
|
272
|
+
const stockLocationId = event.target.dataset.stockLocationId
|
273
|
+
const childrenCountOnHand = this.variantsContainerTarget.querySelectorAll(
|
274
|
+
`[data-variant-name^="${variantName}/"] input[data-slot="[stock_items_attributes][${stockLocationId}][count_on_hand]_input"]`
|
275
|
+
)
|
276
|
+
const parentCountOnHand = event.target.value
|
277
|
+
|
278
|
+
childrenCountOnHand.forEach((countOnHandInput) => {
|
279
|
+
countOnHandInput.value = parentCountOnHand
|
280
|
+
})
|
281
|
+
|
282
|
+
const childrenCountOnHandKeys = this.variantsValue
|
283
|
+
.filter((variant) => variant.internalName.startsWith(variantName))
|
284
|
+
.map((variant) => variant.internalName)
|
285
|
+
|
286
|
+
childrenCountOnHandKeys.forEach((key) => {
|
287
|
+
this.updateStockItemForVariant(key, { count_on_hand: parentCountOnHand }, stockLocationId)
|
288
|
+
})
|
289
|
+
|
290
|
+
this.updateShopLocationCountOnHand()
|
291
|
+
}
|
292
|
+
|
293
|
+
updateParentPrice(event) {
|
294
|
+
const { variantName } = event.target.closest('[data-variants-form-target="variant"]').dataset
|
295
|
+
const currency = event.target.dataset.currency
|
296
|
+
const childrenPrices = this.variantsContainerTarget.querySelectorAll(
|
297
|
+
`[data-variant-name^="${variantName}/"] input[data-slot="[prices_attributes][${currency}][amount]_input"]`
|
298
|
+
)
|
299
|
+
const parentPrice = event.target.value
|
300
|
+
|
301
|
+
childrenPrices.forEach((priceInput) => {
|
302
|
+
priceInput.value = parentPrice
|
303
|
+
})
|
304
|
+
const childrenPricesKeys = this.variantsValue
|
305
|
+
.filter((variant) => variant.internalName.startsWith(variantName))
|
306
|
+
.map((variant) => variant.internalName)
|
307
|
+
|
308
|
+
childrenPricesKeys.forEach((key) => {
|
309
|
+
this.updatePriceForVariant(key, parentPrice, currency)
|
310
|
+
})
|
311
|
+
}
|
312
|
+
|
313
|
+
selectChildVariants(event) {
|
314
|
+
const { variantName } = event.target.closest('[data-variants-form-target="variant"]').dataset
|
315
|
+
|
316
|
+
const children = this.variantsContainerTarget.querySelectorAll(
|
317
|
+
`[data-variant-name^="${variantName}/"] input[type="checkbox"]`
|
318
|
+
)
|
319
|
+
|
320
|
+
children.forEach((child) => {
|
321
|
+
child.checked = event.target.checked
|
322
|
+
})
|
323
|
+
|
324
|
+
this.refresh()
|
325
|
+
}
|
326
|
+
|
327
|
+
prepareParentVariant(existingVariant, internalName) {
|
328
|
+
this.currenciesValue.forEach((currency) => {
|
329
|
+
const parentPriceInput = existingVariant.querySelector(
|
330
|
+
`input[data-slot="[prices_attributes][${currency}][amount]_input"]`
|
331
|
+
)
|
332
|
+
parentPriceInput.name = ''
|
333
|
+
parentPriceInput.dataset.action = `input->variants-form#updateParentPrice`
|
334
|
+
})
|
335
|
+
this.stockLocationsValue.forEach((stockLocationId) => {
|
336
|
+
const parentCountOnHandInput = existingVariant.querySelector(
|
337
|
+
`input[data-slot="[stock_items_attributes][${stockLocationId}][count_on_hand]_input"]`
|
338
|
+
)
|
339
|
+
parentCountOnHandInput.name = ''
|
340
|
+
parentCountOnHandInput.dataset.action = 'input->variants-form#updateParentCountOnHand'
|
341
|
+
})
|
342
|
+
|
343
|
+
const checkbox = existingVariant.querySelector('input[type="checkbox"][id^="checkbox_"]')
|
344
|
+
if (!checkbox) return
|
345
|
+
const checkboxLabel = existingVariant.querySelector('label[for^="checkbox_"]')
|
346
|
+
checkbox.id = `parent_checkbox_${internalName}`
|
347
|
+
checkboxLabel.htmlFor = `parent_checkbox_${internalName}`
|
348
|
+
checkbox.dataset.action = 'click->variants-form#selectChildVariants'
|
349
|
+
checkbox.value = internalName
|
350
|
+
}
|
351
|
+
|
352
|
+
updatePrice(event) {
|
353
|
+
const { variantName } = event.target.closest('[data-variants-form-target="variant"]').dataset
|
354
|
+
const currency = event.target.dataset.currency
|
355
|
+
const nestingLevel = variantName.split('/').length
|
356
|
+
this.updatePriceForVariant(variantName, event.target.value, currency)
|
357
|
+
if (nestingLevel > 1) {
|
358
|
+
const parentName = variantName.split('/')[0]
|
359
|
+
this.updateParentPriceRange(parentName, currency)
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
replaceBlankWithZero(event) {
|
364
|
+
if (event.target.value === '') {
|
365
|
+
event.target.value = 0
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
updateCountOnHand(event) {
|
370
|
+
const variantEl = event.target.closest('[data-variants-form-target="variant"]')
|
371
|
+
const variantName = variantEl.dataset.variantName
|
372
|
+
|
373
|
+
const nestingLevel = variantName.split('/').length
|
374
|
+
const stockLocationId = event.target.dataset.stockLocationId
|
375
|
+
const countOnHand = event.target.value || 0
|
376
|
+
|
377
|
+
this.updateStockItemForVariant(variantName, { count_on_hand: countOnHand }, stockLocationId)
|
378
|
+
|
379
|
+
if (nestingLevel > 1) {
|
380
|
+
const parentName = variantName.split('/')[0]
|
381
|
+
this.updateParentStockSum(parentName, stockLocationId)
|
382
|
+
}
|
383
|
+
|
384
|
+
this.updateShopLocationCountOnHand()
|
385
|
+
}
|
386
|
+
|
387
|
+
updateParentPriceRange(variantName, currency) {
|
388
|
+
const parentPriceEl = this.variantsContainerTarget.querySelector(
|
389
|
+
`div:not(.nested)[data-variant-name="${variantName}"] [data-slot="[prices_attributes][${currency}][amount]_input"]`
|
390
|
+
)
|
391
|
+
if (!parentPriceEl) return
|
392
|
+
|
393
|
+
const currentVariantKeys = Array.from(
|
394
|
+
this.variantsContainerTarget.querySelectorAll(`[data-variant-name^="${variantName}/"]`)
|
395
|
+
).map((el) => el.dataset.variantName)
|
396
|
+
|
397
|
+
const pricesVariation = new Set(
|
398
|
+
Object.keys(this.pricesValue)
|
399
|
+
.filter((key) => currentVariantKeys.includes(key))
|
400
|
+
.map((key) => this.priceForVariant(key, currency).amount)
|
401
|
+
)
|
402
|
+
|
403
|
+
pricesVariation.delete(null)
|
404
|
+
|
405
|
+
if (pricesVariation.size === 0) {
|
406
|
+
parentPriceEl.value = this.priceForVariant(variantName, currency).amount
|
407
|
+
parentPriceEl.placeholder = ''
|
408
|
+
return
|
409
|
+
}
|
410
|
+
const minPrice = Math.min(...pricesVariation)
|
411
|
+
const maxPrice = Math.max(...pricesVariation)
|
412
|
+
|
413
|
+
if (minPrice !== maxPrice) {
|
414
|
+
parentPriceEl.value = null
|
415
|
+
parentPriceEl.placeholder = `${minPrice} - ${maxPrice}`
|
416
|
+
} else {
|
417
|
+
parentPriceEl.value = minPrice
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
updateParentStockSum(variantName, stockLocationId) {
|
422
|
+
const parentStockEl = this.variantsContainerTarget.querySelector(
|
423
|
+
`div:not(.nested)[data-variant-name="${variantName}"] [data-slot="[stock_items_attributes][${stockLocationId}][count_on_hand]_input"]`
|
424
|
+
)
|
425
|
+
if (!parentStockEl) return
|
426
|
+
|
427
|
+
const currentVariantKeys = Array.from(
|
428
|
+
this.variantsContainerTarget.querySelectorAll(`[data-variant-name^="${variantName}/"]`)
|
429
|
+
).map((el) => el.dataset.variantName)
|
430
|
+
|
431
|
+
if (currentVariantKeys.length === 0) {
|
432
|
+
parentStockEl.value = this.stockItemForVariant(variantName, stockLocationId).count_on_hand
|
433
|
+
parentStockEl.placeholder = ''
|
434
|
+
this.updateShopLocationCountOnHand()
|
435
|
+
return
|
436
|
+
}
|
437
|
+
|
438
|
+
const countsOnHand = Object.keys(this.stockValue)
|
439
|
+
.filter((key) => currentVariantKeys.includes(key))
|
440
|
+
.map((key) => this.stockItemForVariant(key, stockLocationId).count_on_hand)
|
441
|
+
|
442
|
+
const sum = countsOnHand.reduce((acc, value) => acc + parseInt(value) || 0, 0)
|
443
|
+
|
444
|
+
parentStockEl.placeholder = String(sum)
|
445
|
+
parentStockEl.value = null
|
446
|
+
}
|
447
|
+
|
448
|
+
variantsValueChanged() {
|
449
|
+
let keys = Object.keys(this.variantsValue[0] || {}).filter((key) => key !== 'internalName')
|
450
|
+
|
451
|
+
const currentVariants = new Set()
|
452
|
+
|
453
|
+
if (keys.length) {
|
454
|
+
this.variantsTableTarget.classList.remove('d-none')
|
455
|
+
|
456
|
+
const nestingLevel = Math.min(keys.length, 2)
|
457
|
+
let idx = 0
|
458
|
+
|
459
|
+
for (let i = 0; i < nestingLevel; i++) {
|
460
|
+
this.variantsValue.forEach((variant) => {
|
461
|
+
const { name, internalName } = this.calculateVariantName(variant, keys, i)
|
462
|
+
if (currentVariants.has(internalName) || this.ignoredVariants.has(internalName)) {
|
463
|
+
idx++
|
464
|
+
return
|
465
|
+
}
|
466
|
+
currentVariants.add(internalName)
|
467
|
+
|
468
|
+
const existingVariant = this.variantsContainerTarget.querySelector(`[data-variant-name="${internalName}"]`)
|
469
|
+
if (existingVariant) {
|
470
|
+
if (i === 0 && nestingLevel > 1) {
|
471
|
+
existingVariant.querySelectorAll("input[type='hidden']").forEach((input) => input.remove())
|
472
|
+
|
473
|
+
this.prepareParentVariant(existingVariant, internalName)
|
474
|
+
}
|
475
|
+
idx++
|
476
|
+
return
|
477
|
+
}
|
478
|
+
|
479
|
+
const template = this.variantTemplateTarget.content.cloneNode(true)
|
480
|
+
const variantNameContainer = template.querySelector('[data-slot="variantName"]')
|
481
|
+
const variantTarget = template.querySelector('[data-variants-form-target="variant"]')
|
482
|
+
variantTarget.dataset.variantName = internalName
|
483
|
+
|
484
|
+
const variantId = this.variantIdsValue[internalName]
|
485
|
+
if (variantId) {
|
486
|
+
const variantEditButton = variantTarget.querySelector('[data-slot="variantEditButton"]')
|
487
|
+
|
488
|
+
if (variantEditButton) {
|
489
|
+
variantEditButton.href = `/admin/products/${this.productIdValue}/variants/${variantId}/edit`
|
490
|
+
variantEditButton.classList.remove('invisible')
|
491
|
+
}
|
492
|
+
}
|
493
|
+
|
494
|
+
let previousVariant = null
|
495
|
+
|
496
|
+
if (i > 0) {
|
497
|
+
const { internalName: parentInternalName } = this.calculateVariantName(variant, keys, 0)
|
498
|
+
const variantsInThisGroup = this.variantsContainerTarget.querySelectorAll(
|
499
|
+
`[data-variant-name^="${parentInternalName}/"]`
|
500
|
+
)
|
501
|
+
if (variantsInThisGroup.length > 0) {
|
502
|
+
// If there are already variants in this option type then we want to render this variant after the last variant in the group
|
503
|
+
previousVariant = variantsInThisGroup[variantsInThisGroup.length - 1]
|
504
|
+
} else {
|
505
|
+
// Otherwise we want to render this variant after the parent variant
|
506
|
+
previousVariant = this.variantsContainerTarget.querySelector(
|
507
|
+
`[data-variant-name="${parentInternalName}"]`
|
508
|
+
)
|
509
|
+
}
|
510
|
+
variantTarget.classList.add('nested')
|
511
|
+
} else if (nestingLevel > 1) {
|
512
|
+
template.querySelectorAll("input[type='hidden']").forEach((input) => input.remove())
|
513
|
+
this.prepareParentVariant(template, internalName)
|
514
|
+
}
|
515
|
+
|
516
|
+
if (i === nestingLevel - 1) {
|
517
|
+
const inputs = this.createInputsForVariant(keys, variant, idx)
|
518
|
+
inputs.forEach((input) => {
|
519
|
+
variantTarget.appendChild(input)
|
520
|
+
})
|
521
|
+
|
522
|
+
const checkbox = template.querySelector('input[type="checkbox"]#checkbox_')
|
523
|
+
if (checkbox) {
|
524
|
+
const checkboxLabel = template.querySelector('label[for="checkbox_"]')
|
525
|
+
checkbox.id = `checkbox_${internalName}`
|
526
|
+
checkboxLabel.htmlFor = `checkbox_${internalName}`
|
527
|
+
checkbox.value = internalName
|
528
|
+
}
|
529
|
+
|
530
|
+
this.preparePriceInputs(variantTarget, internalName, idx)
|
531
|
+
|
532
|
+
this.prepareStockInputs(variantTarget, internalName, idx)
|
533
|
+
}
|
534
|
+
idx++
|
535
|
+
|
536
|
+
variantNameContainer.textContent = name
|
537
|
+
if (previousVariant) {
|
538
|
+
previousVariant.after(template)
|
539
|
+
} else {
|
540
|
+
this.variantsContainerTarget.appendChild(template)
|
541
|
+
}
|
542
|
+
})
|
543
|
+
}
|
544
|
+
} else {
|
545
|
+
this.variantsTableTarget.classList.add('d-none')
|
546
|
+
}
|
547
|
+
|
548
|
+
this.variantsContainerTarget.querySelectorAll('[data-variants-form-target="variant"]').forEach((variant) => {
|
549
|
+
const variantName = variant.dataset.variantName
|
550
|
+
if (!currentVariants.has(variantName)) {
|
551
|
+
variant.remove()
|
552
|
+
}
|
553
|
+
})
|
554
|
+
|
555
|
+
// When going back from variant edit page the `variantsValueChanged` method is called before the `connect` method, so `this.productFormController` is not set yet
|
556
|
+
if (this.productFormController) {
|
557
|
+
this.productFormController.hasVariantsValue = this.variantsValue.length > 0
|
558
|
+
}
|
559
|
+
|
560
|
+
this.refreshParentInputs()
|
561
|
+
}
|
562
|
+
|
563
|
+
refreshParentInputs() {
|
564
|
+
const firstOption = Object.values(this.optionsValue)[0]
|
565
|
+
if (firstOption) {
|
566
|
+
firstOption.values.forEach((name) => {
|
567
|
+
this.currenciesValue.forEach((currency) => {
|
568
|
+
this.updateParentPriceRange(name, currency)
|
569
|
+
})
|
570
|
+
this.stockLocationsValue.forEach((stockLocationId) => {
|
571
|
+
this.updateParentStockSum(name, stockLocationId)
|
572
|
+
})
|
573
|
+
this.updateShopLocationCountOnHand()
|
574
|
+
})
|
575
|
+
}
|
576
|
+
}
|
577
|
+
|
578
|
+
createInputsForVariant(keys, variant, i) {
|
579
|
+
const inputs = []
|
580
|
+
if (this.variantIdsValue[variant.internalName]) {
|
581
|
+
const idInput = document.createElement('input')
|
582
|
+
idInput.type = 'hidden'
|
583
|
+
idInput.name = `product[variants_attributes][${i}][id]`
|
584
|
+
idInput.value = this.variantIdsValue[variant.internalName]
|
585
|
+
inputs.push(idInput)
|
586
|
+
}
|
587
|
+
|
588
|
+
keys.forEach((key) => {
|
589
|
+
const nameInput = document.createElement('input')
|
590
|
+
nameInput.type = 'hidden'
|
591
|
+
nameInput.name = `product[variants_attributes][${i}][options][][name]`
|
592
|
+
nameInput.value = key
|
593
|
+
inputs.push(nameInput)
|
594
|
+
|
595
|
+
const positionInput = document.createElement('input')
|
596
|
+
positionInput.type = 'hidden'
|
597
|
+
positionInput.name = `product[variants_attributes][${i}][options][][position]`
|
598
|
+
positionInput.value = Object.values(this.optionsValue)
|
599
|
+
.filter(Boolean)
|
600
|
+
.find((option) => option.name === key).position
|
601
|
+
inputs.push(positionInput)
|
602
|
+
|
603
|
+
const valueInput = document.createElement('input')
|
604
|
+
valueInput.type = 'hidden'
|
605
|
+
valueInput.name = `product[variants_attributes][${i}][options][][value]`
|
606
|
+
valueInput.value = variant[key]
|
607
|
+
inputs.push(valueInput)
|
608
|
+
})
|
609
|
+
|
610
|
+
return inputs
|
611
|
+
}
|
612
|
+
|
613
|
+
prepareStockInputs(variantTarget, internalName, idx) {
|
614
|
+
this.stockLocationsValue.forEach((stockLocationId) => {
|
615
|
+
const stockInput = variantTarget.querySelector(
|
616
|
+
`input[data-slot="[stock_items_attributes][${stockLocationId}][count_on_hand]_input"]`
|
617
|
+
)
|
618
|
+
const stockIdInput = variantTarget.querySelector(
|
619
|
+
`input[data-slot="[stock_items_attributes][${stockLocationId}][id]_input"]`
|
620
|
+
)
|
621
|
+
const stockLocationIdInput = variantTarget.querySelector(
|
622
|
+
`input[data-slot="[stock_items_attributes][${stockLocationId}][stock_location_id]_input"]`
|
623
|
+
)
|
624
|
+
let stockItem = this.stockItemForVariant(internalName, stockLocationId)
|
625
|
+
if (!stockItem.id) {
|
626
|
+
const oldInternalName = internalName.split('/').slice(0, -1).join('/')
|
627
|
+
const oldStock = this.stockItemForVariant(oldInternalName, stockLocationId).count_on_hand ?? 0
|
628
|
+
|
629
|
+
stockItem.count_on_hand = oldStock
|
630
|
+
|
631
|
+
this.updateStockItemForVariant(internalName, stockItem, stockLocationId)
|
632
|
+
}
|
633
|
+
|
634
|
+
stockInput.name = `product[variants_attributes][${idx}][stock_items_attributes][${stockLocationId}][count_on_hand]`
|
635
|
+
stockLocationIdInput.name = `product[variants_attributes][${idx}][stock_items_attributes][${stockLocationId}][stock_location_id]`
|
636
|
+
stockIdInput.name = `product[variants_attributes][${idx}][stock_items_attributes][${stockLocationId}][id]`
|
637
|
+
|
638
|
+
stockInput.value = stockItem.count_on_hand
|
639
|
+
if (String(stockLocationId) === String(this.currentStockLocationIdValue)) {
|
640
|
+
stockInput.classList.remove('d-none')
|
641
|
+
stockInput.classList.add('d-block')
|
642
|
+
} else {
|
643
|
+
stockInput.classList.remove('d-block')
|
644
|
+
stockInput.classList.add('d-none')
|
645
|
+
}
|
646
|
+
if (stockItem.id) {
|
647
|
+
stockIdInput.value = stockItem.id
|
648
|
+
}
|
649
|
+
})
|
650
|
+
}
|
651
|
+
|
652
|
+
preparePriceInputs(variantTarget, internalName, idx) {
|
653
|
+
this.currenciesValue.forEach((currency, currencyIndex) => {
|
654
|
+
const priceInput = variantTarget.querySelector(
|
655
|
+
`input[data-slot="[prices_attributes][${currency}][amount]_input"]`
|
656
|
+
)
|
657
|
+
const currencyInput = variantTarget.querySelector(
|
658
|
+
`input[data-slot="[prices_attributes][${currency}][currency]_input"]`
|
659
|
+
)
|
660
|
+
const idInput = variantTarget.querySelector(`input[data-slot="[prices_attributes][${currency}][id]_input"]`)
|
661
|
+
priceInput.name = `product[variants_attributes][${idx}][prices_attributes][${currency}]`
|
662
|
+
if (currency === this.currentCurrencyValue) {
|
663
|
+
priceInput.parentElement.classList.remove('d-none')
|
664
|
+
priceInput.parentElement.classList.add('d-flex')
|
665
|
+
} else {
|
666
|
+
priceInput.parentElement.classList.remove('d-flex')
|
667
|
+
priceInput.parentElement.classList.add('d-none')
|
668
|
+
}
|
669
|
+
|
670
|
+
const existingPrice = this.priceForVariant(internalName, currency)
|
671
|
+
priceInput.value = existingPrice.amount
|
672
|
+
currencyInput.value = currency
|
673
|
+
if (existingPrice.id) {
|
674
|
+
idInput.value = existingPrice.id
|
675
|
+
}
|
676
|
+
|
677
|
+
priceInput.name = `product[variants_attributes][${idx}][prices_attributes][${currencyIndex}][amount]`
|
678
|
+
currencyInput.name = `product[variants_attributes][${idx}][prices_attributes][${currencyIndex}][currency]`
|
679
|
+
idInput.name = `product[variants_attributes][${idx}][prices_attributes][${currencyIndex}][id]`
|
680
|
+
})
|
681
|
+
}
|
682
|
+
|
683
|
+
addOption(name, option_values = [], id) {
|
684
|
+
let color = false
|
685
|
+
let position = Object.keys(this.optionsValue).length + 1
|
686
|
+
let newOptionsPositions = {}
|
687
|
+
|
688
|
+
const template = this.optionTemplate(name, option_values, id, color)
|
689
|
+
|
690
|
+
this.optionsValue = {
|
691
|
+
...this.optionsValue,
|
692
|
+
...newOptionsPositions,
|
693
|
+
[id]: {
|
694
|
+
name,
|
695
|
+
values: option_values,
|
696
|
+
position: position
|
697
|
+
}
|
698
|
+
}
|
699
|
+
|
700
|
+
if (position === 1) {
|
701
|
+
this.optionsContainerTarget.prepend(document.importNode(template, true))
|
702
|
+
} else {
|
703
|
+
this.optionsContainerTarget.appendChild(document.importNode(template, true))
|
704
|
+
}
|
705
|
+
}
|
706
|
+
|
707
|
+
// After selecting an option name (eg. "Color"), we fetch the option values for that option name and update the tom select options
|
708
|
+
async handleSelectedOptionName(event) {
|
709
|
+
const targetInput = event.target
|
710
|
+
this.lastOptionNameId = targetInput.value
|
711
|
+
|
712
|
+
if (this.lastOptionNameId) {
|
713
|
+
const response = await get(`/admin/option_types/${this.lastOptionNameId}/option_values/select_options`)
|
714
|
+
|
715
|
+
if (response.ok) {
|
716
|
+
this.currentOptionValues[this.lastOptionNameId] = await response.json
|
717
|
+
|
718
|
+
const optionsCreatorContainer = targetInput.closest('.options-creator__option')
|
719
|
+
const newOptionValuesSelects = optionsCreatorContainer.querySelectorAll('[data-variants-form-target="newOptionValuesSelect"]')
|
720
|
+
|
721
|
+
newOptionValuesSelects.forEach((select) => this.replaceSelectOptions(select))
|
722
|
+
}
|
723
|
+
}
|
724
|
+
}
|
725
|
+
|
726
|
+
replaceSelectOptions(select) {
|
727
|
+
const tomSelect = select.tomselect
|
728
|
+
|
729
|
+
if (tomSelect) {
|
730
|
+
tomSelect.clear()
|
731
|
+
tomSelect.clearOptions()
|
732
|
+
tomSelect.addOptions(this.currentOptionValues[this.lastOptionNameId])
|
733
|
+
}
|
734
|
+
}
|
735
|
+
|
736
|
+
newOptionValuesSelectTargetConnected(select) {
|
737
|
+
if (this.lastOptionNameId)
|
738
|
+
this.replaceSelectOptions(select)
|
739
|
+
}
|
740
|
+
|
741
|
+
handleNewOption(_event) {
|
742
|
+
const newOptionName = this.newOptionNameInputTarget.options[this.newOptionNameInputTarget.selectedIndex].text
|
743
|
+
const newOptionId = String(this.newOptionNameInputTarget.value)
|
744
|
+
const newOptionValues = this.newOptionValuesSelectContainerTarget.values()
|
745
|
+
|
746
|
+
if (
|
747
|
+
!newOptionName.length ||
|
748
|
+
this.optionsValue[newOptionId] ||
|
749
|
+
newOptionValues.length === 0 ||
|
750
|
+
Object.values(this.optionsValue)
|
751
|
+
.filter(Boolean)
|
752
|
+
.map((v) => v.name)
|
753
|
+
.includes(newOptionName)
|
754
|
+
) {
|
755
|
+
return
|
756
|
+
}
|
757
|
+
|
758
|
+
this.addOption(newOptionName, newOptionValues, newOptionId)
|
759
|
+
|
760
|
+
this.hideNewOptionForm()
|
761
|
+
}
|
762
|
+
|
763
|
+
hideNewOptionForm() {
|
764
|
+
this.newOptionNameInputTarget.tomselect.clear()
|
765
|
+
this.newOptionValuesSelectContainerTarget.reset()
|
766
|
+
|
767
|
+
this.newOptionFormTarget.classList.add('d-none')
|
768
|
+
|
769
|
+
this.newOptionButtonTarget.classList.remove('d-none')
|
770
|
+
}
|
771
|
+
|
772
|
+
editOption(event) {
|
773
|
+
let { optionId } = event.params
|
774
|
+
optionId = String(optionId)
|
775
|
+
|
776
|
+
const option = this.optionsContainerTarget.querySelector(`#option-${optionId}`)
|
777
|
+
|
778
|
+
const { name, values } = this.optionsValue[optionId]
|
779
|
+
const availableOptions = this.availableOptionsValue[optionId] || this.currentOptionValues[optionId]?.map((option) => ({ id: option.id, name: option.name }))
|
780
|
+
|
781
|
+
const form = this.optionFormTemplate(name, values, optionId, availableOptions)
|
782
|
+
|
783
|
+
option.replaceWith(form)
|
784
|
+
|
785
|
+
// Disable the option name in the select tag that is already picked
|
786
|
+
const optionContainer = this.optionsContainerTarget.querySelector(`#option-${optionId}`)
|
787
|
+
const optionNameSelect = optionContainer.querySelector('select[name="option_name"]')
|
788
|
+
const options = Array.from(optionNameSelect.options)
|
789
|
+
|
790
|
+
const alreadySelectedOptions = Object.keys(this.optionsValue).filter((k) => this.optionsValue[k] !== null)
|
791
|
+
const optionsToDisable = options.filter((option) => option.text != name && alreadySelectedOptions.includes(option.value))
|
792
|
+
|
793
|
+
optionsToDisable.forEach((option) => option.disabled = true)
|
794
|
+
}
|
795
|
+
|
796
|
+
saveOption(event) {
|
797
|
+
let { optionId } = event.params
|
798
|
+
optionId = String(optionId)
|
799
|
+
|
800
|
+
const option = this.optionsContainerTarget.querySelector(`#option-${optionId}`)
|
801
|
+
const optionForm = option.closest('[data-slot="optionForm"]')
|
802
|
+
const optionNameSelect = option.querySelector('select[name="option_name"]')
|
803
|
+
const optionName = optionNameSelect.options[optionNameSelect.selectedIndex].text
|
804
|
+
const newId = String(optionNameSelect.value)
|
805
|
+
|
806
|
+
if ((newId != optionId && this.optionsValue[newId]) || !optionName.length) {
|
807
|
+
return
|
808
|
+
}
|
809
|
+
|
810
|
+
let color = false
|
811
|
+
let position = this.optionsValue[optionId].position
|
812
|
+
let newOptionsPositions = {}
|
813
|
+
|
814
|
+
const optionValues = option.querySelector('[data-slot="optionValuesSelectContainer"]').values()
|
815
|
+
|
816
|
+
if (optionValues.length === 0) {
|
817
|
+
return
|
818
|
+
}
|
819
|
+
|
820
|
+
const template = this.optionTemplate(optionName, optionValues, newId, color)
|
821
|
+
|
822
|
+
if (color) {
|
823
|
+
this.optionsContainerTarget.prepend(template)
|
824
|
+
optionForm.remove()
|
825
|
+
} else {
|
826
|
+
optionForm.replaceWith(template)
|
827
|
+
}
|
828
|
+
|
829
|
+
const newOptions = {
|
830
|
+
...this.optionsValue,
|
831
|
+
...newOptionsPositions,
|
832
|
+
[newId]: {
|
833
|
+
...this.optionsValue[optionId],
|
834
|
+
name: optionName,
|
835
|
+
values: optionValues,
|
836
|
+
position: position
|
837
|
+
}
|
838
|
+
}
|
839
|
+
if (optionId != newId) {
|
840
|
+
delete newOptions[optionId]
|
841
|
+
}
|
842
|
+
|
843
|
+
this.optionsValue = newOptions
|
844
|
+
}
|
845
|
+
|
846
|
+
showNewOptionForm(event) {
|
847
|
+
event.preventDefault()
|
848
|
+
this.newOptionFormTarget.classList.remove('d-none')
|
849
|
+
this.newOptionButtonTarget.classList.add('d-none')
|
850
|
+
this.refreshOptionNameSelect()
|
851
|
+
}
|
852
|
+
|
853
|
+
optionTemplate(name, values, id, color = false) {
|
854
|
+
const template = this.optionTemplateTarget.content.cloneNode(true)
|
855
|
+
template.querySelectorAll('[data-variants-form-option-id-param]').forEach((el) => {
|
856
|
+
el.dataset.variantsFormOptionIdParam = id
|
857
|
+
})
|
858
|
+
const optionName = template.querySelector('[data-slot="optionName"]')
|
859
|
+
const optionValuesTemplates = this.optionValueTemplate(values)
|
860
|
+
const optionValuesContainer = template.querySelector('[data-slot="optionValuesContainer"]')
|
861
|
+
optionValuesTemplates.forEach((optionValueTemplate) => {
|
862
|
+
optionValuesContainer.appendChild(optionValueTemplate)
|
863
|
+
})
|
864
|
+
const mainContainer = template.querySelector('[data-variants-form-target="option"]')
|
865
|
+
mainContainer.id = `option-${id}`
|
866
|
+
|
867
|
+
optionName.textContent = name
|
868
|
+
if (color) {
|
869
|
+
mainContainer.classList.add('color-option')
|
870
|
+
mainContainer.querySelector('.draggable').disabled = true
|
871
|
+
}
|
872
|
+
return template
|
873
|
+
}
|
874
|
+
|
875
|
+
discardOption(event) {
|
876
|
+
let { optionId } = event.params
|
877
|
+
optionId = String(optionId)
|
878
|
+
|
879
|
+
const option = this.optionsContainerTarget.querySelector(`#option-${optionId}`)
|
880
|
+
option.remove()
|
881
|
+
this.optionsValue = { ...this.optionsValue, [optionId]: null }
|
882
|
+
this.refreshParentInputs()
|
883
|
+
}
|
884
|
+
|
885
|
+
optionFormTemplate(optionName, optionValues, id, availableOptions) {
|
886
|
+
const template = this.optionFormTemplateTarget.content.cloneNode(true)
|
887
|
+
|
888
|
+
const optionNameSelect = template.querySelector('select[name="option_name"]')
|
889
|
+
|
890
|
+
let optionExists = false
|
891
|
+
// If options includes the optionName, set it as selected
|
892
|
+
optionNameSelect.querySelectorAll('option').forEach((option) => {
|
893
|
+
if (String(option.value) === id) {
|
894
|
+
option.selected = true
|
895
|
+
optionExists = true
|
896
|
+
}
|
897
|
+
})
|
898
|
+
// Otherwise, create a new option, and select it
|
899
|
+
if (!optionExists) {
|
900
|
+
const newOption = document.createElement('option')
|
901
|
+
newOption.text = optionName
|
902
|
+
newOption.value = id
|
903
|
+
newOption.selected = true
|
904
|
+
optionNameSelect.appendChild(newOption)
|
905
|
+
}
|
906
|
+
|
907
|
+
const optionValuesSelectContainer = template.querySelector('[data-slot="optionValuesSelectContainer"]')
|
908
|
+
const tomSelectOptionValues = optionValues.map((optionValue) => {
|
909
|
+
return {
|
910
|
+
id: availableOptions.find((availableOption) => availableOption.name === optionValue)?.id,
|
911
|
+
name: optionValue
|
912
|
+
}
|
913
|
+
})
|
914
|
+
|
915
|
+
optionValuesSelectContainer.setAttribute('data-multi-tom-select-preloaded-options-value', JSON.stringify(availableOptions))
|
916
|
+
optionValuesSelectContainer.setAttribute('data-multi-tom-select-preloaded-values-value', JSON.stringify(tomSelectOptionValues))
|
917
|
+
|
918
|
+
template.querySelectorAll('[data-variants-form-option-id-param]').forEach((el) => {
|
919
|
+
el.dataset.variantsFormOptionIdParam = id
|
920
|
+
})
|
921
|
+
|
922
|
+
const mainContainer = template.querySelector('[data-slot="optionForm"]')
|
923
|
+
mainContainer.id = `option-${id}`
|
924
|
+
|
925
|
+
return template
|
926
|
+
}
|
927
|
+
|
928
|
+
optionValueTemplate(values) {
|
929
|
+
const templates = []
|
930
|
+
|
931
|
+
values.forEach((value) => {
|
932
|
+
const template = this.optionValueTemplateTarget.content.cloneNode(true)
|
933
|
+
const optionValueNameEl = template.querySelector('[data-slot="optionValueName"]')
|
934
|
+
optionValueNameEl.textContent = value
|
935
|
+
optionValueNameEl.dataset.name = value
|
936
|
+
|
937
|
+
templates.push(template)
|
938
|
+
})
|
939
|
+
|
940
|
+
return templates
|
941
|
+
}
|
942
|
+
|
943
|
+
refreshOptionNameSelect() {
|
944
|
+
const alreadySelectedOptions = Object.keys(this.optionsValue).filter((k) => this.optionsValue[k] !== null)
|
945
|
+
|
946
|
+
Array.from(this.newOptionNameInputTarget.options).forEach((option) => {
|
947
|
+
const tomSelect = this.newOptionNameInputTarget.tomselect
|
948
|
+
if (!tomSelect) return
|
949
|
+
|
950
|
+
const tomselectOption = tomSelect.getOption(option.value)
|
951
|
+
if (!tomselectOption) return
|
952
|
+
|
953
|
+
const alreadySelected = alreadySelectedOptions.includes(option.value)
|
954
|
+
tomselectOption.ariaDisabled = alreadySelected
|
955
|
+
|
956
|
+
if (alreadySelected) {
|
957
|
+
tomselectOption.removeAttribute('data-selectable')
|
958
|
+
} else {
|
959
|
+
tomselectOption.setAttribute('data-selectable', '')
|
960
|
+
}
|
961
|
+
|
962
|
+
tomselectOption.disabled = alreadySelected
|
963
|
+
})
|
964
|
+
|
965
|
+
const optionNameTomSelect = this.newOptionNameInputTarget.tomselect
|
966
|
+
|
967
|
+
if (optionNameTomSelect) {
|
968
|
+
optionNameTomSelect.sync()
|
969
|
+
optionNameTomSelect.refreshOptions(false)
|
970
|
+
}
|
971
|
+
}
|
972
|
+
|
973
|
+
generateVariants(optionsValue) {
|
974
|
+
const options = Object.values(optionsValue)
|
975
|
+
.filter(Boolean)
|
976
|
+
.sort((a, b) => a.position - b.position)
|
977
|
+
|
978
|
+
if (options.length === 0) {
|
979
|
+
return []
|
980
|
+
}
|
981
|
+
|
982
|
+
const optionValues = options.map((option) => option.values)
|
983
|
+
const optionNames = options.map((option) => option.name)
|
984
|
+
|
985
|
+
const cartesianProduct = this.cartesianProduct(optionValues)
|
986
|
+
|
987
|
+
return cartesianProduct.map((variant) => {
|
988
|
+
variant = Array.isArray(variant) ? variant : [variant]
|
989
|
+
const variantObj = variant.reduce((acc, value, index) => {
|
990
|
+
acc[options[index].name] = value
|
991
|
+
return acc
|
992
|
+
}, {})
|
993
|
+
variantObj.internalName = this.calculateVariantName(variantObj, optionNames, optionNames.length - 1).internalName
|
994
|
+
return variantObj
|
995
|
+
})
|
996
|
+
}
|
997
|
+
|
998
|
+
cartesianProduct(arr) {
|
999
|
+
return arr.reduce((a, b) => a.flatMap((d) => b.map((e) => [d, e].flat())))
|
1000
|
+
}
|
1001
|
+
|
1002
|
+
stockItemForVariant(variantName, stockLocationId) {
|
1003
|
+
const existingStock = this.stockValue[variantName]?.[String(stockLocationId)]
|
1004
|
+
if (existingStock) return existingStock
|
1005
|
+
|
1006
|
+
return { count_on_hand: 0, backorderable: false, id: null }
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
updateStockItemForVariant(variantName, newStockItem, stockLocationId) {
|
1010
|
+
const existingStockItem = this.stockItemForVariant(variantName, stockLocationId)
|
1011
|
+
this.stockValue = {
|
1012
|
+
...this.stockValue,
|
1013
|
+
[variantName]: {
|
1014
|
+
...this.stockValue[variantName],
|
1015
|
+
[stockLocationId]: {
|
1016
|
+
...existingStockItem,
|
1017
|
+
...newStockItem
|
1018
|
+
}
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
priceForVariant(variantName, currency) {
|
1024
|
+
const existingPrice = this.pricesValue[variantName]?.[currency.toLowerCase()]
|
1025
|
+
if (existingPrice) {
|
1026
|
+
return {
|
1027
|
+
...existingPrice,
|
1028
|
+
amount: existingPrice.amount ? parseFloat(existingPrice.amount) : existingPrice.amount
|
1029
|
+
}
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
return { amount: null, id: null }
|
1033
|
+
}
|
1034
|
+
|
1035
|
+
updatePriceForVariant(variantName, newPrice, currency) {
|
1036
|
+
const existingPrice = this.priceForVariant(variantName, currency)
|
1037
|
+
this.pricesValue = {
|
1038
|
+
...this.pricesValue,
|
1039
|
+
[variantName]: {
|
1040
|
+
...this.pricesValue[variantName],
|
1041
|
+
[currency.toLowerCase()]: {
|
1042
|
+
...existingPrice,
|
1043
|
+
amount: parseFloat(newPrice)
|
1044
|
+
}
|
1045
|
+
}
|
1046
|
+
}
|
1047
|
+
}
|
1048
|
+
}
|